Skip to content

Groth16 trusted setup, multi-party (MPC) procedure

VDI uses Groth16 over BN128. Soundness requires that the proving key (*.zkey) was produced in a setup where at least one participant behaved honestly and destroyed their toxic waste (the randomness used during their contribution). A multi-party ceremony achieves this without trusting any single operator: if you trust that any one contributor was honest, the final parameters are secure.

This document is the operational counterpart to the “Trusted Setup Note” in protocol/NCC_REVIEW_PACKET.md.

What gets generated

PhaseArtifactPurpose
Phase 1pot{N}_*.ptaupot{N}_final.ptauPowers of Tau, shared across all circuits of sufficient constraint size
Phase 2{circuit}_0000.zkey → contributions → final zkeyCircuit-specific Groth16 proving key
Export{circuit}.vkey.jsonVerification key embedded in attestations

The reference tool is snarkjs (via npx snarkjs). Phase 1 can be run once per curve/power level; Phase 2 is repeated per circuit (or per R1CS revision).

Prerequisites

  • npx / Node.js ≥ 18
  • jq (for JSON transcript)
  • snarkjs resolved by npx (project or global)
  • Circom already compiled the circuit to R1CS (and WASM for proving at runtime)

One-shot MPC (Phase 1 + Phase 2)

From the repository root, after R1CS exists (example: zk-cp causal circuit):

bash
export MPC_CONTRIBUTORS=3
export MPC_CIRCUIT_NAME=causalProof
export MPC_R1CS_PATH=zk-cp/build/causalProof/causalProof.r1cs
export MPC_OUTPUT_DIR=zk-cp/build
export MPC_POWERS=14
bash protocol/scripts/mpc-snarkjs-ceremony.sh

Adjust paths if your Circom outputs live under zk-cp/build/causalProof/ (see zk-cp/scripts/build-all-circuits.sh).

The script:

  1. Runs Phase 1 with MPC_CONTRIBUTORS sequential contributions (or skips if MPC_PTAU_FINAL is set; see below).
  2. Runs Phase 2 Groth16 setup + the same number of zkey contributions.
  3. Exports ${MPC_CIRCUIT_NAME}.vkey.json into MPC_OUTPUT_DIR.
  4. Copies the final proving key to ${MPC_CIRCUIT_NAME}_0001.zkey (name kept for compatibility with existing prover paths).
  5. Writes mpc_transcript_${MPC_CIRCUIT_NAME}.json and mpc_ceremony.log under MPC_OUTPUT_DIR.
  6. Runs snarkjs zkey verify on the final key.

Minimum contributors: the script defaults to requiring at least 2 contributors (override with MPC_MIN_CONTRIBUTORS). Production ceremonies often use 3+ independent parties.

Reusing Powers of Tau (Phase 2 only)

If you already have a final Phase 1 file (e.g. pot14_final.ptau from a prior MPC or a published PTAU you audited):

bash
export MPC_PTAU_FINAL=/absolute/path/to/pot14_final.ptau
export MPC_SKIP_PHASE1=1
# ... same MPC_CIRCUIT_NAME, MPC_R1CS_PATH, MPC_OUTPUT_DIR, MPC_CONTRIBUTORS
bash protocol/scripts/mpc-snarkjs-ceremony.sh

Phase 2 still uses multiple zkey contributions; only Phase 1 is skipped.

VDI policy circuits (protocol/build)

After compiling Circom sources under protocol/circuits/ to protocol/build/<Circuit>/, run the same script with:

  • MPC_R1CS_PATH=protocol/build/fairLending/fairLending.r1cs (example)
  • MPC_OUTPUT_DIR=protocol/build/fairLending
  • MPC_CIRCUIT_NAME=fairLending

Then refresh protocol/ARTIFACT_MANIFEST.json using the steps in Post-ceremony: manifest pin below.

Operational security

  1. Entropy: Contributors should supply their own high-entropy secret (or HSM-backed randomness); the script supports interactive input when a TTY is available.
  2. Toxic waste: Each contributor must delete their contribution secret after the step; coordinators should not retain it.
  3. Transcripts: Publish mpc_transcript_*.json and SHA-256 hashes of final ptau / zkey / vkey for third-party verification.
  4. Hermez / community PTAU: Many teams reuse well-known pot*_final.ptau files for BN128; if you use one, document the exact file hash you pinned.

Post-ceremony: manifest pin

After mpc-snarkjs-ceremony.sh completes, pin the transcript and (optionally) refresh on-disk artifact hashes in ARTIFACT_MANIFEST.json so verifiers can enforce circuit governance (VDI-SPEC §14).

1. Regenerate base manifest (optional)

If you added a new circuit or changed Circom sources:

bash
cd protocol
node scripts/generate-artifact-manifest.js

2. Merge MPC transcript + refresh hashes

Recommended after MPC (new zkey / vkey on disk, wasm/r1cs unchanged):

bash
cd protocol
npm run manifest:post-mpc -- \
  --transcript ../zk-cp/build/mpc_transcript_causalProof.json \
  --circuit-dir ../zk-cp/build \
  --refresh-hashes
  • --transcript: path to mpc_transcript_<circuit>.json from the ceremony.
  • --circuit-dir: directory that contains {circuit}_js/, {circuit}.r1cs, {circuit}_0001.zkey, {circuit}.vkey.json (same layout as generate-artifact-manifest.js).
  • --refresh-hashes: recomputes artifacts.*.sha256 and sizes from files. Omit it if you only want to attach ceremony metadata (transcript SHA, ptau/zkey/vkey hashes from the transcript) without touching wasm/r1cs entries.

The merge adds a per-circuit ceremony object (contributor count, dates, transcript SHA-256, phase-1 skip flag, and hashes copied from the transcript).

3. Commit and publish

Commit ARTIFACT_MANIFEST.json, the transcript JSON, and (if you version them) final ptau / zkey references. Publish transcript + manifest hashes for third-party verification.

Relationship to existing scripts

  • verifier-api/circuits/scripts/mpc-ceremony.sh, older compliance_certificate–specific ceremony; prefer protocol/scripts/mpc-snarkjs-ceremony.sh for new work.
  • protocol/scripts/compile-circuits.sh, dev single-contributor flow; replace proving keys with MPC outputs before production.

Verification keys are embedded in attestations. The verifier is open source.