Skip to main content
Version: V4

Semaphore groups

A Semaphore group contains identity commitments of group members. Example uses of groups include the following:

  • poll question that attendees join to rate an event,
  • ballot that members join to vote on a proposal,
  • whistleblowers who are verified employees of an organization.
info

Semaphore V4 uses the ZK-Kit LeanIMT (i.e., Lean Incremental Merkle Tree) Solidity and JavaScript implementations for managing groups. Groups are Merkle trees, and the group members (i.e., identity commitments) are their leaves.

Off-chain groups​

Use the @semaphore-protocol/group package to manage off-chain groups.

Install package​

npm install @semaphore-protocol/group
info

Semaphore also provides @semaphore-protocol/core, which includes the functions of the following core packages: @semaphore-protocol/identity, @semaphore-protocol/group, @semaphore-protocol/proof.

Create a group​

To create a group instantiate Group without any parameters. For example:

import { Group } from "@semaphore-protocol/group"

const group1 = new Group()

You can also initialize a group with multiple members by passing the list of identity commitments as the first parameter when creating the group:

const members = [
11237622825477336339577122413451117718539783476837539122310492284566644730311n,
9332663527862709610616009715800254142772436825222910251631161087138559093425n,
13255821893820536903335282929376140649646180444238593676033702344407594536519n
]

const group2 = new Group(members)

Add members​

Use the addMember method to add a member to a group. For example:

import { Identity } from "@semaphore-protocol/identity"

const { commitment } = new Identity()

group1.addMember(commitment)

To add a batch of members to a group, pass an array to the addMembers method. For example:

group1.addMembers(members)
caution

When you use the same Semaphore identity across multiple groups, if an attacker takes control of that identity all the groups it is part of will be compromised. Consider using different identities for each group.

Remove or update members​

To remove members from a group, pass the member index to the removeMember method. For example:

group.removeMember(0)

To update members in a group, pass the member index and the new value to the updateMember method. For example:

group.updateMember(0, 2n)
caution

Removing a member from a group sets its value to 0. Given that the member isn't removed, the number of members (i.e., group.size on group.members.length) doesn't change.

Generate a Merkle proof​

Semaphore groups are Merkle trees, and it is therefore possible to calculate the Merkle proof of a group member (i.e., tree leaf) by passing the index of the member to the generateMerkleProof. For example:

group.generateMerkleProof(0)

On-chain groups​

Semaphore provides Semaphore.sol, a contract designed for managing on-chain groups (deployed on major testnets).

Use the @semaphore-protocol/contracts package to import the ISemaphore.sol interface in your contract and start using its functions.

Install package​

npm install @semaphore-protocol/contracts

Create a group​

To create a group initialize your contract with the Semaphore.sol address. The createGroup function can be used to create a Semaphore group. For example:

pragma solidity ^0.8.23;

import "@semaphore-protocol/contracts/interfaces/ISemaphore.sol";

contract YourContract {
ISemaphore public semaphore;

uint256 public groupId;

constructor(ISemaphore _semaphore) {
semaphore = _semaphore;

groupId = semaphore.createGroup();
}
}

Semaphore.sol also includes a mechanism to verify Semaphore proofs created with old Merkle tree roots, the duration of which can optionally be defined by the admin in the createGroup function. The default value duration is 1 hour and it should be fine for most use-cases. For more context see the issue #98.

Add members​

Use the addMember function to add a member to a group. For example:

function addMember(uint256 identityCommitment) external {
semaphore.addMember(groupId, identityCommitment);
}

To add a batch of members to a group, pass an array to the addMembers function. For example:

function addMembers(uint256[] calldata identityCommitments) external {
semaphore.addMembers(groupId, identityCommitments);
}

Remove or update members​

To update members in a group, pass the identity commitment of the member you want to update, its new identity commitment and the siblings of the Merkle proof for that member. For example:

function updateMember(uint256 identityCommitment, uint256 newIdentityCommitment, uint256[] calldata merkleProofSiblings) external {
semaphore.updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);
}
info

To calculate the Merkle proof of a group member you can use the generateMerkleProof method of the JavaScript Group class described above.

To remove members from a group, pass the identity commitment of the member you want to remove and the siblings of the Merkle proof for that member. For example:

function removeMember(uint256 identityCommitment, uint256[] calldata merkleProofSiblings) external {
semaphore.removeMember(groupId, identityCommitment, merkleProofSiblings);
}
info

If you want to see an example of a working contract, have a look at the contracts-hardhat CLI template. You can also create a project with that template by running semaphore create my-app --template contracts-hardhat.