@semaphore-protocol/contracts 3.0.0 → 3.2.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/README.md +4 -1
- package/base/Pairing.sol +7 -7
- package/package.json +34 -34
- package/Semaphore.sol +0 -193
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
🔎 Issues
|
|
35
35
|
</a>
|
|
36
36
|
<span> | </span>
|
|
37
|
-
<a href="https://
|
|
37
|
+
<a href="https://semaphore.appliedzkp.org/discord">
|
|
38
38
|
🗣️ Chat & Support
|
|
39
39
|
</a>
|
|
40
40
|
</h4>
|
|
@@ -111,6 +111,9 @@ If you want to deploy your contract in a specific network you can set up the `DE
|
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
113
|
yarn deploy:semaphore --network goerli
|
|
114
|
+
yarn deploy:semaphore --network sepolia
|
|
115
|
+
yarn deploy:semaphore --network mumbai
|
|
116
|
+
yarn deploy:semaphore --network optimism-goerli
|
|
114
117
|
yarn deploy:semaphore --network arbitrum
|
|
115
118
|
```
|
|
116
119
|
|
package/base/Pairing.sol
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
pragma solidity ^0.8.4;
|
|
10
10
|
|
|
11
11
|
library Pairing {
|
|
12
|
-
error
|
|
12
|
+
error InvalidProof();
|
|
13
13
|
|
|
14
14
|
// The prime q in the base field F_q for G1
|
|
15
15
|
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
|
@@ -56,7 +56,7 @@ library Pairing {
|
|
|
56
56
|
|
|
57
57
|
// Validate input or revert
|
|
58
58
|
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) {
|
|
59
|
-
revert
|
|
59
|
+
revert InvalidProof();
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
|
@@ -82,7 +82,7 @@ library Pairing {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
if (!success) {
|
|
85
|
-
revert
|
|
85
|
+
revert InvalidProof();
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -92,7 +92,7 @@ library Pairing {
|
|
|
92
92
|
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
|
93
93
|
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
|
94
94
|
if (s >= SCALAR_MODULUS) {
|
|
95
|
-
revert
|
|
95
|
+
revert InvalidProof();
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
uint256[3] memory input;
|
|
@@ -109,7 +109,7 @@ library Pairing {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
if (!success) {
|
|
112
|
-
revert
|
|
112
|
+
revert InvalidProof();
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -120,7 +120,7 @@ library Pairing {
|
|
|
120
120
|
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
|
121
121
|
// respective groups of the right order.
|
|
122
122
|
if (p1.length != p2.length) {
|
|
123
|
-
revert
|
|
123
|
+
revert InvalidProof();
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
uint256 elements = p1.length;
|
|
@@ -145,7 +145,7 @@ library Pairing {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
if (!success || out[0] != 1) {
|
|
148
|
-
revert
|
|
148
|
+
revert InvalidProof();
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
}
|
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
2
|
+
"name": "@semaphore-protocol/contracts",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"**/*.sol"
|
|
8
|
+
],
|
|
9
|
+
"keywords": [
|
|
10
|
+
"blockchain",
|
|
11
|
+
"ethereum",
|
|
12
|
+
"hardhat",
|
|
13
|
+
"smart-contracts",
|
|
14
|
+
"semaphore",
|
|
15
|
+
"identity",
|
|
16
|
+
"solidity",
|
|
17
|
+
"zero-knowledge",
|
|
18
|
+
"zk-snarks",
|
|
19
|
+
"zero-knowledge-proofs",
|
|
20
|
+
"circom",
|
|
21
|
+
"proof-of-membership"
|
|
22
|
+
],
|
|
23
|
+
"repository": "https://github.com/semaphore-protocol/semaphore",
|
|
24
|
+
"homepage": "https://github.com/semaphore-protocol/semaphore/tree/main/packages/contracts",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@openzeppelin/contracts": "4.7.3",
|
|
33
|
+
"@zk-kit/incremental-merkle-tree.sol": "1.3.3"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/Semaphore.sol
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
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
|
-
}
|