@semaphore-protocol/group 3.15.2 → 4.0.0-alpha.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Ethereum Foundation
3
+ Copyright (c) 2024 Ethereum Foundation
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -49,8 +49,8 @@
49
49
  </h4>
50
50
  </div>
51
51
 
52
- | This library is an abstraction of [`@zk-kit/incremental-merkle-tree`](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/incremental-merkle-tree). The main goal is to make it easier to create offchain groups, which are also used to generate Semaphore proofs. Semaphore groups are actually incremental Merkle trees, and the group members are tree leaves. Since the Merkle tree implementation we are using is a binary tree, the maximum number of members of a group is equal to `2^treeDepth`. |
53
- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
+ | This library is an abstraction of the LeanIMT data structure (part of [`@zk-kit/imt`](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/imt)). The main goal is to make it easier to create offchain groups, which are also used to generate Semaphore proofs. Semaphore groups are actually Merkle trees, and the group members are tree leaves. |
53
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
54
 
55
55
  ## 🛠 Install
56
56
 
@@ -70,54 +70,102 @@ yarn add @semaphore-protocol/group
70
70
 
71
71
  ## 📜 Usage
72
72
 
73
- \# **new Group**(groupId: _Member_, treeDepth = 20): _Group_
73
+ \# **new Group**(members: _BigNumberish[]_ = []): _Group_
74
74
 
75
75
  ```typescript
76
76
  import { Group } from "@semaphore-protocol/group"
77
77
  import { Identity } from "@semaphore-protocol/identity"
78
78
 
79
- // Group with max 1048576 members (20^²).
80
- const group1 = new Group(1)
79
+ const group1 = new Group()
81
80
 
82
- // Group with max 65536 members (16^²).
83
- const group2 = new Group(1, 16)
84
-
85
- // Group with max 16777216 members (24^²).
86
- const group3 = new Group(1, 24)
87
-
88
- // Group with a list of predefined members.
89
81
  const identity1 = new Identity()
90
82
  const identity2 = new Identity()
91
- const identity3 = new Identity()
92
83
 
93
- const group3 = new Group(1, 16, [identity1.commitment, identity2.commitment, identity3.commitment])
84
+ const group2 = new Group([identity1.commitment, identity2.commitment])
94
85
  ```
95
86
 
96
- \# **addMember**(identityCommitment: _Member_)
87
+ \# **addMember**(member: _BigNumberish_)
97
88
 
98
89
  ```typescript
90
+ import { Group } from "@semaphore-protocol/group"
99
91
  import { Identity } from "@semaphore-protocol/identity"
100
92
 
101
- const identity = new Identity()
102
- const commitment = identity.generateCommitment()
93
+ const group = new Group()
94
+
95
+ const { commitment } = new Identity()
103
96
 
104
97
  group.addMember(commitment)
98
+
99
+ // "12989101133047504182892154686643420754368236204022364847543591045056549053997"
100
+ console.log(group.members[0])
101
+ ```
102
+
103
+ \# **addMembers**(members: _BigNumberish[]_)
104
+
105
+ ```typescript
106
+ import { Group } from "@semaphore-protocol/group"
107
+ import { Identity } from "@semaphore-protocol/identity"
108
+
109
+ const group = new Group()
110
+
111
+ const identity1 = new Identity()
112
+ const identity2 = new Identity()
113
+
114
+ group.addMembers([identity1.commitment, identity2.commitment])
115
+ ```
116
+
117
+ \# **updateMember**(index: _number_, member: _BigNumberish_)
118
+
119
+ ```typescript
120
+ import { Group } from "@semaphore-protocol/group"
121
+
122
+ const group = new Group([1, 3])
123
+
124
+ group.updateMember(0, 2)
125
+
126
+ console.log(group.members[0]) // "2"
105
127
  ```
106
128
 
107
129
  \# **removeMember**(index: _number_)
108
130
 
109
131
  ```typescript
132
+ import { Group } from "@semaphore-protocol/group"
133
+
134
+ const group = new Group([1, 3])
135
+
110
136
  group.removeMember(0)
137
+
138
+ console.log(group.members[0]) // "0"
111
139
  ```
112
140
 
