@semaphore-protocol/contracts 3.2.0 → 3.2.1
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 +193 -0
- package/package.json +2 -1
package/Semaphore.sol
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.4;
|
|
3
|
+
|
|
4
|
+
import "./interfaces/ISemaphore.sol";
|
|
5
|
+
import "./interfaces/ISemaphoreVerifier.sol";
|
|
6
|
+
import "./base/SemaphoreGroups.sol";
|
|
7
|
+
|
|
8
|
+
/// @title Semaphore
|
|
9
|
+
/// @dev This contract uses the Semaphore base contracts to provide a complete service
|
|
10
|
+
/// to allow admins to create and manage groups and their members to generate Semaphore proofs
|
|
11
|
+
/// and verify them. Group admins can add, update or remove group members, and can be
|
|
12
|
+
/// an Ethereum account or a smart contract. This contract also assigns each new Merkle tree
|
|
13
|
+
/// generated with a new root a duration (or an expiry) within which the proofs generated with that root
|
|
14
|
+
/// can be validated.
|
|
15
|
+
contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
16
|
+
ISemaphoreVerifier public verifier;
|
|
17
|
+
|
|
18
|
+
/// @dev Gets a group id and returns the group parameters.
|
|
19
|
+
mapping(uint256 => Group) public groups;
|
|
20
|
+
|
|
21
|
+
/// @dev Checks if the group admin is the transaction sender.
|
|
22
|
+
/// @param groupId: Id of the group.
|
|
23
|
+
modifier onlyGroupAdmin(uint256 groupId) {
|
|
24
|
+
if (groups[groupId].admin != _msgSender()) {
|
|
25
|
+
revert Semaphore__CallerIsNotTheGroupAdmin();
|
|
26
|
+
}
|
|
27
|
+
_;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @dev Checks if there is a verifier for the given tree depth.
|
|
31
|
+
/// @param merkleTreeDepth: Depth of the tree.
|
|
32
|
+
modifier onlySupportedMerkleTreeDepth(uint256 merkleTreeDepth) {
|
|
33
|
+
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
|
|
34
|
+
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
|
35
|
+
}
|
|
36
|
+
_;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
|
|
40
|
+
/// @param _verifier: Semaphore verifier address.
|
|
41
|
+
constructor(ISemaphoreVerifier _verifier) {
|
|
42
|
+
verifier = _verifier;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @dev See {ISemaphore-createGroup}.
|
|
46
|
+
function createGroup(
|
|
47
|
+
uint256 groupId,
|
|
48
|
+
uint256 merkleTreeDepth,
|
|
49
|
+
address admin
|
|
50
|
+
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
|
|
51
|
+
_createGroup(groupId, merkleTreeDepth);
|
|
52
|
+
|
|
53
|
+
groups[groupId].admin = admin;
|
|
54
|
+
groups[groupId].merkleTreeDuration = 1 hours;
|
|
55
|
+
|
|
56
|
+
emit GroupAdminUpdated(groupId, address(0), admin);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// @dev See {ISemaphore-createGroup}.
|
|
60
|
+
function createGroup(
|
|
61
|
+
uint256 groupId,
|
|
62
|
+
uint256 merkleTreeDepth,
|
|
63
|
+
address admin,
|
|
64
|
+
uint256 merkleTreeDuration
|
|
65
|
+
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
|
|
66
|
+
_createGroup(groupId, merkleTreeDepth);
|
|
67
|
+
|
|
68
|
+
groups[groupId].admin = admin;
|
|
69
|
+
groups[groupId].merkleTreeDuration = merkleTreeDuration;
|
|
70
|
+
|
|
71
|
+
emit GroupAdminUpdated(groupId, address(0), admin);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// @dev See {ISemaphore-updateGroupAdmin}.
|
|
75
|
+
function updateGroupAdmin(uint256 groupId, address newAdmin) external override onlyGroupAdmin(groupId) {
|
|
76
|
+
groups[groupId].admin = newAdmin;
|
|
77
|
+
|
|
78
|
+
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
|
|
82
|
+
function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration)
|
|
83
|
+
external
|
|
84
|
+
override
|
|
85
|
+
onlyGroupAdmin(groupId)
|
|
86
|
+
{
|
|
87
|
+
uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;
|
|
88
|
+
|
|
89
|
+
groups[groupId].merkleTreeDuration = newMerkleTreeDuration;
|
|
90
|
+
|
|
91
|
+
emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// @dev See {ISemaphore-addMember}.
|
|
95
|
+
function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
|
|
96
|
+
_addMember(groupId, identityCommitment);
|
|
97
|
+
|
|
98
|
+
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
99
|
+
|
|
100
|
+
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// @dev See {ISemaphore-addMembers}.
|
|
104
|
+
function addMembers(uint256 groupId, uint256[] calldata identityCommitments)
|
|
105
|
+
external
|
|
106
|
+
override
|
|
107
|
+
onlyGroupAdmin(groupId)
|
|
108
|
+
{
|
|
109
|
+
for (uint256 i = 0; i < identityCommitments.length; ) {
|
|
110
|
+
_addMember(groupId, identityCommitments[i]);
|
|
111
|
+
|
|
112
|
+
unchecked {
|
|
113
|
+
++i;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
118
|
+
|
|
119
|
+
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// @dev See {ISemaphore-updateMember}.
|
|
123
|
+
function updateMember(
|
|
124
|
+
uint256 groupId,
|
|
125
|
+
uint256 identityCommitment,
|
|
126
|
+
uint256 newIdentityCommitment,
|
|
127
|
+
uint256[] calldata proofSiblings,
|
|
128
|
+
uint8[] calldata proofPathIndices
|
|
129
|
+
) external override onlyGroupAdmin(groupId) {
|
|
130
|
+
_updateMember(groupId, identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
|
|
131
|
+
|
|
132
|
+
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
133
|
+
|
|
134
|
+
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// @dev See {ISemaphore-removeMember}.
|
|
138
|
+
function removeMember(
|
|
139
|
+
uint256 groupId,
|
|
140
|
+
uint256 identityCommitment,
|
|
141
|
+
uint256[] calldata proofSiblings,
|
|
142
|
+
uint8[] calldata proofPathIndices
|
|
143
|
+
) external override onlyGroupAdmin(groupId) {
|
|
144
|
+
_removeMember(groupId, identityCommitment, proofSiblings, proofPathIndices);
|
|
145
|
+
|
|
146
|
+
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
147
|
+
|
|
148
|
+
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// @dev See {ISemaphore-verifyProof}.
|
|
152
|
+
function verifyProof(
|
|
153
|
+
uint256 groupId,
|
|
154
|
+
uint256 merkleTreeRoot,
|
|
155
|
+
uint256 signal,
|
|
156
|
+
uint256 nullifierHash,
|
|
157
|
+
uint256 externalNullifier,
|
|
158
|
+
uint256[8] calldata proof
|
|
159
|
+
) external override {
|
|
160
|
+
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
|
|
161
|
+
|
|
162
|
+
if (merkleTreeDepth == 0) {
|
|
163
|
+
revert Semaphore__GroupDoesNotExist();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
167
|
+
|
|
168
|
+
// A proof could have used an old Merkle tree root.
|
|
169
|
+
// https://github.com/semaphore-protocol/semaphore/issues/98
|
|
170
|
+
if (merkleTreeRoot != currentMerkleTreeRoot) {
|
|
171
|
+
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
|
|
172
|
+
uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;
|
|
173
|
+
|
|
174
|
+
if (merkleRootCreationDate == 0) {
|
|
175
|
+
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (block.timestamp > merkleRootCreationDate + merkleTreeDuration) {
|
|
179
|
+
revert Semaphore__MerkleTreeRootIsExpired();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (groups[groupId].nullifierHashes[nullifierHash]) {
|
|
184
|
+
revert Semaphore__YouAreUsingTheSameNillifierTwice();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
verifier.verifyProof(merkleTreeRoot, nullifierHash, signal, externalNullifier, proof, merkleTreeDepth);
|
|
188
|
+
|
|
189
|
+
groups[groupId].nullifierHashes[nullifierHash] = true;
|
|
190
|
+
|
|
191
|
+
emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
|
|
192
|
+
}
|
|
193
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semaphore-protocol/contracts",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
7
|
+
"Semaphore.sol",
|
|
7
8
|
"**/*.sol"
|
|
8
9
|
],
|
|
9
10
|
"keywords": [
|