Recursive proof composition without the abyss: Halo to Nova
The path from Halo's accumulation scheme to Nova's folding scheme, derived from the recurrence relation. Where Halo2, Nova, SuperNova, and HyperNova actually differ, and which one to reach for in 2026.
- FROM
- Dax the Dev <[email protected]>
- SOURCE
- https://blog.skill-issue.dev/blog/recursive_proofs_halo_to_nova/
- FILED
- 2026-05-02 16:00 UTC
- REVISED
- 2026-05-02 16:00 UTC
- TIME
- 14 min read
- SERIES
- ZK SNARKs in production
- TAGS
A recursive SNARK is a proof that proves another proof was checked correctly. A program that runs for steps and produces a proof of correct execution at each step can — recursively — collapse all proofs into one. The verifier work goes from to . This is the structural reason ZK rollups exist. It is also the reason “incrementally verifiable computation” stopped being a research curiosity in 2020 and became a deployment target.
The two papers that sit underneath every recursive SNARK shipped today are Halo (Bowe, Grigg, Hopwood 2019) and Nova (Kothapalli, Setty, Tzialla 2022). They take very different routes to the same destination. This post is the math of both, the trade-off table for picking one in 2026, and a Rust skeleton for the Nova folding step.
The problem recursive SNARKs are solving
You have a program that runs for steps. At each step you produce a proof that the step was executed correctly. Naively, the verifier checks all proofs — verifier cost , no better than re-running the program. Useless.
The recursive trick: at step , instead of producing a fresh proof, you produce a proof that says “step was executed correctly, and the proof from step verifies.” The proof for step recursively absorbs the proof for step . After steps you have one proof; the verifier checks one proof; the cost is in the program length.
The hardest part is making the inner verification cheap. If the verifier work for one proof is and you embed that work in the circuit for the next proof, you’ve blown up the prover cost by . Recursion is only useful if is constant or near-constant in the original circuit size — which is exactly what Groth16, Halo, and Nova all aim for in different ways.
flowchart LR subgraph S0[Step 0] P0[execute step 0] P0 --> Pr0[proof pi_0] end subgraph S1[Step 1] P1[execute step 1] --> V1[verify pi_0] V1 --> Pr1[proof pi_1: 'step 1 ran AND pi_0 verified'] end subgraph S2[Step 2] P2[execute step 2] --> V2[verify pi_1] V2 --> Pr2[proof pi_2: 'step 2 ran AND pi_1 verified'] end Pr0 --> V1 Pr1 --> V2 Pr2 --> Final[final verifier checks ONE proof] classDef step fill:#0a0a0a,stroke:#4ade80,color:#4ade80 class S0,S1,S2 step
The math problem reduces to one question: how cheaply can you verify a SNARK inside a SNARK?
The Halo trick: accumulation without recursion-in-circuit
Pre-Halo recursion required a cycle of pairing-friendly elliptic curves. Two curves with the property that the scalar field of is the base field of and vice versa, so that arithmetic over one curve can be expressed natively in the other curve’s circuit. Pasta (Pallas / Vesta) and MNT4/6 are the canonical cycles. The reason this matters: if you want to verify a Groth16 proof inside a Groth16 circuit, you need pairing-friendly arithmetic inside the circuit, which means the circuit field has to support the pairing curve. A cycle gives you two curves where each can verify proofs over the other.
The cycle constraint is annoying. Pasta’s curves don’t have efficient pairings (they’re cycle-friendly, not pairing-friendly), so they trade pairing efficiency for cycle availability. MNT cycles have very large fields and slow arithmetic. There’s no free lunch.
Halo (Bowe, Grigg, Hopwood 2019) was the first practical example of recursive proof composition that broke this constraint. The insight: instead of verifying the inner proof inside the circuit, you accumulate the most expensive part of the verification (the multiscalar multiplication, MSM) into a running sum, and defer the actual MSM check to the end of the recursion.
Formally: the verifier of an inner-product-argument-based proof has to check an equation of the form
for some derived scalars and group elements . This is the bottleneck — it’s a multiscalar multiplication of size linear in the circuit. The accumulation-scheme trick is: at step , instead of checking this equation, you produce a fresh “accumulator” that combines the current step’s MSM with the previous accumulator. After steps you have one accumulator and one MSM check. Verifier cost: for the recursion plus one final MSM.
The Halo paper formalises this as a polynomial commitment with deferred opening. It works because the recursive composition can defer expensive arithmetic, not because it embeds full verification in-circuit. From the abstract:
We present Halo, the first practical example of recursive proof composition without a trusted setup, using only the discrete logarithm assumption over normal cycles of elliptic curves. Recursion is achieved by amortizing away the expensive verification procedures from within the proof verification cycle, deferring them until the end of the recursion.
Halo2, the Zcash production deployment, uses the same construction over Pasta and ships it in Orchard (Zcash’s NU5 upgrade in 2022). Halo2 is also the basis of Aztec Connect, the Scroll zkEVM, and the Filecoin Snark-pack.
The Nova trick: folding instead of accumulating
Two years after Halo, Nova (Kothapalli, Setty, Tzialla 2022) reframed the problem entirely. Instead of accumulating an MSM, Nova introduces a folding scheme: a primitive that takes two instances of a relation and folds them into a single instance, with prover cost for some step circuit and no SNARK at all in the recursion.
The Nova relation is a relaxed R1CS instance:
where are the constraint matrices, is the witness extended with public inputs, is a slack scalar (1 in the standard R1CS case), and is an error vector (zero in the standard case). The “relaxed” part is that and are allowed to be nonzero — that’s what makes folding possible.
Given two relaxed R1CS instances and , the folding scheme produces a single instance via a random challenge :
with a “cross-term” the prover sends to the verifier. The folded instance is satisfying iff both originals were (with overwhelming probability). Crucially, folding does not require the verifier to do any expensive cryptographic work: is a vector commitment, is a Fiat-Shamir challenge, and the new is a linear combination. No pairings. No SNARK.
The Nova incrementally verifiable computation (IVC) recurrence is then:
where the second instance is a fresh R1CS encoding of “step of the program executed correctly.” After steps, you have one relaxed R1CS instance, and you produce a single SNARK that proves it’s satisfying. The SNARK runs once, at the end. Every step in between is folding.
The cost asymmetry is the entire pitch. Halo’s per-step cost is for the step plus for the recursion. Nova’s per-step cost is just — no recursion overhead. For long computations () Nova is significantly cheaper. The trade-off: Nova gives you one final SNARK to verify, while Halo gives you a SNARK at every step.
flowchart LR subgraph N0[Nova step 0] F0[execute F at step 0] --> R0[R1CS instance z_0] end subgraph N1[Nova step 1] F1[execute F at step 1] --> R1[fresh R1CS z_1] Acc0[accumulator U_0] --> Fold1[fold] R1 --> Fold1 Fold1 --> Acc1[accumulator U_1] end subgraph N2[Nova step 2] F2[execute F at step 2] --> R2[fresh R1CS z_2] Acc1 --> Fold2[fold] R2 --> Fold2 Fold2 --> Acc2[accumulator U_2] end R0 --> Acc0 Acc2 --> SNARK[final SNARK proves U_T satisfying] classDef step fill:#0a0a0a,stroke:#4ade80,color:#4ade80 class N0,N1,N2 step
The folding scheme is the entire idea. Everything else in Nova is bookkeeping around it.
Halo2, Nova, SuperNova, HyperNova — what’s the difference
Four production-grade recursive systems, four design points.
| Option | Cost | Latency | Blast radius | Notes |
|---|---|---|---|---|
| Halo2 (Zcash, Pasta curves) | Per-step prover ~constant in T; verifier O(log T) MSM | Step proof ~5-15s for non-trivial circuits | Production since 2022 (Zcash NU5); audited | Best for protocols that already use the IPA / Pasta stack. Wide deployment. |
| Nova (Pallas/Vesta cycle) | Per-step prover O(|F|) with NO SNARK; one final SNARK | Per-step ~100ms-1s; final SNARK ~5-15s | Production via microsoft/Nova, Lurk; younger than Halo2 | Best when T is very large and you can defer the SNARK. The right choice for a zkVM step circuit. |
| SuperNova | Per-step proportional to the SIZE of the invoked instruction circuit | Per-step ~50ms-300ms (varies by instruction) | Newer; production zkVMs (RISC0, Jolt-shape) are exploring it | Right answer for instruction-set machines (EVM, RISC-V) where steps don't all use the same circuit. |
| HyperNova (CCS) | Folds CCS instead of R1CS; supports Plonkish/AIR/R1CS uniformly | Comparable to Nova with a richer constraint system | Newest of the four; CRYPTO 2024 | The unification target. Drop-in upgrade for protocols that want CCS flexibility without rewriting. |
| Plain Groth16 + cycle | Per-step verifier embedding ~10k constraints | Per-step ~10s+ | What everyone did before Halo and Nova | Mostly historical now. Don't reach for this in 2026. |
The two questions that decide which one to reach for in 2026:
- Is your computation a uniform step that repeats, or a heterogeneous instruction set? Uniform: Nova. Heterogeneous: SuperNova. (HyperNova handles both via CCS.)
- Do you need a SNARK at every step, or can you defer to one final SNARK? Every step: Halo2. Defer: Nova / SuperNova / HyperNova.
For a privacy-pool transfer, neither of these is the right shape — you want a single SNARK per spend, no recursion. For zera-sdk we ship Groth16 and don’t recurse. For a rollup settling many transfers in a batch, Nova-flavoured folding is the right structural answer because the per-step cost is dominated by the transfer logic and the final SNARK only runs once per epoch.
A Nova folding step, in Rust
The cleanest way to see what’s actually happening in a folding step is to write one out. The skeleton below is a Nova-shaped folding step over a toy R1CS — no pairings, no real curve, no soundness, but the linear-combination structure is the real thing.
The shape is the thing. The fold is just three linear combinations: , , . The cross-term is what the prover sends; the challenge is Fiat-Shamir over the transcript. In real Nova the witness is replaced by a Pedersen commitment to it (so the verifier never sees the witness), and the error vector is replaced by a commitment as well. The linear structure of the fold is preserved by the additive-homomorphic property of the Pedersen commitment, which is the entire reason Pedersen is the right primitive here.
Where this lands for ZERA
The honest answer about recursion in zera-sdk v1: we don’t use it. A privacy transfer is one Groth16 proof per spend, and there’s nothing to recurse over. The advantage of recursion shows up when:
- You’re settling many transfers in a batch (rollup shape) and want to compress them into one proof.
- You’re running a zkVM (Lurk, Jolt, RISC0) where the program has many uniform steps.
- You’re building a light client that has to verify a long chain of proofs cheaply.
For ZERA’s transfer flow, none of these apply. For the eventual settlement layer that sits underneath a chain of ZERA transfers (think: a state-root proof every epoch), Nova-style folding is the right shape, and the design seam is in crates/zera-sdk-core/src/recursion.rs. Empty file today. We’ve left the door open.
The reason I wrote this post anyway is that recursion is the part of the ZK stack that’s most actively moving in 2026. HyperNova landed at CRYPTO 2024 with a CCS-based unification of R1CS / AIR / Plonkish that was supposed to take five more years. The next two years are going to compress IVC primitives down to “one folding scheme, three commitment choices, pick your poison.” Anyone deploying a ZK system today should know what shape that compressed primitive will be, because the migration cost will be the difference between a clean refactor and a rewrite.
Further reading
- Halo: Recursive Proof Composition without a Trusted Setup — Bowe, Grigg, Hopwood (2019) — the accumulation-scheme paper.
- Nova: Recursive Zero-Knowledge Arguments from Folding Schemes — Kothapalli, Setty, Tzialla (CRYPTO 2022) — the folding-scheme paper.
- SuperNova: Proving universal machine executions without universal circuits — Kothapalli, Setty (2022) — the per-instruction folding extension.
- HyperNova: Recursive Arguments for Customizable Constraint Systems — Kothapalli, Setty (CRYPTO 2024) — CCS-based unification.
- microsoft/Nova — the canonical Rust implementation.
- Halo2 book — the production deployment behind Zcash NU5.
- Poseidon, by hand and by code — the hash function inside the recursion circuit.
- Why BN254, and when to switch off it — the curve choice underneath the SNARK that closes the recursion.