Skip to content

Commit 2b05a94

Browse files
committed
refactor(contracts): move access logic to group contract
1 parent b7d58bd commit 2b05a94

File tree

7 files changed

+128
-139
lines changed

7 files changed

+128
-139
lines changed

packages/contracts/contracts/Semaphore.sol

Lines changed: 15 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,65 +18,29 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
1818
/// @dev Gets a group id and returns the group parameters.
1919
mapping(uint256 => Group) public groups;
2020

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 the group exists.
31-
/// @param groupId: Id of the group.
32-
modifier onlyExistingGroup(uint256 groupId) {
33-
if (groups[groupId].admin == address(0)) {
34-
revert Semaphore__GroupDoesNotExist();
35-
}
36-
37-
_;
38-
}
39-
4021
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
4122
/// @param _verifier: Semaphore verifier address.
4223
constructor(ISemaphoreVerifier _verifier) {
4324
verifier = _verifier;
4425
}
4526

46-
/// @dev See {ISemaphore-createGroup}.
27+
/// @dev See {SemaphoreGroups-_createGroup}.
4728
function createGroup(uint256 groupId, address admin) external override {
48-
if (groups[groupId].admin != address(0)) {
49-
revert Semaphore__GroupAlreadyExists();
50-
}
29+
_createGroup(groupId, admin);
5130

52-
groups[groupId].admin = admin;
5331
groups[groupId].merkleTreeDuration = 1 hours;
54-
55-
emit GroupCreated(groupId);
56-
emit GroupAdminUpdated(groupId, address(0), admin);
5732
}
5833

5934
/// @dev See {ISemaphore-createGroup}.
6035
function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external override {
61-
if (groups[groupId].admin != address(0)) {
62-
revert Semaphore__GroupAlreadyExists();
63-
}
36+
_createGroup(groupId, admin);
6437

65-
groups[groupId].admin = admin;
6638
groups[groupId].merkleTreeDuration = merkleTreeDuration;
67-
68-
emit GroupCreated(groupId);
69-
emit GroupAdminUpdated(groupId, address(0), admin);
7039
}
7140

72-
/// @dev See {ISemaphore-updateGroupAdmin}.
73-
function updateGroupAdmin(
74-
uint256 groupId,
75-
address newAdmin
76-
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
77-
groups[groupId].admin = newAdmin;
78-
79-
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
41+
/// @dev See {SemaphoreGroups-_updateGroupAdmin}.
42+
function updateGroupAdmin(uint256 groupId, address newAdmin) external override {
43+
_updateGroupAdmin(groupId, newAdmin);
8044
}
8145

8246
/// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
@@ -91,56 +55,44 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
9155
emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
9256
}
9357

94-
/// @dev See {ISemaphore-addMember}.
95-
function addMember(
96-
uint256 groupId,
97-
uint256 identityCommitment
98-
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
58+
/// @dev See {SemaphoreGroups-_addMember}.
59+
function addMember(uint256 groupId, uint256 identityCommitment) external override {
9960
_addMember(groupId, identityCommitment);
10061

10162
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
10263

10364
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
10465
}
10566

106-
/// @dev See {ISemaphore-addMembers}.
107-
function addMembers(
108-
uint256 groupId,
109-
uint256[] calldata identityCommitments
110-
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
111-
for (uint256 i = 0; i < identityCommitments.length; ) {
112-
_addMember(groupId, identityCommitments[i]);
113-
114-
unchecked {
115-
++i;
116-
}
117-
}
67+
/// @dev See {SemaphoreGroups-_addMembers}.
68+
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
69+
_addMembers(groupId, identityCommitments);
11870

11971
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
12072

12173
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
12274
}
12375

124-
/// @dev See {ISemaphore-updateMember}.
76+
/// @dev See {SemaphoreGroups-_updateMember}.
12577
function updateMember(
12678
uint256 groupId,
12779
uint256 identityCommitment,
12880
uint256 newIdentityCommitment,
12981
uint256[] calldata merkleProofSiblings
130-
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
82+
) external override {
13183
_updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
13284

13385
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
13486

13587
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
13688
}
13789

138-
/// @dev See {ISemaphore-removeMember}.
90+
/// @dev See {SemaphoreGroups-_removeMember}.
13991
function removeMember(
14092
uint256 groupId,
14193
uint256 identityCommitment,
14294
uint256[] calldata merkleProofSiblings
143-
) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
95+
) external override {
14496
_removeMember(groupId, identityCommitment, merkleProofSiblings);
14597

14698
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);

packages/contracts/contracts/base/SemaphoreGroups.sol

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,90 @@ pragma solidity 0.8.4;
33

