@semaphore-protocol/identity 0.1.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,9 +18,6 @@
18
18
  <a href="https://npmjs.org/package/@semaphore-protocol/identity">
19
19
  <img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/identity.svg?style=flat-square" />
20
20
  </a>
21
- <a href="https://bundlephobia.com/package/@semaphore-protocol/identity">
22
- <img alt="npm bundle size (scoped)" src="https://img.shields.io/bundlephobia/minzip/@semaphore-protocol/identity" />
23
- </a>
24
21
  <a href="https://eslint.org/">
25
22
  <img alt="Linter eslint" src="https://img.shields.io/badge/linter-eslint-8080f2?style=flat-square&logo=eslint" />
26
23
  </a>
@@ -61,37 +58,35 @@ yarn add @semaphore-protocol/identity
61
58
 
62
59
  ## 📜 Usage
63
60
 
64
- ### Creating an identity with a random strategy:
61
+ \# **new Identity**(identityOrMessage?: _string_): _Identity_
65
62
 
66
63
  ```typescript
67
64
  import { Identity } from "@semaphore-protocol/identity"
68
- // const { Identity } = require("@semaphore-protocol/identity") // with commonJS
69
65
 
70
- const identity = new Identity()
66
+ // Trapdoor and nullifier are generated randomly.
67
+ const identity1 = new Identity()
71
68
 
72
- const trapdoor = identity.getTrapdoor()
73
- const nullifier = identity.getNullifier()
74
- const secret = identity.getSecret()
75
- const multipartSecret = identity.getMultipartSecret()
69
+ // Trapdoor and nullifier are generated deterministically from a secret message.
70
+ const identity2 = new Identity("secret-message")
76
71
 
77
- const identityCommitment = identity.genIdentityCommitment()
72
+ // Trapdoor and nullifier are generated from an existing identity.
73
+ const identity3 = new Identity(identity1.toString())
78
74
  ```
79
75
 
80
- ### Creating an identity with a message strategy:
76
+ \# **getTrapdoor**(): _bigint_
81
77
 
82
78
  ```typescript
83
- import { Identity, Strategy } from "@semaphore-protocol/identity"
84
-
85
- const identity = new Identity(Strategy.MESSAGE, "message")
79
+ const trapdoor = identity.getTrapdoor()
86
80
  ```
87
81
 
88
- ### Creating an identity with a serialized strategy:
82
+ \# **getNullifier**(): _bigint_
89
83
 
90
84
  ```typescript
91
- import { Identity, Strategy } from "@semaphore-protocol/identity"
85
+ const nullifier = identity.getNullifier()
86
+ ```
92
87
 
93
- const identity = new Identity()
94
- const serializedIdentity = identity.serializeIdentity()
88
+ \# **generateCommitment**(): _bigint_
95
89
 
96
- const identity2 = new Identity(Strategy.SERIALIZED, serializedIdentity)
90
+ ```typescript
91
+ const commitment = identity.generateCommitment()
97
92
  ```
package/dist/index.mjs CHANGED
@@ -1,15 +1,22 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/identity
3
- * @version 0.1.0
3
+ * @version 0.2.2
4
4
  * @file A library for managing Semaphore identities.
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
7
- * @see [Github]{@link https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/proof}
7
+ * @see [Github]{@link https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/proof}
8
8
  */
9
9
  import { BigNumber } from '@ethersproject/bignumber';
10
10
  import { poseidon } from 'circomlibjs';
11
11
  import { randomBytes } from '@ethersproject/random';
12
- import _sha256 from 'crypto-js/sha256';
12
+ import { sha256 as sha256$1 } from '@ethersproject/sha2';
13
+ import { toUtf8Bytes } from '@ethersproject/strings';
14
+
15
+ function checkParameter(value, name, type) {
16
+ if (typeof value !== type) {
17
+ throw new TypeError("Parameter '".concat(name, "' is not a ").concat(type));
18
+ }
19
+ }
13
20
 
14
21
  /**
15
22
  * Returns an hexadecimal sha256 hash of the message passed as parameter.
@@ -17,8 +24,8 @@ import _sha256 from 'crypto-js/sha256';
17
24
  * @returns The hexadecimal hash of the message.
18
25
  */
19
26
  function sha256(message) {
20
- var hash = _sha256(message);
21
- return hash.toString();
27
+ var hash = sha256$1(toUtf8Bytes(message));
28
+ return hash;
22
29
  }
23
30
  /**
24
31
  * Generates a random big number.
@@ -28,119 +35,73 @@ function sha256(message) {
28
35
  function genRandomNumber(numberOfBytes) {
29
36
  if (numberOfBytes === void 0) { numberOfBytes = 31; }
30
37
  return BigNumber.from(randomBytes(numberOfBytes)).toBigInt();
38
+ }
39
+ /**
40
+ * Checks if a string is a JSON.
41
+ * @param jsonString The JSON string.
42
+ * @returns True or false.
43
+ */
44
+ function isJsonArray(jsonString) {
45
+ try {
46
+ return Array.isArray(JSON.parse(jsonString));
47
+ }
48
+ catch (error) {
49
+ return false;
50
+ }
31
51
  }
32
52
 
