Skip to main content

Signal anonymously

Using zero knowledge, Semaphore allows Ethereum users to prove their membership of a group and send signals such as votes or endorsements without revealing their original identity.

Building an Ethereum dApp? Semaphore components make it simple to add a privacy layer!

Solidity contract
zkSNARK circuits
JavaScript libraries

Semaphore identities

Given to all Semaphore group members, it is comprised of three parts: identity commitment, trapdoor, and nullifier.

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

const { trapdoor, nullifier, commitment } = new Identity()

Private values

Trapdoor and nullifier values are the private values of the Semaphore identity. To avoid fraud, the owner must keep both values secret.

Public values

Semaphore uses the Poseidon hash function to create the identity commitment from the identity private values. Identity commitments can be made public, similarly to Ethereum addresses.

Generate identities

Semaphore identities can be generated deterministically or randomly. Deterministic identities can be generated from the hash of a secret message.

Semaphore groups

Semaphore groups are binary incremental Merkle trees that store the public identity commitment of each member.

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

const group = new Group()


Merkle trees

Each leaf contains an identity commitment for a user. The identity commitment proves that the user is a group member without revealing the private identity of the user.

Types of groups

Groups can be created and managed in a decentralized fashion with Semaphore contracts or off-chain with our JavaScript libraries.

Group management

Users can join and leave groups by themselves, or an admin can add and remove them. Admins can be centralized authorities, Ethereum accounts, multi-sig wallets or smart contracts.

Semaphore proofs

Semaphore group members can anonymously prove that they are part of a group and that they are generating their own proofs and signals.

Generate Semaphore proofs
import { generateProof, verifyProof } from "@semaphore-protocol/proof"

const externalNullifier = BigInt(1)
const signal = "Hello world"

const fullProof = await generateProof(identity, group, externalNullifier, signal, {
zkeyFilePath: "./semaphore.zkey",
wasmFilePath: "./semaphore.wasm"

const verificationKey = JSON.parse(fs.readFileSync("./semaphore.json", "utf-8"))

await verifyProof(verificationKey, fullProof)


Only users who are part of a group can generate a valid proof for that group.


Group users can anonymously broadcast signals such as votes or endorsements without revealing their original identity.


Semaphore proofs can be verified with Semaphore contracts on-chain or with our JavaScript libraries off-chain.