44
import "../interfaces/ISemaphoreGroups.sol";
55
import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol";
6-
import "@openzeppelin/contracts/utils/Context.sol";
76

87
/// @title Semaphore groups contract.
98
/// @dev This contract allows you to create groups, add, remove and update members.
109
/// You can use getters to obtain informations about groups (root, depth, number of leaves).
11-
abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
10+
abstract contract SemaphoreGroups is ISemaphoreGroups {
1211
using InternalLeanIMT for LeanIMTData;
1312

14-
/// @dev Gets a group id and returns the tree data.
13+
/// @dev Gets a group id and returns its tree data.
1514
mapping(uint256 => LeanIMTData) internal merkleTrees;
1615

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.
39+
/// @param groupId: Id of the group.
40+
/// @param admin: Admin of the group.
41+
function _createGroup(uint256 groupId, address admin) internal virtual {
42+
if (admins[groupId] != address(0)) {
43+
revert Semaphore__GroupAlreadyExists();
44+
}
45+
46+
admins[groupId] = admin;
47+
48+
emit GroupCreated(groupId);
49+
emit GroupAdminUpdated(groupId, address(0), admin);
50+
}
51+
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);
62+
}
63+
1764
/// @dev Adds an identity commitment to an existing group.
1865
/// @param groupId: Id of the group.
1966
/// @param identityCommitment: New identity commitment.
20-
function _addMember(uint256 groupId, uint256 identityCommitment) internal virtual {
67+
function _addMember(
68+
uint256 groupId,
69+
uint256 identityCommitment
70+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
2171
uint256 merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);
2272
uint256 leafIndex = getMerkleTreeSize(groupId) - 1;
2373

2474
emit MemberAdded(groupId, leafIndex, identityCommitment, merkleTreeRoot);
2575
}
2676

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+
for (uint256 i = 0; i < identityCommitments.length; ) {
82+
_addMember(groupId, identityCommitments[i]);
83+
84+
unchecked {
85+
++i;
86+
}
87+
}
88+
}
89+
2790
/// @dev Updates an identity commitment of an existing group. A proof of membership is
2891
/// needed to check if the node to be updated is part of the tree.
2992
/// @param groupId: Id of the group.
@@ -35,13 +98,14 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
3598
uint256 oldIdentityCommitment,
3699
uint256 newIdentityCommitment,
37100
uint256[] calldata merkleProofSiblings
38-
) internal virtual {
101+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
102+
uint256 leafIndex = merkleTrees[groupId]._indexOf(oldIdentityCommitment);
103+
39104
uint256 merkleTreeRoot = merkleTrees[groupId]._update(
40105
oldIdentityCommitment,
41106
newIdentityCommitment,
42107
merkleProofSiblings
43108
);
44-
uint256 leafIndex = merkleTrees[groupId]._indexOf(newIdentityCommitment);
45109

46110
emit MemberUpdated(groupId, leafIndex, oldIdentityCommitment, newIdentityCommitment, merkleTreeRoot);
47111
}
@@ -55,8 +119,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
55119
uint256 groupId,
56120
uint256 identityCommitment,
57121
uint256[] calldata merkleProofSiblings
58-
) internal virtual {
122+
) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
59123
uint256 leafIndex = merkleTrees[groupId]._indexOf(identityCommitment);
124+
60125
uint256 merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);
61126

62127
emit MemberRemoved(groupId, leafIndex, identityCommitment, merkleTreeRoot);

packages/contracts/contracts/interfaces/ISemaphore.sol

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,20 @@ pragma solidity 0.8.4;
33

