@semaphore-protocol/contracts 2.1.0 → 2.4.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 +61 -2
- package/Semaphore.sol +21 -2
- package/base/SemaphoreGroups.sol +29 -3
- package/interfaces/ISemaphore.sol +15 -1
- package/interfaces/ISemaphoreGroups.sol +7 -3
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<a href="https://github.com/semaphore-protocol">
|
|
10
|
-
<img src="https://img.shields.io/badge/project-
|
|
10
|
+
<img src="https://img.shields.io/badge/project-Semaphore-blue.svg?style=flat-square">
|
|
11
11
|
</a>
|
|
12
12
|
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/LICENSE">
|
|
13
13
|
<img alt="Github license" src="https://img.shields.io/github/license/semaphore-protocol/semaphore.svg?style=flat-square">
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
🔎 Issues
|
|
35
35
|
</a>
|
|
36
36
|
<span> | </span>
|
|
37
|
-
<a href="https://
|
|
37
|
+
<a href="https://discord.gg/6mSdGHnstH">
|
|
38
38
|
🗣️ Chat & Support
|
|
39
39
|
</a>
|
|
40
40
|
</h4>
|
|
@@ -59,3 +59,62 @@ or yarn:
|
|
|
59
59
|
```bash
|
|
60
60
|
yarn add @semaphore-protocol/contracts
|
|
61
61
|
```
|
|
62
|
+
|
|
63
|
+
## 📜 Usage
|
|
64
|
+
|
|
65
|
+
### Compile contracts
|
|
66
|
+
|
|
67
|
+
Compile the smart contracts with [Hardhat](https://hardhat.org/):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
yarn compile
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Testing
|
|
74
|
+
|
|
75
|
+
Run [Mocha](https://mochajs.org/) to test the contracts:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
yarn test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
You can also generate a test coverage report:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
yarn test:coverage
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or a test gas report:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
yarn test:report-gas
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Deploy contracts
|
|
94
|
+
|
|
95
|
+
Deploy a verifier contract with depth = 20:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
yarn deploy:verifier --depth 20
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Deploy the `Semaphore.sol` contract with one verifier:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
yarn deploy:semaphore --verifiers '[{"merkleTreeDepth": 20, "contractAddress": "0x06bcD633988c1CE7Bd134DbE2C12119b6f3E4bD1"}]'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Deploy all verifiers and Semaphore contract:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
yarn deploy:all
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you want to deploy contracts in a specific network you can set up the `DEFAULT_NETWORK` variable in your `.env` file with the name of one of our supported networks (hardhat, localhost, goerli, arbitrum). Or you can specify it as option:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
yarn deploy:all --network goerli
|
|
117
|
+
yarn deploy:all --network localhost
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
If you want to deploy contracts on Goerli or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.
|
package/Semaphore.sol
CHANGED
|
@@ -94,6 +94,25 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
|
|
94
94
|
merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/// @dev See {ISemaphore-addMembers}.
|
|
98
|
+
function addMembers(uint256 groupId, uint256[] calldata identityCommitments)
|
|
99
|
+
external
|
|
100
|
+
override
|
|
101
|
+
onlyGroupAdmin(groupId)
|
|
102
|
+
{
|
|
103
|
+
for (uint8 i = 0; i < identityCommitments.length; ) {
|
|
104
|
+
_addMember(groupId, identityCommitments[i]);
|
|
105
|
+
|
|
106
|
+
unchecked {
|
|
107
|
+
++i;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
112
|
+
|
|
113
|
+
merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
114
|
+
}
|
|
115
|
+
|
|
97
116
|
/// @dev See {ISemaphore-updateMember}.
|
|
98
117
|
function updateMember(
|
|
99
118
|
uint256 groupId,
|
|
@@ -149,8 +168,8 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
|
|
149
168
|
|
|
150
169
|
_verifyProof(signal, merkleTreeRoot, nullifierHash, externalNullifier, proof, verifier);
|
|
151
170
|
|
|
152
|
-
_saveNullifierHash(nullifierHash);
|
|
171
|
+
_saveNullifierHash(uint256(keccak256(abi.encodePacked(groupId, nullifierHash))));
|
|
153
172
|
|
|
154
|
-
emit ProofVerified(groupId, signal);
|
|
173
|
+
emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
|
|
155
174
|
}
|
|
156
175
|
}
|
package/base/SemaphoreGroups.sol
CHANGED
|
@@ -48,8 +48,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
|
|
48
48
|
groups[groupId].insert(identityCommitment);
|
|
49
49
|
|
|
50
50
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
51
|
+
uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
|
|
51
52
|
|
|
52
|
-
emit MemberAdded(groupId, identityCommitment, merkleTreeRoot);
|
|
53
|
+
emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
/// @dev Updates an identity commitment of an existing group. A proof of membership is
|
|
@@ -73,8 +74,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
|
|
73
74
|
groups[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
|
|
74
75
|
|
|
75
76
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
77
|
+
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
|
|
76
78
|
|
|
77
|
-
emit MemberUpdated(groupId, identityCommitment, newIdentityCommitment, merkleTreeRoot);
|
|
79
|
+
emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
/// @dev Removes an identity commitment from an existing group. A proof of membership is
|
|
@@ -96,8 +98,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
|
|
96
98
|
groups[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
|
|
97
99
|
|
|
98
100
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
101
|
+
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
|
|
99
102
|
|
|
100
|
-
emit MemberRemoved(groupId, identityCommitment, merkleTreeRoot);
|
|
103
|
+
emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
/// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
|
|
@@ -114,4 +117,27 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
|
|
114
117
|
function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
|
|
115
118
|
return groups[groupId].numberOfLeaves;
|
|
116
119
|
}
|
|
120
|
+
|
|
121
|
+
/// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
|
|
122
|
+
/// @param proofPathIndices: Path of the proof of membership.
|
|
123
|
+
/// @return Index of a group member.
|
|
124
|
+
function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
|
|
125
|
+
uint256 memberIndex = 0;
|
|
126
|
+
|
|
127
|
+
for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
|
|
128
|
+
if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
|
|
129
|
+
memberIndex *= 2;
|
|
130
|
+
|
|
131
|
+
if (proofPathIndices[i - 1] == 1) {
|
|
132
|
+
memberIndex += 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
unchecked {
|
|
137
|
+
--i;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return memberIndex;
|
|
142
|
+
}
|
|
117
143
|
}
|
|
@@ -29,8 +29,17 @@ interface ISemaphore {
|
|
|
29
29
|
|
|
30
30
|
/// @dev Emitted when a Semaphore proof is verified.
|
|
31
31
|
/// @param groupId: Id of the group.
|
|
32
|
+
/// @param merkleTreeRoot: Root of the Merkle tree.
|
|
33
|
+
/// @param externalNullifier: External nullifier.
|
|
34
|
+
/// @param nullifierHash: Nullifier hash.
|
|
32
35
|
/// @param signal: Semaphore signal.
|
|
33
|
-
event ProofVerified(
|
|
36
|
+
event ProofVerified(
|
|
37
|
+
uint256 indexed groupId,
|
|
38
|
+
uint256 merkleTreeRoot,
|
|
39
|
+
uint256 externalNullifier,
|
|
40
|
+
uint256 nullifierHash,
|
|
41
|
+
bytes32 signal
|
|
42
|
+
);
|
|
34
43
|
|
|
35
44
|
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
|
|
36
45
|
/// if the zero-knowledge proof is valid.
|
|
@@ -85,6 +94,11 @@ interface ISemaphore {
|
|
|
85
94
|
/// @param identityCommitment: New identity commitment.
|
|
86
95
|
function addMember(uint256 groupId, uint256 identityCommitment) external;
|
|
87
96
|
|
|
97
|
+
/// @dev Adds new members to an existing group.
|
|
98
|
+
/// @param groupId: Id of the group.
|
|
99
|
+
/// @param identityCommitments: New identity commitments.
|
|
100
|
+
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external;
|
|
101
|
+
|
|
88
102
|
/// @dev Updates an identity commitment of an existing group. A proof of membership is
|
|
89
103
|
/// needed to check if the node to be updated is part of the tree.
|
|
90
104
|
/// @param groupId: Id of the group.
|
|
@@ -16,17 +16,20 @@ interface ISemaphoreGroups {
|
|
|
16
16
|
|
|
17
17
|
/// @dev Emitted when a new identity commitment is added.
|
|
18
18
|
/// @param groupId: Group id of the group.
|
|
19
|
+
/// @param index: Identity commitment index.
|
|
19
20
|
/// @param identityCommitment: New identity commitment.
|
|
20
21
|
/// @param merkleTreeRoot: New root hash of the tree.
|
|
21
|
-
event MemberAdded(uint256 indexed groupId, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
22
|
+
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
22
23
|
|
|
23
24
|
/// @dev Emitted when an identity commitment is updated.
|
|
24
25
|
/// @param groupId: Group id of the group.
|
|
25
|
-
/// @param
|
|
26
|
+
/// @param index: Identity commitment index.
|
|
27
|
+
/// @param identityCommitment: Existing identity commitment to be updated.
|
|
26
28
|
/// @param newIdentityCommitment: New identity commitment.
|
|
27
29
|
/// @param merkleTreeRoot: New root hash of the tree.
|
|
28
30
|
event MemberUpdated(
|
|
29
31
|
uint256 indexed groupId,
|
|
32
|
+
uint256 index,
|
|
30
33
|
uint256 identityCommitment,
|
|
31
34
|
uint256 newIdentityCommitment,
|
|
32
35
|
uint256 merkleTreeRoot
|
|
@@ -34,9 +37,10 @@ interface ISemaphoreGroups {
|
|
|
34
37
|
|
|
35
38
|
/// @dev Emitted when a new identity commitment is removed.
|
|
36
39
|
/// @param groupId: Group id of the group.
|
|
40
|
+
/// @param index: Identity commitment index.
|
|
37
41
|
/// @param identityCommitment: Existing identity commitment to be removed.
|
|
38
42
|
/// @param merkleTreeRoot: New root hash of the tree.
|
|
39
|
-
event MemberRemoved(uint256 indexed groupId, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
43
|
+
event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
40
44
|
|
|
41
45
|
/// @dev Returns the last root hash of a group.
|
|
42
46
|
/// @param groupId: Id of the group.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semaphore-protocol/contracts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -20,11 +20,8 @@
|
|
|
20
20
|
"circom",
|
|
21
21
|
"proof-of-membership"
|
|
22
22
|
],
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/semaphore-protocol/semaphore.git.git"
|
|
27
|
-
},
|
|
23
|
+
"repository": "https://github.com/semaphore-protocol/semaphore",
|
|
24
|
+
"homepage": "https://github.com/semaphore-protocol/semaphore/tree/main/packages/contracts",
|
|
28
25
|
"bugs": {
|
|
29
26
|
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
|
|
30
27
|
},
|