@semaphore-protocol/contracts 2.4.0 → 2.6.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 +19 -18
- package/base/SemaphoreCore.sol +0 -16
- package/base/SemaphoreGroups.sol +9 -9
- package/extensions/SemaphoreVoting.sol +9 -2
- package/interfaces/ISemaphore.sol +7 -5
- package/interfaces/ISemaphoreCore.sol +0 -2
- package/interfaces/ISemaphoreVoting.sol +1 -0
- package/package.json +3 -3
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
|
|
15
|
-
mapping(uint256 =>
|
|
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 (
|
|
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
|
-
|
|
60
|
-
|
|
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
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
154
|
-
uint256
|
|
150
|
+
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
|
|
151
|
+
uint256 merkleRootDuration = groups[groupId].merkleRootDuration;
|
|
155
152
|
|
|
156
|
-
if (
|
|
153
|
+
if (merkleRootCreationDate == 0) {
|
|
157
154
|
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
if (block.timestamp >
|
|
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
|
-
|
|
172
|
+
groups[groupId].nullifierHashes[nullifierHash] = true;
|
|
172
173
|
|
|
173
174
|
emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
|
|
174
175
|
}
|
package/base/SemaphoreCore.sol
CHANGED
|
@@ -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.
|
package/base/SemaphoreGroups.sol
CHANGED
|
@@ -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
|
|
16
|
-
mapping(uint256 => IncrementalTreeData) internal
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
uint256
|
|
21
|
-
mapping(uint256 => uint256)
|
|
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);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semaphore-protocol/contracts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@openzeppelin/contracts": "4.
|
|
33
|
-
"@zk-kit/incremental-merkle-tree.sol": "1.3.
|
|
32
|
+
"@openzeppelin/contracts": "4.7.3",
|
|
33
|
+
"@zk-kit/incremental-merkle-tree.sol": "1.3.1"
|
|
34
34
|
}
|
|
35
35
|
}
|