@semaphore-protocol/contracts 2.4.0 → 2.5.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/Semaphore.sol CHANGED
@@ -11,16 +11,13 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
11
11
  /// @dev Gets a tree depth and returns its verifier address.
12
12
  mapping(uint256 => IVerifier) public verifiers;
13
13
 
14
- /// @dev Gets a group id and returns the group admin address.
15
- mapping(uint256 => address) public groupAdmins;
16
-
17
- /// @dev Gets a group id and returns data to check if a Merkle root is expired.
18
- mapping(uint256 => MerkleTreeExpiry) public merkleTreeExpiries;
14
+ /// @dev Gets a group id and returns the group parameters.
15
+ mapping(uint256 => Group) public groups;
19
16
 
20
17
  /// @dev Checks if the group admin is the transaction sender.
21
18
  /// @param groupId: Id of the group.
22
19
  modifier onlyGroupAdmin(uint256 groupId) {
23
- if (groupAdmins[groupId] != _msgSender()) {
20
+ if (groups[groupId].admin != _msgSender()) {
24
21
  revert Semaphore__CallerIsNotTheGroupAdmin();
25
22
  }
26
23
  _;
@@ -56,8 +53,8 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
56
53
  ) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
57
54
  _createGroup(groupId, merkleTreeDepth, zeroValue);
58
55
 
59
- groupAdmins[groupId] = admin;
60
- merkleTreeExpiries[groupId].rootDuration = 1 hours;
56
+ groups[groupId].admin = admin;
57
+ groups[groupId].merkleRootDuration = 1 hours;
61
58
 
62
59
  emit GroupAdminUpdated(groupId, address(0), admin);
63
60
  }
@@ -72,15 +69,15 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
72
69
  ) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
73
70
  _createGroup(groupId, merkleTreeDepth, zeroValue);
74
71
 
75
- groupAdmins[groupId] = admin;
76
- merkleTreeExpiries[groupId].rootDuration = merkleTreeRootDuration;
72
+ groups[groupId].admin = admin;
73
+ groups[groupId].merkleRootDuration = merkleTreeRootDuration;
77
74
 
78
75
  emit GroupAdminUpdated(groupId, address(0), admin);
79
76
  }
80
77
 
81
78
  /// @dev See {ISemaphore-updateGroupAdmin}.
82
79
  function updateGroupAdmin(uint256 groupId, address newAdmin) external override onlyGroupAdmin(groupId) {
83
- groupAdmins[groupId] = newAdmin;
80
+ groups[groupId].admin = newAdmin;
84
81
 
85
82
  emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
86
83
  }
@@ -91,7 +88,7 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
91
88
 
92
89
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
93
90
 
94
- merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
91
+ groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
95
92
  }
96
93
 
97
94
  /// @dev See {ISemaphore-addMembers}.
@@ -110,7 +107,7 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
110
107
 
111
108
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
112
109
 
113
- merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
110
+ groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
114
111
  }
115
112
 
116
113
  /// @dev See {ISemaphore-updateMember}.
@@ -150,25 +147,29 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
150
147
  }
151
148
 
152
149
  if (merkleTreeRoot != currentMerkleTreeRoot) {
153
- uint256 rootCreationDate = merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot];
154
- uint256 rootDuration = merkleTreeExpiries[groupId].rootDuration;
150
+ uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
151
+ uint256 merkleRootDuration = groups[groupId].merkleRootDuration;
155
152
 
156
- if (rootCreationDate == 0) {
153
+ if (merkleRootCreationDate == 0) {
157
154
  revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
158
155
  }
159
156
 
160
- if (block.timestamp > rootCreationDate + rootDuration) {
157
+ if (block.timestamp > merkleRootCreationDate + merkleRootDuration) {
161
158
  revert Semaphore__MerkleTreeRootIsExpired();
162
159
  }
163
160
  }
164
161
 
162
+ if (groups[groupId].nullifierHashes[nullifierHash]) {
163
+ revert Semaphore__YouAreUsingTheSameNillifierTwice();
164
+ }
165
+
165
166
  uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
166
167
 
167
168
  IVerifier verifier = verifiers[merkleTreeDepth];
168
169
 
169
170
  _verifyProof(signal, merkleTreeRoot, nullifierHash, externalNullifier, proof, verifier);
170
171
 
171
- _saveNullifierHash(uint256(keccak256(abi.encodePacked(groupId, nullifierHash))));
172
+ groups[groupId].nullifierHashes[nullifierHash] = true;
172
173
 
173
174
  emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
174
175
  }
