Semaphore groups
Use Semaphore in your application or smart contract to create off-chain and on-chain 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.
A Semaphore group is an incremental Merkle tree, and group members (i.e., identity commitments) are tree leaves. Semaphore groups set the following tree parameters:
- Tree depth: the maximum number of members a group can contain (
max size = 2 ^ tree depth
). - Zero value: the value used to calculate the zero nodes of the incremental Merkle tree.
Learn how to work with groups.
Off-chain groups​
Create an off-chain group​
Use the @semaphore-protocol/group
library Group
class to create an off-chain group.
Options​
- Tree depth: (default
20
) the maximum number of members a group can contain (max size = 2 ^ tree depth
). - Zero value: (default
BigInt(0)
) the value for a tree node that doesn't have a member assigned.
To create a group with default treeDepth
and zeroValue
, call the Group
constructor without parameters--for example:
import { Group } from "@semaphore-protocol/group"
// Default parameters: treeDepth = 20, zeroValue = BigInt(0).
const group = new Group()
The following example code passes treeDepth
to create a group for 2 ^ 30 = 1073741824
members:
import { Group } from "@semaphore-protocol/group"
const group = new Group(30)
The following example code creates a group with a zeroValue
of BigInt(1)
:
import { Group } from "@semaphore-protocol/group"
const group = new Group(20, BigInt(1))
Add members to an off-chain group​
Use the Group addMember
function to add a member (identity commitment) to a group--for example:
group.addMember(identityCommitment)
To add a batch of members to a group, pass an array to the Group addMembers
function--for example:
group.addMembers([identityCommitment1, identityCommitment2])
Remove members from an off-chain group​
To remove members from a group, pass the member index to the Group removeMember
function--for example:
group.removeMember(0)
caution
Removing a member from a group sets the node value to zeroValue
.
Given that the node isn't removed, the length of the group.members
array doesn't change.
On-chain groups​
The SemaphoreGroups
contract uses a the IncrementalBinaryTree
library and provides methods to create groups and add/remove members.
To use on-chain groups, import SemaphoreGroups
and call its internal methods.
The following code sample shows how the Semaphore
contract uses SemaphoreGroups
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./interfaces/ISemaphore.sol";
import "./base/SemaphoreCore.sol";
import "./base/SemaphoreGroups.sol";
/// @title Semaphore
contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
...
function createGroup(
uint256 groupId,
uint8 depth,
uint256 zeroValue,
address admin
) external override onlySupportedDepth(depth) {
_createGroup(groupId, depth, zeroValue);
groupAdmins[groupId] = admin;
emit GroupAdminUpdated(groupId, address(0), admin);
}
function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
_addMember(groupId, identityCommitment);
}
function removeMember(
uint256 groupId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external override onlyGroupAdmin(groupId) {
_removeMember(groupId, identityCommitment, proofSiblings, proofPathIndices);
}
...
}