@semaphore-protocol/contracts 3.15.1 → 4.0.0-alpha
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/LICENSE +1 -1
- package/README.md +5 -5
- package/Semaphore.sol +75 -89
- package/base/SemaphoreGroups.sol +94 -82
- package/base/SemaphoreVerifier.sol +358 -104
- package/interfaces/ISemaphore.sol +65 -74
- package/interfaces/ISemaphoreGroups.sol +35 -6
- package/interfaces/ISemaphoreVerifier.sol +7 -31
- package/package.json +2 -3
- package/base/Pairing.sol +0 -151
- package/extensions/SemaphoreVoting.sol +0 -96
- package/extensions/SemaphoreWhistleblowing.sol +0 -77
- package/interfaces/ISemaphoreVoting.sol +0 -78
- package/interfaces/ISemaphoreWhistleblowing.sol +0 -53
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
</h4>
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
|
-
To learn more about contracts visit [semaphore.pse.dev](https://semaphore.pse.dev/
|
|
43
|
+
To learn more about contracts visit [semaphore.pse.dev](https://docs.semaphore.pse.dev/technical-reference/contracts).
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
@@ -107,14 +107,14 @@ yarn deploy:semaphore --semaphoreVerifier <address>
|
|
|
107
107
|
> **Note**
|
|
108
108
|
> Run `yarn deploy:semaphore --help` to see the complete list.
|
|
109
109
|
|
|
110
|
-
If you want to deploy your contract 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,
|
|
110
|
+
If you want to deploy your contract 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, sepolia, arbitrum). Or you can specify it as an option:
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
yarn deploy:semaphore --network goerli
|
|
114
113
|
yarn deploy:semaphore --network sepolia
|
|
115
114
|
yarn deploy:semaphore --network mumbai
|
|
116
|
-
yarn deploy:semaphore --network optimism-
|
|
115
|
+
yarn deploy:semaphore --network optimism-sepolia
|
|
116
|
+
yarn deploy:semaphore --network arbitrum-sepolia
|
|
117
117
|
yarn deploy:semaphore --network arbitrum
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
If you want to deploy contracts on
|
|
120
|
+
If you want to deploy contracts on Sepolia or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.
|
package/Semaphore.sol
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity 0.8.23;
|
|
3
3
|
|
|
4
|
-
import "./interfaces/ISemaphore.sol";
|
|
5
|
-
import "./interfaces/ISemaphoreVerifier.sol";
|
|
6
|
-
import "./base/SemaphoreGroups.sol";
|
|
4
|
+
import {ISemaphore} from "./interfaces/ISemaphore.sol";
|
|
5
|
+
import {ISemaphoreVerifier} from "./interfaces/ISemaphoreVerifier.sol";
|
|
6
|
+
import {SemaphoreGroups} from "./base/SemaphoreGroups.sol";
|
|
7
7
|
|
|
8
8
|
/// @title Semaphore
|
|
9
9
|
/// @dev This contract uses the Semaphore base contracts to provide a complete service
|
|
@@ -18,71 +18,36 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
18
18
|
/// @dev Gets a group id and returns the group parameters.
|
|
19
19
|
mapping(uint256 => Group) public groups;
|
|
20
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
21
|
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
|
|
40
|
-
/// @param _verifier: Semaphore verifier
|
|
22
|
+
/// @param _verifier: Semaphore verifier addresse.
|
|
41
23
|
constructor(ISemaphoreVerifier _verifier) {
|
|
42
24
|
verifier = _verifier;
|
|
43
25
|
}
|
|
44
26
|
|
|
45
|
-
/// @dev See {
|
|
46
|
-
function createGroup(
|
|
47
|
-
|
|
48
|
-
uint256 merkleTreeDepth,
|
|
49
|
-
address admin
|
|
50
|
-
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
|
|
51
|
-
_createGroup(groupId, merkleTreeDepth);
|
|
27
|
+
/// @dev See {SemaphoreGroups-_createGroup}.
|
|
28
|
+
function createGroup(uint256 groupId, address admin) external override {
|
|
29
|
+
_createGroup(groupId, admin);
|
|
52
30
|
|
|
53
|
-
groups[groupId].admin = admin;
|
|
54
31
|
groups[groupId].merkleTreeDuration = 1 hours;
|
|
55
|
-
|
|
56
|
-
emit GroupAdminUpdated(groupId, address(0), admin);
|
|
57
32
|
}
|
|
58
33
|
|
|
59
34
|
/// @dev See {ISemaphore-createGroup}.
|
|
60
|
-
function createGroup(
|
|
61
|
-
|
|
62
|
-
uint256 merkleTreeDepth,
|
|
63
|
-
address admin,
|
|
64
|
-
uint256 merkleTreeDuration
|
|
65
|
-
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
|
|
66
|
-
_createGroup(groupId, merkleTreeDepth);
|
|
35
|
+
function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external override {
|
|
36
|
+
_createGroup(groupId, admin);
|
|
67
37
|
|
|
68
|
-
groups[groupId].admin = admin;
|
|
69
38
|
groups[groupId].merkleTreeDuration = merkleTreeDuration;
|
|
70
|
-
|
|
71
|
-
emit GroupAdminUpdated(groupId, address(0), admin);
|
|
72
39
|
}
|
|
73
40
|
|
|
74
|
-
/// @dev See {
|
|
75
|
-
function updateGroupAdmin(uint256 groupId, address newAdmin) external override
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
|
|
41
|
+
/// @dev See {SemaphoreGroups-_updateGroupAdmin}.
|
|
42
|
+
function updateGroupAdmin(uint256 groupId, address newAdmin) external override {
|
|
43
|
+
_updateGroupAdmin(groupId, newAdmin);
|
|
79
44
|
}
|
|
80
45
|
|
|
81
46
|
/// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
|
|
82
47
|
function updateGroupMerkleTreeDuration(
|
|
83
48
|
uint256 groupId,
|
|
84
49
|
uint256 newMerkleTreeDuration
|
|
85
|
-
) external override onlyGroupAdmin(groupId) {
|
|
50
|
+
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
|
|
86
51
|
uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;
|
|
87
52
|
|
|
88
53
|
groups[groupId].merkleTreeDuration = newMerkleTreeDuration;
|
|
@@ -90,8 +55,8 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
90
55
|
emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
|
|
91
56
|
}
|
|
92
57
|
|
|
93
|
-
/// @dev See {
|
|
94
|
-
function addMember(uint256 groupId, uint256 identityCommitment) external override
|
|
58
|
+
/// @dev See {SemaphoreGroups-_addMember}.
|
|
59
|
+
function addMember(uint256 groupId, uint256 identityCommitment) external override {
|
|
95
60
|
_addMember(groupId, identityCommitment);
|
|
96
61
|
|
|
97
62
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
@@ -99,66 +64,81 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
99
64
|
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
100
65
|
}
|
|
101
66
|
|
|
102
|
-
/// @dev See {
|
|
103
|
-
function addMembers(
|
|
104
|
-
|
|
105
|
-
uint256[] calldata identityCommitments
|
|
106
|
-
) external override onlyGroupAdmin(groupId) {
|
|
107
|
-
for (uint256 i = 0; i < identityCommitments.length; ) {
|
|
108
|
-
_addMember(groupId, identityCommitments[i]);
|
|
109
|
-
|
|
110
|
-
unchecked {
|
|
111
|
-
++i;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
67
|
+
/// @dev See {SemaphoreGroups-_addMembers}.
|
|
68
|
+
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
|
|
69
|
+
_addMembers(groupId, identityCommitments);
|
|
114
70
|
|
|
115
71
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
116
72
|
|
|
117
73
|
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
118
74
|
}
|
|
119
75
|
|
|
120
|
-
/// @dev See {
|
|
76
|
+
/// @dev See {SemaphoreGroups-_updateMember}.
|
|
121
77
|
function updateMember(
|
|
122
78
|
uint256 groupId,
|
|
123
79
|
uint256 identityCommitment,
|
|
124
80
|
uint256 newIdentityCommitment,
|
|
125
|
-
uint256[] calldata
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
_updateMember(groupId, identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
|
|
81
|
+
uint256[] calldata merkleProofSiblings
|
|
82
|
+
) external override {
|
|
83
|
+
_updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
|
|
129
84
|
|
|
130
85
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
131
86
|
|
|
132
87
|
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
133
88
|
}
|
|
134
89
|
|
|
135
|
-
/// @dev See {
|
|
90
|
+
/// @dev See {SemaphoreGroups-_removeMember}.
|
|
136
91
|
function removeMember(
|
|
137
92
|
uint256 groupId,
|
|
138
93
|
uint256 identityCommitment,
|
|
139
|
-
uint256[] calldata
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
_removeMember(groupId, identityCommitment, proofSiblings, proofPathIndices);
|
|
94
|
+
uint256[] calldata merkleProofSiblings
|
|
95
|
+
) external override {
|
|
96
|
+
_removeMember(groupId, identityCommitment, merkleProofSiblings);
|
|
143
97
|
|
|
144
98
|
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
145
99
|
|
|
146
100
|
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
147
101
|
}
|
|
148
102
|
|
|
149
|
-
|
|
103
|
+
function validateProof(
|
|
104
|
+
uint256 groupId,
|
|
105
|
+
uint256 merkleTreeDepth,
|
|
106
|
+
uint256 merkleTreeRoot,
|
|
107
|
+
uint256 nullifier,
|
|
108
|
+
uint256 message,
|
|
109
|
+
uint256 scope,
|
|
110
|
+
uint256[8] calldata proof
|
|
111
|
+
) external override onlyExistingGroup(groupId) {
|
|
112
|
+
if (groups[groupId].nullifiers[nullifier]) {
|
|
113
|
+
revert Semaphore__YouAreUsingTheSameNullifierTwice();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!verifyProof(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, message, scope, proof)) {
|
|
117
|
+
revert Semaphore__InvalidProof();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
groups[groupId].nullifiers[nullifier] = true;
|
|
121
|
+
|
|
122
|
+
emit ProofValidated(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, message, scope, proof);
|
|
123
|
+
}
|
|
124
|
+
|
|
150
125
|
function verifyProof(
|
|
151
126
|
uint256 groupId,
|
|
127
|
+
uint256 merkleTreeDepth,
|
|
152
128
|
uint256 merkleTreeRoot,
|
|
153
|
-
uint256
|
|
154
|
-
uint256
|
|
155
|
-
uint256
|
|
129
|
+
uint256 nullifier,
|
|
130
|
+
uint256 message,
|
|
131
|
+
uint256 scope,
|
|
156
132
|
uint256[8] calldata proof
|
|
157
|
-
)
|
|
158
|
-
|
|
133
|
+
) public view override onlyExistingGroup(groupId) returns (bool) {
|
|
134
|
+
if (merkleTreeDepth < 1 || merkleTreeDepth > 12) {
|
|
135
|
+
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
|
136
|
+
}
|
|
159
137
|
|
|
160
|
-
|
|
161
|
-
|
|
138
|
+
uint256 merkleTreeSize = getMerkleTreeSize(groupId);
|
|
139
|
+
|
|
140
|
+
if (merkleTreeSize == 0) {
|
|
141
|
+
revert Semaphore__GroupHasNoMembers();
|
|
162
142
|
}
|
|
163
143
|
|
|
164
144
|
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
@@ -178,14 +158,20 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
178
158
|
}
|
|
179
159
|
}
|
|
180
160
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
161
|
+
return
|
|
162
|
+
verifier.verifyProof(
|
|
163
|
+
[proof[0], proof[1]],
|
|
164
|
+
[[proof[2], proof[3]], [proof[4], proof[5]]],
|
|
165
|
+
[proof[6], proof[7]],
|
|
166
|
+
[merkleTreeRoot, nullifier, _hash(message), _hash(scope)],
|
|
167
|
+
merkleTreeDepth
|
|
168
|
+
);
|
|
169
|
+
}
|
|
188
170
|
|
|
189
|
-
|
|
171
|
+
/// @dev Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
|
|
172
|
+
/// @param message: Message to be hashed.
|
|
173
|
+
/// @return Message digest.
|
|
174
|
+
function _hash(uint256 message) private pure returns (uint256) {
|
|
175
|
+
return uint256(keccak256(abi.encodePacked(message))) >> 8;
|
|
190
176
|
}
|
|
191
177
|
}
|
package/base/SemaphoreGroups.sol
CHANGED
|
@@ -1,106 +1,141 @@
|
|
|
1
1
|
//SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity 0.8.23;
|
|
3
3
|
|
|
4
|
-
import "../interfaces/ISemaphoreGroups.sol";
|
|
5
|
-
import "@zk-kit/
|
|
6
|
-
import "@openzeppelin/contracts/utils/Context.sol";
|
|
4
|
+
import {ISemaphoreGroups} from "../interfaces/ISemaphoreGroups.sol";
|
|
5
|
+
import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol";
|
|
7
6
|
|
|
8
7
|
/// @title Semaphore groups contract.
|
|
9
8
|
/// @dev This contract allows you to create groups, add, remove and update members.
|
|
10
9
|
/// You can use getters to obtain informations about groups (root, depth, number of leaves).
|
|
11
|
-
abstract contract SemaphoreGroups is
|
|
12
|
-
using
|
|
10
|
+
abstract contract SemaphoreGroups is ISemaphoreGroups {
|
|
11
|
+
using InternalLeanIMT for LeanIMTData;
|
|
13
12
|
|
|
14
|
-
/// @dev Gets a group id and returns
|
|
15
|
-
mapping(uint256 =>
|
|
13
|
+
/// @dev Gets a group id and returns its tree data.
|
|
14
|
+
mapping(uint256 => LeanIMTData) internal merkleTrees;
|
|
16
15
|
|
|
17
|
-
/// @dev
|
|
16
|
+
/// @dev Gets a group id and returns its admin.
|
|
17
|
+
mapping(uint256 => address) internal admins;
|
|
18
|
+
|
|
19
|
+
/// @dev Checks if the group admin is the transaction sender.
|
|
20
|
+
/// @param groupId: Id of the group.
|
|
21
|
+
modifier onlyGroupAdmin(uint256 groupId) {
|
|
22
|
+
if (admins[groupId] != msg.sender) {
|
|
23
|
+
revert Semaphore__CallerIsNotTheGroupAdmin();
|
|
24
|
+
}
|
|
25
|
+
_;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// @dev Checks if the group exists.
|
|
29
|
+
/// @param groupId: Id of the group.
|
|
30
|
+
modifier onlyExistingGroup(uint256 groupId) {
|
|
31
|
+
if (admins[groupId] == address(0)) {
|
|
32
|
+
revert Semaphore__GroupDoesNotExist();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// @dev Creates a new group. Only the admin will be able to add or remove members.
|
|
18
39
|
/// @param groupId: Id of the group.
|
|
19
|
-
/// @param
|
|
20
|
-
function _createGroup(uint256 groupId,
|
|
21
|
-
if (
|
|
40
|
+
/// @param admin: Admin of the group.
|
|
41
|
+
function _createGroup(uint256 groupId, address admin) internal virtual {
|
|
42
|
+
if (admins[groupId] != address(0)) {
|
|
22
43
|
revert Semaphore__GroupAlreadyExists();
|
|
23
44
|
}
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
// Although there is a remote possibility that the preimage of
|
|
27
|
-
// the hash may be calculated, using this value we aim to minimize the risk.
|
|
28
|
-
uint256 zeroValue = uint256(keccak256(abi.encodePacked(groupId))) >> 8;
|
|
46
|
+
admins[groupId] = admin;
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
emit GroupCreated(groupId);
|
|
49
|
+
emit GroupAdminUpdated(groupId, address(0), admin);
|
|
50
|
+
}
|
|
31
51
|
|
|
32
|
-
|
|
52
|
+
/// @dev Updates the group admin.
|
|
53
|
+
/// @param groupId: Id of the group.
|
|
54
|
+
/// @param newAdmin: New admin of the group.
|
|
55
|
+
function _updateGroupAdmin(
|
|
56
|
+
uint256 groupId,
|
|
57
|
+
address newAdmin
|
|
58
|
+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
|
|
59
|
+
admins[groupId] = newAdmin;
|
|
60
|
+
|
|
61
|
+
emit GroupAdminUpdated(groupId, msg.sender, newAdmin);
|
|
33
62
|
}
|
|
34
63
|
|
|
35
64
|
/// @dev Adds an identity commitment to an existing group.
|
|
36
65
|
/// @param groupId: Id of the group.
|
|
37
66
|
/// @param identityCommitment: New identity commitment.
|
|
38
|
-
function _addMember(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
67
|
+
function _addMember(
|
|
68
|
+
uint256 groupId,
|
|
69
|
+
uint256 identityCommitment
|
|
70
|
+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
|
|
71
|
+
uint256 index = getMerkleTreeSize(groupId);
|
|
72
|
+
uint256 merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);
|
|
42
73
|
|
|
43
|
-
|
|
74
|
+
emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
|
|
75
|
+
}
|
|
44
76
|
|
|
45
|
-
|
|
46
|
-
|
|
77
|
+
/// @dev Adds new members to an existing group.
|
|
78
|
+
/// @param groupId: Id of the group.
|
|
79
|
+
/// @param identityCommitments: New identity commitments.
|
|
80
|
+
function _addMembers(uint256 groupId, uint256[] calldata identityCommitments) internal virtual {
|
|
81
|
+
uint256 startIndex = getMerkleTreeSize(groupId);
|
|
82
|
+
uint256 merkleTreeRoot = merkleTrees[groupId]._insertMany(identityCommitments);
|
|
47
83
|
|
|
48
|
-
emit
|
|
84
|
+
emit MembersAdded(groupId, startIndex, identityCommitments, merkleTreeRoot);
|
|
49
85
|
}
|
|
50
86
|
|
|
51
87
|
/// @dev Updates an identity commitment of an existing group. A proof of membership is
|
|
52
88
|
/// needed to check if the node to be updated is part of the tree.
|
|
53
89
|
/// @param groupId: Id of the group.
|
|
54
|
-
/// @param
|
|
90
|
+
/// @param oldIdentityCommitment: Existing identity commitment to be updated.
|
|
55
91
|
/// @param newIdentityCommitment: New identity commitment.
|
|
56
|
-
/// @param
|
|
57
|
-
/// @param proofPathIndices: Path of the proof of membership.
|
|
92
|
+
/// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
|
|
58
93
|
function _updateMember(
|
|
59
94
|
uint256 groupId,
|
|
60
|
-
uint256
|
|
95
|
+
uint256 oldIdentityCommitment,
|
|
61
96
|
uint256 newIdentityCommitment,
|
|
62
|
-
uint256[] calldata
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
|
|
73
|
-
|
|
74
|
-
emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
|
|
97
|
+
uint256[] calldata merkleProofSiblings
|
|
98
|
+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
|
|
99
|
+
uint256 index = merkleTrees[groupId]._indexOf(oldIdentityCommitment);
|
|
100
|
+
uint256 merkleTreeRoot = merkleTrees[groupId]._update(
|
|
101
|
+
oldIdentityCommitment,
|
|
102
|
+
newIdentityCommitment,
|
|
103
|
+
merkleProofSiblings
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
emit MemberUpdated(groupId, index, oldIdentityCommitment, newIdentityCommitment, merkleTreeRoot);
|
|
75
107
|
}
|
|
76
108
|
|
|
77
109
|
/// @dev Removes an identity commitment from an existing group. A proof of membership is
|
|
78
110
|
/// needed to check if the node to be deleted is part of the tree.
|
|
79
111
|
/// @param groupId: Id of the group.
|
|
80
112
|
/// @param identityCommitment: Existing identity commitment to be removed.
|
|
81
|
-
/// @param
|
|
82
|
-
/// @param proofPathIndices: Path of the proof of membership.
|
|
113
|
+
/// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
|
|
83
114
|
function _removeMember(
|
|
84
115
|
uint256 groupId,
|
|
85
116
|
uint256 identityCommitment,
|
|
86
|
-
uint256[] calldata
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (getMerkleTreeDepth(groupId) == 0) {
|
|
90
|
-
revert Semaphore__GroupDoesNotExist();
|
|
91
|
-
}
|
|
117
|
+
uint256[] calldata merkleProofSiblings
|
|
118
|
+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
|
|
119
|
+
uint256 index = merkleTrees[groupId]._indexOf(identityCommitment);
|
|
92
120
|
|
|
93
|
-
merkleTrees[groupId].
|
|
94
|
-
|
|
95
|
-
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
96
|
-
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
|
|
121
|
+
uint256 merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);
|
|
97
122
|
|
|
98
123
|
emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
|
|
99
124
|
}
|
|
100
125
|
|
|
126
|
+
/// @dev See {ISemaphoreGroups-hasMember}.
|
|
127
|
+
function hasMember(uint256 groupId, uint256 identityCommitment) public view virtual override returns (bool) {
|
|
128
|
+
return merkleTrees[groupId]._has(identityCommitment);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// @dev See {ISemaphoreGroups-indexOf}.
|
|
132
|
+
function indexOf(uint256 groupId, uint256 identityCommitment) public view virtual override returns (uint256) {
|
|
133
|
+
return merkleTrees[groupId]._indexOf(identityCommitment);
|
|
134
|
+
}
|
|
135
|
+
|
|
101
136
|
/// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
|
|
102
137
|
function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
|
|
103
|
-
return merkleTrees[groupId].
|
|
138
|
+
return merkleTrees[groupId]._root();
|
|
104
139
|
}
|
|
105
140
|
|
|
106
141
|
/// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
|
|
@@ -108,31 +143,8 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
|
|
108
143
|
return merkleTrees[groupId].depth;
|
|
109
144
|
}
|
|
110
145
|
|
|
111
|
-
/// @dev See {ISemaphoreGroups-
|
|
112
|
-
function
|
|
113
|
-
return merkleTrees[groupId].
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
|
|
117
|
-
/// @param proofPathIndices: Path of the proof of membership.
|
|
118
|
-
/// @return Index of a group member.
|
|
119
|
-
function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
|
|
120
|
-
uint256 memberIndex = 0;
|
|
121
|
-
|
|
122
|
-
for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
|
|
123
|
-
if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
|
|
124
|
-
memberIndex *= 2;
|
|
125
|
-
|
|
126
|
-
if (proofPathIndices[i - 1] == 1) {
|
|
127
|
-
memberIndex += 1;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
unchecked {
|
|
132
|
-
--i;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return memberIndex;
|
|
146
|
+
/// @dev See {ISemaphoreGroups-getMerkleTreeSize}.
|
|
147
|
+
function getMerkleTreeSize(uint256 groupId) public view virtual override returns (uint256) {
|
|
148
|
+
return merkleTrees[groupId].size;
|
|
137
149
|
}
|
|
138
150
|
}
|