Skip to main content

BlindFold Zero-Knowledge Protocol

BlindFold is Jolt’s zero-knowledge protocol that makes all sumcheck proofs zero-knowledge without requiring SNARK composition. Instead of revealing sumcheck round polynomial coefficients in the clear, BlindFold commits to them and proves correctness through a compact verifier R1CS.

Overview

Traditional zkSNARKs for virtual machines either:
  1. Reveal partial information through sumcheck round polynomials (not fully zero-knowledge)
  2. Use recursive SNARK composition to hide round polynomials (expensive and complex)
BlindFold provides a third approach: encode the sumcheck verifier computation as a small R1CS constraint system, and prove its satisfaction using Nova folding and Spartan.

How BlindFold Works

High-Level Protocol

  1. Committed sumchecks (Stages 1-7): During Jolt’s seven sumcheck stages, the prover commits to each round polynomial’s coefficients using Pedersen commitments instead of revealing them
  2. R1CS construction (Stage 8): Both prover and verifier build the same VerifierR1CS that encodes all sumcheck verification checks
  3. Nova folding: The real R1CS instance is folded with a random satisfying instance to hide the witness
  4. Spartan proof: A Spartan outer sumcheck proves the folded relaxed R1CS is satisfied
  5. Hyrax opening: Final polynomial openings verify the witness commitment

Key Innovation

Rather than proving “the sumcheck verifier accepts” using a full SNARK recursion (which would require proving Jolt inside another SNARK), BlindFold exploits the fact that the sumcheck verifier is already arithmetic and can be encoded directly as R1CS constraints.

Architecture

BlindFold is implemented in jolt-core/subprotocols/blindfold/ with the following modules:

Core Modules

  • mod.rs: R1CS primitives (Variable, LinearCombination, Constraint), stage configuration, and public inputs
  • protocol.rs: BlindFoldProver, BlindFoldVerifier, BlindFoldProof - main protocol implementation
  • r1cs.rs: VerifierR1CS, VerifierR1CSBuilder - sparse R1CS encoding of sumcheck verification
  • witness.rs: BlindFoldWitness - witness assignment from sumcheck stage data
  • folding.rs: Nova folding - cross-term computation and random instance sampling
  • spartan.rs: Spartan outer/inner sumcheck over folded R1CS
  • relaxed_r1cs.rs: Relaxed R1CS instance/witness with Hyrax grid layout
  • output_constraint.rs: Constraint types for claim binding (InputClaimConstraint, OutputClaimConstraint)
  • layout.rs: Witness grid layout computation for Hyrax commitment structure

Integration with Jolt

Feature Flag: zk

BlindFold is activated via the zk Cargo feature flag. The Jolt prover operates in two modes:
AspectStandard (--features host)ZK (--features host,zk)
Sumcheck provingprove() - cleartext round polynomialsprove_zk() - Pedersen-committed
Univariate skipprove_uniskip_round()prove_uniskip_round_zk()
Proof structureContains Claims<F> (opening claims)Contains BlindFoldProof
Input claimsAppended to Fiat-Shamir transcriptSkipped; used in R1CS
Opening proofRaw evaluation bindingCommitted evaluation binding

Prover Pipeline

In zero-knowledge mode (feature zk enabled), the Jolt prover executes:
  1. Trace execution: Same as standard mode
  2. Witness generation: Same polynomial structure
  3. Streaming commitment: Same Dory commitments
  4. Spartan stage: Standard R1CS proof
  5. Sumcheck stages 1-7: Use prove_zk variants that commit round polynomials via Pedersen
  6. Opening proofs: Use bind_opening_inputs_zk for committed evaluations
  7. BlindFold stage 8: Generate BlindFoldProof proving all sumcheck verifications are correct

Supporting Components

BlindFold required several additions to Jolt’s cryptographic toolkit:
  • Pedersen commitments (poly/commitment/pedersen.rs): Commit to small vectors (round polynomials)
  • Curve abstractions (curve.rs): JoltCurve and JoltGroupElement traits for elliptic curve operations
  • ZK Dory openings (poly/commitment/dory/commitment_scheme.rs): Committed evaluation proofs (y_com)
  • ZK sumcheck variants (sumcheck.rs, univariate_skip.rs): prove_zk and verify_zk methods