113
- \# **indexOf**(member: _Member_): _number_
141
+ \# **indexOf**(member: _BigNumberish_): _number_
114
142
 
115
143
  ```typescript
116
- group.indexOf(commitment) // 0
144
+ import { Group } from "@semaphore-protocol/group"
145
+
146
+ const group = new Group([1])
147
+
148
+ const index = group.indexOf(1)
149
+
150
+ console.log(index) // 0
117
151
  ```
118
152
 
119
153
  \# **generateMerkleProof**(index: _number_): _MerkleProof_
120
154
 
121
155
  ```typescript
156
+ import { Group } from "@semaphore-protocol/group"
157
+
158
+ const group = new Group([1, 3])
159
+
122
160
  const proof = group.generateMerkleProof(0)
161
+
162
+ console.log(proof)
163
+ /*
164
+ {
165
+ index: 0,
166
+ leaf: '1',
167
+ root: '21106761926285267690763443010820487107972411248208546226053195422384279971821',
168
+ siblings: [ '3' ]
169
+ }
170
+ */
123
171
  ```
package/dist/index.mjs CHANGED
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/group
3
- * @version 3.15.2
3
+ * @version 4.0.0-alpha.1
4
4
  * @file A library to create and manage Semaphore groups.
5
- * @copyright Ethereum Foundation 2022
5
+ * @copyright Ethereum Foundation 2024
6
6
  * @license MIT
