@semaphore-protocol/contracts 4.0.0-alpha.8 → 4.0.0-beta.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
CHANGED
|
@@ -7,11 +7,10 @@ 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
|
|
10
|
-
/// to allow admins to create and manage groups and their members to
|
|
11
|
-
///
|
|
12
|
-
///
|
|
13
|
-
///
|
|
14
|
-
/// can be validated.
|
|
10
|
+
/// to allow admins to create and manage groups and their members to verify Semaphore proofs
|
|
11
|
+
/// Group admins can add, update or remove group members, and can be an Ethereum account or a smart contract.
|
|
12
|
+
/// This contract also assigns each new Merkle tree generated with a new root a duration (or an expiry)
|
|
13
|
+
/// within which the proofs generated with that root can be validated.
|
|
15
14
|
contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
16
15
|
ISemaphoreVerifier public verifier;
|
|
17
16
|
|
|
@@ -100,18 +99,24 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
100
99
|
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
|
101
100
|
}
|
|
102
101
|
|
|
102
|
+
/// @dev See {ISemaphore-validateProof}.
|
|
103
103
|
function validateProof(
|
|
104
104
|
uint256 groupId,
|
|
105
105
|
SemaphoreProof calldata proof
|
|
106
106
|
) external override onlyExistingGroup(groupId) {
|
|
107
|
+
// The function will revert if the nullifier that is part of the proof,
|
|
108
|
+
// was already used inside the group with id groupId.
|
|
107
109
|
if (groups[groupId].nullifiers[proof.nullifier]) {
|
|
108
110
|
revert Semaphore__YouAreUsingTheSameNullifierTwice();
|
|
109
111
|
}
|
|
110
112
|
|
|
113
|
+
// The function will revert if the proof is not verified successfully.
|
|
111
114
|
if (!verifyProof(groupId, proof)) {
|
|
112
115
|
revert Semaphore__InvalidProof();
|
|
113
116
|
}
|
|
114
117
|
|
|
118
|
+
// Saves the nullifier so that it cannot be used again to successfully verify a proof
|
|
119
|
+
// that is part of the group with id groupId.
|
|
115
120
|
groups[groupId].nullifiers[proof.nullifier] = true;
|
|
116
121
|
|
|
117
122
|
emit ProofValidated(
|
|
@@ -125,20 +130,26 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
|
|
|
125
130
|
);
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
/// @dev See {ISemaphore-verifyProof}.
|
|
128
134
|
function verifyProof(
|
|
129
135
|
uint256 groupId,
|
|
130
136
|
SemaphoreProof calldata proof
|
|
131
137
|
) public view override onlyExistingGroup(groupId) returns (bool) {
|
|
138
|
+
// The function will revert if the Merkle tree depth is not supported.
|
|
132
139
|
if (proof.merkleTreeDepth < 1 || proof.merkleTreeDepth > 12) {
|
|
133
140
|
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
|
134
141
|
}
|
|
135
142
|
|
|
143
|
+
// Gets the number of leaves in the Incremental Merkle Tree that represents the group
|
|
144
|
+
// with id groupId which is the same as the number of members in the group groupId.
|
|
136
145
|
uint256 merkleTreeSize = getMerkleTreeSize(groupId);
|
|
137
146
|
|
|
147
|
+
// The function will revert if there are no members in the group.
|
|
138
148
|
if (merkleTreeSize == 0) {
|
|
139
149
|
revert Semaphore__GroupHasNoMembers();
|
|
140
150
|
}
|
|
141
151
|
|
|
152
|
+
// Gets the Merkle root of the Incremental Merkle Tree that represents the group with id groupId.
|
|
142
153
|
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
|
|
143
154
|
|
|
144
155
|
// A proof could have used an old Merkle tree root.
|
package/base/SemaphoreGroups.sol
CHANGED
|
@@ -11,9 +11,12 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
|
|
|
11
11
|
using InternalLeanIMT for LeanIMTData;
|
|
12
12
|
|
|
13
13
|
/// @dev Gets a group id and returns its tree data.
|
|
14
|
+
/// The tree is an Incremental Merkle Tree
|
|
15
|
+
/// which is called Lean Incremental Merkle Tree.
|
|
14
16
|
mapping(uint256 => LeanIMTData) internal merkleTrees;
|
|
15
17
|
|
|
16
18
|
/// @dev Gets a group id and returns its admin.
|
|
19
|
+
/// The admin can be an Ethereum account or a smart contract.
|
|
17
20
|
mapping(uint256 => address) internal admins;
|
|
18
21
|
|
|
19
22
|
/// @dev Checks if the group admin is the transaction sender.
|
|
@@ -21,6 +21,12 @@ contract SemaphoreVerifier {
|
|
|
21
21
|
uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
|
|
22
22
|
uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
|
|
23
23
|
|
|
24
|
+
// TODO: Add more variables when Semaphore supports tree depth > 12.
|
|
25
|
+
// Right now Semaphore supports tree depth 1-12.
|
|
26
|
+
|
|
27
|
+
// Verification Key points.
|
|
28
|
+
// These values are taken from the verification key json file generated with snarkjs.
|
|
29
|
+
// It allows to use the same verifier to verify proofs for all the tree depths supported by Semaphore.
|
|
24
30
|
uint256[14][12] VK_POINTS = [
|
|
25
31
|
[
|
|
26
32
|
563562783592406106461234396505774794044312891062077216951605541624542949349,
|
|
@@ -17,7 +17,7 @@ interface ISemaphore {
|
|
|
17
17
|
mapping(uint256 => bool) nullifiers;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/// It defines all the
|
|
20
|
+
/// It defines all the Semaphore proof parameters used by Semaphore.sol.
|
|
21
21
|
struct SemaphoreProof {
|
|
22
22
|
uint256 merkleTreeDepth;
|
|
23
23
|
uint256 merkleTreeRoot;
|
|
@@ -27,7 +27,7 @@ interface ISemaphore {
|
|
|
27
27
|
uint256[8] points;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/// @dev
|
|
30
|
+
/// @dev Event emitted when the Merkle tree duration of a group is updated.
|
|
31
31
|
/// @param groupId: Id of the group.
|
|
32
32
|
/// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
|
|
33
33
|
/// @param newMerkleTreeDuration: New Merkle tree duration of the group.
|
|
@@ -37,7 +37,7 @@ interface ISemaphore {
|
|
|
37
37
|
uint256 newMerkleTreeDuration
|
|
38
38
|
);
|
|
39
39
|
|
|
40
|
-
/// @dev
|
|
40
|
+
/// @dev Event emitted when a Semaphore proof is validated.
|
|
41
41
|
/// @param groupId: Id of the group.
|
|
42
42
|
/// @param merkleTreeDepth: Depth of the Merkle tree.
|
|
43
43
|
/// @param merkleTreeRoot: Root of the Merkle tree.
|
|
@@ -60,7 +60,7 @@ interface ISemaphore {
|
|
|
60
60
|
|
|
61
61
|
/// @dev It creates a group with a custom Merkle tree duration.
|
|
62
62
|
/// @param groupId: Id of the group.
|
|
63
|
-
/// @param admin: Admin of the group.
|
|
63
|
+
/// @param admin: Admin of the group. It can be an Ethereum account or a smart contract.
|
|
64
64
|
/// @param merkleTreeDuration: Merkle tree duration.
|
|
65
65
|
function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external;
|
|
66
66
|
|
|
@@ -89,14 +89,14 @@ interface ISemaphore {
|
|
|
89
89
|
/// @dev See {SemaphoreGroups-_removeMember}.
|
|
90
90
|
function removeMember(uint256 groupId, uint256 identityCommitment, uint256[] calldata merkleProofSiblings) external;
|
|
91
91
|
|
|
92
|
-
/// @dev Saves the nullifier hash to
|
|
92
|
+
/// @dev Saves the nullifier hash to prevent double signaling and emits an event
|
|
93
93
|
/// if the zero-knowledge proof is valid.
|
|
94
94
|
/// @param groupId: Id of the group.
|
|
95
|
-
/// @param proof:
|
|
95
|
+
/// @param proof: Semaphore zero-knowledge proof.
|
|
96
96
|
function validateProof(uint256 groupId, SemaphoreProof calldata proof) external;
|
|
97
97
|
|
|
98
98
|
/// @dev Verifies a zero-knowledge proof by returning true or false.
|
|
99
99
|
/// @param groupId: Id of the group.
|
|
100
|
-
/// @param proof:
|
|
100
|
+
/// @param proof: Semaphore zero-knowledge proof.
|
|
101
101
|
function verifyProof(uint256 groupId, SemaphoreProof calldata proof) external view returns (bool);
|
|
102
102
|
}
|
|
@@ -7,24 +7,24 @@ interface ISemaphoreGroups {
|
|
|
7
7
|
error Semaphore__GroupAlreadyExists();
|
|
8
8
|
error Semaphore__CallerIsNotTheGroupAdmin();
|
|
9
9
|
|
|
10
|
-
/// @dev
|
|
10
|
+
/// @dev Event emitted when a new group is created.
|
|
11
11
|
/// @param groupId: Id of the group.
|
|
12
12
|
event GroupCreated(uint256 indexed groupId);
|
|
13
13
|
|
|
14
|
-
/// @dev
|
|
14
|
+
/// @dev Event emitted when an admin is assigned to a group.
|
|
15
15
|
/// @param groupId: Id of the group.
|
|
16
16
|
/// @param oldAdmin: Old admin of the group.
|
|
17
17
|
/// @param newAdmin: New admin of the group.
|
|
18
18
|
event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
|
|
19
19
|
|
|
20
|
-
/// @dev
|
|
20
|
+
/// @dev Event emitted when a new identity commitment is added.
|
|
21
21
|
/// @param groupId: Group id of the group.
|
|
22
22
|
/// @param index: Merkle tree leaf index.
|
|
23
23
|
/// @param identityCommitment: New identity commitment.
|
|
24
24
|
/// @param merkleTreeRoot: New root hash of the tree.
|
|
25
25
|
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
26
26
|
|
|
27
|
-
/// @dev
|
|
27
|
+
/// @dev Event emitted when many identity commitments are added at the same time.
|
|
28
28
|
/// @param groupId: Group id of the group.
|
|
29
29
|
/// @param startIndex: Index of the first element of the new identity commitments in the merkle tree.
|
|
30
30
|
/// @param identityCommitments: The new identity commitments.
|
|
@@ -36,7 +36,7 @@ interface ISemaphoreGroups {
|
|
|
36
36
|
uint256 merkleTreeRoot
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
/// @dev
|
|
39
|
+
/// @dev Event emitted when an identity commitment is updated.
|
|
40
40
|
/// @param groupId: Group id of the group.
|
|
41
41
|
/// @param index: Identity commitment index.
|
|
42
42
|
/// @param identityCommitment: Existing identity commitment to be updated.
|
|
@@ -50,14 +50,14 @@ interface ISemaphoreGroups {
|
|
|
50
50
|
uint256 merkleTreeRoot
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
/// @dev
|
|
53
|
+
/// @dev Event emitted when a new identity commitment is removed.
|
|
54
54
|
/// @param groupId: Group id of the group.
|
|
55
55
|
/// @param index: Identity commitment index.
|
|
56
56
|
/// @param identityCommitment: Existing identity commitment to be removed.
|
|
57
57
|
/// @param merkleTreeRoot: New root hash of the tree.
|
|
58
58
|
event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
|
|
59
59
|
|
|
60
|
-
/// @dev Returns the address of the group admin.
|
|
60
|
+
/// @dev Returns the address of the group admin. The group admin can be an Ethereum account or a smart contract.
|
|
61
61
|
/// @param groupId: Id of the group.
|
|
62
62
|
/// @return Address of the group admin.
|
|
63
63
|
function getGroupAdmin(uint256 groupId) external view returns (address);
|
|
@@ -3,6 +3,13 @@ pragma solidity 0.8.23;
|
|
|
3
3
|
|
|
4
4
|
/// @title SemaphoreVerifier contract interface.
|
|
5
5
|
interface ISemaphoreVerifier {
|
|
6
|
+
/// @dev Returns true if the proof was successfully verified.
|
|
7
|
+
/// @param _pA: Point A.
|
|
8
|
+
/// @param _pB: Point B.
|
|
9
|
+
/// @param _pC: Point C.
|
|
10
|
+
/// @param _pubSignals: Public signals.
|
|
11
|
+
/// @param merkleTreeDepth: Merkle tree depth.
|
|
12
|
+
/// @return True if the proof was successfully verified, false otherwise.
|
|
6
13
|
function verifyProof(
|
|
7
14
|
uint[2] calldata _pA,
|
|
8
15
|
uint[2][2] calldata _pB,
|