33
- // The strategy used to generate the Identity.
34
- var Strategy;
35
- (function (Strategy) {
36
- Strategy[Strategy["RANDOM"] = 0] = "RANDOM";
37
- Strategy[Strategy["MESSAGE"] = 1] = "MESSAGE";
38
- Strategy[Strategy["SERIALIZED"] = 2] = "SERIALIZED"; // Identity parameters are passed from outside.
39
- })(Strategy || (Strategy = {}));
40
53
  var Identity = /** @class */ (function () {
41
54
  /**
42
55
  * Initializes the class attributes based on the strategy passed as parameter.
43
- * @param strategy The strategy for identity generation.
44
- * @param metadata Additional data needed to create identity for given strategy.
56
+ * @param identityOrMessage Additional data needed to create identity for given strategy.
45
57
  */
46
- function Identity(strategy, metadata) {
47
- if (strategy === void 0) { strategy = Strategy.RANDOM; }
48
- this._secret = [];
49
- switch (strategy) {
50
- case Strategy.RANDOM: {
51
- this._identityTrapdoor = genRandomNumber();
52
- this._identityNullifier = genRandomNumber();
53
- this._secret = [this._identityNullifier, this._identityTrapdoor];
54
- break;
55
- }
56
- case Strategy.MESSAGE: {
57
- if (!metadata) {
58
- throw new Error("The message is not defined");
59
- }
60
- if (typeof metadata !== "string") {
61
- throw new Error("The message is not a string");
62
- }
63
- var messageHash = sha256(metadata);
64
- this._identityTrapdoor = BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_trapdoor")))).toBigInt();
65
- this._identityNullifier = BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_nullifier")))).toBigInt();
66
- this._secret = [this._identityNullifier, this._identityTrapdoor];
67
- break;
68
- }
69
- case Strategy.SERIALIZED: {
70
- if (!metadata) {
71
- throw new Error("The serialized identity is not defined");
72
- }
73
- if (typeof metadata === "string") {
74
- try {
75
- metadata = JSON.parse(metadata);
76
- }
77
- catch (error) {
78
- throw new Error("The serialized identity cannot be parsed");
79
- }
80
- }
81
- if (!("identityNullifier" in metadata) ||
82
- !("identityTrapdoor" in metadata) ||
83
- !("secret" in metadata)) {
84
- throw new Error("The serialized identity does not contain the right parameter");
85
- }
86
- var identityNullifier = metadata.identityNullifier, identityTrapdoor = metadata.identityTrapdoor, secret = metadata.secret;
87
- this._identityNullifier = BigNumber.from("0x".concat(identityNullifier)).toBigInt();
88
- this._identityTrapdoor = BigNumber.from("0x".concat(identityTrapdoor)).toBigInt();
89
- this._secret = secret.map(function (item) { return BigNumber.from("0x".concat(item)).toBigInt(); });
90
- break;
91
- }
92
- default:
93
- throw new Error("The provided strategy is not supported");
58
+ function Identity(identityOrMessage) {
59
+ if (identityOrMessage === undefined) {
60
+ this._trapdoor = genRandomNumber();
61
+ this._nullifier = genRandomNumber();
62
+ return;
94
63
  }
64
+ checkParameter(identityOrMessage, "identityOrMessage", "string");
65
+ if (!isJsonArray(identityOrMessage)) {
66
+ var messageHash = sha256(identityOrMessage).slice(2);
67
+ this._trapdoor = BigNumber.from(sha256("".concat(messageHash, "identity_trapdoor"))).toBigInt();
68
+ this._nullifier = BigNumber.from(sha256("".concat(messageHash, "identity_nullifier"))).toBigInt();
69
+ return;
70
+ }
71
+ var _a = JSON.parse(identityOrMessage), trapdoor = _a[0], nullifier = _a[1];
72
+ this._trapdoor = BigNumber.from("0x".concat(trapdoor)).toBigInt();
73
+ this._nullifier = BigNumber.from("0x".concat(nullifier)).toBigInt();
95
74
  }
96
75
  /**
97
76
  * Returns the identity trapdoor.
98
77
  * @returns The identity trapdoor.
99
78
  */
100
79
  Identity.prototype.getTrapdoor = function () {
101
- return this._identityTrapdoor;
80
+ return this._trapdoor;
102
81
  };
103
82
  /**
104
83
  * Returns the identity nullifier.
105
84
  * @returns The identity nullifier.
106
85
  */
107
86
  Identity.prototype.getNullifier = function () {
108
- return this._identityNullifier;
109
- };
110
- /**
111
- * Returns the secret.
112
- * @returns The secret.
113
- */
114
- Identity.prototype.getSecret = function () {
115
- return this._secret;
116
- };
117
- /**
118
- * Returns the Poseidon hash of the secret.
119
- * @returns The hash of the secret.
120
- */
121
- Identity.prototype.getSecretHash = function () {
122
- return poseidon(this._secret);
87
+ return this._nullifier;
123
88
  };
124
89
  /**
125
- * Generates the identity commitment from the secret.
90
+ * Generates the identity commitment from trapdoor and nullifier.
126
91
  * @returns identity commitment
127
92
  */
128
- Identity.prototype.genIdentityCommitment = function () {
129
- return poseidon([this.getSecretHash()]);
93
+ Identity.prototype.generateCommitment = function () {
94
+ return poseidon([poseidon([this._nullifier, this._trapdoor])]);
130
95
  };
131
96
  /**
132
- * Serializes the class attributes and returns a stringified object.
133
- * @returns The stringified serialized identity.
97
+ * Returns a JSON string with trapdoor and nullifier. It can be used
98
+ * to export the identity and reuse it later.
99
+ * @returns The string representation of the identity.
134
100
  */
135
- Identity.prototype.serializeIdentity = function () {
136
- var data = {
137
- identityNullifier: this._identityNullifier.toString(16),
138
- identityTrapdoor: this._identityTrapdoor.toString(16),
139
- secret: this._secret.map(function (item) { return item.toString(16); })
140
- };
141
- return JSON.stringify(data);
101
+ Identity.prototype.toString = function () {
102
+ return JSON.stringify([this._trapdoor.toString(16), this._nullifier.toString(16)]);
142
103
  };
143
104
  return Identity;
144
105
  }());
145
106
 
146
- export { Identity, Strategy };
107
+ export { Identity };
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/identity
3
- * @version 0.1.0
3
+ * @version 0.2.2
4
4
  * @file A library for managing Semaphore identities.
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
7
- * @see [Github]{@link https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/proof}
7
+ * @see [Github]{@link https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/proof}
8
8
  */
9
9
  'use strict';
10
10
 
@@ -13,11 +13,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
13
13
  var bignumber = require('@ethersproject/bignumber');
14
14
  var circomlibjs = require('circomlibjs');
15
15
  var random = require('@ethersproject/random');
16
- var _sha256 = require('crypto-js/sha256');
16
+ var sha2 = require('@ethersproject/sha2');
17
+ var strings = require('@ethersproject/strings');
17
18
 
18
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
-
20
- var _sha256__default = /*#__PURE__*/_interopDefaultLegacy(_sha256);
19
+ function checkParameter(value, name, type) {
20
+ if (typeof value !== type) {
21
+ throw new TypeError("Parameter '".concat(name, "' is not a ").concat(type));
22
+ }
23
+ }
21
24
 
22
25
  /**
23
26
  * Returns an hexadecimal sha256 hash of the message passed as parameter.
@@ -25,8 +28,8 @@ var _sha256__default = /*#__PURE__*/_interopDefaultLegacy(_sha256);
25
28
  * @returns The hexadecimal hash of the message.
26
29
  */
27
30
  function sha256(message) {
28
- var hash = _sha256__default["default"](message);
29
- return hash.toString();
31
+ var hash = sha2.sha256(strings.toUtf8Bytes(message));
32
+ return hash;
30
33
  }
31
34
  /**
32
35
  * Generates a random big number.
@@ -36,117 +39,71 @@ function sha256(message) {
36
39
  function genRandomNumber(numberOfBytes) {
37
40
  if (numberOfBytes === void 0) { numberOfBytes = 31; }
38
41
  return bignumber.BigNumber.from(random.randomBytes(numberOfBytes)).toBigInt();
42
+ }
43
+ /**
44
+ * Checks if a string is a JSON.
45
+ * @param jsonString The JSON string.
46
+ * @returns True or false.
47
+ */
48
+ function isJsonArray(jsonString) {
49
+ try {
50
+ return Array.isArray(JSON.parse(jsonString));
51
+ }
52
+ catch (error) {
53
+ return false;
54
+ }
39
55
  }
40
56
 
41
- // The strategy used to generate the Identity.
42
- exports.Strategy = void 0;
43
- (function (Strategy) {
44
- Strategy[Strategy["RANDOM"] = 0] = "RANDOM";
45
- Strategy[Strategy["MESSAGE"] = 1] = "MESSAGE";
46
- Strategy[Strategy["SERIALIZED"] = 2] = "SERIALIZED"; // Identity parameters are passed from outside.
47
- })(exports.Strategy || (exports.Strategy = {}));
48
57
  var Identity = /** @class */ (function () {
49
58
  /**
50
59
  * Initializes the class attributes based on the strategy passed as parameter.
51
- * @param strategy The strategy for identity generation.
52
- * @param metadata Additional data needed to create identity for given strategy.
60
+ * @param identityOrMessage Additional data needed to create identity for given strategy.
53
61
  */
54
- function Identity(strategy, metadata) {
55
- if (strategy === void 0) { strategy = exports.Strategy.RANDOM; }
56
- this._secret = [];
57
- switch (strategy) {
58
- case exports.Strategy.RANDOM: {
59
- this._identityTrapdoor = genRandomNumber();
60
- this._identityNullifier = genRandomNumber();
61
- this._secret = [this._identityNullifier, this._identityTrapdoor];
62
- break;
63
- }
64
- case exports.Strategy.MESSAGE: {
65
- if (!metadata) {
66
- throw new Error("The message is not defined");
67
- }
68
- if (typeof metadata !== "string") {
69
- throw new Error("The message is not a string");
70
- }
71
- var messageHash = sha256(metadata);
72
- this._identityTrapdoor = bignumber.BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_trapdoor")))).toBigInt();
73
- this._identityNullifier = bignumber.BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_nullifier")))).toBigInt();
74
- this._secret = [this._identityNullifier, this._identityTrapdoor];
75
- break;
76
- }
77
- case exports.Strategy.SERIALIZED: {
78
- if (!metadata) {
79
- throw new Error("The serialized identity is not defined");
80
- }
81
- if (typeof metadata === "string") {
82
- try {
83
- metadata = JSON.parse(metadata);
84
- }
85
- catch (error) {
86
- throw new Error("The serialized identity cannot be parsed");
87
- }
88
- }
89
- if (!("identityNullifier" in metadata) ||
90
- !("identityTrapdoor" in metadata) ||
91
- !("secret" in metadata)) {
92
- throw new Error("The serialized identity does not contain the right parameter");
93
- }
94
- var identityNullifier = metadata.identityNullifier, identityTrapdoor = metadata.identityTrapdoor, secret = metadata.secret;
95
- this._identityNullifier = bignumber.BigNumber.from("0x".concat(identityNullifier)).toBigInt();
96
- this._identityTrapdoor = bignumber.BigNumber.from("0x".concat(identityTrapdoor)).toBigInt();
97
- this._secret = secret.map(function (item) { return bignumber.BigNumber.from("0x".concat(item)).toBigInt(); });
98
- break;
99
- }
100
- default:
101
- throw new Error("The provided strategy is not supported");
62
+ function Identity(identityOrMessage) {
63
+ if (identityOrMessage === undefined) {
64
+ this._trapdoor = genRandomNumber();
65
+ this._nullifier = genRandomNumber();
66
+ return;
102
67
  }
68
+ checkParameter(identityOrMessage, "identityOrMessage", "string");
69
+ if (!isJsonArray(identityOrMessage)) {
70
+ var messageHash = sha256(identityOrMessage).slice(2);
71
+ this._trapdoor = bignumber.BigNumber.from(sha256("".concat(messageHash, "identity_trapdoor"))).toBigInt();
72
+ this._nullifier = bignumber.BigNumber.from(sha256("".concat(messageHash, "identity_nullifier"))).toBigInt();
73
+ return;
74
+ }
75
+ var _a = JSON.parse(identityOrMessage), trapdoor = _a[0], nullifier = _a[1];
76
+ this._trapdoor = bignumber.BigNumber.from("0x".concat(trapdoor)).toBigInt();
77
+ this._nullifier = bignumber.BigNumber.from("0x".concat(nullifier)).toBigInt();
103
78
  }
104
79
  /**
105
80
  * Returns the identity trapdoor.
106
81
  * @returns The identity trapdoor.
107
82
  */
108
83
  Identity.prototype.getTrapdoor = function () {
109
- return this._identityTrapdoor;
84
+ return this._trapdoor;
110
85
  };
111
86
  /**
112
87
  * Returns the identity nullifier.
113
88
  * @returns The identity nullifier.
114
89
  */
115
90
  Identity.prototype.getNullifier = function () {
116
- return this._identityNullifier;
117
- };
118
- /**
119
- * Returns the secret.
120
- * @returns The secret.
121
- */
122
- Identity.prototype.getSecret = function () {
123
- return this._secret;
124
- };
125
- /**
126
- * Returns the Poseidon hash of the secret.
127
- * @returns The hash of the secret.
128
- */
129
- Identity.prototype.getSecretHash = function () {
130
- return circomlibjs.poseidon(this._secret);
91
+ return this._nullifier;
131
92
  };
132
93
  /**
133
- * Generates the identity commitment from the secret.
94
+ * Generates the identity commitment from trapdoor and nullifier.
134
95
  * @returns identity commitment
135
96
  */
136
- Identity.prototype.genIdentityCommitment = function () {
137
- return circomlibjs.poseidon([this.getSecretHash()]);
97
+ Identity.prototype.generateCommitment = function () {
98
+ return circomlibjs.poseidon([circomlibjs.poseidon([this._nullifier, this._trapdoor])]);
138
99
  };
139
100
  /**
140
- * Serializes the class attributes and returns a stringified object.
141
- * @returns The stringified serialized identity.
101
+ * Returns a JSON string with trapdoor and nullifier. It can be used
102
+ * to export the identity and reuse it later.
103
+ * @returns The string representation of the identity.
142
104
  */
143
- Identity.prototype.serializeIdentity = function () {
144
- var data = {
145
- identityNullifier: this._identityNullifier.toString(16),
146
- identityTrapdoor: this._identityTrapdoor.toString(16),
147
- secret: this._secret.map(function (item) { return item.toString(16); })
148
- };
149
- return JSON.stringify(data);
105
+ Identity.prototype.toString = function () {
106
+ return JSON.stringify([this._trapdoor.toString(16), this._nullifier.toString(16)]);
150
107
  };
151
108
  return Identity;
152
109
  }());
@@ -0,0 +1 @@
1
+ export default function checkParameter(value: any, name: string, type: string): void;
@@ -1,19 +1,11 @@
1
- import { SerializedIdentity } from "./types";
2
- export declare enum Strategy {
3
- RANDOM = 0,
4
- MESSAGE = 1,
5
- SERIALIZED = 2
6
- }
7
1
  export default class Identity {
8
- private _identityTrapdoor;
9
- private _identityNullifier;
10
- private _secret;
2
+ private _trapdoor;
3
+ private _nullifier;
11
4
  /**
12
5
  * Initializes the class attributes based on the strategy passed as parameter.
13
- * @param strategy The strategy for identity generation.
14
- * @param metadata Additional data needed to create identity for given strategy.
6
+ * @param identityOrMessage Additional data needed to create identity for given strategy.
15
7
  */
16
- constructor(strategy?: Strategy, metadata?: string | SerializedIdentity);
8
+ constructor(identityOrMessage?: string);
17
9
  /**
18
10
  * Returns the identity trapdoor.
19
11
  * @returns The identity trapdoor.
@@ -25,23 +17,14 @@ export default class Identity {
25
17
  */
26
18
  getNullifier(): bigint;
27
19
  /**
28
- * Returns the secret.
29
- * @returns The secret.
30
- */
31
- getSecret(): bigint[];
32
- /**
33
- * Returns the Poseidon hash of the secret.
34
- * @returns The hash of the secret.
35
- */
36
- getSecretHash(): bigint;
37
- /**
38
- * Generates the identity commitment from the secret.
20
+ * Generates the identity commitment from trapdoor and nullifier.
39
21
  * @returns identity commitment
40
22
  */
41
- genIdentityCommitment(): bigint;
23
+ generateCommitment(): bigint;
42
24
  /**
43
- * Serializes the class attributes and returns a stringified object.
44
- * @returns The stringified serialized identity.
25
+ * Returns a JSON string with trapdoor and nullifier. It can be used
26
+ * to export the identity and reuse it later.
27
+ * @returns The string representation of the identity.
45
28
  */
46
- serializeIdentity(): string;
29
+ toString(): string;
47
30
  }
@@ -1,2 +1,2 @@
1
- import Identity, { Strategy } from "./identity";
2
- export { Identity, Strategy };
1
+ import Identity from "./identity";
2
+ export { Identity };
@@ -10,3 +10,9 @@ export declare function sha256(message: string): string;
10
10
  * @returns The generated random number.
11
11
  */
12
12
  export declare function genRandomNumber(numberOfBytes?: number): bigint;
13
+ /**
14
+ * Checks if a string is a JSON.
15
+ * @param jsonString The JSON string.
16
+ * @returns True or false.
17
+ */
18
+ export declare function isJsonArray(jsonString: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/identity",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "A library for managing Semaphore identities.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.node.js",
@@ -15,8 +15,8 @@
15
15
  "LICENSE",
16
16
  "README.md"
17
17
  ],
18
- "repository": "https://github.com/privacy-scaling-explorations/zk-kit",
19
- "homepage": "https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/proof",
18
+ "repository": "https://github.com/semaphore-protocol/semaphore.js",
19
+ "homepage": "https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/proof",
20
20
  "scripts": {
21
21
  "build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
22
22
  "build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
@@ -27,7 +27,6 @@
27
27
  "access": "public"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/crypto-js": "^4.1.1",
31
30
  "rollup-plugin-cleanup": "^3.2.1",
32
31
  "rollup-plugin-typescript2": "^0.31.2",
33
32
  "typedoc": "^0.22.11"
@@ -35,8 +34,8 @@
35
34
  "dependencies": {
36
35
  "@ethersproject/bignumber": "^5.5.0",
37
36
  "@ethersproject/random": "^5.5.1",
38
- "circomlibjs": "0.0.8",
39
- "crypto-js": "^4.1.1"
40
- },
41
- "gitHead": "6c1b469a4b5ffaac562f478fc2bbc78731734e81"
37
+ "@ethersproject/sha2": "^5.6.1",
38
+ "@ethersproject/strings": "^5.6.1",
39
+ "circomlibjs": "0.0.8"
40
+ }
42
41
  }
@@ -0,0 +1,5 @@
1
+ export default function checkParameter(value: any, name: string, type: string) {
2
+ if (typeof value !== type) {
3
+ throw new TypeError(`Parameter '${name}' is not a ${type}`)
4
+ }
5
+ }
@@ -1,92 +1,114 @@
1
- import Identity, { Strategy } from "./identity"
1
+ import { BigNumber } from "@ethersproject/bignumber"
2
+ import Identity from "./identity"
2
3
 
3
4
  describe("Identity", () => {
4
- describe("Create identity", () => {
5
- it("Should not create a identity if the strategy is wrong", () => {
6
- const fun = () => new Identity("wrong" as any)
5
+ describe("# Identity", () => {
6
+ it("Should not create a identity if the parameter is not valid", () => {
7
+ const fun1 = () => new Identity(13 as any)
8
+ const fun2 = () => new Identity(true as any)
9
+ const fun3 = () => new Identity((() => true) as any)
10
+
11
+ expect(fun1).toThrow("Parameter 'identityOrMessage' is not a string")
12
+ expect(fun2).toThrow("Parameter 'identityOrMessage' is not a string")
13
+ expect(fun3).toThrow("Parameter 'identityOrMessage' is not a string")
14
+ })
15
+
16
+ it("Should create random identities", () => {
17
+ const identity1 = new Identity()
18
+ const identity2 = new Identity()
7
19
 
8
- expect(fun).toThrow("strategy is not supported")
20
+ expect(identity1.getTrapdoor()).not.toBe(identity2.getTrapdoor())
21
+ expect(identity1.getNullifier()).not.toBe(identity2.getNullifier())
9
22
  })
10
23
 
11
- it("Should create a identity", () => {
12
- const identity = new Identity()
24
+ it("Should create deterministic identities from a message", () => {
25
+ const identity1 = new Identity("message")
26
+ const identity2 = new Identity("message")
13
27
 
14
- expect(typeof identity).toBe("object")
28
+ expect(identity1.getTrapdoor()).toBe(identity2.getTrapdoor())
29
+ expect(identity1.getNullifier()).toBe(identity2.getNullifier())
15
30
  })
16
31
 
17
- it("Should not create a identity with a message strategy if there is no message", () => {
18
- const fun = () => new Identity(Strategy.MESSAGE)
32
+ it("Should create deterministic identities from number/boolean messages", () => {
33
+ const identity1 = new Identity("true")
34
+ const identity2 = new Identity("true")
35
+ const identity3 = new Identity("7")
36
+ const identity4 = new Identity("7")
19
37
 
20
- expect(fun).toThrow("The message is not defined")
38
+ expect(identity1.getTrapdoor()).toBe(identity2.getTrapdoor())
39
+ expect(identity1.getNullifier()).toBe(identity2.getNullifier())
40
+ expect(identity3.getTrapdoor()).toBe(identity4.getTrapdoor())
41
+ expect(identity3.getNullifier()).toBe(identity4.getNullifier())
21
42
  })
22
43
 
23
- it("Should not create a identity with a message strategy if the message is not a string", () => {
24
- const fun = () => new Identity(Strategy.MESSAGE, 1 as any)
44
+ it("Should not recreate an existing invalid identity", () => {
45
+ const fun = () => new Identity('[true, "01323"]')
25
46
 
26
- expect(fun).toThrow("The message is not a string")
47
+ expect(fun).toThrow("invalid BigNumber string")
27
48
  })
28
49
 
29
- it("Should create a identity with a message strategy", () => {
30
- const identity = new Identity(Strategy.MESSAGE, "message")
50
+ it("Should recreate an existing identity", () => {
51
+ const identity1 = new Identity("message")
52
+
53
+ const identity2 = new Identity(identity1.toString())
54
+
55
+ expect(identity1.getTrapdoor()).toBe(identity2.getTrapdoor())
56
+ expect(identity1.getNullifier()).toBe(identity2.getNullifier())
57
+ })
58
+ })
59
+
60
+ describe("# getTrapdoor", () => {
61
+ it("Should return the identity trapdoor", () => {
62
+ const identity = new Identity("message")
31
63
 
32
64
  const trapdoor = identity.getTrapdoor()
33
- const nullifier = identity.getNullifier()
34
- const identitySecret = identity.getSecret()
35
65
 
36
- expect(typeof identity).toBe("object")
37
66
  expect(trapdoor).toBe(
38
67
  BigInt("58952291509798197436757858062402199043831251943841934828591473955215726495831")
39
68
  )
69
+ })
70
+ })
71
+
72
+ describe("# getNullifier", () => {
73
+ it("Should return the identity nullifier", () => {
74
+ const identity = new Identity("message")
75
+
76
+ const nullifier = identity.getNullifier()
77
+
40
78
  expect(nullifier).toBe(
41
79
  BigInt("44673097405870585416457571638073245190425597599743560105244308998175651589997")
42
80
  )
43
- expect(identitySecret).toHaveLength(2)
44
- expect(typeof identitySecret).toBe("object")
45
81
  })
82
+ })
83
+
84
+ describe("# generateCommitment", () => {
85
+ it("Should generate an identity commitment", () => {
86
+ const identity = new Identity("message")
46
87
 
47
- it("Should generate an identity commitment secret", () => {
48
- const identity = new Identity(Strategy.MESSAGE, "message")
49
- const identityCommitment = identity.genIdentityCommitment()
88
+ const commitment = identity.generateCommitment()
50
89
 
51
- expect(identityCommitment).toBe(
90
+ expect(commitment).toBe(
52
91
  BigInt("1720349790382552497189398984241859233944354304766757200361065203741879866188")
53
92
  )
54
93
  })
94
+ })
55
95
 
56
- it("Should serialize an identity", () => {
57
- const identity = new Identity()
58
- const serialized = identity.serializeIdentity()
59
-
60
- expect(typeof serialized).toBe("string")
61
- })
62
-
63
- it("Should not create a identity with a serialized strategy if there is no serialize identity", () => {
64
- const fun = () => new Identity(Strategy.SERIALIZED)
65
-
66
- expect(fun).toThrow("serialized identity is not defined")
67
- })
96
+ describe("# toString", () => {
97
+ it("Should return a string", () => {
98
+ const identity = new Identity("message")
68
99
 
69
- it("Should not create a identity with a serialized strategy if the serialize identity cannot be parsed", () => {
70
- const fun = () => new Identity(Strategy.SERIALIZED, "{a}")
100
+ const identityString = identity.toString()
71
101
 
72
- expect(fun).toThrow("The serialized identity cannot be parsed")
102
+ expect(typeof identityString).toBe("string")
73
103
  })
74
104
 
75
- it("Should not create a identity with a serialized strategy if the serialize identity does not contain the right parameters", () => {
76
- const fun = () =>
77
- new Identity(Strategy.SERIALIZED, {
78
- identityTrapdoor: "234"
79
- } as any)
105
+ it("Should return a valid identity string", () => {
106
+ const identity = new Identity("message")
80
107
 
81
- expect(fun).toThrow("The serialized identity does not contain the right parameter")
82
- })
83
-
84
- it("Should create a identity with a serialized strategy", () => {
85
- const identity1 = new Identity()
86
- const serialized = identity1.serializeIdentity()
87
- const identity2 = new Identity(Strategy.SERIALIZED, serialized)
108
+ const [trapdoor, nullifier] = JSON.parse(identity.toString())
88
109
 
89
- expect(identity2).toStrictEqual(identity1)
110
+ expect(BigNumber.from(`0x${trapdoor}`).toBigInt()).toBe(identity.getTrapdoor())
111
+ expect(BigNumber.from(`0x${nullifier}`).toBigInt()).toBe(identity.getNullifier())
90
112
  })
91
113
  })
92
114
  })
package/src/identity.ts CHANGED
@@ -1,82 +1,39 @@
1
1
  import { BigNumber } from "@ethersproject/bignumber"
2
2
  import { poseidon } from "circomlibjs"
3
- import { SerializedIdentity } from "./types"
4
- import { genRandomNumber, sha256 } from "./utils"
5
-
6
- // The strategy used to generate the Identity.
7
- export enum Strategy {
8
- RANDOM, // Identity is generated randomly.
9
- MESSAGE, // Identity is generated from a message.
10
- SERIALIZED // Identity parameters are passed from outside.
11
- }
3
+ import checkParameter from "./checkParameter"
4
+ import { genRandomNumber, isJsonArray, sha256 } from "./utils"
12
5
 
13
6
  export default class Identity {
14
- private _identityTrapdoor: bigint
15
- private _identityNullifier: bigint
16
-
17
- private _secret: bigint[] = []
7
+ private _trapdoor: bigint
8
+ private _nullifier: bigint
18
9
 
19
10
  /**
20
11
  * Initializes the class attributes based on the strategy passed as parameter.
21
- * @param strategy The strategy for identity generation.
22
- * @param metadata Additional data needed to create identity for given strategy.
12
+ * @param identityOrMessage Additional data needed to create identity for given strategy.
23
13
  */
24
- constructor(strategy: Strategy = Strategy.RANDOM, metadata?: string | SerializedIdentity) {
25
- switch (strategy) {
26
- case Strategy.RANDOM: {
27
- this._identityTrapdoor = genRandomNumber()
28
- this._identityNullifier = genRandomNumber()
29
- this._secret = [this._identityNullifier, this._identityTrapdoor]
30
- break
31
- }
32
- case Strategy.MESSAGE: {
33
- if (!metadata) {
34
- throw new Error("The message is not defined")
35
- }
14
+ constructor(identityOrMessage?: string) {
15
+ if (identityOrMessage === undefined) {
16
+ this._trapdoor = genRandomNumber()
17
+ this._nullifier = genRandomNumber()
36
18
 
37
- if (typeof metadata !== "string") {
38
- throw new Error("The message is not a string")
39
- }
40
-
41
- const messageHash = sha256(metadata)
19
+ return
20
+ }
42
21
 
43
- this._identityTrapdoor = BigNumber.from(`0x${sha256(`${messageHash}identity_trapdoor`)}`).toBigInt()
44
- this._identityNullifier = BigNumber.from(`0x${sha256(`${messageHash}identity_nullifier`)}`).toBigInt()
45
- this._secret = [this._identityNullifier, this._identityTrapdoor]
46
- break
47
- }
48
- case Strategy.SERIALIZED: {
49
- if (!metadata) {
50
- throw new Error("The serialized identity is not defined")
51
- }
22
+ checkParameter(identityOrMessage, "identityOrMessage", "string")
52
23
 
53
- if (typeof metadata === "string") {
54
- try {
55
- metadata = JSON.parse(metadata) as SerializedIdentity
56
- } catch (error) {
57
- throw new Error("The serialized identity cannot be parsed")
58
- }
59
- }
24
+ if (!isJsonArray(identityOrMessage)) {
25
+ const messageHash = sha256(identityOrMessage).slice(2)
60
26
 
61
- if (
62
- !("identityNullifier" in metadata) ||
63
- !("identityTrapdoor" in metadata) ||
64
- !("secret" in metadata)
65
- ) {
66
- throw new Error("The serialized identity does not contain the right parameter")
67
- }
27
+ this._trapdoor = BigNumber.from(sha256(`${messageHash}identity_trapdoor`)).toBigInt()
28
+ this._nullifier = BigNumber.from(sha256(`${messageHash}identity_nullifier`)).toBigInt()
68
29
 
69
- const { identityNullifier, identityTrapdoor, secret } = metadata
30
+ return
31
+ }
70
32
 
71
- this._identityNullifier = BigNumber.from(`0x${identityNullifier}`).toBigInt()
72
- this._identityTrapdoor = BigNumber.from(`0x${identityTrapdoor}`).toBigInt()
73
- this._secret = secret.map((item) => BigNumber.from(`0x${item}`).toBigInt())
33
+ const [trapdoor, nullifier] = JSON.parse(identityOrMessage)
74
34
 
75
- break
76
- }
77
- default:
78
- throw new Error("The provided strategy is not supported")
79
- }
35
+ this._trapdoor = BigNumber.from(`0x${trapdoor}`).toBigInt()
36
+ this._nullifier = BigNumber.from(`0x${nullifier}`).toBigInt()
80
37
  }
81
38
 
82
39
  /**
@@ -84,7 +41,7 @@ export default class Identity {
84
41
  * @returns The identity trapdoor.
85
42
  */
86
43
  public getTrapdoor(): bigint {
87
- return this._identityTrapdoor
44
+ return this._trapdoor
88
45
  }
89
46
 
90
47
  /**
@@ -92,44 +49,23 @@ export default class Identity {
92
49
  * @returns The identity nullifier.
93
50
  */
94
51
  public getNullifier(): bigint {
95
- return this._identityNullifier
52
+ return this._nullifier
96
53
  }
97
54
 
98
55
  /**
99
- * Returns the secret.
100
- * @returns The secret.
101
- */
102
- public getSecret(): bigint[] {
103
- return this._secret
104
- }
105
-
106
- /**
107
- * Returns the Poseidon hash of the secret.
108
- * @returns The hash of the secret.
109
- */
110
- public getSecretHash(): bigint {
111
- return poseidon(this._secret)
112
- }
113
-
114
- /**
115
- * Generates the identity commitment from the secret.
56
+ * Generates the identity commitment from trapdoor and nullifier.
116
57
  * @returns identity commitment
117
58
  */
118
- public genIdentityCommitment(): bigint {
119
- return poseidon([this.getSecretHash()])
59
+ public generateCommitment(): bigint {
60
+ return poseidon([poseidon([this._nullifier, this._trapdoor])])
120
61
  }
121
62
 
122
63
  /**
123
- * Serializes the class attributes and returns a stringified object.
124
- * @returns The stringified serialized identity.
64
+ * Returns a JSON string with trapdoor and nullifier. It can be used
65
+ * to export the identity and reuse it later.
66
+ * @returns The string representation of the identity.
125
67
  */
126
- public serializeIdentity(): string {
127
- const data: SerializedIdentity = {
128
- identityNullifier: this._identityNullifier.toString(16),
129
- identityTrapdoor: this._identityTrapdoor.toString(16),
130
- secret: this._secret.map((item) => item.toString(16))
131
- }
132
-
133
- return JSON.stringify(data)
68
+ public toString(): string {
69
+ return JSON.stringify([this._trapdoor.toString(16), this._nullifier.toString(16)])
134
70
  }
135
71
  }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
- import Identity, { Strategy } from "./identity"
1
+ import Identity from "./identity"
2
2
 
3
- export { Identity, Strategy }
3
+ // eslint-disable-next-line import/prefer-default-export
4
+ export { Identity }
package/src/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BigNumber } from "@ethersproject/bignumber"
2
2
  import { randomBytes } from "@ethersproject/random"
3
- import _sha256 from "crypto-js/sha256"
3
+ import { sha256 as _sha256 } from "@ethersproject/sha2"
4
+ import { toUtf8Bytes } from "@ethersproject/strings"
4
5
 
5
6
  /**
6
7
  * Returns an hexadecimal sha256 hash of the message passed as parameter.
@@ -8,9 +9,9 @@ import _sha256 from "crypto-js/sha256"
8
9
  * @returns The hexadecimal hash of the message.
9
10
  */
10
11
  export function sha256(message: string): string {
11
- const hash = _sha256(message)
12
+ const hash = _sha256(toUtf8Bytes(message))
12
13
 
13
- return hash.toString()
14
+ return hash
14
15
  }
15
16
 
16
17
  /**
@@ -21,3 +22,16 @@ export function sha256(message: string): string {
21
22
  export function genRandomNumber(numberOfBytes = 31): bigint {
22
23
  return BigNumber.from(randomBytes(numberOfBytes)).toBigInt()
23
24
  }
25
+
26
+ /**
27
+ * Checks if a string is a JSON.
28
+ * @param jsonString The JSON string.
29
+ * @returns True or false.
30
+ */
31
+ export function isJsonArray(jsonString: string) {
32
+ try {
33
+ return Array.isArray(JSON.parse(jsonString))
34
+ } catch (error) {
35
+ return false
36
+ }
37
+ }
@@ -1,5 +0,0 @@
1
- export declare type SerializedIdentity = {
2
- identityNullifier: string;
3
- identityTrapdoor: string;
4
- secret: string[];
5
- };
@@ -1,5 +0,0 @@
1
- export type SerializedIdentity = {
2
- identityNullifier: string
3
- identityTrapdoor: string
4
- secret: string[]
5
- }