15 - Trusted setup ceremonies
1. Why this chapter exists
The Sprout and Sapling SNARKs require a structured reference
string (SRS) that must be generated by a procedure no single
party can subvert. If the toxic waste leaks, the soundness of
Groth16 collapses and an adversary can forge proofs. The integrity
of every wallet that uses librustzcash rests on three SHA-256
constants in
zcash_proofs/src/lib.rs
and the chain of MPC-ceremony transcripts they pin. A contributor
touching parameter loading, downloader code, or any MockTxProver
call site must understand what the SRS contains, why
verify_hash is the load-bearing check, and what Orchard's Halo 2
gains by avoiding the ceremony altogether.
2. Definitions
Definition (structured reference string, SRS)
The Groth16 verifying key has the form
for uniformly random and a polynomial-in- structure that depends on the circuit. The proving key is much larger: many and points derived from the same secret scalars. The pair is the SRS.
Definition (toxic waste)
The set of scalars used to derive the SRS. Anyone who learns them can forge proofs of false statements. The trusted setup is the procedure of generating and the proving key without anyone learning the toxic waste.
Definition (multi-party computation, MPC, ceremony)
A sequential protocol where each participant contributes a secret and produces a transcript that the next participant verifies. Concretely, to generate for :
- samples and outputs .
- samples and outputs .
- ... outputs .
If any one is uniform and the corresponding participant erases their share, no coalition of the others recovers . Each participant publishes a verifiable transcript proving they followed the protocol without revealing .
Definition (Powers of Tau)
For Groth16, is not a single scalar but a vector
plus -shifted and -shifted variants. The 2018 Zcash Powers of Tau ceremony generated up to with GB output. The output is the Phase 1 SRS.
Definition (Phase 2 / circuit-specific MPC)
Takes the Phase 1 SRS and a specific R1CS circuit, produces the
proving/verifying keys for that circuit. The Sapling MPC ran in
early 2018 with participants and produced
sapling-spend.params, sapling-output.params, and
sprout-groth16.params.
Invariant (parameter integrity)
For each parameter file consumed by a wallet, the SHA-512 of the
file bytes must match the corresponding constant
(SAPLING_SPEND_HASH, SAPLING_OUTPUT_HASH, SPROUT_HASH) in
zcash_proofs/src/lib.rs.
A mismatch must abort loading. This is the only check that
prevents a substituted (potentially backdoored) parameter file
from being silently used.
3. The code
3.1 Hardcoded parameter hashes
The three SHA-512 hashes for the parameter files live at the top
of zcash_proofs::lib:
loading...
The byte-length constants are paired with the hashes so a wallet that fails to read the full file (network truncation, disk error) gets an explicit length mismatch rather than a confusing hash mismatch.
3.2 The verify_hash helper
load_parameters and the download path both stream parameter
bytes through a hashing reader, then call verify_hash to
compare against the hardcoded constant:
loading...
The function compares the computed hash against expected_hash
and returns an InvalidData error on mismatch. The byte-count
mismatch path produces an expected vs actual bytes error
message that aids debugging without leaking parameter content.
3.3 The MPC ceremonies in summary
Powers of Tau (2018). 87 participants. Each generated on an air-gapped machine and destroyed it. Transcripts (gigabytes each) were transferred on encrypted USB drives. Each new transcript was verified by the next participant using the pairing check
The final transcript hash was published; anyone can re-verify it.
Sapling MPC (2018, Phase 2). participants. Took the Powers of Tau output and produced the per-circuit and for Sapling Spend and Sapling Output. The same MPC produced the "hybrid Sprout" parameters (post CVE-2019-7167, see chapter 12).
The three resulting files and their hashes:
| File | Hash constant | Approx. size |
|---|---|---|
sapling-spend.params | SAPLING_SPEND_HASH in zcash_proofs | 47 MB |
sapling-output.params | SAPLING_OUTPUT_HASH in zcash_proofs | 3.6 MB |
sprout-groth16.params | SPROUT_HASH in zcash_proofs | 725 MB |
3.4 The Sprout-Groth16 addendum
The original Sprout (BCTV14) parameters were generated in a
separate 2016 ceremony. After CVE-2019-7167, the Sprout circuit
was re-expressed in bellman for Groth16 and parameters were
regenerated in the 2018 Sapling MPC. The proving key is large
because the Sprout circuit was tuned for BCTV14 and never
re-architected for Groth16 efficiency. Sprout is legacy: closed
to new outputs since NU5.
3.5 Verifying the ceremony
Anyone can verify the Powers of Tau and Sapling MPC transcripts. The verification involves:
- Hash chaining: each contributor's transcript embeds the hash of the prior transcript, forming a tamper-evident chain.
- Pairing checks: each transcript satisfies a sequence of pairing equations that prove the contributor multiplied the prior SRS by some scalar without revealing which.
- Public attestation: each contributor signs and publishes their step.
Full re-verification takes hours on a single machine but is
deterministic. Volunteers have run it independently after the
ceremony. If the SHA-512 of your downloaded sapling-spend.params
matches SAPLING_SPEND_HASH, the file has not been substituted.
3.6 What is in the proving key
For Groth16, the proving key contains:
- The QAP polynomials evaluated at , encoded as points: .
- The products in .
- The -table used to commit to the quotient polynomial.
For a circuit with wires and degree constraints, this is group elements. For Sapling Spend, constraints; hence the MB key.
The verifier only needs and for public-input length . The verifying-key file is tens of kilobytes.
3.7 bellman's representation of the proving key
bellman::groth16::Parameters stores:
pub struct Parameters<E: Engine> {
pub vk: VerifyingKey<E>,
pub h: Arc<Vec<E::G1Affine>>,
pub l: Arc<Vec<E::G1Affine>>,
pub a: Arc<Vec<E::G1Affine>>,
pub b_g1: Arc<Vec<E::G1Affine>>,
pub b_g2: Arc<Vec<E::G2Affine>>,
}
The on-disk format is a serialised version of this structure.
zcash_proofs::load_parameters parses it after verifying the
SHA-512. The proving key is Arc'd because it is shared between
threads in multicore proving; it is read-only once loaded.
3.8 PreparedVerifyingKey
bellman::groth16::PreparedVerifyingKey precomputes the pairing
ingredients to make verification faster:
pub struct PreparedVerifyingKey<E: Engine> {
pub alpha_g1_beta_g2: E::Gt,
pub neg_gamma_g2: <E::G2Affine as PreparedCurveAffine>::Prepared,
pub neg_delta_g2: ...,
pub ic: Vec<E::G1Affine>,
}
The wallet calls prepare_verifying_key(&vk) once and caches the
result. Each verification is then a Miller-loop plus final
exponentiation plus a constant-size multi-scalar multiplication.
3.9 Halo 2's transparent setup
Halo 2 has no per-circuit setup. The SRS is the set of generators
derived deterministically from a hash function applied to a fixed personalisation string and a counter. Any verifier with the hash function definition can re-derive the generators independently.
No toxic waste; no MPC. The trade-off is larger prover/verifier
work. The generators come from
halo2_proofs::poly::commitment::Params::new(k). The Orchard
verifier constructs them on demand or caches them.
3.10 Soundness implications
For Groth16: as long as one MPC participant was honest, soundness holds. The Sapling parameters have participants; even if 89 are malicious, soundness is preserved.
For Halo 2 / IPA: soundness reduces to the discrete-log assumption on Pallas. No participant honesty is needed; the curve and the hash-to-curve are public. This is one of the main reasons Orchard chose Halo 2: it removes "what if the ceremony was rigged" from the trust model.
3.11 The download-params and bundled-prover flows
zcash_proofs::download_parameters (feature-gated behind
download-params) fetches parameters from a CDN, verifies the
SHA-512, and caches locally at ~/.zcash-params/. Production
wallets download once at install time.
The bundled-prover feature embeds parameters directly into the
binary, eliminating the runtime download at the cost of
MB of binary size. The bundled parameters still have their
SHA-512 verified at runtime against the hardcoded hashes;
bundling is an optimisation, not a trust short-cut.
3.12 Future directions
A rebuild today would likely use Halo 2 (no trusted setup). The migration cost is high (different proof system, new circuit, parameter compatibility break) and has not been deemed worth it given the existing setup's strong public-attestation record. For future shielded-asset proposals (chapter 21), the proof system choice is open: Halo 2 for transparency, or one of the newer trusted-setup-free SNARKs (HyperPlonk, Spartan, Nova-style folding, Plonky3). The codebase is set up so the proving system is modular per pool.
4. Failure modes
- Skipping
verify_hash. A substituted parameter file passes silently. The entire trusted-setup argument depends on this check; removing it is a critical vulnerability. The hash must be checked even when the file is bundled into the binary. - Hardcoding a wrong hash constant. A typo in
SAPLING_SPEND_HASHcauses every honest wallet to reject the ceremony output. The byte-length constants exist partly to catch this earlier. - Re-reading the parameter file per proof. The file is large
(Sprout is 725 MB). Re-reading wastes I/O and CPU; production
code loads once into an
Arcand reuses. A regression that re-loads will not break correctness but will make the wallet appear unresponsive. - Using
MockTxProveroutside#[cfg(test)]. The mock prover generates parameters locally with fresh toxic waste every time. This is unsound for shipping cryptocurrencies and must remain feature-gated to tests. - Generating parameters locally in production. Same as
above.
bellmansupports it but doing so per wallet defeats the ceremony entirely. - Disabling
bundled-proverSHA-512 verification under a benchmark flag. A common temptation when measuring startup cost; never ship with this disabled.
5. Spec pointers
- Groth, On the size of pairing-based non-interactive arguments (Eurocrypt 2016): the Groth16 paper defining the SRS structure and verifying equation cited in section 2.
- Bowe, Gabizon, Green, A multi-party protocol for constructing the public parameters of the Pinocchio zk-SNARK (ePrint 2017/602): the Phase 1 / Phase 2 MPC construction Zcash used.
- Powers of Tau ceremony attestations (Zcash Foundation): the public transcripts of the 2018 ceremony.
- Sapling MPC attestations: the Phase 2 ceremony transcripts producing the parameter files this chapter cites.
- ZIP 207 (Funding Streams) and ZIP 213 (Shielded coinbase): not directly about setup, but cited because they pin the network upgrades that activated the post-Sapling parameter set.
- Bowe, Grigg, Hopwood, Halo: Recursive Proof Composition without a Trusted Setup (ePrint 2019/1021): the transparent-setup argument behind Halo 2.
6. Exercises
- Inspect the hashes. Open
zcash_proofs/src/lib.rsand confirm thatSAPLING_SPEND_HASH,SAPLING_OUTPUT_HASH, andSPROUT_HASHmatch the published ceremony attestations. List which hash algorithm is used (hint: the constant is 128 hex chars). - Trace the load path. Starting from
load_parametersinzcash_proofs/src/lib.rs, follow the read path toverify_hash(lines 468 onward). Identify the exact line where a mismatch becomes anInvalidDataerror. What error would a wallet display if the file were truncated? - Add a negative test. In a checkout, write an integration
test that constructs a "parameter" file consisting of
SAPLING_SPEND_BYTESrandom bytes and asserts thatverify_hashrejects it. The test should pass; the assertion is that the returned error isio::ErrorKind::InvalidData.
Answers in the code
- Hardcoded hashes and byte counts:
zcash_proofs/src/lib.rs#L49-L57. verify_hashimplementation:zcash_proofs/src/lib.rs#L468-L509.bellman::groth16::ParametersandPreparedVerifyingKeylive in the externalbellmancrate.
7. Further reading
- Chapter 12: CVE-2019-7167, the reason the Sprout-Groth16 parameters had to be regenerated.
- Chapter 16: the Pedersen hash that dominates the Sapling Spend circuit's constraint count and thus the proving-key size.
- Chapter 17: the Halo 2 / IPA machinery that makes the transparent-setup alternative feasible.
- Ben-Sasson, Bentov, Horesh, Riabzev, Scalable, transparent, and post-quantum secure computational integrity (ePrint 2018/046): the STARK family that motivates several "no trusted setup" research directions.