@semaphore-protocol/group 3.15.1 → 4.0.0-alpha
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 +1 -1
- package/README.md +67 -19
- package/dist/index.mjs +26 -57
- package/dist/index.node.js +26 -57
- package/dist/types/group.d.ts +10 -19
- package/dist/types/types/index.d.ts +2 -0
- package/package.json +2 -5
- package/src/group.ts +28 -46
- package/src/types/index.ts +3 -0
- package/dist/types/group.test.d.ts +0 -1
- package/dist/types/hash.d.ts +0 -7
- package/src/group.test.ts +0 -112
- package/src/hash.ts +0 -15
package/LICENSE
CHANGED
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/
|
|
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**(
|
|
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
|
-
|
|
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
|
|
84
|
+
const group2 = new Group([identity1.commitment, identity2.commitment])
|
|
94
85
|
```
|
|
95
86
|
|
|
96
|
-
\# **addMember**(
|
|
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
|
|
102
|
-
|
|
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:
|
|
141
|
+
\# **indexOf**(member: _BigNumberish_): _number_
|
|
114
142
|
|
|
115
143
|
```typescript
|
|
116
|
-
|
|
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
|
+
* @version 4.0.0-alpha
|
|
4
4
|
* @file A library to create and manage Semaphore groups.
|
|
5
|
-
* @copyright Ethereum Foundation
|
|
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 {
|
|
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(
|
|
129
|
-
if (treeDepth === void 0) { treeDepth = 20; }
|
|
112
|
+
function Group(members) {
|
|
130
113
|
if (members === void 0) { members = []; }
|
|
131
|
-
|
|
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
|
-
|
|
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.
|
|
134
|
+
return this.leanIMT.depth;
|
|
166
135
|
},
|
|
167
136
|
enumerable: false,
|
|
168
137
|
configurable: true
|
|
169
138
|
});
|
|
170
|
-
Object.defineProperty(Group.prototype, "
|
|
139
|
+
Object.defineProperty(Group.prototype, "size", {
|
|
171
140
|
/**
|
|
172
|
-
* Returns the
|
|
173
|
-
* @returns Tree
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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 (
|
|
239
|
-
var
|
|
240
|
-
|
|
241
|
-
|
|
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
|
}());
|
package/dist/index.node.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @semaphore-protocol/group
|
|
3
|
-
* @version
|
|
3
|
+
* @version 4.0.0-alpha
|
|
4
4
|
* @file A library to create and manage Semaphore groups.
|
|
5
|
-
* @copyright Ethereum Foundation
|
|
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
|
|
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(
|
|
133
|
-
if (treeDepth === void 0) { treeDepth = 20; }
|
|
116
|
+
function Group(members) {
|
|
134
117
|
if (members === void 0) { members = []; }
|
|
135
|
-
|
|
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
|
-
|
|
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.
|
|
138
|
+
return this.leanIMT.depth;
|
|
170
139
|
},
|
|
171
140
|
enumerable: false,
|
|
172
141
|
configurable: true
|
|
173
142
|
});
|
|
174
|
-
Object.defineProperty(Group.prototype, "
|
|
143
|
+
Object.defineProperty(Group.prototype, "size", {
|
|
175
144
|
/**
|
|
176
|
-
* Returns the
|
|
177
|
-
* @returns Tree
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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 (
|
|
243
|
-
var
|
|
244
|
-
|
|
245
|
-
|
|
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
|
}());
|
package/dist/types/group.d.ts
CHANGED
|
@@ -1,40 +1,32 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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(
|
|
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():
|
|
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
|
|
30
|
-
* @returns Tree
|
|
21
|
+
* Returns the size of the tree (i.e. number of leaves).
|
|
22
|
+
* @returns Tree depth.
|
|
31
23
|
*/
|
|
32
|
-
get
|
|
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():
|
|
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(
|
|
62
|
+
generateMerkleProof(_index: number): MerkleProof;
|
|
72
63
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semaphore-protocol/group",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-alpha",
|
|
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
|
-
"@
|
|
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 {
|
|
1
|
+
import { LeanIMT } from "@zk-kit/imt"
|
|
2
2
|
import { poseidon2 } from "poseidon-lite/poseidon2"
|
|
3
|
-
import
|
|
4
|
-
import { BigNumberish } from "./types"
|
|
3
|
+
import { BigNumberish, MerkleProof } from "./types"
|
|
5
4
|
|
|
6
5
|
export default class Group {
|
|
7
|
-
|
|
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(
|
|
18
|
-
|
|
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():
|
|
39
|
-
return this.
|
|
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.
|
|
29
|
+
return this.leanIMT.depth
|
|
48
30
|
}
|
|
49
31
|
|
|
50
32
|
/**
|
|
51
|
-
* Returns the
|
|
52
|
-
* @returns Tree
|
|
33
|
+
* Returns the size of the tree (i.e. number of leaves).
|
|
34
|
+
* @returns Tree depth.
|
|
53
35
|
*/
|
|
54
|
-
get
|
|
55
|
-
return this.
|
|
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():
|
|
63
|
-
return this.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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(
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/types/hash.d.ts
DELETED
|
@@ -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
|
-
}
|