Halo 2 Primer
1. Why This Chapter Exists
The Orchard Action circuit is a Halo 2 circuit. A reader who has
only seen R1CS-style systems will not be able to navigate
src/circuit.rs
without first learning what advice columns, selectors, custom
gates, and lookups are. By the end the reader can read a Halo 2
Config struct and predict the column layout it will produce.
2. Definitions
Definition 2.1 (PLONKish Table)
A Halo 2 circuit is a rectangular table with rows and a fixed number of columns of four kinds:
- advice columns , populated by the prover;
- fixed columns , populated by the verifier during trusted preprocessing;
- instance columns , the public inputs;
- selector columns , fixed columns that toggle constraints on or off per row.
Definition 2.2 (Custom Gate)
A custom gate is a multivariate polynomial together with a selector . For every row ,
where each is some column at some row . The offsets are rotations and let gates couple adjacent rows.
Definition 2.3 (Lookup)
A lookup argument requires that for every row , the tuple appears as a row of a fixed table . Lookups encode range checks () and the Sinsemilla windowed multiplication table.
Definition 2.4 (Inner-Product Argument Commitment)
A column of length is committed as for a fixed basis . The IPA protocol opens at a point in rounds with no trusted setup. In Orchard, is the Vesta curve.
Definition 2.5 (Transcript)
The Fiat-Shamir transcript is a Blake2b instance personalised with
"Halo2-Transcript". Every commitment and challenge is absorbed
in protocol order. The outer transcript is not recursive in
Orchard. The personalisation is set in the Blake2bRead::init
and Blake2bWrite::init constructors of halo2_proofs, both
pinned to the halo2_proofs-0.3.0 tag that Orchard 0.13.1
depends on:
loading...
loading...
3. The Code
3.1 The Halo 2 Imports
loading...
The plonk re-exports name the column kinds, the Constraints
builder, the Expression type used in gates, and the verifier
choices (SingleVerifier, BatchVerifier). The transcript
re-exports give Blake2b read/write halves.
3.2 The Chip / Gadget Pattern
A chip is a Config (column layout, gate definitions) plus the
synthesis code that populates a region of the table. A gadget is
a higher-level construction composed of one or more chips. Orchard
pulls the ECC and Sinsemilla chips from
halo2_gadgets
and adds its own Orchard-specific chips:
CommitIvkChip
and
NoteCommitChip.
Example. Inside the Action circuit's Circuit::configure,
each chip is constructed by calling its associated configure
function with the columns and helpers it needs. The ECC chip is
representative:
loading...
The call returns a typed EccConfig that records which advice,
fixed, and lookup columns the chip owns. That EccConfig is
stored inside the Action circuit's Config struct and later
handed to EccChip::construct(config) during synthesis, so
every region that uses curve arithmetic shares the same column
layout. The Sinsemilla, Poseidon, and Merkle chips just below
the ECC call in the same function follow exactly the same
pattern.
3.3 The K Constant
The Action circuit uses , giving rows in the
PLONKish table. The constant lives at the top of src/circuit.rs:
loading...
is the row count of the table; larger admits more
constraints but doubles the prover time per increment. The same
value appears at the top of the pinned circuit description, which
serialises the verifier key produced from this K:
loading...
3.4 The Lookup Table
The Sinsemilla windowed multiplication uses a fixed lookup table
populated from
src/constants/sinsemilla.rs.
The table has rows, one per ten-bit window value, and
maps the window to the precomputed generator multiple.
4. Failure Modes
- Region overlap. Chips synthesise into regions. Two chips with overlapping selectors silently corrupt each other; the reviewer must trace the region offsets.
- Constraint not gated. A custom gate that lacks a selector multiplier applies to every row, including padding rows whose advice columns are zero. The Halo 2 dev-mode prover catches this; production proving silently produces a wrong proof.
- Wrong
K. SettingKtoo small causesError::NotEnoughRows; too large is silent and wastes prover time. Thecircuit_descriptionsnapshot pins the chosenK. - Transcript divergence between prover and verifier. If a field element is absorbed in a different order or under a different personalisation string, verification fails. This is the most common cause of a "passes locally, fails in CI" report after a Halo 2 dependency bump.
5. Spec Pointers
- PLONK paper: the underlying argument.
- Halo paper: the IPA-based recursion that motivated Halo 2.
- Halo 2 Book: the canonical reference for the column model, gates, and lookups.
zcash/halo2: the source ofhalo2_proofsandhalo2_gadgets.
6. Exercises
- Open
src/circuit.rsand find theKconstant. State its value and explain how2^Krelates to the constraint count. - List every
meta.advice_column()andmeta.fixed_column()call insrc/circuit.rs. Group them by the chip that consumes them. - Code task. Add a new advice column to the Action circuit
without consuming it (a dead column). Run
cargo test --lib circuit::tests. Confirm the dev-mode prover rejects the change with an "unused column" lint, then revert.
7. Further Reading
- Halo 2 Book, Concepts: Plonkish arithmetisation:
the formal model used by
halo2_proofs. halo2_gadgetssource: the chip library most ofsrc/circuit.rsbuilds on.