# Semaphore proofs

Learn how to use Semaphore to generate and verify zero-knowledge 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 properties 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.

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 = "proposal_1"

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

zkeyFilePath: "./semaphore.zkey",

wasmFilePath: "./semaphore.wasm"

})

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

: the Semaphore proof.`proof`

: the JavaScript object in the`verificationKey`

`semaphore.json`

trusted setup file.

The following code sample shows how to parse the verification key object from `semaphore.json`

and verify the previously generated proof:

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

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

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

`verifyProof`

returns a Promise that resolves to `true`

or `false`

.

## Verify a proof on-chainâ€‹

Use the `SemaphoreCore`

contract to verify proofs on-chain. It uses a verifier deployed to Ethereum and provides methods hash the signal and verify a proof.

You can import `SemaphoreCore`

and other Semaphore contracts from the `@semaphore-protocol/contracts`

NPM module.

To verify Semaphore proofs in your contract, import `SemaphoreCore`

and pass the following to the `_verifyProof`

internal method:

: The Semaphore signal to prove.`signal`

: The root of the Merkle tree.`root`

: a nullifier hash.`nullifierHash`

: The external nullifier.`externalNullifier`

: A`proof`

*Solidity-compatible*Semaphore proof.: The verifier address.`verifier`

Remember to save the `nullifierHash`

on-chain to avoid double-signaling.

Alternatively, you can use an already deployed `Semaphore`

contract and use its `verifyProof`

external function.

### Generate a Solidity-compatible proofâ€‹

To transform a proof to be compatible with Solidity contracts, pass the proof to the `packToSolidityProof`

utility function--for example:

`import { packToSolidityProof } from "@semaphore-protocol/proof"`

const solidityProof = packToSolidityProof(fullProof.proof)

Semaphore returns a new Solidity-compatible instance of the proof.

### Retrieve a nullifier hashâ€‹

To get the Semaphore proof nullifier hash, access the proof's `publicSignals.nullifierHash`

property--for example:

`const { nullifierHash } = fullProof.publicSignals`