@semaphore-protocol/contracts 3.15.2 → 4.0.0-alpha.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Ethereum Foundation
3
+ Copyright (c) 2024 Ethereum Foundation
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -107,14 +107,14 @@ yarn deploy:semaphore --semaphoreVerifier <address>
107
107
  > **Note**
108
108
  > Run `yarn deploy:semaphore --help` to see the complete list.
109
109
 
110
- If you want to deploy your contract in a specific network you can set up the `DEFAULT_NETWORK` variable in your `.env` file with the name of one of our supported networks (hardhat, localhost, goerli, arbitrum). Or you can specify it as an option:
110
+ If you want to deploy your contract in a specific network you can set up the `DEFAULT_NETWORK` variable in your `.env` file with the name of one of our supported networks (hardhat, localhost, sepolia, arbitrum). Or you can specify it as an option:
111
111
 
112
112
  ```bash
113
- yarn deploy:semaphore --network goerli
114
113
  yarn deploy:semaphore --network sepolia
115
114
  yarn deploy:semaphore --network mumbai
116
- yarn deploy:semaphore --network optimism-goerli
115
+ yarn deploy:semaphore --network optimism-sepolia
116
+ yarn deploy:semaphore --network arbitrum-sepolia
117
117
  yarn deploy:semaphore --network arbitrum
118
118
  ```
119
119
 
120
- If you want to deploy contracts on Goerli or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.
120
+ If you want to deploy contracts on Sepolia or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.
package/Semaphore.sol CHANGED
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
2
+ pragma solidity 0.8.23;
3
3
 
4
- import "./interfaces/ISemaphore.sol";
5
- import "./interfaces/ISemaphoreVerifier.sol";
6
- import "./base/SemaphoreGroups.sol";
4
+ import {ISemaphore} from "./interfaces/ISemaphore.sol";
5
+ import {ISemaphoreVerifier} from "./interfaces/ISemaphoreVerifier.sol";
6
+ 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
@@ -18,71 +18,36 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
18
18
  /// @dev Gets a group id and returns the group parameters.
19
19
  mapping(uint256 => Group) public groups;
20
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
21
  /// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
40
- /// @param _verifier: Semaphore verifier address.
22
+ /// @param _verifier: Semaphore verifier addresse.
41
23
  constructor(ISemaphoreVerifier _verifier) {
42
24
  verifier = _verifier;
43
25
  }
44
26
 
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);
27
+ /// @dev See {SemaphoreGroups-_createGroup}.
28
+ function createGroup(uint256 groupId, address admin) external override {
29
+ _createGroup(groupId, admin);
52
30
 
53
- groups[groupId].admin = admin;
54
31
  groups[groupId].merkleTreeDuration = 1 hours;
55
-
56
- emit GroupAdminUpdated(groupId, address(0), admin);
57
32
  }
58
33
 
59
34
  /// @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);
35
+ function createGroup(uint256 groupId, address admin, uint256 merkleTreeDuration) external override {
36
+ _createGroup(groupId, admin);
67
37
 
68
- groups[groupId].admin = admin;
69
38
  groups[groupId].merkleTreeDuration = merkleTreeDuration;
70
-
71
- emit GroupAdminUpdated(groupId, address(0), admin);
72
39
  }
73
40
 
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);
41
+ /// @dev See {SemaphoreGroups-_updateGroupAdmin}.
42
+ function updateGroupAdmin(uint256 groupId, address newAdmin) external override {
43
+ _updateGroupAdmin(groupId, newAdmin);
79
44
  }
80
45
 
81
46
  /// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
82
47
  function updateGroupMerkleTreeDuration(
83
48
  uint256 groupId,
84
49
  uint256 newMerkleTreeDuration
85
- ) external override onlyGroupAdmin(groupId) {
50
+ ) external override onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
86
51
  uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;
87
52
 
88
53
  groups[groupId].merkleTreeDuration = newMerkleTreeDuration;
@@ -90,8 +55,8 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
90
55
  emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
91
56
  }
92
57
 
93
- /// @dev See {ISemaphore-addMember}.
94
- function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
58
+ /// @dev See {SemaphoreGroups-_addMember}.
59
+ function addMember(uint256 groupId, uint256 identityCommitment) external override {
95
60
  _addMember(groupId, identityCommitment);
96
61
 
97
62
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
@@ -99,74 +64,87 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
99
64
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
100
65
  }
101
66
 
