@semaphore-protocol/contracts 4.0.0-beta.1 → 4.0.0-beta.3

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
@@ -4,6 +4,7 @@ pragma solidity 0.8.23;
4
4
  import {ISemaphore} from "./interfaces/ISemaphore.sol";
5
5
  import {ISemaphoreVerifier} from "./interfaces/ISemaphoreVerifier.sol";
6
6
  import {SemaphoreGroups} from "./base/SemaphoreGroups.sol";
7
+ import {MIN_DEPTH, MAX_DEPTH} from "./base/Constants.sol";
7
8
 
8
9
  /// @title Semaphore
9
10
  /// @dev This contract uses the Semaphore base contracts to provide a complete service
@@ -17,6 +18,9 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
17
18
  /// @dev Gets a group id and returns the group parameters.
18
19
  mapping(uint256 => Group) public groups;
19
20
 
21
+ /// @dev Counter to assign an incremental id to the groups.
22
+ uint256 public groupCounter;
23
+
20
24
  /// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
21
25
  /// @param _verifier: Semaphore verifier addresse.
22
26
  constructor(ISemaphoreVerifier _verifier) {
@@ -24,14 +28,24 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
24
28
  }
25
29
 
26
30
  /// @dev See {SemaphoreGroups-_createGroup}.
27
- function createGroup(uint256 groupId, address admin) external override {
31
+ function createGroup() external override returns (uint256 groupId) {
32
+ groupId = groupCounter++;
33
+ _createGroup(groupId, msg.sender);
34
+
35
+ groups[groupId].merkleTreeDuration = 1 hours;
36
+ }
37
+
38
+ /// @dev See {SemaphoreGroups-_createGroup}.
39
+ function createGroup(address admin) external override returns (uint256 groupId) {
40
+ groupId = groupCounter++;
28
41
  _createGroup(groupId, admin);
29
42
 
30
43
  groups[groupId].merkleTreeDuration = 1 hours;
31
44
  }
32
45
 
33
46
  /// @dev See {ISemaphore-createGroup}.
34
- function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external override {
47
+ function createGroup(address admin, uint256 merkleTreeDuration) external override returns (uint256 groupId) {
48
+ groupId = groupCounter++;
35
49
  _createGroup(groupId, admin);
36
50
 
37
51
  groups[groupId].merkleTreeDuration = merkleTreeDuration;
@@ -46,7 +60,7 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
46
60
  function updateGroupMerkleTreeDuration(
47
61
  uint256 groupId,
48
62
  uint256 newMerkleTreeDuration
49
- ) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
63
+ ) external override onlyGroupAdmin(groupId) {
50
64
  uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;
51
65
 
52
66
  groups[groupId].merkleTreeDuration = newMerkleTreeDuration;
@@ -56,18 +70,14 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
56
70
 
57
71
  /// @dev See {SemaphoreGroups-_addMember}.
58
72
  function addMember(uint256 groupId, uint256 identityCommitment) external override {
59
- _addMember(groupId, identityCommitment);
60
-
61
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
73
+ uint256 merkleTreeRoot = _addMember(groupId, identityCommitment);
62
74
 
63
75
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
64
76
  }
65
77
 
66
78
  /// @dev See {SemaphoreGroups-_addMembers}.
67
79
  function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
68
- _addMembers(groupId, identityCommitments);
69
-
70
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
80
+ uint256 merkleTreeRoot = _addMembers(groupId, identityCommitments);
71
81
 
72
82
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
73
83
  }
@@ -79,9 +89,7 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
79
89
  uint256 newIdentityCommitment,
80
90
  uint256[] calldata merkleProofSiblings
81
91
  ) external override {
82
- _updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
83
-
84
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
92
+ uint256 merkleTreeRoot = _updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
85
93
 
86
94
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
87
95
  }
@@ -92,18 +100,13 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
92
100
  uint256 identityCommitment,
93
101
  uint256[] calldata merkleProofSiblings
94
102
  ) external override {
95
- _removeMember(groupId, identityCommitment, merkleProofSiblings);
96
-
97
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
103
+ uint256 merkleTreeRoot = _removeMember(groupId, identityCommitment, merkleProofSiblings);
98
104
 
99
105
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
100
106
  }
101
107
 
