skip to content
Skill Issue Dev | Dax the Dev
search

Halo2 in 2026: what changed since the Zcash era

Print view

Sections

When Zcash open-sourced Halo2 in 2020, it was a research artefact attached to a single deployment target — Zcash’s Orchard pool — and a single arithmetisation choice — IPA over the Pasta cycle of curves. Six years later it is a small ecosystem of forks, used by Scroll, Taiko, Axiom, and roughly half the EVM rollups under construction in 2026. The original repository has been in maintenance mode since 2024.

This post is the orientation I wish someone had handed me when I started auditing Halo2 circuits seriously. What stayed the same? The arithmetisation. The lookup argument. The mental model of chips inside regions inside columns. What evolved? The polynomial commitment scheme, the curve choices, the gadget library, and most of all the fork landscape. By the end you should have a defensible answer to “which Halo2 do you mean?” — which is the question every serious ZK conversation in 2026 reduces to within five minutes.

What stayed: the PLONKish arithmetisation

The shape of a Halo2 circuit hasn’t changed since 2020. You define columns — advice (witness), fixed (constants), and instance (public inputs) — and a rectangular grid of cells indexed by row and column. The prover assigns values to advice cells; the constraint system asserts polynomial relations on those values, evaluated at every row.

Three families of constraints make up a Halo2 circuit:

  1. Custom gates. A polynomial identity that must hold on every row, possibly gated by a selector column. q_mul · (a · b - c) = 0 is the canonical example: when q_mul = 1, the constraint forces a · b = c; when q_mul = 0, the constraint vanishes.
  2. Permutation arguments. Cells that should be equal across rows or columns are wired into a permutation. This is what gives you “this output of gate A is the input to gate B” without paying the cost of an extra constraint per copy.
  3. Lookup arguments. A cell must be in some pre-declared table. This is what makes range checks (x<216x < 2^{16}) cost ~1 row per check instead of 16, and what makes XOR / S-box / SHA tables tractable inside a SNARK.

The novelty in 2020 wasn’t any single one of those — PLONK had given us custom gates and permutations, plookup had given us lookups — but the combination, the user-facing API (chips, regions, layouters), and the recursion-friendly proof system underneath it.

The arithmetisation is so durable that every Halo2 fork in 2026 still uses the same Circuit trait, the same Layouter, the same Region, the same Selector. If you wrote a Halo2 chip in 2021, it compiles in 2026 against PSE-Halo2 with one or two trait-bound tweaks. That’s an extraordinary track record for a 6-year-old framework.

What evolved: from IPA to KZG

The original Zcash Halo2 used IPA (inner-product argument) over the Pasta cycle of curves (Pallas + Vesta). That choice was deliberate: IPA needs no trusted setup, and the Pasta cycle let Zcash do recursion without pairings. Beautiful in theory; expensive in practice. IPA proofs are kilobytes; verification is logarithmic in circuit size and dominated by group operations.

The dominant 2026 fork — Privacy Scaling Explorations’ privacy-scaling-explorations/halo2 — replaced IPA with KZG over BN254. The trade-off:

  • You give up: trustless setup. KZG needs a Powers-of-Tau ceremony.
  • You get: constant-size proofs (~600 bytes), pairing-based verification that’s an order of magnitude cheaper, and Solidity verifier compatibility — which is the single feature that turned Halo2 from “Zcash internal tool” into “the EVM rollup substrate”.

This is the trade-off every serious ZK design makes once. (The same trade-off shows up in Plonky3, the small-fast-cheap revolution on a different axis.) Trusted setup is back on the table in 2026 because the Ethereum KZG ceremony — 140,000+ participants — is good enough for the threat model most rollups operate under. See On the death of the trusted setup for the argument.

The fork landscape in 2026

ForkBackendStatusWhat it’s for
zcash/halo2IPA, PastaMaintenance / archivalThe reference, where the model originated
privacy-scaling-explorations/halo2KZG, BN254Maintenance since Jan 2025The EVM-compatible workhorse
axiom-crypto/halo2-axiomKZG, BN254ActiveThe PSE successor for new features
Scroll’s halo2KZG, BN254Active inside ScrollzkEVM-tuned, custom gates for EVM ops
appliedzkp/halo2-baseKZG, BN254ActiveHigher-level chip-authoring API on top of PSE / Axiom

