Skip to content

Design digest

The load-bearing decisions, compressed. Each row links the full rationale on GitHub — read those when you need the argument, not just the rule.

The two non-negotiables

  1. Scheme- and implementation-agnostic. No block assumes a proving scheme or any one downstream prover (a zkVM, zkML, zkTLS). Anything scheme-specific lives in the consumer; the test for "belongs in zorch" is would a second, unrelated prover reuse it unchanged?
  2. Fusion is a correctness-of-design property. A round, an absorb/squeeze, a commit/open, a fold step, and a hash permutation must each lower to one replayable device unit by construction — never by hoping a compiler pattern-match recovers it.

Fusion north star, compressed

The unit is a captured device graph replay, not necessarily one kernel: measured today, a sumcheck round lowers to two kernels (round poly = one reduction kernel, fold = one element-wise kernel) and that is fine — what breaks the contract is a host round-trip mid-round. Two enablers keep a round capturable: the whole body in one traced region, and a device-side transcript (DuplexTranscript) so observe/sample are device ops. Bodies are written fusion-ready — element-wise field ops plus the one inherent Σ. Full statement

One decision per block

Block The decision that shapes it Full WHY
Rounds & stages Only the message crosses roles; challenges both sides derive ride the carry. A stage's malformed-shape input raises ValueError; an algebraic failure returns ok=False. stage-composition
Transcript Two flavours, on purpose: device-algebraic (DuplexTranscript, keeps rounds capturable) vs host-byte (SHA-256, for byte-matching references). transcript
Polynomials eq ships two forms (prover's 2ⁿ expansion, verifier's O(n) closed form); the additive Basefold fold and the multilinear bind are separate functions because conflating them is a silent bug. poly
Hashing One Permutation seam; a consumer ships only a params object (width, field, constants) — sponge and compression code never fork. Lives in hash-frx, below zorch, so a signature scheme can take it without a proving-block dependency. hash-frx
Merkle A binary tree over Sponge (leaves) + Compression (nodes) — commitment reuses the hash seams instead of owning hashing. commit
Codes LinearCode is a seam; the FRI fold lives with the code (it is a codeword-domain operation), not inside any PCS. coding
PCS A PCS is a committer plus an opening stage; FRI/BaseFold/WHIR/… are instances sharing the fold machinery, so a consumer swaps schemes without new plumbing. pcs
Sumcheck The smallest complete stage; zerocheck, lincheck and LogUp-GKR configure it (a summand + round wiring) rather than reimplement it. sumcheck
LogUp-GKR A fractional-sum circuit reducing a public output claim layer by layer to an input claim a PCS opening discharges. logup-gkr
Spartan The worked composite, shipped as importable code — proof that the blocks assemble into a full SNARK without private plumbing. spartan

If you remember three things

  • Inject parameters through seams; never fork a block.
  • The transcript is explicit everywhere; challenges are carry, not message.
  • Keep round bodies element-wise + one Σ; no host round-trips mid-round.