@@ -10,10 +10,6 @@ import "../interfaces/IVerifier.sol";
10
10
  /// nullifier to prevent double-signaling. External nullifier and Merkle trees (i.e. groups) must be
11
11
  /// managed externally.
12
12
  contract SemaphoreCore is ISemaphoreCore {
13
- /// @dev Gets a nullifier hash and returns true or false.
14
- /// It is used to prevent double-signaling.
15
- mapping(uint256 => bool) internal nullifierHashes;
16
-
17
13
  /// @dev Asserts that no nullifier already exists and if the zero-knowledge proof is valid.
18
14
  /// Otherwise it reverts.
19
15
  /// @param signal: Semaphore signal.
@@ -30,10 +26,6 @@ contract SemaphoreCore is ISemaphoreCore {
30
26
  uint256[8] calldata proof,
31
27
  IVerifier verifier
32
28
  ) internal view {
33
- if (nullifierHashes[nullifierHash]) {
34
- revert Semaphore__YouAreUsingTheSameNillifierTwice();
35
- }
36
-
37
29
  uint256 signalHash = _hashSignal(signal);
38
30
 
39
31
  verifier.verifyProof(
@@ -44,14 +36,6 @@ contract SemaphoreCore is ISemaphoreCore {
44
36
  );
45
37
  }
46
38
 
47
- /// @dev Stores the nullifier hash to prevent double-signaling.
48
- /// Attention! Remember to call it when you verify a proof if you
49
- /// need to prevent double-signaling.
50
- /// @param nullifierHash: Semaphore nullifier hash.
51
- function _saveNullifierHash(uint256 nullifierHash) internal {
52
- nullifierHashes[nullifierHash] = true;
53
- }
54
-
55
39
  /// @dev Creates a keccak256 hash of the signal.
56
40
  /// @param signal: Semaphore signal.
57
41
  /// @return Hash of the signal.
@@ -12,8 +12,8 @@ import "@openzeppelin/contracts/utils/Context.sol";
12
12
  abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
13
13
  using IncrementalBinaryTree for IncrementalTreeData;
14
14
 
15
- /// @dev Gets a group id and returns the group/tree data.
16
- mapping(uint256 => IncrementalTreeData) internal groups;
15
+ /// @dev Gets a group id and returns the tree data.
16
+ mapping(uint256 => IncrementalTreeData) internal merkleTree;
17
17
 
18
18
  /// @dev Creates a new group by initializing the associated tree.
19
19
  /// @param groupId: Id of the group.
@@ -32,7 +32,7 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
32
32
  revert Semaphore__GroupAlreadyExists();
33
33
  }
34
34
 
35
- groups[groupId].init(merkleTreeDepth, zeroValue);
35
+ merkleTree[groupId].init(merkleTreeDepth, zeroValue);
36
36
 
37
37
  emit GroupCreated(groupId, merkleTreeDepth, zeroValue);
38
38
  }
@@ -45,7 +45,7 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
45
45
  revert Semaphore__GroupDoesNotExist();
46
46
  }
47
47
 
48
- groups[groupId].insert(identityCommitment);
48
+ merkleTree[groupId].insert(identityCommitment);
49
49
 
50
50
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
51
51
  uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
@@ -71,7 +71,7 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
71
71
  revert Semaphore__GroupDoesNotExist();
72
72
  }
73
73
 
