@semaphore-protocol/group 0.1.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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/index.mjs +121 -0
- package/dist/index.node.js +125 -0
- package/dist/types/group.d.ts +64 -0
- package/dist/types/group.test.d.ts +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/types/index.d.ts +1 -0
- package/package.json +38 -0
- package/src/group.test.ts +95 -0
- package/src/group.ts +105 -0
- package/src/index.ts +4 -0
- package/src/types/index.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Ethereum Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">
|
|
3
|
+
Semaphore group
|
|
4
|
+
</h1>
|
|
5
|
+
<p align="center">A library for managing Semaphore groups.</p>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://github.com/semaphore-protocol/semaphore.js">
|
|
10
|
+
<img src="https://img.shields.io/badge/project-semaphore-blue.svg?style=flat-square">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/semaphore-protocol/semaphore.js/blob/main/packages/group/LICENSE">
|
|
13
|
+
<img alt="Github license" src="https://img.shields.io/github/license/semaphore-protocol/semaphore.js.svg?style=flat-square">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@semaphore-protocol/group">
|
|
16
|
+
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/group?style=flat-square" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://npmjs.org/package/@semaphore-protocol/group">
|
|
19
|
+
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/group.svg?style=flat-square" />
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://eslint.org/">
|
|
22
|
+
<img alt="Linter eslint" src="https://img.shields.io/badge/linter-eslint-8080f2?style=flat-square&logo=eslint" />
|
|
23
|
+
</a>
|
|
24
|
+
<a href="https://prettier.io/">
|
|
25
|
+
<img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<div align="center">
|
|
30
|
+
<h4>
|
|
31
|
+
<a href="https://t.me/joinchat/B-PQx1U3GtAh--Z4Fwo56A">
|
|
32
|
+
🗣️ Chat & Support
|
|
33
|
+
</a>
|
|
34
|
+
<span> | </span>
|
|
35
|
+
<a href="https://semaphore-protocol.github.io/semaphore.js/group">
|
|
36
|
+
📘 Docs
|
|
37
|
+
</a>
|
|
38
|
+
</h4>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
| 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`. |
|
|
42
|
+
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
|
|
44
|
+
## 🛠 Install
|
|
45
|
+
|
|
46
|
+
### npm or yarn
|
|
47
|
+
|
|
48
|
+
Install the `@semaphore-protocol/group` package with npm:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm i @semaphore-protocol/group
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
or yarn:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
yarn add @semaphore-protocol/group
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 📜 Usage
|
|
61
|
+
|
|
62
|
+
\# **new Group**(treeDepth = 20, zeroValue = BigInt(0)): _Group_
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Group } from "@semaphore-protocol/group"
|
|
66
|
+
|
|
67
|
+
// Group with max 1048576 members (20^²).
|
|
68
|
+
const group1 = new Group()
|
|
69
|
+
|
|
70
|
+
// Group with max 65536 members (16^²).
|
|
71
|
+
const group2 = new Group(16)
|
|
72
|
+
|
|
73
|
+
// Group with max 16777216 members (24^²).
|
|
74
|
+
const group3 = new Group(24)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
\# **addMember**(identityCommitment: _Member_)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Identity } from "@semaphore-protocol/identity"
|
|
81
|
+
|
|
82
|
+
const identity = new Identity()
|
|
83
|
+
const commitment = identity.generateCommitment()
|
|
84
|
+
|
|
85
|
+
group.addMember(commitment)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
\# **addMembers**(identityCommitments: _Member\[]_)
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
let identityCommitments: bigint[]
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < 10; i++) {
|
|
94
|
+
const identity = new Identity()
|
|
95
|
+
const commitment = identity.generateCommitment()
|
|
96
|
+
|
|
97
|
+
identityCommitments.push(commitment)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
group.addMember(identityCommitments)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
\# **removeMember**(index: _number_)
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
group.removeMember(0)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
\# **indexOf**(member: _Member_): _number_
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
group.indexOf(commitment) // 0
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
\# **generateProofOfMembership**(index: _number_): _MerkleProof_
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const proof = group.generateProofOfMembership(0)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
\# **verifyProofOfMembership**(proof: _MerkleProof_): _boolean_
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
group.verifyProofOfMembership(proof) // true
|
|
125
|
+
```
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @semaphore-protocol/group
|
|
3
|
+
* @version 0.1.0
|
|
4
|
+
* @file A library for managing Semaphore groups.
|
|
5
|
+
* @copyright Ethereum Foundation 2022
|
|
6
|
+
* @license MIT
|
|
7
|
+
* @see [Github]{@link https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/group}
|
|
8
|
+
*/
|
|
9
|
+
import { IncrementalMerkleTree } from '@zk-kit/incremental-merkle-tree';
|
|
10
|
+
import { poseidon } from 'circomlibjs';
|
|
11
|
+
|
|
12
|
+
var Group = /** @class */ (function () {
|
|
13
|
+
/**
|
|
14
|
+
* Initializes the group with the tree depth and the zero value.
|
|
15
|
+
* @param treeDepth Tree depth.
|
|
16
|
+
* @param zeroValue Zero values for zeroes.
|
|
17
|
+
*/
|
|
18
|
+
function Group(treeDepth, zeroValue) {
|
|
19
|
+
if (treeDepth === void 0) { treeDepth = 20; }
|
|
20
|
+
if (zeroValue === void 0) { zeroValue = BigInt(0); }
|
|
21
|
+
if (treeDepth < 16 || treeDepth > 32) {
|
|
22
|
+
throw new Error("The tree depth must be between 16 and 32");
|
|
23
|
+
}
|
|
24
|
+
this._merkleTree = new IncrementalMerkleTree(poseidon, treeDepth, zeroValue, 2);
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(Group.prototype, "root", {
|
|
27
|
+
/**
|
|
28
|
+
* Returns the root hash of the tree.
|
|
29
|
+
* @returns Root hash.
|
|
30
|
+
*/
|
|
31
|
+
get: function () {
|
|
32
|
+
return this._merkleTree.root;
|
|
33
|
+
},
|
|
34
|
+
enumerable: false,
|
|
35
|
+
configurable: true
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(Group.prototype, "depth", {
|
|
38
|
+
/**
|
|
39
|
+
* Returns the depth of the tree.
|
|
40
|
+
* @returns Tree depth.
|
|
41
|
+
*/
|
|
42
|
+
get: function () {
|
|
43
|
+
return this._merkleTree.depth;
|
|
44
|
+
},
|
|
45
|
+
enumerable: false,
|
|
46
|
+
configurable: true
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(Group.prototype, "zeroValue", {
|
|
49
|
+
/**
|
|
50
|
+
* Returns the zero value of the tree.
|
|
51
|
+
* @returns Tree zero value.
|
|
52
|
+
*/
|
|
53
|
+
get: function () {
|
|
54
|
+
return this._merkleTree.zeroes[0];
|
|
55
|
+
},
|
|
56
|
+
enumerable: false,
|
|
57
|
+
configurable: true
|
|
58
|
+
});
|
|
59
|
+
Object.defineProperty(Group.prototype, "members", {
|
|
60
|
+
/**
|
|
61
|
+
* Returns the members (i.e. identity commitments) of the group.
|
|
62
|
+
* @returns List of members.
|
|
63
|
+
*/
|
|
64
|
+
get: function () {
|
|
65
|
+
return this._merkleTree.leaves;
|
|
66
|
+
},
|
|
67
|
+
enumerable: false,
|
|
68
|
+
configurable: true
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Returns the index of a member. If the member does not exist it returns -1.
|
|
72
|
+
* @param member Group member.
|
|
73
|
+
* @returns Index of the member.
|
|
74
|
+
*/
|
|
75
|
+
Group.prototype.indexOf = function (member) {
|
|
76
|
+
return this._merkleTree.indexOf(member);
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Adds a new member to the group.
|
|
80
|
+
* @param identityCommitment New member.
|
|
81
|
+
*/
|
|
82
|
+
Group.prototype.addMember = function (identityCommitment) {
|
|
83
|
+
this._merkleTree.insert(identityCommitment);
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Adds new members to the group.
|
|
87
|
+
* @param identityCommitments New members.
|
|
88
|
+
*/
|
|
89
|
+
Group.prototype.addMembers = function (identityCommitments) {
|
|
90
|
+
for (var _i = 0, identityCommitments_1 = identityCommitments; _i < identityCommitments_1.length; _i++) {
|
|
91
|
+
var identityCommitment = identityCommitments_1[_i];
|
|
92
|
+
this.addMember(identityCommitment);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Removes a member from the group.
|
|
97
|
+
* @param index Index of the member to be removed.
|
|
98
|
+
*/
|
|
99
|
+
Group.prototype.removeMember = function (index) {
|
|
100
|
+
this._merkleTree.delete(index);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Creates a proof of membership.
|
|
104
|
+
* @param index Index of the proof's member.
|
|
105
|
+
* @returns Proof object.
|
|
106
|
+
*/
|
|
107
|
+
Group.prototype.generateProofOfMembership = function (index) {
|
|
108
|
+
return this._merkleTree.createProof(index);
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Verifies a proof of membership and return true or false.
|
|
112
|
+
* @param proof Proof to be verified.
|
|
113
|
+
* @returns True or false.
|
|
114
|
+
*/
|
|
115
|
+
Group.prototype.verifyProofOfMembership = function (proof) {
|
|
116
|
+
return this._merkleTree.verifyProof(proof);
|
|
117
|
+
};
|
|
118
|
+
return Group;
|
|
119
|
+
}());
|
|
120
|
+
|
|
121
|
+
export { Group };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @semaphore-protocol/group
|
|
3
|
+
* @version 0.1.0
|
|
4
|
+
* @file A library for managing Semaphore groups.
|
|
5
|
+
* @copyright Ethereum Foundation 2022
|
|
6
|
+
* @license MIT
|
|
7
|
+
* @see [Github]{@link https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/group}
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
12
|
+
|
|
13
|
+
var incrementalMerkleTree = require('@zk-kit/incremental-merkle-tree');
|
|
14
|
+
var circomlibjs = require('circomlibjs');
|
|
15
|
+
|
|
16
|
+
var Group = /** @class */ (function () {
|
|
17
|
+
/**
|
|
18
|
+
* Initializes the group with the tree depth and the zero value.
|
|
19
|
+
* @param treeDepth Tree depth.
|
|
20
|
+
* @param zeroValue Zero values for zeroes.
|
|
21
|
+
*/
|
|
22
|
+
function Group(treeDepth, zeroValue) {
|
|
23
|
+
if (treeDepth === void 0) { treeDepth = 20; }
|
|
24
|
+
if (zeroValue === void 0) { zeroValue = BigInt(0); }
|
|
25
|
+
if (treeDepth < 16 || treeDepth > 32) {
|
|
26
|
+
throw new Error("The tree depth must be between 16 and 32");
|
|
27
|
+
}
|
|
28
|
+
this._merkleTree = new incrementalMerkleTree.IncrementalMerkleTree(circomlibjs.poseidon, treeDepth, zeroValue, 2);
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(Group.prototype, "root", {
|
|
31
|
+
/**
|
|
32
|
+
* Returns the root hash of the tree.
|
|
33
|
+
* @returns Root hash.
|
|
34
|
+
*/
|
|
35
|
+
get: function () {
|
|
36
|
+
return this._merkleTree.root;
|
|
37
|
+
},
|
|
38
|
+
enumerable: false,
|
|
39
|
+
configurable: true
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(Group.prototype, "depth", {
|
|
42
|
+
/**
|
|
43
|
+
* Returns the depth of the tree.
|
|
44
|
+
* @returns Tree depth.
|
|
45
|
+
*/
|
|
46
|
+
get: function () {
|
|
47
|
+
return this._merkleTree.depth;
|
|
48
|
+
},
|
|
49
|
+
enumerable: false,
|
|
50
|
+
configurable: true
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(Group.prototype, "zeroValue", {
|
|
53
|
+
/**
|
|
54
|
+
* Returns the zero value of the tree.
|
|
55
|
+
* @returns Tree zero value.
|
|
56
|
+
*/
|
|
57
|
+
get: function () {
|
|
58
|
+
return this._merkleTree.zeroes[0];
|
|
59
|
+
},
|
|
60
|
+
enumerable: false,
|
|
61
|
+
configurable: true
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(Group.prototype, "members", {
|
|
64
|
+
/**
|
|
65
|
+
* Returns the members (i.e. identity commitments) of the group.
|
|
66
|
+
* @returns List of members.
|
|
67
|
+
*/
|
|
68
|
+
get: function () {
|
|
69
|
+
return this._merkleTree.leaves;
|
|
70
|
+
},
|
|
71
|
+
enumerable: false,
|
|
72
|
+
configurable: true
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Returns the index of a member. If the member does not exist it returns -1.
|
|
76
|
+
* @param member Group member.
|
|
77
|
+
* @returns Index of the member.
|
|
78
|
+
*/
|
|
79
|
+
Group.prototype.indexOf = function (member) {
|
|
80
|
+
return this._merkleTree.indexOf(member);
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Adds a new member to the group.
|
|
84
|
+
* @param identityCommitment New member.
|
|
85
|
+
*/
|
|
86
|
+
Group.prototype.addMember = function (identityCommitment) {
|
|
87
|
+
this._merkleTree.insert(identityCommitment);
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Adds new members to the group.
|
|
91
|
+
* @param identityCommitments New members.
|
|
92
|
+
*/
|
|
93
|
+
Group.prototype.addMembers = function (identityCommitments) {
|
|
94
|
+
for (var _i = 0, identityCommitments_1 = identityCommitments; _i < identityCommitments_1.length; _i++) {
|
|
95
|
+
var identityCommitment = identityCommitments_1[_i];
|
|
96
|
+
this.addMember(identityCommitment);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Removes a member from the group.
|
|
101
|
+
* @param index Index of the member to be removed.
|
|
102
|
+
*/
|
|
103
|
+
Group.prototype.removeMember = function (index) {
|
|
104
|
+
this._merkleTree.delete(index);
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Creates a proof of membership.
|
|
108
|
+
* @param index Index of the proof's member.
|
|
109
|
+
* @returns Proof object.
|
|
110
|
+
*/
|
|
111
|
+
Group.prototype.generateProofOfMembership = function (index) {
|
|
112
|
+
return this._merkleTree.createProof(index);
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Verifies a proof of membership and return true or false.
|
|
116
|
+
* @param proof Proof to be verified.
|
|
117
|
+
* @returns True or false.
|
|
118
|
+
*/
|
|
119
|
+
Group.prototype.verifyProofOfMembership = function (proof) {
|
|
120
|
+
return this._merkleTree.verifyProof(proof);
|
|
121
|
+
};
|
|
122
|
+
return Group;
|
|
123
|
+
}());
|
|
124
|
+
|
|
125
|
+
exports.Group = Group;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { MerkleProof } from "@zk-kit/incremental-merkle-tree";
|
|
2
|
+
import { Member } from "./types";
|
|
3
|
+
export default class Group {
|
|
4
|
+
private _merkleTree;
|
|
5
|
+
/**
|
|
6
|
+
* Initializes the group with the tree depth and the zero value.
|
|
7
|
+
* @param treeDepth Tree depth.
|
|
8
|
+
* @param zeroValue Zero values for zeroes.
|
|
9
|
+
*/
|
|
10
|
+
constructor(treeDepth?: number, zeroValue?: Member);
|
|
11
|
+
/**
|
|
12
|
+
* Returns the root hash of the tree.
|
|
13
|
+
* @returns Root hash.
|
|
14
|
+
*/
|
|
15
|
+
get root(): Member;
|
|
16
|
+
/**
|
|
17
|
+
* Returns the depth of the tree.
|
|
18
|
+
* @returns Tree depth.
|
|
19
|
+
*/
|
|
20
|
+
get depth(): number;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the zero value of the tree.
|
|
23
|
+
* @returns Tree zero value.
|
|
24
|
+
*/
|
|
25
|
+
get zeroValue(): Member;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the members (i.e. identity commitments) of the group.
|
|
28
|
+
* @returns List of members.
|
|
29
|
+
*/
|
|
30
|
+
get members(): Member[];
|
|
31
|
+
/**
|
|
32
|
+
* Returns the index of a member. If the member does not exist it returns -1.
|
|
33
|
+
* @param member Group member.
|
|
34
|
+
* @returns Index of the member.
|
|
35
|
+
*/
|
|
36
|
+
indexOf(member: Member): number;
|
|
37
|
+
/**
|
|
38
|
+
* Adds a new member to the group.
|
|
39
|
+
* @param identityCommitment New member.
|
|
40
|
+
*/
|
|
41
|
+
addMember(identityCommitment: Member): void;
|
|
42
|
+
/**
|
|
43
|
+
* Adds new members to the group.
|
|
44
|
+
* @param identityCommitments New members.
|
|
45
|
+
*/
|
|
46
|
+
addMembers(identityCommitments: Member[]): void;
|
|
47
|
+
/**
|
|
48
|
+
* Removes a member from the group.
|
|
49
|
+
* @param index Index of the member to be removed.
|
|
50
|
+
*/
|
|
51
|
+
removeMember(index: number): void;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a proof of membership.
|
|
54
|
+
* @param index Index of the proof's member.
|
|
55
|
+
* @returns Proof object.
|
|
56
|
+
*/
|
|
57
|
+
generateProofOfMembership(index: number): MerkleProof;
|
|
58
|
+
/**
|
|
59
|
+
* Verifies a proof of membership and return true or false.
|
|
60
|
+
* @param proof Proof to be verified.
|
|
61
|
+
* @returns True or false.
|
|
62
|
+
*/
|
|
63
|
+
verifyProofOfMembership(proof: MerkleProof): boolean;
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare type Member = string | bigint;
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@semaphore-protocol/group",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A library for managing Semaphore groups.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.node.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
"import": "./dist/index.mjs",
|
|
9
|
+
"require": "./dist/index.node.js"
|
|
10
|
+
},
|
|
11
|
+
"types": "dist/types/index.d.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"src/",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"repository": "https://github.com/semaphore-protocol/semaphore.js",
|
|
19
|
+
"homepage": "https://github.com/semaphore-protocol/semaphore.js/tree/main/packages/group",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
|
|
22
|
+
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
|
|
23
|
+
"prepublishOnly": "yarn build",
|
|
24
|
+
"docs": "typedoc src/index.ts --out ../../docs/group"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"rollup-plugin-cleanup": "^3.2.1",
|
|
31
|
+
"rollup-plugin-typescript2": "^0.31.2",
|
|
32
|
+
"typedoc": "^0.22.11"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@zk-kit/incremental-merkle-tree": "0.4.3",
|
|
36
|
+
"circomlibjs": "0.0.8"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import Group from "./group"
|
|
2
|
+
|
|
3
|
+
describe("Group", () => {
|
|
4
|
+
describe("# Group", () => {
|
|
5
|
+
it("Should create a group", () => {
|
|
6
|
+
const group = new Group()
|
|
7
|
+
|
|
8
|
+
expect(group.root.toString()).toContain("150197")
|
|
9
|
+
expect(group.depth).toBe(20)
|
|
10
|
+
expect(group.zeroValue).toBe(BigInt(0))
|
|
11
|
+
expect(group.members).toHaveLength(0)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it("Should not create a group with a wrong tree depth", () => {
|
|
15
|
+
const fun = () => new Group(33)
|
|
16
|
+
|
|
17
|
+
expect(fun).toThrow("The tree depth must be between 16 and 32")
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("Should create a group with different parameters", () => {
|
|
21
|
+
const group = new Group(32, BigInt(1))
|
|
22
|
+
|
|
23
|
+
expect(group.root.toString()).toContain("640470")
|
|
24
|
+
expect(group.depth).toBe(32)
|
|
25
|
+
expect(group.zeroValue).toBe(BigInt(1))
|
|
26
|
+
expect(group.members).toHaveLength(0)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe("# addMember", () => {
|
|
31
|
+
it("Should add a member to a group", () => {
|
|
32
|
+
const group = new Group()
|
|
33
|
+
|
|
34
|
+
group.addMember(BigInt(3))
|
|
35
|
+
|
|
36
|
+
expect(group.members).toHaveLength(1)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe("# addMembers", () => {
|
|
41
|
+
it("Should add many members to a group", () => {
|
|
42
|
+
const group = new Group()
|
|
43
|
+
|
|
44
|
+
group.addMembers([BigInt(1), BigInt(3)])
|
|
45
|
+
|
|
46
|
+
expect(group.members).toHaveLength(2)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe("# indexOf", () => {
|
|
51
|
+
it("Should return the index of a member in a group", () => {
|
|
52
|
+
const group = new Group()
|
|
53
|
+
group.addMembers([BigInt(1), BigInt(3)])
|
|
54
|
+
|
|
55
|
+
const index = group.indexOf(BigInt(3))
|
|
56
|
+
|
|
57
|
+
expect(index).toBe(1)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe("# removeMember", () => {
|
|
62
|
+
it("Should remove a member from a group", () => {
|
|
63
|
+
const group = new Group()
|
|
64
|
+
group.addMembers([BigInt(1), BigInt(3)])
|
|
65
|
+
|
|
66
|
+
group.removeMember(0)
|
|
67
|
+
|
|
68
|
+
expect(group.members).toHaveLength(2)
|
|
69
|
+
expect(group.members[0]).toBe(group.zeroValue)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe("# generateProofOfMembership", () => {
|
|
74
|
+
it("Should generate a proof of membership", () => {
|
|
75
|
+
const group = new Group()
|
|
76
|
+
group.addMembers([BigInt(1), BigInt(3)])
|
|
77
|
+
|
|
78
|
+
const proof = group.generateProofOfMembership(0)
|
|
79
|
+
|
|
80
|
+
expect(proof.leaf).toBe(BigInt(1))
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe("# verifyProofOfMembership", () => {
|
|
85
|
+
it("Should verify a proof of membership", () => {
|
|
86
|
+
const group = new Group()
|
|
87
|
+
group.addMembers([BigInt(1), BigInt(3)])
|
|
88
|
+
const proof = group.generateProofOfMembership(0)
|
|
89
|
+
|
|
90
|
+
const response = group.verifyProofOfMembership(proof)
|
|
91
|
+
|
|
92
|
+
expect(response).toBeTruthy()
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
})
|
package/src/group.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree"
|
|
2
|
+
import { poseidon } from "circomlibjs"
|
|
3
|
+
import { Member } from "./types"
|
|
4
|
+
|
|
5
|
+
export default class Group {
|
|
6
|
+
private _merkleTree: IncrementalMerkleTree
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initializes the group with the tree depth and the zero value.
|
|
10
|
+
* @param treeDepth Tree depth.
|
|
11
|
+
* @param zeroValue Zero values for zeroes.
|
|
12
|
+
*/
|
|
13
|
+
constructor(treeDepth = 20, zeroValue: Member = BigInt(0)) {
|
|
14
|
+
if (treeDepth < 16 || treeDepth > 32) {
|
|
15
|
+
throw new Error("The tree depth must be between 16 and 32")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
this._merkleTree = new IncrementalMerkleTree(poseidon, treeDepth, zeroValue, 2)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the root hash of the tree.
|
|
23
|
+
* @returns Root hash.
|
|
24
|
+
*/
|
|
25
|
+
get root(): Member {
|
|
26
|
+
return this._merkleTree.root
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the depth of the tree.
|
|
31
|
+
* @returns Tree depth.
|
|
32
|
+
*/
|
|
33
|
+
get depth(): number {
|
|
34
|
+
return this._merkleTree.depth
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the zero value of the tree.
|
|
39
|
+
* @returns Tree zero value.
|
|
40
|
+
*/
|
|
41
|
+
get zeroValue(): Member {
|
|
42
|
+
return this._merkleTree.zeroes[0]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns the members (i.e. identity commitments) of the group.
|
|
47
|
+
* @returns List of members.
|
|
48
|
+
*/
|
|
49
|
+
get members(): Member[] {
|
|
50
|
+
return this._merkleTree.leaves
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the index of a member. If the member does not exist it returns -1.
|
|
55
|
+
* @param member Group member.
|
|
56
|
+
* @returns Index of the member.
|
|
57
|
+
*/
|
|
58
|
+
indexOf(member: Member): number {
|
|
59
|
+
return this._merkleTree.indexOf(member)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Adds a new member to the group.
|
|
64
|
+
* @param identityCommitment New member.
|
|
65
|
+
*/
|
|
66
|
+
addMember(identityCommitment: Member) {
|
|
67
|
+
this._merkleTree.insert(identityCommitment)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Adds new members to the group.
|
|
72
|
+
* @param identityCommitments New members.
|
|
73
|
+
*/
|
|
74
|
+
addMembers(identityCommitments: Member[]) {
|
|
75
|
+
for (const identityCommitment of identityCommitments) {
|
|
76
|
+
this.addMember(identityCommitment)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Removes a member from the group.
|
|
82
|
+
* @param index Index of the member to be removed.
|
|
83
|
+
*/
|
|
84
|
+
removeMember(index: number) {
|
|
85
|
+
this._merkleTree.delete(index)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a proof of membership.
|
|
90
|
+
* @param index Index of the proof's member.
|
|
91
|
+
* @returns Proof object.
|
|
92
|
+
*/
|
|
93
|
+
generateProofOfMembership(index: number): MerkleProof {
|
|
94
|
+
return this._merkleTree.createProof(index)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Verifies a proof of membership and return true or false.
|
|
99
|
+
* @param proof Proof to be verified.
|
|
100
|
+
* @returns True or false.
|
|
101
|
+
*/
|
|
102
|
+
verifyProofOfMembership(proof: MerkleProof): boolean {
|
|
103
|
+
return this._merkleTree.verifyProof(proof)
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Member = string | bigint
|