trace to proof
the concrete journey from a nox execution to a zheng proof. there are two paths: one statement is compiled into one relation; a run of any length is a trace of the nox machine. both end in sumchecks and one Reed–Solomon opening per committed object; neither uses a quotient polynomial or FRI.
1. one statement: the compiled relation (profiles 0–3)
the relation compiler turns the nox program and the shape of its subject into one CCS: every operand, intermediate value and output is a wire; field operations, conditionals, word operations and hemera rounds are rows, of degree 1 to 7. the verifier compiles the same CCS from the same program and places z[0] = 1, the inputs, the outputs and the cost itself, so a proof can only fill the free witness positions.
nox program + statement (io, cycles)
→ relation compiler → CCS (verifier and prover alike)
→ prover fills the witness w
→ public profile (0, 3): disclose w; the verifier checks every row exactly
→ succinct profile (1): commit w̃ (Reed–Solomon + hemera Merkle root)
→ Spartan over Fp3 (outer + inner sumcheck) → point r
→ one WHIR opening of w̃(r)
→ zk profile "veil" (2): masked sumchecks + one hiding RS tensor opening
one hemera hash of a digest costs about 2,700 constrained wires, because nox hashes nouns structurally (every atom decomposed into 64 bits); one relation is capped at 2^20 rows. hash.tri gives a 6,463 B public certificate and a 16,756 B succinct proof (audit/succinct-profile-2026-10.md; soft3 audit/proof-latency-2026-10.md).
2. a run of any length: the machine trace (profiles 4–6)
nox::reduce on any program becomes a trace of one fixed row relation (machine): 64 phase-1 columns, 15 phase-2 columns, 2 challenges, degree 8, 604 constraints, the same for every program and input — so the verifier's key does not depend on the program.
[0, P) INIT one init entry per row: the program and subject DAG
[P, P + M) machine one row per continuation-machine step, the last one TERM
[P + M, start) PAD
[start, N) PERM 32-row blocks: one hemera permutation each
- memory is write-once: atoms, pairs, continuation frames, digests and state reads are tuples checked by a logUp argument over Fp3, so every read equals a written value.
- each evaluation row carries one of sixteen opcode flags and adds nox's cost for that opcode, so the statement's cycle count is enforced row by row.
- the statement enters through public columns the verifier evaluates itself: the init region, the phases of the permutation blocks, hemera's round constants, the output digest and
cycles. - the PERM blocks are hemera 0.3.1's permutation (4 + 4 full rounds, 16 partial rounds), the version the crate pins; the frozen hemera 0.4 re-cuts the block in the draft sweep zheng#69/#73.
the trace is cut into segments of 2^14 rows. each segment is committed as Reed–Solomon codewords under hemera Merkle trees and proved by a sumcheck zerocheck over its rows plus a successor (shift) argument linking consecutive rows; what is left are evaluation claims on the committed words. those claims are accumulated (profile 4), checked inside the next step (IVC, profile 5), and wrapped to at most 64,213 B (profile 6) — see recursion.
multilinear encoding
both paths commit tables the same way. a table of 2^n rows and 2^m columns is one multilinear polynomial in n + m boolean variables: the first n address the row, the last m the column, and the polynomial is the unique multilinear extension that agrees with the table on every binary input. padding to a power of two lets the sumcheck protocol range over the full hypercube {0,1}^{n+m}. a constraint that must hold on every row becomes a claim that a polynomial vanishes on the hypercube; a random eq weight turns it into a sum, and sumcheck reduces the sum to one evaluation at a random point of Fp3, which the commitment opens.
the retired register trace
the 0.3 design proved a fixed 16-register trace (one row per reduction, one column per register, a selector over 18 pattern constraints) by folding it into an accumulator and opening it with an expander-code commitment. the fold was never checked, the statement was unbound and the commitment had no real opening (recursive-brakedown). that code survives only behind the cargo feature legacy (unsound, off by default) until phase 5 deletes it.
references
- see whirlaway for the architecture of the succinct profile
- see superspartan for the IOP that verifies a compiled relation
- see nox for the VM specification and pattern definitions
- see hemera for the Poseidon2 hash used in the relation and in every Merkle commitment