44
/// @title Semaphore contract interface.
55
interface ISemaphore {
6-
error Semaphore__GroupDoesNotExist();
7-
error Semaphore__GroupAlreadyExists();
86
error Semaphore__GroupHasNoMembers();
9-
error Semaphore__CallerIsNotTheGroupAdmin();
107
error Semaphore__MerkleTreeDepthIsNotSupported();
118
error Semaphore__MerkleTreeRootIsExpired();
129
error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
1310
error Semaphore__YouAreUsingTheSameNillifierTwice();
1411
error Semaphore__InvalidProof();
1512

16-
/// It defines all the group parameters, in addition to those in the Merkle tree.
13+
/// It defines all the group parameters used by Semaphore.sol.
1714
struct Group {
18-
address admin;
1915
uint256 merkleTreeDuration;
2016
mapping(uint256 => uint256) merkleRootCreationDates;
2117
mapping(uint256 => bool) nullifiers;
2218
}
2319

24-
/// @dev Emitted when a new group is created.
25-
/// @param groupId: Id of the group.
26-
event GroupCreated(uint256 indexed groupId);
27-
28-
/// @dev Emitted when an admin is assigned to a group.
29-
/// @param groupId: Id of the group.
30-
/// @param oldAdmin: Old admin of the group.
31-
/// @param newAdmin: New admin of the group.
32-
event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
33-
3420
/// @dev Emitted when the Merkle tree duration of a group is updated.
3521
/// @param groupId: Id of the group.
3622
/// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
@@ -57,71 +43,54 @@ interface ISemaphore {
5743
uint256[8] proof
5844
);
5945

60-
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
61-
/// if the zero-knowledge proof is valid.
62-
/// @param groupId: Id of the group.
63-
/// @param merkleTreeRoot: Root of the Merkle tree.
64-
/// @param nullifier: Nullifier.
65-
/// @param message: Semaphore message.
66-
/// @param scope: Scope.
67-
/// @param proof: Zero-knowledge proof.
68-
function verifyProof(
69-
uint256 groupId,
70-
uint256 merkleTreeRoot,
71-
uint256 nullifier,
72-
uint256 message,
73-
uint256 scope,
74-
uint256[8] calldata proof
75-
) external;
76-
77-
/// @dev Creates a new group. Only the admin will be able to add or remove members.
78-
/// @param groupId: Id of the group.
79-
/// @param admin: Admin of the group.
46+
/// @dev See {SemaphoreGroups-_createGroup}.
8047
function createGroup(uint256 groupId, address admin) external;
8148

82-
/// @dev Creates a new group. Only the admin will be able to add or remove members.
49+
/// @dev It creates a group with a custom Merkle tree duration.
8350
/// @param groupId: Id of the group.
8451
/// @param admin: Admin of the group.
85-
/// @param merkleTreeRootDuration: Time before the validity of a root expires.
86-
function createGroup(uint256 groupId, address admin, uint256 merkleTreeRootDuration) external;
52+
/// @param merkleTreeDuration: Merkle tree duration.
53+
function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external;
8754

88-
/// @dev Updates the group admin.
89-
/// @param groupId: Id of the group.
90-
/// @param newAdmin: New admin of the group.
55+
/// @dev See {SemaphoreGroups-_updateGroupAdmin}.
9156
function updateGroupAdmin(uint256 groupId, address newAdmin) external;
9257

9358
/// @dev Updates the group Merkle tree duration.
9459
/// @param groupId: Id of the group.
9560
/// @param newMerkleTreeDuration: New Merkle tree duration.
9661
function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;
9762

98-
/// @dev Adds a new member to an existing group.
99-
/// @param groupId: Id of the group.
100-
/// @param identityCommitment: New identity commitment.
63+
/// @dev See {SemaphoreGroups-_addMember}.
10164
function addMember(uint256 groupId, uint256 identityCommitment) external;
10265

103-
/// @dev Adds new members to an existing group.
104-
/// @param groupId: Id of the group.
105-
/// @param identityCommitments: New identity commitments.
66+
/// @dev See {SemaphoreGroups-_addMembers}.
10667
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external;
10768

108-
/// @dev Updates an identity commitment of an existing group. A proof of membership is
109-
/// needed to check if the node to be updated is part of the tree.
110-
/// @param groupId: Id of the group.
111-
/// @param oldIdentityCommitment: Existing identity commitment to be updated.
112-
/// @param newIdentityCommitment: New identity commitment.
113-
/// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
69+
/// @dev See {SemaphoreGroups-_updateMember}.
11470
function updateMember(
11571
uint256 groupId,
11672
uint256 oldIdentityCommitment,
11773
uint256 newIdentityCommitment,
11874
uint256[] calldata merkleProofSiblings
11975
) external;
12076

121-
/// @dev Removes a member from an existing group. A proof of membership is
122-
/// needed to check if the node to be removed is part of the tree.
123-
/// @param groupId: Id of the group.
124-
/// @param identityCommitment: Identity commitment to be removed.
125-
/// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
77+
/// @dev See {SemaphoreGroups-_removeMember}.
12678
function removeMember(uint256 groupId, uint256 identityCommitment, uint256[] calldata merkleProofSiblings) external;
79+
80+
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
81+
/// if the zero-knowledge proof is valid.
82+
/// @param groupId: Id of the group.
83+
/// @param merkleTreeRoot: Root of the Merkle tree.
84+
/// @param nullifier: Nullifier.
85+
/// @param message: Semaphore message.
86+
/// @param scope: Scope.
87+
/// @param proof: Zero-knowledge proof.
88+
function verifyProof(
89+
uint256 groupId,
90+
uint256 merkleTreeRoot,
91+
uint256 nullifier,
92+
uint256 message,
93+
uint256 scope,
94+
uint256[8] calldata proof
95+
) external;
12796
}

0 commit comments

Comments
 (0)