Skip to content

Commit

Permalink
Merge pull request #133 from semaphore-protocol/feat/member-index
Browse files Browse the repository at this point in the history
feat: add member index parameter to events
  • Loading branch information
cedoor authored Sep 14, 2022
2 parents 8e841a3 + bcf09a6 commit 2bbacbe
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 13 deletions.
32 changes: 29 additions & 3 deletions contracts/base/SemaphoreGroups.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
groups[groupId].insert(identityCommitment);

uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;

emit MemberAdded(groupId, identityCommitment, merkleTreeRoot);
emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
}

/// @dev Updates an identity commitment of an existing group. A proof of membership is
Expand All @@ -73,8 +74,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
groups[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);

uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);

emit MemberUpdated(groupId, identityCommitment, newIdentityCommitment, merkleTreeRoot);
emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
}

/// @dev Removes an identity commitment from an existing group. A proof of membership is
Expand All @@ -96,8 +98,9 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
groups[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);

uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);

emit MemberRemoved(groupId, identityCommitment, merkleTreeRoot);
emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
}

/// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
Expand All @@ -114,4 +117,27 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].numberOfLeaves;
}

/// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
/// @param proofPathIndices: Path of the proof of membership.
/// @return Index of a group member.
function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
uint256 memberIndex = 0;

for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
memberIndex *= 2;

if (proofPathIndices[i - 1] == 1) {
memberIndex += 1;
}
}

unchecked {
--i;
}
}

return memberIndex;
}
}
10 changes: 7 additions & 3 deletions contracts/interfaces/ISemaphoreGroups.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,31 @@ interface ISemaphoreGroups {

/// @dev Emitted when a new identity commitment is added.
/// @param groupId: Group id of the group.
/// @param index: Identity commitment index.
/// @param identityCommitment: New identity commitment.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberAdded(uint256 indexed groupId, uint256 identityCommitment, uint256 merkleTreeRoot);
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);

/// @dev Emitted when an identity commitment is updated.
/// @param groupId: Group id of the group.
/// @param identityCommitment: New identity commitment.
/// @param index: Identity commitment index.
/// @param identityCommitment: Existing identity commitment to be updated.
/// @param newIdentityCommitment: New identity commitment.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberUpdated(
uint256 indexed groupId,
uint256 index,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256 merkleTreeRoot
);

/// @dev Emitted when a new identity commitment is removed.
/// @param groupId: Group id of the group.
/// @param index: Identity commitment index.
/// @param identityCommitment: Existing identity commitment to be removed.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberRemoved(uint256 indexed groupId, uint256 identityCommitment, uint256 merkleTreeRoot);
event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);

/// @dev Returns the last root hash of a group.
/// @param groupId: Id of the group.
Expand Down
15 changes: 9 additions & 6 deletions test/Semaphore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe("Semaphore", () => {
.to.emit(contract, "MemberAdded")
.withArgs(
groupId,
0,
members[0],
"18951329906296061785889394467312334959162736293275411745101070722914184798221"
)
Expand All @@ -125,7 +126,7 @@ describe("Semaphore", () => {

const transaction = contract.addMembers(groupId, members)

await expect(transaction).to.emit(contract, "MemberAdded").withArgs(groupId, BigInt(3), group.root)
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(groupId, 2, BigInt(3), group.root)
})
})

Expand All @@ -152,7 +153,9 @@ describe("Semaphore", () => {

const transaction = contract.updateMember(groupId, BigInt(1), BigInt(4), siblings, pathIndices)

await expect(transaction).to.emit(contract, "MemberUpdated").withArgs(groupId, BigInt(1), BigInt(4), root)
await expect(transaction)
.to.emit(contract, "MemberUpdated")
.withArgs(groupId, 0, BigInt(1), BigInt(4), root)
})
})

Expand All @@ -170,16 +173,16 @@ describe("Semaphore", () => {

group.addMembers(members)

group.removeMember(0)
group.removeMember(2)

await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
await contract.addMembers(groupId, members)

const { siblings, pathIndices, root } = group.generateProofOfMembership(0)
const { siblings, pathIndices, root } = group.generateProofOfMembership(2)

const transaction = contract.removeMember(groupId, BigInt(1), siblings, pathIndices)
const transaction = contract.removeMember(groupId, BigInt(3), siblings, pathIndices)

await expect(transaction).to.emit(contract, "MemberRemoved").withArgs(groupId, BigInt(1), root)
await expect(transaction).to.emit(contract, "MemberRemoved").withArgs(groupId, 2, BigInt(3), root)
})
})

Expand Down
1 change: 1 addition & 0 deletions test/SemaphoreVoting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ describe("SemaphoreVoting", () => {
.to.emit(contract, "MemberAdded")
.withArgs(
pollIds[1],
0,
identityCommitment,
"14787813191318312920980352979830075893203307366494541177071234930769373297362"
)
Expand Down
2 changes: 2 additions & 0 deletions test/SemaphoreWhistleblowing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ describe("SemaphoreWhistleblowing", () => {
.to.emit(contract, "MemberAdded")
.withArgs(
entityIds[0],
0,
identityCommitment,
"14787813191318312920980352979830075893203307366494541177071234930769373297362"
)
Expand Down Expand Up @@ -129,6 +130,7 @@ describe("SemaphoreWhistleblowing", () => {
.to.emit(contract, "MemberRemoved")
.withArgs(
entityIds[0],
0,
identityCommitment,
"15019797232609675441998260052101280400536945603062888308240081994073687793470"
)
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6483,7 +6483,7 @@ __metadata:
dependencies:
bn.js: ^4.11.8
ethereumjs-util: ^6.0.0
checksum: ae074be0bb012857ab5d3ae644d1163b908a48dd724b7d2567cfde309dc72222d460438f2411936a70dc949dc604ce1ef7118f7273bd525815579143c907e336
checksum: 03127d09960e5f8a44167463faf25b2894db2f746376dbb8195b789ed11762f93db9c574eaa7c498c400063508e9dfc1c80de2edf5f0e1406b25c87d860ff2f1
languageName: node
linkType: hard

Expand Down

0 comments on commit 2bbacbe

Please sign in to comment.