Skip to main content
Version: V3

Semaphore proofs

Once a user joins their Semaphore identity to a Semaphore group, the user can signal anonymously with a zero-knowledge proof that proves the following:

  • the user is a member of the group,
  • the same user created the signal and the proof.

Developers can use Semaphore for the following:

Generate a proof off-chain​

Use the @semaphore-protocol/proof library to generate an off-chain proof. To generate a proof, pass the following parameters to the generateProof function:

  • identity: the Semaphore identity of the user broadcasting the signal and generating the proof;
  • group: the group to which the user belongs;
  • externalNullifier: the value that prevents double-signaling;
  • signal: the signal the user wants to send anonymously;
  • snarkArtifacts: the zkey and wasm trusted setup files.

Install library:​

npm install @semaphore-protocol/proof@^3

In the voting system use case, once all the voters have joined their identities to the ballot group, a voter can generate a proof to vote for a proposal. In the call to generateProof, the voting system passes the unique ballot ID (the Merkle tree root of the group) as the externalNullifier to prevent the voter signaling more than once for the ballot. The following code sample shows how to use generateProof to generate the voting proof:

import { generateProof } from "@semaphore-protocol/proof"

const externalNullifier = group.root
const signal = 1

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

If you are generating the proof on the client side, you can avoid adding the snark artifacts because they are fetched automatically:

const fullProof = await generateProof(identity, group, externalNullifier, signal)

Verify a proof off-chain​

Use the @semaphore-protocol/proof library to verify a Semaphore proof off-chain. To verify a proof, pass the following to the verifyProof function:

  • fullProof: the Semaphore proof;
  • treeDepth: the Merkle tree depth.

The following code sample shows how to verify the previously generated proof:

import { verifyProof } from "@semaphore-protocol/proof"

await verifyProof(fullProof, 20) // true or false.

verifyProof returns a Promise that resolves to true or false.

Verify a proof on-chain​

Use the Semaphore.sol contract to verify proofs on-chain.

info

See our deployed contracts to find the addresses for your network.

To verify Semaphore proofs in your contract, import ISemaphore.sol, pass it the Semaphore.sol address and call the verifyProof method with following parameters:

  • groupId: the identifier of the group;
  • merkleTreeRoot: the root of the Merkle tree;
  • signal: the signal the user wants to send anonymously;
  • nullifierHash: a nullifier hash;
  • externalNullifier: the value that prevents double-signaling;
  • proof: a Solidity-compatible Semaphore proof.
info

You can import ISemaphore.sol and other Semaphore contracts from the @semaphore-protocol/contracts NPM module.