@semaphore-protocol/identity 0.1.0 → 0.2.0

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,16 +1,22 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/identity
3
- * @version 0.1.0
3
+ * @version 0.2.0
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
12
  import _sha256 from 'crypto-js/sha256';
13
13
 
14
+ function checkParameter(value, name, type) {
15
+ if (typeof value !== type) {
16
+ throw new TypeError("Parameter '".concat(name, "' is not a ").concat(type));
17
+ }
18
+ }
19
+
14
20
  /**
15
21
  * Returns an hexadecimal sha256 hash of the message passed as parameter.
16
22
  * @param message The string to hash.
@@ -28,119 +34,74 @@ function sha256(message) {
28
34
  function genRandomNumber(numberOfBytes) {
29
35
  if (numberOfBytes === void 0) { numberOfBytes = 31; }
30
36
  return BigNumber.from(randomBytes(numberOfBytes)).toBigInt();
37
+ }
38
+ /**
39
+ * Checks if a string is a JSON.
40
+ * @param jsonString The JSON string.
41
+ * @returns True or false.
42
+ */
43
+ function isJson(jsonString) {
44
+ try {
45
+ JSON.parse(jsonString);
46
+ }
47
+ catch (error) {
48
+ return false;
49
+ }
50
+ return true;
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 (!isJson(identityOrMessage)) {
66
+ var messageHash = sha256(identityOrMessage);
67
+ this._trapdoor = BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_trapdoor")))).toBigInt();
68
+ this._nullifier = BigNumber.from("0x".concat(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.0
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
 
@@ -19,6 +19,12 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
19
19
 
20
20
  var _sha256__default = /*#__PURE__*/_interopDefaultLegacy(_sha256);
21
21
 
22
+ function checkParameter(value, name, type) {
23
+ if (typeof value !== type) {
24
+ throw new TypeError("Parameter '".concat(name, "' is not a ").concat(type));
25
+ }
26
+ }
27
+
22
28
  /**
23
29
  * Returns an hexadecimal sha256 hash of the message passed as parameter.
24
30
  * @param message The string to hash.
@@ -36,117 +42,72 @@ function sha256(message) {
36
42
  function genRandomNumber(numberOfBytes) {
37
43
  if (numberOfBytes === void 0) { numberOfBytes = 31; }
38
44
  return bignumber.BigNumber.from(random.randomBytes(numberOfBytes)).toBigInt();
45
+ }
46
+ /**
47
+ * Checks if a string is a JSON.
48
+ * @param jsonString The JSON string.
49
+ * @returns True or false.
50
+ */
51
+ function isJson(jsonString) {
52
+ try {
53
+ JSON.parse(jsonString);
54
+ }
55
+ catch (error) {
56
+ return false;
57
+ }
58
+ return true;
39
59
  }
40
60
 
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
61
  var Identity = /** @class */ (function () {
49
62
  /**
50
63
  * 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.
64
+ * @param identityOrMessage Additional data needed to create identity for given strategy.
53
65
  */
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");
66
+ function Identity(identityOrMessage) {
67
+ if (identityOrMessage === undefined) {
68
+ this._trapdoor = genRandomNumber();
69
+ this._nullifier = genRandomNumber();
70
+ return;
102
71
  }
72
+ checkParameter(identityOrMessage, "identityOrMessage", "string");
73
+ if (!isJson(identityOrMessage)) {
74
+ var messageHash = sha256(identityOrMessage);
75
+ this._trapdoor = bignumber.BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_trapdoor")))).toBigInt();
76
+ this._nullifier = bignumber.BigNumber.from("0x".concat(sha256("".concat(messageHash, "identity_nullifier")))).toBigInt();
77
+ return;
78
+ }
79
+ var _a = JSON.parse(identityOrMessage), trapdoor = _a[0], nullifier = _a[1];
80
+ this._trapdoor = bignumber.BigNumber.from("0x".concat(trapdoor)).toBigInt();
81
+ this._nullifier = bignumber.BigNumber.from("0x".concat(nullifier)).toBigInt();
103
82
  }
104
83
  /**
105
84
  * Returns the identity trapdoor.
106
85
  * @returns The identity trapdoor.
107
86
  */
108
87
  Identity.prototype.getTrapdoor = function () {
109
- return this._identityTrapdoor;
88
+ return this._trapdoor;
110
89
  };
111
90
  /**
112
91
  * Returns the identity nullifier.
113
92
  * @returns The identity nullifier.
114
93
  */
115
94
  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);
95
+ return this._nullifier;
131
96
  };
132
97
  /**
133
- * Generates the identity commitment from the secret.
98
+ * Generates the identity commitment from trapdoor and nullifier.
134
99
  * @returns identity commitment
135
100
  */
136
- Identity.prototype.genIdentityCommitment = function () {
137
- return circomlibjs.poseidon([this.getSecretHash()]);
101
+ Identity.prototype.generateCommitment = function () {
102
+ return circomlibjs.poseidon([circomlibjs.poseidon([this._nullifier, this._trapdoor])]);
138
103
  };
139
104
  /**
140
- * Serializes the class attributes and returns a stringified object.
141
- * @returns The stringified serialized identity.
105
+ * Returns a JSON string with trapdoor and nullifier. It can be used
106
+ * to export the identity and reuse it later.
107
+ * @returns The string representation of the identity.
142
108
  */
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);
109
+ Identity.prototype.toString = function () {
110
+ return JSON.stringify([this._trapdoor.toString(16), this._nullifier.toString(16)]);
150
111
  };
151
112
  return Identity;
152
113
  }());
@@ -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 isJson(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.0",
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",
@@ -37,6 +37,5 @@
37
37
  "@ethersproject/random": "^5.5.1",
38
38
  "circomlibjs": "0.0.8",
39
39
  "crypto-js": "^4.1.1"
40
- },
41
- "gitHead": "6c1b469a4b5ffaac562f478fc2bbc78731734e81"
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,102 @@
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 not recreate an existing invalid identity", () => {
33
+ const fun = () => new Identity('[true, "01323"]')
19
34
 
20
- expect(fun).toThrow("The message is not defined")
35
+ expect(fun).toThrow("invalid BigNumber string")
21
36
  })