102
108
  /// @dev See {ISemaphore-validateProof}.
103
- function validateProof(
104
- uint256 groupId,
105
- SemaphoreProof calldata proof
106
- ) external override onlyExistingGroup(groupId) {
109
+ function validateProof(uint256 groupId, SemaphoreProof calldata proof) external override {
107
110
  // The function will revert if the nullifier that is part of the proof,
108
111
  // was already used inside the group with id groupId.
109
112
  if (groups[groupId].nullifiers[proof.nullifier]) {
@@ -136,7 +139,7 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
136
139
  SemaphoreProof calldata proof
137
140
  ) public view override onlyExistingGroup(groupId) returns (bool) {
138
141
  // The function will revert if the Merkle tree depth is not supported.
139
- if (proof.merkleTreeDepth < 1 || proof.merkleTreeDepth > 12) {
142
+ if (proof.merkleTreeDepth < MIN_DEPTH || proof.merkleTreeDepth > MAX_DEPTH) {
140
143
  revert Semaphore__MerkleTreeDepthIsNotSupported();
141
144
  }
142
145
 
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.23;
3
+
4
+ /// @dev Minimum supported tree depth.
5
+ uint8 constant MIN_DEPTH = 1;
6
+
7
+ /// @dev Maximum supported tree depth.
8
+ uint8 constant MAX_DEPTH = 12;
@@ -42,10 +42,6 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
42
42
  /// @param groupId: Id of the group.
43
43
  /// @param admin: Admin of the group.
44
44
  function _createGroup(uint256 groupId, address admin) internal virtual {
45
- if (admins[groupId] != address(0)) {
46
- revert Semaphore__GroupAlreadyExists();
47
- }
48
-
49
45
  admins[groupId] = admin;
50
46
 
51
47
  emit GroupCreated(groupId);
@@ -55,10 +51,7 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
55
51
  /// @dev Updates the group admin.
56
52
  /// @param groupId: Id of the group.
57
53
  /// @param newAdmin: New admin of the group.
58
- function _updateGroupAdmin(
59
- uint256 groupId,
60
- address newAdmin
61
- ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
54
+ function _updateGroupAdmin(uint256 groupId, address newAdmin) internal virtual onlyGroupAdmin(groupId) {
62
55
  admins[groupId] = newAdmin;
63
56
 
64
57
  emit GroupAdminUpdated(groupId, msg.sender, newAdmin);
@@ -67,12 +60,13 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
67
60
  /// @dev Adds an identity commitment to an existing group.
68
61
  /// @param groupId: Id of the group.
69
62
  /// @param identityCommitment: New identity commitment.
63
+ /// @return merkleTreeRoot New root hash of the tree.
70
64
  function _addMember(
71
65
  uint256 groupId,
72
66
  uint256 identityCommitment
73
- ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
67
+ ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
74
68
  uint256 index = getMerkleTreeSize(groupId);
75
- uint256 merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);
69
+ merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);
76
70
 
77
71
  emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
78
72
  }
@@ -80,9 +74,13 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
80
74
  /// @dev Adds new members to an existing group.
81
75
  /// @param groupId: Id of the group.
82
76
  /// @param identityCommitments: New identity commitments.
83
- function _addMembers(uint256 groupId, uint256[] calldata identityCommitments) internal virtual {
77
+ /// @return merkleTreeRoot New root hash of the tree.
78
+ function _addMembers(
79
+ uint256 groupId,
80
+ uint256[] calldata identityCommitments
81
+ ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
84
82
  uint256 startIndex = getMerkleTreeSize(groupId);
85
- uint256 merkleTreeRoot = merkleTrees[groupId]._insertMany(identityCommitments);
83
+ merkleTreeRoot = merkleTrees[groupId]._insertMany(identityCommitments);
86
84
 
87
85
  emit MembersAdded(groupId, startIndex, identityCommitments, merkleTreeRoot);
88
86
  }
@@ -93,14 +91,15 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
93
91
  /// @param oldIdentityCommitment: Existing identity commitment to be updated.
94
92
  /// @param newIdentityCommitment: New identity commitment.
95
93
  /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
94
+ /// @return merkleTreeRoot New root hash of the tree.
96
95
  function _updateMember(
97
96
  uint256 groupId,
98
97
  uint256 oldIdentityCommitment,
99
98
  uint256 newIdentityCommitment,
100
99
  uint256[] calldata merkleProofSiblings
101
- ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
100
+ ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
102
101
  uint256 index = merkleTrees[groupId]._indexOf(oldIdentityCommitment);
103
- uint256 merkleTreeRoot = merkleTrees[groupId]._update(
102
+ merkleTreeRoot = merkleTrees[groupId]._update(
104
103
  oldIdentityCommitment,
105
104
  newIdentityCommitment,
106
105
  merkleProofSiblings
@@ -114,14 +113,15 @@ abstract contract SemaphoreGroups is ISemaphoreGroups {
114
113
  /// @param groupId: Id of the group.
115
114
  /// @param identityCommitment: Existing identity commitment to be removed.
116
115
  /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
116
+ /// @return merkleTreeRoot New root hash of the tree.
117
117
  function _removeMember(
118
118
  uint256 groupId,
119
119
  uint256 identityCommitment,
120
120
  uint256[] calldata merkleProofSiblings
121
- ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
121
+ ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
122
122
  uint256 index = merkleTrees[groupId]._indexOf(identityCommitment);
123
123
 
124
- uint256 merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);
124
+ merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);
125
125
 
126
126
  emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
127
127
  }
@@ -3,6 +3,8 @@
3
3
 
4
4
  pragma solidity 0.8.23;
5
5
 
6
+ import {MAX_DEPTH} from "./Constants.sol";
7
+
6
8
  contract SemaphoreVerifier {
7
9
  // Scalar field size
8
10
  uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
@@ -22,12 +24,12 @@ contract SemaphoreVerifier {
22
24
  uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
23
25
 
24
26
  // TODO: Add more variables when Semaphore supports tree depth > 12.
25
- // Right now Semaphore supports tree depth 1-12.
27
+ // Right now Semaphore supports tree depth 1-12. It will support up to 32.
26
28
 
27
29
  // Verification Key points.
28
30
  // These values are taken from the verification key json file generated with snarkjs.
29
31
  // It allows to use the same verifier to verify proofs for all the tree depths supported by Semaphore.
30
- uint256[14][12] VK_POINTS = [
32
+ uint256[14][MAX_DEPTH] VK_POINTS = [
31
33
  [
32
34
  563562783592406106461234396505774794044312891062077216951605541624542949349,
33
35
  16293410697967515504861065986355060225819302510590370360517024529684437085892,
@@ -56,13 +56,16 @@ interface ISemaphore {
56
56
  );
57
57
 
58
58
  /// @dev See {SemaphoreGroups-_createGroup}.
59
- function createGroup(uint256 groupId, address admin) external;
59
+ function createGroup() external returns (uint256);
60
+
61
+ /// @dev See {SemaphoreGroups-_createGroup}.
62
+ function createGroup(address admin) external returns (uint256);
60
63
 
61
64
  /// @dev It creates a group with a custom Merkle tree duration.
62
- /// @param groupId: Id of the group.
63
65
  /// @param admin: Admin of the group. It can be an Ethereum account or a smart contract.
64
66
  /// @param merkleTreeDuration: Merkle tree duration.
65
- function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external;
67
+ /// @return Id of the group.
68
+ function createGroup(address admin, uint256 merkleTreeDuration) external returns (uint256);
66
69
 
67
70
  /// @dev See {SemaphoreGroups-_updateGroupAdmin}.
68
71
  function updateGroupAdmin(uint256 groupId, address newAdmin) external;
@@ -4,7 +4,6 @@ pragma solidity 0.8.23;
4
4
  /// @title SemaphoreGroups contract interface.
5
5
  interface ISemaphoreGroups {
6
6
  error Semaphore__GroupDoesNotExist();
7
- error Semaphore__GroupAlreadyExists();
8
7
  error Semaphore__CallerIsNotTheGroupAdmin();
9
8
 
10
9
  /// @dev Event emitted when a new group is created.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/contracts",
3
- "version": "4.0.0-beta.1",
3
+ "version": "4.0.0-beta.3",
4
4
  "description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -30,6 +30,6 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@zk-kit/imt.sol": "2.0.0-beta.5"
33
+ "@zk-kit/imt.sol": "2.0.0-beta.8"
34
34
  }
35
35
  }