@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 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-semaphore-blue.svg?style=flat-square">
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>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
37
- <a href="https://t.me/joinchat/B-PQx1U3GtAh--Z4Fwo56A">
37
+ <a href="https://discord.gg/6mSdGHnstH">
38
38
  🗣️ Chat &amp; 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
  }
@@ -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(uint256 indexed groupId, bytes32 signal);
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 identityCommitment: New identity commitment.
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.1.0",
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
- "homepage": "https://github.com/semaphore-protocol/semaphore.git#readme",
24
- "repository": {
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
  },