Critical Invariant: Claim/Constraint Synchronization

The most important correctness requirement for BlindFold is that every sumcheck’s claim computation must exactly match its R1CS constraint. Every sumcheck instance implements SumcheckInstanceParams with paired methods:
// Compute claim value from polynomial openings
fn input_claim(&self, accumulator: &mut Accumulator) -> F;

// Describe the same computation as R1CS constraints
fn input_claim_constraint(&self) -> InputClaimConstraint;

// Provide challenge values used in the constraint
fn input_constraint_challenge_values(&self, accumulator: &Accumulator) -> Vec<F>;
Any change to input_claim() must have a matching update to input_claim_constraint(). If these become desynchronized:
  • The R1CS becomes unsatisfiable
  • BlindFold proof generation fails
  • The muldiv end-to-end test catches this error
The same synchronization requirement applies to output claims via output_claim_constraint().

Concrete Implementations

Claim/constraint pairs are implemented in:
  • spartan/outer.rs: OuterRemainingSumcheckParams
  • ram/read_write_checking.rs: RamReadWriteCheckingParams
  • instruction_lookups/ra_virtual.rs: InstructionRaSumcheckParams
  • claim_reductions/*.rs: All claim reduction parameter types

Verification

The BlindFold verifier:
  1. Detects ZK mode from the proof structure: proof.stage1_sumcheck_proof.is_zk()
  2. Builds the same VerifierR1CS from staged configurations and public inputs
  3. Verifies the Nova folding was performed correctly
  4. Verifies the Spartan proof of the folded R1CS
  5. Verifies the Hyrax opening proofs for witness commitments

Verifier Mode Consistency

The verifier must support both standard and ZK modes from the same binary. This creates a subtle requirement:
  • In ZK mode, input_claim() is never called (claims are verified inside BlindFold R1CS)
  • In standard mode, input_claim() is called (claims must match prover exactly)
When witness values are decomposed for BlindFold constraints (e.g., splitting into public and advice components), the verifier’s new_from_verifier must reconstruct the full value for standard mode using helpers like ram::reconstruct_full_eval().

Performance Characteristics

BlindFold’s overhead compared to non-ZK mode:
  • Prover time: Additional Pedersen commitments per sumcheck round (~5-10% overhead)
  • Proof size: Adds BlindFoldProof structure (Nova + Spartan + Hyrax openings)
  • Verifier time: Additional R1CS verification (~minimal overhead)

Memory Efficiency

BlindFold uses Hyrax-style grid layout for witness commitments to balance:
  • Row commitment cost (fewer rows = fewer commitments)
  • Opening proof size (fewer columns = smaller proofs per opening)
Layout optimization is handled in layout.rs via compute_witness_layout().

Configuration

Stage Configuration

Each sumcheck stage provides a StageConfig describing:
  • Number of instances in the stage
  • Number of rounds per instance
  • Degree of round polynomials
  • Claim constraints (input and output)

Baked Public Inputs

Fiat-Shamir challenges and other public values are “baked” directly into the R1CS matrix coefficients, avoiding the need for public input wires. This is implemented via BakedPublicInputs.

Hyrax Parameters

HyraxParams controls the witness grid dimensions, balancing commitment cost and opening proof size.

Testing

BlindFold correctness is verified through:
  • muldiv e2e test: Run in both modes (--features host and --features host,zk)
  • Advice tests: Exercise non-ZK mode with advice polynomials to catch verifier reconstruction bugs
  • Unit tests: Individual sumcheck constraint satisfaction tests

Academic Context

BlindFold draws on several lines of research: The specific application to making sumcheck protocols zero-knowledge is novel to Jolt.

Future Directions

Potential improvements to BlindFold:
  • Optimized folding schemes (e.g., SuperNova for non-uniform computation)
  • Alternative commitment schemes for round polynomials
  • Further R1CS optimization via constraint sharing across stages

Build docs developers (and LLMs) love