102
- /// @dev See {ISemaphore-addMembers}.
103
- function addMembers(
104
- uint256 groupId,
105
- uint256[] calldata identityCommitments
106
- ) external override onlyGroupAdmin(groupId) {
107
- for (uint256 i = 0; i < identityCommitments.length; ) {
108
- _addMember(groupId, identityCommitments[i]);
109
-
110
- unchecked {
111
- ++i;
112
- }
113
- }
67
+ /// @dev See {SemaphoreGroups-_addMembers}.
68
+ function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
69
+ _addMembers(groupId, identityCommitments);
114
70
 
115
71
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
116
72
 
117
73
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
118
74
  }
119
75
 
120
- /// @dev See {ISemaphore-updateMember}.
76
+ /// @dev See {SemaphoreGroups-_updateMember}.
121
77
  function updateMember(
122
78
  uint256 groupId,
123
79
  uint256 identityCommitment,
124
80
  uint256 newIdentityCommitment,
125
- uint256[] calldata proofSiblings,
126
- uint8[] calldata proofPathIndices
127
- ) external override onlyGroupAdmin(groupId) {
128
- _updateMember(groupId, identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
81
+ uint256[] calldata merkleProofSiblings
82
+ ) external override {
83
+ _updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
129
84
 
130
85
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
131
86
 
132
87
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
133
88
  }
134
89
 
135
- /// @dev See {ISemaphore-removeMember}.
90
+ /// @dev See {SemaphoreGroups-_removeMember}.
136
91
  function removeMember(
137
92
  uint256 groupId,
138
93
  uint256 identityCommitment,
139
- uint256[] calldata proofSiblings,
140
- uint8[] calldata proofPathIndices
141
- ) external override onlyGroupAdmin(groupId) {
142
- _removeMember(groupId, identityCommitment, proofSiblings, proofPathIndices);
94
+ uint256[] calldata merkleProofSiblings
95
+ ) external override {
96
+ _removeMember(groupId, identityCommitment, merkleProofSiblings);
143
97
 
144
98
  uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
145
99
 
146
100
  groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
147
101
  }
148
102
 
149
- /// @dev See {ISemaphore-verifyProof}.
103
+ function validateProof(
104
+ uint256 groupId,
105
+ SemaphoreProof calldata proof
106
+ ) external override onlyExistingGroup(groupId) {
107
+ if (groups[groupId].nullifiers[proof.nullifier]) {
108
+ revert Semaphore__YouAreUsingTheSameNullifierTwice();
109
+ }
110
+
111
+ if (!verifyProof(groupId, proof)) {
112
+ revert Semaphore__InvalidProof();
113
+ }
114
+
115
+ groups[groupId].nullifiers[proof.nullifier] = true;
116
+
117
+ emit ProofValidated(
118
+ groupId,
119
+ proof.merkleTreeDepth,
120
+ proof.merkleTreeRoot,
121
+ proof.nullifier,
122
+ proof.message,
123
+ proof.scope,
124
+ proof.points
125
+ );
126
+ }
127
+
150
128
  function verifyProof(
151
129
  uint256 groupId,
152
- uint256 merkleTreeRoot,
153
- uint256 signal,
154
- uint256 nullifierHash,
155
- uint256 externalNullifier,
156
- uint256[8] calldata proof
157
- ) external override {
158
- uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
130
+ SemaphoreProof calldata proof
131
+ ) public view override onlyExistingGroup(groupId) returns (bool) {
132
+ if (proof.merkleTreeDepth < 1 || proof.merkleTreeDepth > 12) {
133
+ revert Semaphore__MerkleTreeDepthIsNotSupported();
134
+ }
135
+
136
+ uint256 merkleTreeSize = getMerkleTreeSize(groupId);
159
137
 
160
- if (merkleTreeDepth == 0) {
161
- revert Semaphore__GroupDoesNotExist();
138
+ if (merkleTreeSize == 0) {
139
+ revert Semaphore__GroupHasNoMembers();
162
140
  }
163
141
 
164
142
  uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
165
143
 
166
144
  // A proof could have used an old Merkle tree root.
167
145
  // https://github.com/semaphore-protocol/semaphore/issues/98
168
- if (merkleTreeRoot != currentMerkleTreeRoot) {
169
- uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
146
+ if (proof.merkleTreeRoot != currentMerkleTreeRoot) {
147
+ uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[proof.merkleTreeRoot];
170
148
  uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;
171
149
 
172
150
  if (merkleRootCreationDate == 0) {
@@ -178,14 +156,20 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
178
156
  }
179
157
  }
180
158
 
181
- if (groups[groupId].nullifierHashes[nullifierHash]) {
182
- revert Semaphore__YouAreUsingTheSameNillifierTwice();
183
- }
184
-
185
- verifier.verifyProof(merkleTreeRoot, nullifierHash, signal, externalNullifier, proof, merkleTreeDepth);
186
-
187
- groups[groupId].nullifierHashes[nullifierHash] = true;
159
+ return
160
+ verifier.verifyProof(
161
+ [proof.points[0], proof.points[1]],
162
+ [[proof.points[2], proof.points[3]], [proof.points[4], proof.points[5]]],
163
+ [proof.points[6], proof.points[7]],
164
+ [proof.merkleTreeRoot, proof.nullifier, _hash(proof.message), _hash(proof.scope)],
165
+ proof.merkleTreeDepth
166
+ );
167
+ }
188
168
 
189
- emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
169
+ /// @dev Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
170
+ /// @param message: Message to be hashed.
171
+ /// @return Message digest.
172
+ function _hash(uint256 message) private pure returns (uint256) {
173
+ return uint256(keccak256(abi.encodePacked(message))) >> 8;
190
174
  }
191
175
  }
@@ -1,106 +1,141 @@
1
1
  //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
2
+ pragma solidity 0.8.23;
3
3
 
4
- import "../interfaces/ISemaphoreGroups.sol";
5
- import "@zk-kit/incremental-merkle-tree.sol/IncrementalBinaryTree.sol";
6
- import "@openzeppelin/contracts/utils/Context.sol";
4
+ import {ISemaphoreGroups} from "../interfaces/ISemaphoreGroups.sol";
5
+ import {InternalLeanIMT, LeanIMTData} from "@zk-kit/imt.sol/internal/InternalLeanIMT.sol";
7
6
 
8
7
  /// @title Semaphore groups contract.
9
8
  /// @dev This contract allows you to create groups, add, remove and update members.
10
9
  /// You can use getters to obtain informations about groups (root, depth, number of leaves).
11
- abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
12
- using IncrementalBinaryTree for IncrementalTreeData;
10
+ abstract contract SemaphoreGroups is ISemaphoreGroups {
11
+ using InternalLeanIMT for LeanIMTData;
13
12
 
14
- /// @dev Gets a group id and returns the tree data.
15
- mapping(uint256 => IncrementalTreeData) internal merkleTrees;
13
+ /// @dev Gets a group id and returns its tree data.
14
+ mapping(uint256 => LeanIMTData) internal merkleTrees;
16
15
 
17
- /// @dev Creates a new group by initializing the associated tree.
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.
18
39
  /// @param groupId: Id of the group.
19
- /// @param merkleTreeDepth: Depth of the tree.
20
- function _createGroup(uint256 groupId, uint256 merkleTreeDepth) internal virtual {
21
- if (getMerkleTreeDepth(groupId) != 0) {
40
+ /// @param admin: Admin of the group.
41
+ function _createGroup(uint256 groupId, address admin) internal virtual {
42
+ if (admins[groupId] != address(0)) {
22
43
  revert Semaphore__GroupAlreadyExists();
23
44
  }
24
45
 
25
- // The zeroValue is an implicit member of the group, or an implicit leaf of the Merkle tree.
26
- // Although there is a remote possibility that the preimage of
27
- // the hash may be calculated, using this value we aim to minimize the risk.
28
- uint256 zeroValue = uint256(keccak256(abi.encodePacked(groupId))) >> 8;
46
+ admins[groupId] = admin;
29
47
 
30
- merkleTrees[groupId].init(merkleTreeDepth, zeroValue);
48
+ emit GroupCreated(groupId);
49
+ emit GroupAdminUpdated(groupId, address(0), admin);
50
+ }
31
51
 
32
- emit GroupCreated(groupId, merkleTreeDepth, zeroValue);
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);
33
62
  }
34
63
 
35
64
  /// @dev Adds an identity commitment to an existing group.
36
65
  /// @param groupId: Id of the group.
37
66
  /// @param identityCommitment: New identity commitment.
38
- function _addMember(uint256 groupId, uint256 identityCommitment) internal virtual {
39
- if (getMerkleTreeDepth(groupId) == 0) {
40
- revert Semaphore__GroupDoesNotExist();
41
- }
67
+ function _addMember(
68
+ uint256 groupId,
69
+ uint256 identityCommitment
70
+ ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
71
+ uint256 index = getMerkleTreeSize(groupId);
72
+ uint256 merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);
42
73
 
43
- merkleTrees[groupId].insert(identityCommitment);
74
+ emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
75
+ }
44
76
 
45
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
46
- uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
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
+ uint256 startIndex = getMerkleTreeSize(groupId);
82
+ uint256 merkleTreeRoot = merkleTrees[groupId]._insertMany(identityCommitments);
47
83
 
48
- emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
84
+ emit MembersAdded(groupId, startIndex, identityCommitments, merkleTreeRoot);
49
85
  }
50
86
 
51
87
  /// @dev Updates an identity commitment of an existing group. A proof of membership is
52
88
  /// needed to check if the node to be updated is part of the tree.
53
89
  /// @param groupId: Id of the group.
54
- /// @param identityCommitment: Existing identity commitment to be updated.
90
+ /// @param oldIdentityCommitment: Existing identity commitment to be updated.
55
91
  /// @param newIdentityCommitment: New identity commitment.
56
- /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
57
- /// @param proofPathIndices: Path of the proof of membership.
92
+ /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
58
93
  function _updateMember(
59
94
  uint256 groupId,
60
- uint256 identityCommitment,
95
+ uint256 oldIdentityCommitment,
61
96
  uint256 newIdentityCommitment,
62
- uint256[] calldata proofSiblings,
63
- uint8[] calldata proofPathIndices
64
- ) internal virtual {
65
- if (getMerkleTreeDepth(groupId) == 0) {
66
- revert Semaphore__GroupDoesNotExist();
67
- }
68
-
69
- merkleTrees[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
70
-
71
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
72
- uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
73
-
74
- emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
97
+ uint256[] calldata merkleProofSiblings
98
+ ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
99
+ uint256 index = merkleTrees[groupId]._indexOf(oldIdentityCommitment);
100
+ uint256 merkleTreeRoot = merkleTrees[groupId]._update(
101
+ oldIdentityCommitment,
102
+ newIdentityCommitment,
103
+ merkleProofSiblings
104
+ );
105
+
106
+ emit MemberUpdated(groupId, index, oldIdentityCommitment, newIdentityCommitment, merkleTreeRoot);
75
107
  }
76
108
 
77
109
  /// @dev Removes an identity commitment from an existing group. A proof of membership is
78
110
  /// needed to check if the node to be deleted is part of the tree.
79
111
  /// @param groupId: Id of the group.
80
112
  /// @param identityCommitment: Existing identity commitment to be removed.
81
- /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
82
- /// @param proofPathIndices: Path of the proof of membership.
113
+ /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
83
114
  function _removeMember(
84
115
  uint256 groupId,
85
116
  uint256 identityCommitment,
86
- uint256[] calldata proofSiblings,
87
- uint8[] calldata proofPathIndices
88
- ) internal virtual {
89
- if (getMerkleTreeDepth(groupId) == 0) {
90
- revert Semaphore__GroupDoesNotExist();
91
- }
117
+ uint256[] calldata merkleProofSiblings
118
+ ) internal virtual onlyExistingGroup(groupId) onlyGroupAdmin(groupId) {
119
+ uint256 index = merkleTrees[groupId]._indexOf(identityCommitment);
92
120
 
93
- merkleTrees[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
94
-
95
- uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
96
- uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
121
+ uint256 merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);
97
122
 
98
123
  emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
99
124
  }
100
125
 
126
+ /// @dev See {ISemaphoreGroups-hasMember}.
127
+ function hasMember(uint256 groupId, uint256 identityCommitment) public view virtual override returns (bool) {
128
+ return merkleTrees[groupId]._has(identityCommitment);
129
+ }
130
+
131
+ /// @dev See {ISemaphoreGroups-indexOf}.
132
+ function indexOf(uint256 groupId, uint256 identityCommitment) public view virtual override returns (uint256) {
133
+ return merkleTrees[groupId]._indexOf(identityCommitment);
134
+ }
135
+
101
136
  /// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
102
137
  function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
103
- return merkleTrees[groupId].root;
138
+ return merkleTrees[groupId]._root();
104
139
  }
105
140
 
106
141
  /// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
@@ -108,31 +143,8 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
108
143
  return merkleTrees[groupId].depth;
109
144
  }
110
145
 
111
- /// @dev See {ISemaphoreGroups-getNumberOfMerkleTreeLeaves}.
112
- function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
113
- return merkleTrees[groupId].numberOfLeaves;
114
- }
115
-
116
- /// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
117
- /// @param proofPathIndices: Path of the proof of membership.
118
- /// @return Index of a group member.
119
- function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
120
- uint256 memberIndex = 0;
121
-
122
- for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
123
- if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
124
- memberIndex *= 2;
125
-
126
- if (proofPathIndices[i - 1] == 1) {
127
- memberIndex += 1;
128
- }
129
- }
130
-
131
- unchecked {
132
- --i;
133
- }
134
- }
135
-
136
- return memberIndex;
146
+ /// @dev See {ISemaphoreGroups-getMerkleTreeSize}.
147
+ function getMerkleTreeSize(uint256 groupId) public view virtual override returns (uint256) {
148
+ return merkleTrees[groupId].size;
137
149
  }
138
150
  }