74
- groups[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
74
+ merkleTree[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
75
75
 
76
76
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
77
77
  uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
@@ -95,7 +95,7 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
95
95
  revert Semaphore__GroupDoesNotExist();
96
96
  }
97
97
 
98
- groups[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
98
+ merkleTree[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
99
99
 
100
100
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
101
101
  uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
@@ -105,17 +105,17 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
105
105
 
106
106
  /// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
107
107
  function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
108
- return groups[groupId].root;
108
+ return merkleTree[groupId].root;
109
109
  }
110
110
 
111
111
  /// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
112
112
  function getMerkleTreeDepth(uint256 groupId) public view virtual override returns (uint256) {
113
- return groups[groupId].depth;
113
+ return merkleTree[groupId].depth;
114
114
  }
115
115
 
116
116
  /// @dev See {ISemaphoreGroups-getNumberOfMerkleTreeLeaves}.
117
117
  function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
118
- return groups[groupId].numberOfLeaves;
118
+ return merkleTree[groupId].numberOfLeaves;
119
119
  }
120
120
 
121
121
  /// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
@@ -14,6 +14,10 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
14
14
  /// @dev Gets a poll id and returns the poll data.
15
15
  mapping(uint256 => Poll) internal polls;
16
16
 
17
+ /// @dev Gets a nullifier hash and returns true or false.
18
+ /// It is used to prevent double-voting.
19
+ mapping(uint256 => bool) internal nullifierHashes;
20
+
17
21
  /// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
18
22
  /// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
19
23
  constructor(Verifier[] memory _verifiers) {
@@ -90,6 +94,10 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
90
94
  revert Semaphore__PollIsNotOngoing();
91
95
  }
92
96
 
97
+ if (nullifierHashes[nullifierHash]) {
98
+ revert Semaphore__YouAreUsingTheSameNillifierTwice();
99
+ }
100
+
93
101
  uint256 merkleTreeDepth = getMerkleTreeDepth(pollId);
94
102
  uint256 merkleTreeRoot = getMerkleTreeRoot(pollId);
95
103
 
@@ -97,8 +105,7 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
97
105
 
98
106
  _verifyProof(vote, merkleTreeRoot, nullifierHash, pollId, proof, verifier);
99
107
 
100
- // Prevent double-voting (nullifierHash = hash(pollId + identityNullifier)).
101
- _saveNullifierHash(nullifierHash);
108
+ nullifierHashes[nullifierHash] = true;
102
109
 
103
110
  emit VoteAdded(pollId, vote);
104
111
  }
@@ -8,17 +8,19 @@ interface ISemaphore {
8
8
  error Semaphore__MerkleTreeDepthIsNotSupported();
9
9
  error Semaphore__MerkleTreeRootIsExpired();
10
10
  error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
11
+ error Semaphore__YouAreUsingTheSameNillifierTwice();
11
12
 
12
13
  struct Verifier {
13
14
  address contractAddress;
14
15
  uint256 merkleTreeDepth;
15
16
  }
16
17
 
17
- /// It defines all the parameters needed to check whether a
18
- /// zero-knowledge proof generated with a certain Merkle tree is still valid.
19
- struct MerkleTreeExpiry {
20
- uint256 rootDuration;
21
- mapping(uint256 => uint256) rootCreationDates;
18
+ /// It defines all the group parameters, in addition to those in the Merkle tree.
19
+ struct Group {
20
+ address admin;
21
+ uint256 merkleRootDuration;
22
+ mapping(uint256 => uint256) merkleRootCreationDates;
23
+ mapping(uint256 => bool) nullifierHashes;
22
24
  }
23
25
 
24
26
  /// @dev Emitted when an admin is assigned to a group.
@@ -4,8 +4,6 @@ pragma solidity 0.8.4;
4
4
  /// @title SemaphoreCore interface.
5
5
  /// @dev Interface of SemaphoreCore contract.
6
6
  interface ISemaphoreCore {
7
- error Semaphore__YouAreUsingTheSameNillifierTwice();
8
-
9
7
  /// @notice Emitted when a proof is verified correctly and a new nullifier hash is added.
10
8
  /// @param nullifierHash: Hash of external and identity nullifiers.
11
9
  event NullifierHashAdded(uint256 nullifierHash);
@@ -8,6 +8,7 @@ interface ISemaphoreVoting {
8
8
  error Semaphore__MerkleTreeDepthIsNotSupported();
9
9
  error Semaphore__PollHasAlreadyBeenStarted();
10
10
  error Semaphore__PollIsNotOngoing();
11
+ error Semaphore__YouAreUsingTheSameNillifierTwice();
11
12
 
12
13
  enum PollState {
13
14
  Created,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/contracts",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
5
5
  "license": "MIT",
6
6
  "files": [