@semaphore-protocol/contracts 3.2.0 → 3.2.2

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.
Files changed (2) hide show
  1. package/Semaphore.sol +193 -0
  2. 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.0",
3
+ "version": "3.2.2",
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": [