@semaphore-protocol/contracts 4.14.3 → 4.14.4
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 +34 -13
- package/interfaces/ISemaphore.sol +8 -1
- package/package.json +1 -1
package/Semaphore.sol
CHANGED
|
@@ -10,8 +10,8 @@ import {MIN_DEPTH, MAX_DEPTH} from "./base/Constants.sol";
|
|
|
10
10
|
/// @dev This contract uses the Semaphore base contracts to provide a complete service
|
|
11
11
|
/// to allow admins to create and manage groups and their members to verify Semaphore proofs
|
|
12
12
|
/// Group admins can add, update or remove group members, and can be an Ethereum account or a smart contract.
|
|
13
|
-
/// This contract also
|
|
14
|
-
///
|
|
13
|
+
/// This contract also gives each root a duration (or an expiry) within which the proofs generated with
|
|
14
|
+
/// that root can still be validated after the root has been replaced by a newer one.
|
|
15
15
|
contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
16
16
|
ISemaphoreVerifier public verifier;
|
|
17
17
|
|
|
@@ -76,16 +76,26 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
76
76
|
|
|
77
77
|
/// @dev See {SemaphoreGroups-_addMember}.
|
|
78
78
|
function addMember(uint256 groupId, uint256 identityCommitment) external override {
|
|
79
|
-
uint256
|
|
79
|
+
uint256 oldMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
_addMember(groupId, identityCommitment);
|
|
82
|
+
|
|
83
|
+
// 0 marks a root as unknown and is also the root of a group with no members,
|
|
84
|
+
// so it is never stored.
|
|
85
|
+
if (oldMerkleTreeRoot != 0) {
|
|
86
|
+
groups[groupId].merkleRootSupersededDates[oldMerkleTreeRoot] = block.timestamp;
|
|
87
|
+
}
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
/// @dev See {SemaphoreGroups-_addMembers}.
|
|
85
91
|
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
|
|
86
|
-
uint256
|
|
92
|
+
uint256 oldMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
93
|
+
|
|
94
|
+
_addMembers(groupId, identityCommitments);
|
|
87
95
|
|
|
88
|
-
|
|
96
|
+
if (oldMerkleTreeRoot != 0) {
|
|
97
|
+
groups[groupId].merkleRootSupersededDates[oldMerkleTreeRoot] = block.timestamp;
|
|
98
|
+
}
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
/// @dev See {SemaphoreGroups-_updateMember}.
|
|
@@ -95,9 +105,12 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
95
105
|
uint256 newIdentityCommitment,
|
|
96
106
|
uint256[] calldata merkleProofSiblings
|
|
97
107
|
) external override {
|
|
98
|
-
uint256
|
|
108
|
+
uint256 oldMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
109
|
+
|
|
110
|
+
_updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
|
|
99
111
|
|
|
100
|
-
|
|
112
|
+
// A group whose root is 0 has no members to update, so the old root is never 0.
|
|
113
|
+
groups[groupId].merkleRootSupersededDates[oldMerkleTreeRoot] = block.timestamp;
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
/// @dev See {SemaphoreGroups-_removeMember}.
|
|
@@ -106,9 +119,12 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
106
119
|
uint256 identityCommitment,
|
|
107
120
|
uint256[] calldata merkleProofSiblings
|
|
108
121
|
) external override {
|
|
109
|
-
uint256
|
|
122
|
+
uint256 oldMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
123
|
+
|
|
124
|
+
_removeMember(groupId, identityCommitment, merkleProofSiblings);
|
|
110
125
|
|
|
111
|
-
|
|
126
|
+
// A group whose root is 0 has no members to remove, so the old root is never 0.
|
|
127
|
+
groups[groupId].merkleRootSupersededDates[oldMerkleTreeRoot] = block.timestamp;
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
/// @dev See {ISemaphore-validateProof}.
|
|
@@ -164,14 +180,19 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
164
180
|
// A proof could have used an old Merkle tree root.
|
|
165
181
|
// https://github.com/semaphore-protocol/semaphore/issues/98
|
|
166
182
|
if (proof.merkleTreeRoot != currentMerkleTreeRoot) {
|
|
167
|
-
|
|
183
|
+
// An old root is accepted until merkleTreeDuration has passed since it was replaced,
|
|
184
|
+
// giving proofs made while it was still the current root time to arrive. The end of
|
|
185
|
+
// the window is exclusive, so a duration of 0 rejects every old root.
|
|
186
|
+
uint256 merkleRootSupersededDate = groups[groupId].merkleRootSupersededDates[proof.merkleTreeRoot];
|
|
168
187
|
uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;
|
|
169
188
|
|
|
170
|
-
if (
|
|
189
|
+
if (merkleRootSupersededDate == 0) {
|
|
171
190
|
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
|
|
172
191
|
}
|
|
173
192
|
|
|
174
|
-
|
|
193
|
+
// merkleRootSupersededDate is never in the future, so this cannot underflow
|
|
194
|
+
// and the check stays within uint256 for any duration.
|
|
195
|
+
if (block.timestamp - merkleRootSupersededDate >= merkleTreeDuration) {
|
|
175
196
|
revert Semaphore__MerkleTreeRootIsExpired();
|
|
176
197
|
}
|
|
177
198
|
}
|
|
@@ -13,7 +13,10 @@ interface ISemaphore {
|
|
|
13
13
|
/// It defines all the group parameters used by Semaphore.sol.
|
|
14
14
|
struct Group {
|
|
15
15
|
uint256 merkleTreeDuration;
|
|
16
|
-
|
|
16
|
+
/// @dev Gets a Merkle root and returns the time at which it was replaced, which is when
|
|
17
|
+
/// its expiration starts. The current root is not in this mapping, as its expiration
|
|
18
|
+
/// has not started yet.
|
|
19
|
+
mapping(uint256 => uint256) merkleRootSupersededDates;
|
|
17
20
|
mapping(uint256 => bool) nullifiers;
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -78,6 +81,10 @@ interface ISemaphore {
|
|
|
78
81
|
function acceptGroupAdmin(uint256 groupId) external;
|
|
79
82
|
|
|
80
83
|
/// @dev Updates the group Merkle tree duration.
|
|
84
|
+
/// The new duration applies to every past root of the group, not only to roots superseded
|
|
85
|
+
/// after this call, so raising it makes older roots valid again and lowering it invalidates
|
|
86
|
+
/// proofs that are already in flight. It is also how long a removed member can keep proving
|
|
87
|
+
/// membership with an older root, so it should be kept as short as the group can tolerate.
|
|
81
88
|
/// @param groupId: Id of the group.
|
|
82
89
|
/// @param newMerkleTreeDuration: New Merkle tree duration.
|
|
83
90
|
function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;
|