The headline event of 2025 was that PSE-Halo2 went into maintenance and the community migrated to Axiom’s fork as the upstream for new feature work. Existing deployments did not move — the API surface is identical and PSE-Halo2 still receives security backports — but the energy is on axiom-crypto/halo2-axiom and on halo2-base for ergonomic chip authoring.

What evolved: gadgets, lookups, and the Lagrange-form witness

Three quieter shifts since 2022 actually changed how circuits are written:

Gadget libraries got serious. The original Halo2 shipped with halo2_gadgets::poseidon and not much else. By 2026 the halo2-base and halo2-axiom crates ship range checks, ECC, Poseidon, Keccak, RSA, ECDSA, BN254 pairing, and a battery of lookup tables shared across circuits. The “I have to hand-roll a SHA chip” era is over for 90% of use cases.

Lookups became table-shareable. Halo2’s original lookup design assumed each circuit declared its own tables. With circuits hitting 10 million rows, table reuse across sub-circuits became necessary. Both Axiom and PSE landed APIs for declaring a lookup table once and binding it across regions. The constraint-count savings on big circuits are 30–50%.

Lagrange-form witness committed. The witness used to be committed in coefficient form, requiring an NTT before commitment. Modern forks commit in Lagrange form (point-value), saving an NTT per commitment. On large circuits this is a 15–20% prover-time win — the kind of thing that doesn’t show up in marketing copy and matters enormously when you’re proving a million constraints.

A skeleton chip you can read in 30 seconds

Halo2 chips look intimidating. They are not. The shape is: declare the columns you need, declare the constraints in configure, and use them in synthesize. Below is a contrived multiplier chip — the smallest Halo2 chip that does anything — written against the kind of trait surface every fork shares.

halo2 multiplier chip — sketch [ rust ]
open

The proving-time tradeoff in 2026

Four PLONKish-family proof systems in 2026. Halo2's two forks dominate EVM use; arkworks is where research lives; Plonky3 is where new performance wins are coming from.
OptionCostLatencyBlast radiusNotes
Halo2 (PSE, KZG/BN254) Powers-of-Tau ceremony required (Ethereum KZG works); ~MB-scale srs Slower per-shot than Groth16; lookups make constraint-heavy circuits cheap Maintenance since Jan 2025; security backports only Default for EVM rollup verifiers; Solidity verifier ships
Halo2 (Axiom fork) Same SRS as PSE; new features land here Same baseline as PSE; gadget library more complete Active 2026; the upstream for new circuits What I'd pick for a greenfield Halo2 deployment in 2026
arkworks PLONK Library, not a DSL; circuits are Rust types Comparable to Halo2; less optimised gadget library Research-grade; smaller ecosystem Where novel proof systems get prototyped
Plonky3 STARK/PLONK hybrid; small-field; FRI-based Fast on consumer hardware due to Mersenne31 / BabyBear Production at Polygon; growing ecosystem Pick this when you don't need EVM verification

When to actually pick Halo2 in 2026

The honest 2026 answer:

  • Pick Halo2 (Axiom fork) when your target is the EVM, your circuit is dominated by lookups (range checks, table-driven hash functions, RLC-heavy state-transition circuits), and you want a battle-tested gadget library.
  • Don’t pick Halo2 when your target is a non-EVM L1 (Solana, Aptos) where Solidity verifiers don’t help, when your circuit is small (under ~5,000 constraints — Groth16 is faster per shot), or when you need transparent setup (use Plonky3 / RISC0).

What I’d build differently if I were Halo2 in 2027

Three things, in order of how much I’d actually use them:

  1. Native folding integration. Halo2’s original recursion path (IPA + Pasta cycle) was elegant but slow. A folding scheme — Nova, ProtoStar, HyperNova — bolted onto KZG-Halo2 would unlock zkVMs and batch proving without a rewrite. Several teams are working on this; nothing is in main yet.
  2. A real type system for chips. Cell<F> is structurally typed by row/column position. There’s no compile-time guarantee that “this cell holds a u8” or “this cell holds a Boolean” without re-asserting it inside every chip. A phantom-type-driven cell typing would catch a class of audit findings before the auditor ever opens the file.
  3. A standardised lookup-table registry. Range checks, byte tables, S-box tables — every fork ships its own. A shared halo2-tables crate, content-addressed and reusable, would prevent the “every circuit re-declares the same range-16 table” anti-pattern.

I expect (1) within a year and (2)/(3) never. Halo2 is in the durable phase of its life — the kind of framework you build on, not into.

Further reading

Hire me — book a 30-min call $ book →