7
7
  * @see [Github]{@link https://github.com/semaphore-protocol/semaphore/tree/main/packages/group}
8
8
  */
9
- import { IncrementalMerkleTree } from '@zk-kit/incremental-merkle-tree';
10
- import { BigNumber } from '@ethersproject/bignumber';
11
- import { zeroPad } from '@ethersproject/bytes';
12
- import { keccak256 } from '@ethersproject/keccak256';
9
+ import { LeanIMT } from '@zk-kit/imt';
13
10
 
14
11
  var poseidon2$1 = {};
15
12
 
@@ -107,51 +104,23 @@ function poseidon2(inputs) {
107
104
  return (0, _poseidon.default)(inputs, c);
108
105
  }
109
106
 
110
- /**
111
- * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
112
- * @param message The message to be hashed.
113
- * @returns The message digest.
114
- */
115
- function hash(message) {
116
- message = BigNumber.from(message).toTwos(256).toHexString();
117
- message = zeroPad(message, 32);
118
- return BigInt(keccak256(message)) >> BigInt(8);
119
- }
120
-
121
107
  var Group = /** @class */ (function () {
122
108
  /**
123
109
  * Initializes the group with the group id and the tree depth.
124
- * @param id Group identifier.
125
- * @param treeDepth Tree depth.
126
110
  * @param members List of group members.
127
111
  */
128
- function Group(id, treeDepth, members) {
129
- if (treeDepth === void 0) { treeDepth = 20; }
112
+ function Group(members) {
130
113
  if (members === void 0) { members = []; }
131
- if (treeDepth < 16 || treeDepth > 32) {
132
- throw new Error("The tree depth must be between 16 and 32");
133
- }
134
- this._id = id;
135
- this.merkleTree = new IncrementalMerkleTree(poseidon2_2, treeDepth, hash(id), 2, members.map(BigInt));
114
+ this.leanIMT = new LeanIMT(function (a, b) { return poseidon2_2([a, b]); }, members.map(BigInt));
136
115
  }
137
- Object.defineProperty(Group.prototype, "id", {
138
- /**
139
- * Returns the id of the group.
140
- * @returns Group id.
141
- */
142
- get: function () {
143
- return this._id;
144
- },
145
- enumerable: false,
146
- configurable: true
147
- });
148
116
  Object.defineProperty(Group.prototype, "root", {
149
117
  /**
150
118
  * Returns the root hash of the tree.
151
119
  * @returns Root hash.
152
120
  */
153
121
  get: function () {
154
- return this.merkleTree.root;
122
+ var _a;
123
+ return (_a = this.leanIMT.root) === null || _a === void 0 ? void 0 : _a.toString();
155
124
  },
156
125
  enumerable: false,
157
126
  configurable: true
@@ -162,18 +131,18 @@ var Group = /** @class */ (function () {
162
131
  * @returns Tree depth.
163
132
  */
164
133
  get: function () {
165
- return this.merkleTree.depth;
134
+ return this.leanIMT.depth;
166
135
  },
167
136
  enumerable: false,
168
137
  configurable: true
169
138
  });
170
- Object.defineProperty(Group.prototype, "zeroValue", {
139
+ Object.defineProperty(Group.prototype, "size", {
171
140
  /**
172
- * Returns the zero value of the tree.
173
- * @returns Tree zero value.
141
+ * Returns the size of the tree (i.e. number of leaves).
142
+ * @returns Tree depth.
174
143
  */
175
144
  get: function () {
176
- return this.merkleTree.zeroes[0];
145
+ return this.leanIMT.size;
177
146
  },
178
147
  enumerable: false,
179
148
  configurable: true
@@ -184,7 +153,7 @@ var Group = /** @class */ (function () {
184
153
  * @returns List of members.
185
154
  */
186
155
  get: function () {
187
- return this.merkleTree.leaves;
156
+ return this.leanIMT.leaves.map(String);
188
157
  },
189
158
  enumerable: false,
190
159
  configurable: true
@@ -195,25 +164,21 @@ var Group = /** @class */ (function () {
195
164
  * @returns Index of the member.
196
165
  */
197
166
  Group.prototype.indexOf = function (member) {
198
- return this.merkleTree.indexOf(member);
167
+ return this.leanIMT.indexOf(BigInt(member));
199
168
  };
200
169
  /**
201
170
  * Adds a new member to the group.
202
171
  * @param member New member.
203
172
  */
204
173
  Group.prototype.addMember = function (member) {
205
- this.merkleTree.insert(BigInt(member));
174
+ this.leanIMT.insert(BigInt(member));
206
175
  };
207
176
  /**
208
177
  * Adds new members to the group.
209
178
  * @param members New members.
210
- * @deprecated Use the new class parameter to add a list of members.
211
179
  */
212
180
  Group.prototype.addMembers = function (members) {
213
- for (var _i = 0, members_1 = members; _i < members_1.length; _i++) {
214
- var member = members_1[_i];
215
- this.addMember(member);
216
- }
181
+ this.leanIMT.insertMany(members.map(BigInt));
217
182
  };
218
183
  /**
219
184
  * Updates a member in the group.
@@ -221,24 +186,28 @@ var Group = /** @class */ (function () {
221
186
  * @param member New member value.
222
187
  */
223
188
  Group.prototype.updateMember = function (index, member) {
224
- this.merkleTree.update(index, member);
189
+ this.leanIMT.update(index, BigInt(member));
225
190
  };
226
191
  /**
227
192
  * Removes a member from the group.
228
193
  * @param index Index of the member to be removed.
229
194
  */
230
195
  Group.prototype.removeMember = function (index) {
231
- this.merkleTree.delete(index);
196
+ this.leanIMT.update(index, BigInt(0));
232
197
  };
233
198
  /**
234
199
  * Creates a proof of membership.
235
200
  * @param index Index of the proof's member.
236
201
  * @returns Proof object.
237
202
  */
238
- Group.prototype.generateMerkleProof = function (index) {
239
- var merkleProof = this.merkleTree.createProof(index);
240
- merkleProof.siblings = merkleProof.siblings.map(function (s) { return s[0]; });
241
- return merkleProof;
203
+ Group.prototype.generateMerkleProof = function (_index) {
204
+ var _a = this.leanIMT.generateProof(_index), index = _a.index, leaf = _a.leaf, root = _a.root, siblings = _a.siblings;
205
+ return {
206
+ index: index,
207
+ leaf: leaf.toString(),
208
+ root: root.toString(),
209
+ siblings: siblings.map(String)
210
+ };
242
211
  };
243
212
  return Group;
244
213
  }());
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @module @semaphore-protocol/group
3
- * @version 3.15.2
3
+ * @version 4.0.0-alpha.1
4
4
  * @file A library to create and manage Semaphore groups.
5
- * @copyright Ethereum Foundation 2022
5
+ * @copyright Ethereum Foundation 2024
6
6
  * @license MIT
7
7
  * @see [Github]{@link https://github.com/semaphore-protocol/semaphore/tree/main/packages/group}
8
8
  */
@@ -10,10 +10,7 @@
10
10
 
11
11
  Object.defineProperty(exports, '__esModule', { value: true });
12
12
 
13
- var incrementalMerkleTree = require('@zk-kit/incremental-merkle-tree');
14
- var bignumber = require('@ethersproject/bignumber');
15
- var bytes = require('@ethersproject/bytes');
16
- var keccak256 = require('@ethersproject/keccak256');
13
+ var imt = require('@zk-kit/imt');
17
14
 
18
15
  var poseidon2$1 = {};
19
16
 
@@ -111,51 +108,23 @@ function poseidon2(inputs) {
111
108
  return (0, _poseidon.default)(inputs, c);
112
109
  }
113
110
 
114
- /**
115
- * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
116
- * @param message The message to be hashed.
117
- * @returns The message digest.
118
- */
119
- function hash(message) {
120
- message = bignumber.BigNumber.from(message).toTwos(256).toHexString();
121
- message = bytes.zeroPad(message, 32);
122
- return BigInt(keccak256.keccak256(message)) >> BigInt(8);
123
- }
124
-
125
111
  var Group = /** @class */ (function () {
126
112
  /**
127
113
  * Initializes the group with the group id and the tree depth.
128
- * @param id Group identifier.
129
- * @param treeDepth Tree depth.
130
114
  * @param members List of group members.
131
115
  */
132
- function Group(id, treeDepth, members) {
133
- if (treeDepth === void 0) { treeDepth = 20; }
116
+ function Group(members) {
134
117
  if (members === void 0) { members = []; }
135
- if (treeDepth < 16 || treeDepth > 32) {
136
- throw new Error("The tree depth must be between 16 and 32");
137
- }
138
- this._id = id;
139
- this.merkleTree = new incrementalMerkleTree.IncrementalMerkleTree(poseidon2_2, treeDepth, hash(id), 2, members.map(BigInt));
118
+ this.leanIMT = new imt.LeanIMT(function (a, b) { return poseidon2_2([a, b]); }, members.map(BigInt));
140
119
  }
141
- Object.defineProperty(Group.prototype, "id", {
142
- /**
143
- * Returns the id of the group.
144
- * @returns Group id.
145
- */
146
- get: function () {
147
- return this._id;
148
- },
149
- enumerable: false,
150
- configurable: true
151
- });
152
120
  Object.defineProperty(Group.prototype, "root", {
153
121
  /**
154
122
  * Returns the root hash of the tree.
155
123
  * @returns Root hash.
156
124
  */
157
125
  get: function () {
158
- return this.merkleTree.root;
126
+ var _a;
127
+ return (_a = this.leanIMT.root) === null || _a === void 0 ? void 0 : _a.toString();
159
128
  },
160
129
  enumerable: false,
161
130
  configurable: true
@@ -166,18 +135,18 @@ var Group = /** @class */ (function () {
166
135
  * @returns Tree depth.
167
136
  */
168
137
  get: function () {
169
- return this.merkleTree.depth;
138
+ return this.leanIMT.depth;
170
139
  },
171
140
  enumerable: false,
172
141
  configurable: true
173
142
  });
174
- Object.defineProperty(Group.prototype, "zeroValue", {
143
+ Object.defineProperty(Group.prototype, "size", {
175
144
  /**
176
- * Returns the zero value of the tree.
177
- * @returns Tree zero value.
145
+ * Returns the size of the tree (i.e. number of leaves).
146
+ * @returns Tree depth.
178
147
  */
179
148
  get: function () {
180
- return this.merkleTree.zeroes[0];
149
+ return this.leanIMT.size;
181
150
  },
182
151
  enumerable: false,
183
152
  configurable: true
@@ -188,7 +157,7 @@ var Group = /** @class */ (function () {
188
157
  * @returns List of members.
189
158
  */
190
159
  get: function () {
191
- return this.merkleTree.leaves;
160
+ return this.leanIMT.leaves.map(String);
192
161
  },
193
162
  enumerable: false,
194
163
  configurable: true
@@ -199,25 +168,21 @@ var Group = /** @class */ (function () {
199
168
  * @returns Index of the member.
200
169
  */
201
170
  Group.prototype.indexOf = function (member) {
202
- return this.merkleTree.indexOf(member);
171
+ return this.leanIMT.indexOf(BigInt(member));
203
172
  };
204
173
  /**
205
174
  * Adds a new member to the group.
206
175
  * @param member New member.
207
176
  */
208
177
  Group.prototype.addMember = function (member) {
209
- this.merkleTree.insert(BigInt(member));
178
+ this.leanIMT.insert(BigInt(member));
210
179
  };
211
180
  /**
212
181
  * Adds new members to the group.
213
182
  * @param members New members.
214
- * @deprecated Use the new class parameter to add a list of members.
215
183
  */
216
184
  Group.prototype.addMembers = function (members) {
217
- for (var _i = 0, members_1 = members; _i < members_1.length; _i++) {
218
- var member = members_1[_i];
219
- this.addMember(member);
220
- }
185
+ this.leanIMT.insertMany(members.map(BigInt));
221
186
  };
222
187
  /**
223
188
  * Updates a member in the group.
@@ -225,24 +190,28 @@ var Group = /** @class */ (function () {
225
190
  * @param member New member value.
226
191
  */
227
192
  Group.prototype.updateMember = function (index, member) {
228
- this.merkleTree.update(index, member);
193
+ this.leanIMT.update(index, BigInt(member));
229
194
  };
230
195
  /**
231
196
  * Removes a member from the group.
232
197
  * @param index Index of the member to be removed.
233
198
  */
234
199
  Group.prototype.removeMember = function (index) {
235
- this.merkleTree.delete(index);
200
+ this.leanIMT.update(index, BigInt(0));
236
201
  };
237
202
  /**
238
203
  * Creates a proof of membership.
239
204
  * @param index Index of the proof's member.
240
205
  * @returns Proof object.
241
206
  */
242
- Group.prototype.generateMerkleProof = function (index) {
243
- var merkleProof = this.merkleTree.createProof(index);
244
- merkleProof.siblings = merkleProof.siblings.map(function (s) { return s[0]; });
245
- return merkleProof;
207
+ Group.prototype.generateMerkleProof = function (_index) {
208
+ var _a = this.leanIMT.generateProof(_index), index = _a.index, leaf = _a.leaf, root = _a.root, siblings = _a.siblings;
209
+ return {
210
+ index: index,
211
+ leaf: leaf.toString(),
212
+ root: root.toString(),
213
+ siblings: siblings.map(String)
214
+ };
246
215
  };
247
216
  return Group;
248
217
  }());
@@ -1,40 +1,32 @@
1
- import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree";
2
- import { BigNumberish } from "./types";
1
+ import { LeanIMT } from "@zk-kit/imt";
2
+ import { BigNumberish, MerkleProof } from "./types";
3
3
  export default class Group {
4
- private _id;
5
- merkleTree: IncrementalMerkleTree;
4
+ leanIMT: LeanIMT;
6
5
  /**
7
6
  * Initializes the group with the group id and the tree depth.
8
- * @param id Group identifier.
9
- * @param treeDepth Tree depth.
10
7
  * @param members List of group members.
11
8
  */
12
- constructor(id: BigNumberish, treeDepth?: number, members?: BigNumberish[]);
13
- /**
14
- * Returns the id of the group.
15
- * @returns Group id.
16
- */
17
- get id(): BigNumberish;
9
+ constructor(members?: BigNumberish[]);
18
10
  /**
19
11
  * Returns the root hash of the tree.
20
12
  * @returns Root hash.
21
13
  */
22
- get root(): BigNumberish;
14
+ get root(): string | undefined;
23
15
  /**
24
16
  * Returns the depth of the tree.
25
17
  * @returns Tree depth.
26
18
  */
27
19
  get depth(): number;
28
20
  /**
29
- * Returns the zero value of the tree.
30
- * @returns Tree zero value.
21
+ * Returns the size of the tree (i.e. number of leaves).
22
+ * @returns Tree depth.
31
23
  */
32
- get zeroValue(): BigNumberish;
24
+ get size(): number;
33
25
  /**
34
26
  * Returns the members (i.e. identity commitments) of the group.
35
27
  * @returns List of members.
36
28
  */
37
- get members(): BigNumberish[];
29
+ get members(): string[];
38
30
  /**
39
31
  * Returns the index of a member. If the member does not exist it returns -1.
40
32
  * @param member Group member.
@@ -49,7 +41,6 @@ export default class Group {
49
41
  /**
50
42
  * Adds new members to the group.
51
43
  * @param members New members.
52
- * @deprecated Use the new class parameter to add a list of members.
53
44
  */
54
45
  addMembers(members: BigNumberish[]): void;
55
46
  /**
@@ -68,5 +59,5 @@ export default class Group {
68
59
  * @param index Index of the proof's member.
69
60
  * @returns Proof object.
70
61
  */
71
- generateMerkleProof(index: number): MerkleProof;
62
+ generateMerkleProof(_index: number): MerkleProof;
72
63
  }
@@ -1 +1,3 @@
1
+ import { LeanIMTMerkleProof } from "@zk-kit/imt";
1
2
  export type BigNumberish = string | number | bigint;
3
+ export type MerkleProof = LeanIMTMerkleProof<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/group",
3
- "version": "3.15.2",
3
+ "version": "4.0.0-alpha.1",
4
4
  "description": "A library to create and manage Semaphore groups.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.node.js",
@@ -37,9 +37,6 @@
37
37
  "rollup-plugin-typescript2": "^0.31.2"
38
38
  },
39
39
  "dependencies": {
40
- "@ethersproject/bignumber": "^5.7.0",
41
- "@ethersproject/bytes": "^5.7.0",
42
- "@ethersproject/keccak256": "^5.7.0",
43
- "@zk-kit/incremental-merkle-tree": "1.1.0"
40
+ "@zk-kit/imt": "^2.0.0-beta"
44
41
  }
45
42
  }
package/src/group.ts CHANGED
@@ -1,42 +1,24 @@
1
- import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree"
1
+ import { LeanIMT } from "@zk-kit/imt"
2
2
  import { poseidon2 } from "poseidon-lite/poseidon2"
3
- import hash from "./hash"
4
- import { BigNumberish } from "./types"
3
+ import { BigNumberish, MerkleProof } from "./types"
5
4
 
6
5
  export default class Group {
7
- private _id: BigNumberish
8
-
9
- merkleTree: IncrementalMerkleTree
6
+ leanIMT: LeanIMT
10
7
 
11
8
  /**
12
9
  * Initializes the group with the group id and the tree depth.
13
- * @param id Group identifier.
14
- * @param treeDepth Tree depth.
15
10
  * @param members List of group members.
16
11
  */
17
- constructor(id: BigNumberish, treeDepth = 20, members: BigNumberish[] = []) {
18
- if (treeDepth < 16 || treeDepth > 32) {
19
- throw new Error("The tree depth must be between 16 and 32")
20
- }
21
-
22
- this._id = id
23
- this.merkleTree = new IncrementalMerkleTree(poseidon2, treeDepth, hash(id), 2, members.map(BigInt))
24
- }
25
-
26
- /**
27
- * Returns the id of the group.
28
- * @returns Group id.
29
- */
30
- get id(): BigNumberish {
31
- return this._id
12
+ constructor(members: BigNumberish[] = []) {
13
+ this.leanIMT = new LeanIMT((a, b) => poseidon2([a, b]), members.map(BigInt))
32
14
  }
33
15
 
34
16
  /**
35
17
  * Returns the root hash of the tree.
36
18
  * @returns Root hash.
37
19
  */
38
- get root(): BigNumberish {
39
- return this.merkleTree.root
20
+ get root(): string | undefined {
21
+ return this.leanIMT.root?.toString()
40
22
  }
41
23
 
42
24
  /**
@@ -44,23 +26,23 @@ export default class Group {
44
26
  * @returns Tree depth.
45
27
  */
46
28
  get depth(): number {
47
- return this.merkleTree.depth
29
+ return this.leanIMT.depth
48
30
  }
49
31
 
50
32
  /**
51
- * Returns the zero value of the tree.
52
- * @returns Tree zero value.
33
+ * Returns the size of the tree (i.e. number of leaves).
34
+ * @returns Tree depth.
53
35
  */
54
- get zeroValue(): BigNumberish {
55
- return this.merkleTree.zeroes[0]
36
+ get size(): number {
37
+ return this.leanIMT.size
56
38
  }
57
39
 
58
40
  /**
59
41
  * Returns the members (i.e. identity commitments) of the group.
60
42
  * @returns List of members.
61
43
  */
62
- get members(): BigNumberish[] {
63
- return this.merkleTree.leaves
44
+ get members(): string[] {
45
+ return this.leanIMT.leaves.map(String)
64
46
  }
65
47
 
66
48
  /**
@@ -69,7 +51,7 @@ export default class Group {
69
51
  * @returns Index of the member.
70
52
  */
71
53
  indexOf(member: BigNumberish): number {
72
- return this.merkleTree.indexOf(member)
54
+ return this.leanIMT.indexOf(BigInt(member))
73
55
  }
74
56
 
75
57
  /**
@@ -77,18 +59,15 @@ export default class Group {
77
59
  * @param member New member.
78
60
  */
79
61
  addMember(member: BigNumberish) {
80
- this.merkleTree.insert(BigInt(member))
62
+ this.leanIMT.insert(BigInt(member))
81
63
  }
82
64
 
83
65
  /**
84
66
  * Adds new members to the group.
85
67
  * @param members New members.
86
- * @deprecated Use the new class parameter to add a list of members.
87
68
  */
88
69
  addMembers(members: BigNumberish[]) {
89
- for (const member of members) {
90
- this.addMember(member)
91
- }
70
+ this.leanIMT.insertMany(members.map(BigInt))
92
71
  }
93
72
 
94
73
  /**
@@ -97,7 +76,7 @@ export default class Group {
97
76
  * @param member New member value.
98
77
  */
99
78
  updateMember(index: number, member: BigNumberish) {
100
- this.merkleTree.update(index, member)
79
+ this.leanIMT.update(index, BigInt(member))
101
80
  }
102
81
 
103
82
  /**
@@ -105,7 +84,7 @@ export default class Group {
105
84
  * @param index Index of the member to be removed.
106
85
  */
107
86
  removeMember(index: number) {
108
- this.merkleTree.delete(index)
87
+ this.leanIMT.update(index, BigInt(0))
109
88
  }
110
89
 
111
90
  /**
@@ -113,11 +92,14 @@ export default class Group {
113
92
  * @param index Index of the proof's member.
114
93
  * @returns Proof object.
115
94
  */
116
- generateMerkleProof(index: number): MerkleProof {
117
- const merkleProof = this.merkleTree.createProof(index)
118
-
119
- merkleProof.siblings = merkleProof.siblings.map((s) => s[0])
120
-
121
- return merkleProof
95
+ generateMerkleProof(_index: number): MerkleProof {
96
+ const { index, leaf, root, siblings } = this.leanIMT.generateProof(_index)
97
+
98
+ return {
99
+ index,
100
+ leaf: leaf.toString(),
101
+ root: root.toString(),
102
+ siblings: siblings.map(String)
103
+ }
122
104
  }
123
105
  }
@@ -1 +1,4 @@
1
+ import { LeanIMTMerkleProof } from "@zk-kit/imt"
2
+
1
3
  export type BigNumberish = string | number | bigint
4
+ export type MerkleProof = LeanIMTMerkleProof<string>
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- import { BytesLike, Hexable } from "@ethersproject/bytes";
2
- /**
3
- * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
4
- * @param message The message to be hashed.
5
- * @returns The message digest.
6
- */
7
- export default function hash(message: BytesLike | Hexable | number | bigint): bigint;
package/src/group.test.ts DELETED
@@ -1,112 +0,0 @@
1
- import Group from "./group"
2
- import hash from "./hash"
3
-
4
- describe("Group", () => {
5
- describe("# Group", () => {
6
- it("Should create a group", () => {
7
- const group = new Group(1)
8
-
9
- expect(group.id).toBe(1)
10
- expect(group.root.toString()).toContain("103543")
11
- expect(group.depth).toBe(20)
12
- expect(group.zeroValue).toBe(hash(1))
13
- expect(group.members).toHaveLength(0)
14
- })
15
-
16
- it("Should not create a group with a wrong tree depth", () => {
17
- const fun = () => new Group(1, 33)
18
-
19
- expect(fun).toThrow("The tree depth must be between 16 and 32")
20
- })
21
-
22
- it("Should create a group with a different tree depth", () => {
23
- const group = new Group(1, 32)
24
-
25
- expect(group.root.toString()).toContain("460373")
26
- expect(group.depth).toBe(32)
27
- expect(group.zeroValue).toBe(hash(1))
28
- expect(group.members).toHaveLength(0)
29
- })
30
-
31
- it("Should create a group with a list of members", () => {
32
- const group = new Group(2, 20, [1, 2, 3])
33
-
34
- const group2 = new Group(2, 20)
35
-
36
- group2.addMember(1)
37
- group2.addMember(2)
38
- group2.addMember(3)
39
-
40
- expect(group.root.toString()).toContain(group2.root.toString())
41
- expect(group.depth).toBe(20)
42
- expect(group.zeroValue).toBe(hash(2))
43
- expect(group.members).toHaveLength(3)
44
- })
45
- })
46
-
47
- describe("# addMember", () => {
48
- it("Should add a member to a group", () => {
49
- const group = new Group(1)
50
-
51
- group.addMember(BigInt(3))
52
-
53
- expect(group.members).toHaveLength(1)
54
- })
55
- })
56
-
57
- describe("# addMembers", () => {
58
- it("Should add many members to a group", () => {
59
- const group = new Group(1)
60
-
61
- group.addMembers([BigInt(1), BigInt(3)])
62
-
63
- expect(group.members).toHaveLength(2)
64
- })
65
- })
66
-
67
- describe("# indexOf", () => {
68
- it("Should return the index of a member in a group", () => {
69
- const group = new Group(1)
70
- group.addMembers([BigInt(1), BigInt(3)])
71
-
72
- const index = group.indexOf(BigInt(3))
73
-
74
- expect(index).toBe(1)
75
- })
76
- })
77
-
78
- describe("# updateMember", () => {
79
- it("Should update a member in a group", () => {
80
- const group = new Group(1)
81
- group.addMembers([BigInt(1), BigInt(3)])
82
-
83
- group.updateMember(0, BigInt(1))
84
-
85
- expect(group.members).toHaveLength(2)
86
- expect(group.members[0]).toBe(BigInt(1))
87
- })
88
- })
89
-
90
- describe("# removeMember", () => {
91
- it("Should remove a member from a group", () => {
92
- const group = new Group(1)
93
- group.addMembers([BigInt(1), BigInt(3)])
94
-
95
- group.removeMember(0)
96
-
97
- expect(group.members).toHaveLength(2)
98
- expect(group.members[0]).toBe(group.zeroValue)
99
- })
100
- })
101
-
102
- describe("# generateMerkleProof", () => {
103
- it("Should generate a proof of membership", () => {
104
- const group = new Group(1)
105
- group.addMembers([BigInt(1), BigInt(3)])
106
-
107
- const proof = group.generateMerkleProof(0)
108
-
109
- expect(proof.leaf).toBe(BigInt(1))
110
- })
111
- })
112
- })
package/src/hash.ts DELETED
@@ -1,15 +0,0 @@
1
- import { BigNumber } from "@ethersproject/bignumber"
2
- import { BytesLike, Hexable, zeroPad } from "@ethersproject/bytes"
3
- import { keccak256 } from "@ethersproject/keccak256"
4
-
5
- /**
6
- * Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
7
- * @param message The message to be hashed.
8
- * @returns The message digest.
9
- */
10
- export default function hash(message: BytesLike | Hexable | number | bigint): bigint {
11
- message = BigNumber.from(message).toTwos(256).toHexString()
12
- message = zeroPad(message, 32)
13
-
14
- return BigInt(keccak256(message)) >> BigInt(8)
15
- }