22
37
 
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)
38
+ it("Should recreate an existing identity", () => {
39
+ const identity1 = new Identity("message")
25
40
 
26
- expect(fun).toThrow("The message is not a string")
41
+ const identity2 = new Identity(identity1.toString())
42
+
43
+ expect(identity1.getTrapdoor()).toBe(identity2.getTrapdoor())
44
+ expect(identity1.getNullifier()).toBe(identity2.getNullifier())
27
45
  })
46
+ })
28
47
 
29
- it("Should create a identity with a message strategy", () => {
30
- const identity = new Identity(Strategy.MESSAGE, "message")
48
+ describe("# getTrapdoor", () => {
49
+ it("Should return the identity trapdoor", () => {
50
+ const identity = new Identity("message")
31
51
 
32
52
  const trapdoor = identity.getTrapdoor()
33
- const nullifier = identity.getNullifier()
34
- const identitySecret = identity.getSecret()
35
53
 
36
- expect(typeof identity).toBe("object")
37
54
  expect(trapdoor).toBe(
38
55
  BigInt("58952291509798197436757858062402199043831251943841934828591473955215726495831")
39
56
  )
57
+ })
58
+ })
59
+
60
+ describe("# getNullifier", () => {
61
+ it("Should return the identity nullifier", () => {
62
+ const identity = new Identity("message")
63
+
64
+ const nullifier = identity.getNullifier()
65
+
40
66
  expect(nullifier).toBe(
41
67
  BigInt("44673097405870585416457571638073245190425597599743560105244308998175651589997")
42
68
  )
43
- expect(identitySecret).toHaveLength(2)
44
- expect(typeof identitySecret).toBe("object")
45
69
  })
70
+ })
71
+
72
+ describe("# generateCommitment", () => {
73
+ it("Should generate an identity commitment", () => {
74
+ const identity = new Identity("message")
46
75
 
47
- it("Should generate an identity commitment secret", () => {
48
- const identity = new Identity(Strategy.MESSAGE, "message")
49
- const identityCommitment = identity.genIdentityCommitment()
76
+ const commitment = identity.generateCommitment()
50
77
 
51
- expect(identityCommitment).toBe(
78
+ expect(commitment).toBe(
52
79
  BigInt("1720349790382552497189398984241859233944354304766757200361065203741879866188")
53
80
  )
54
81
  })
82
+ })
55
83
 
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
- })
84
+ describe("# toString", () => {
85
+ it("Should return a string", () => {
86
+ const identity = new Identity("message")
68
87
 
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}")
88
+ const identityString = identity.toString()
71
89
 
72
- expect(fun).toThrow("The serialized identity cannot be parsed")
90
+ expect(typeof identityString).toBe("string")
73
91
  })
74
92
 
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)
93
+ it("Should return a valid identity string", () => {
94
+ const identity = new Identity("message")
80
95
 
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)
96
+ const [trapdoor, nullifier] = JSON.parse(identity.toString())
88
97
 
89
- expect(identity2).toStrictEqual(identity1)
98
+ expect(BigNumber.from(`0x${trapdoor}`).toBigInt()).toBe(identity.getTrapdoor())
99
+ expect(BigNumber.from(`0x${nullifier}`).toBigInt()).toBe(identity.getNullifier())
90
100
  })
91
101
  })
92
102
  })
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, isJson, 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 (!isJson(identityOrMessage)) {
25
+ const messageHash = sha256(identityOrMessage)
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(`0x${sha256(`${messageHash}identity_trapdoor`)}`).toBigInt()
28
+ this._nullifier = BigNumber.from(`0x${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
@@ -21,3 +21,18 @@ export function sha256(message: string): string {
21
21
  export function genRandomNumber(numberOfBytes = 31): bigint {
22
22
  return BigNumber.from(randomBytes(numberOfBytes)).toBigInt()
23
23
  }
24
+
25
+ /**
26
+ * Checks if a string is a JSON.
27
+ * @param jsonString The JSON string.
28
+ * @returns True or false.
29
+ */
30
+ export function isJson(jsonString: string) {
31
+ try {
32
+ JSON.parse(jsonString)
33
+ } catch (error) {
34
+ return false
35
+ }
36
+
37
+ return true
38
+ }
@@ -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
- }