---
sidebar_position: 2
title: Groups
---

import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"

# Semaphore groups

A [Semaphore group](/glossary/#group) contains [identity commitments](/glossary/#identity-commitment) 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](https://github.com/privacy-scaling-explorations/zk-kit) LeanIMT (i.e., Lean Incremental
Merkle Tree) [Solidity](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/imt.sol/contracts) and
[JavaScript](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/imt) 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`](https://github.com/semaphore-protocol/semaphore/blob/main/packages/group) package to manage off-chain groups.

### Install package

<Tabs
  defaultValue="npm"
  groupId="package-managers"
  values={[
{label: 'npm', value: 'npm'},
{label: 'Yarn', value: 'yarn'},
{label: 'pnpm', value: 'pnpm'}
]}
>
  <TabItem value="npm">
    ```bash
    npm install @semaphore-protocol/group
    ```
  </TabItem>

  <TabItem value="yarn">
    ```bash
    yarn add @semaphore-protocol/group
    ```
  </TabItem>

  <TabItem value="pnpm">
    ```bash
    pnpm add @semaphore-protocol/group
    ```
  </TabItem>
</Tabs>

:::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:

```ts
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:

```ts
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:

```ts
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:

```ts
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:

```ts
group.removeMember(0)
```

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

```ts
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](/glossary#merkle-tree), 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:

```ts
group.generateMerkleProof(0)
```

## On-chain groups

Semaphore provides [`Semaphore.sol`](https://github.com/semaphore-protocol/semaphore/blob/main/packages/contracts/contracts/Semaphore.sol), a contract designed for managing on-chain groups ([deployed](/deployed-contracts) on major testnets).

Use the [`@semaphore-protocol/contracts`](https://github.com/semaphore-protocol/semaphore/blob/main/packages/contracts) package to import the `ISemaphore.sol` interface in your contract and start using its functions.

### Install package

<Tabs
  defaultValue="npm"
  groupId="package-managers"
  values={[
{label: 'npm', value: 'npm'},
{label: 'Yarn', value: 'yarn'},
{label: 'pnpm', value: 'pnpm'}
]}
>
  <TabItem value="npm">
    ```bash
    npm install @semaphore-protocol/contracts
    ```
  </TabItem>

  <TabItem value="yarn">
    ```bash
    yarn add @semaphore-protocol/contracts
    ```
  </TabItem>

  <TabItem value="pnpm">
    ```bash
    pnpm add @semaphore-protocol/contracts
    ```
  </TabItem>
</Tabs>

### 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:

```solidity
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](https://github.com/semaphore-protocol/semaphore/issues/98).

### Add members

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

```solidity
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:

```solidity
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:

```solidity
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:

```solidity
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`](https://github.com/semaphore-protocol/semaphore/tree/main/packages/cli-template-contracts-hardhat) CLI template. You can also create a project with that template by running `semaphore create my-app --template contracts-hardhat`.
:::
