trace to proof

the concrete journey from nox execution to zheng proof. this article bridges the VM and the proof system, showing exactly how computation becomes cryptographic evidence.

the execution trace

when nox runs a program, it produces a table. each row is one reduction step — one application of a pattern to the current term. the table has 16 columns (registers), indexed 0 through 15:

register  name            role
────────────────────────────────────────────────────
r0        pattern         which of the 16 patterns fired
r1        object_hash     hash of the object being reduced
r2        formula_hash    hash of the formula being applied
r3        operand_a       first operand
r4        operand_b       second operand
r5        result          output of this reduction step
r6        focus_before    focus counter at entry
r7        focus_after     focus counter at exit
r8        type_tag_a      type of operand_a
r9        type_tag_b      type of operand_b
r10       type_tag_out    type of result
r11       aux_0           auxiliary register (pattern-specific)
r12       aux_1           auxiliary register (pattern-specific)
r13       aux_2           auxiliary register (pattern-specific)
r14       status          step status (running / halted / error)
r15       step_index      position in the trace

all values are elements of the Goldilocks field (p = 2^64 - 2^32 + 1). a trace with 1,000 reduction steps is a 1,000 × 16 table of field elements.

padding to power of two

the sumcheck protocol operates over the boolean hypercube {0,1}^n, which has 2^n points. the trace must therefore have exactly 2^n rows. if the raw trace has 1,000 rows, it is padded to 1,024 (2^10).

padding rows replicate the final halted state. the pattern register is set to the halted pattern, and all other registers copy the last valid row's values. these padding rows satisfy the AIR constraints trivially: the halted pattern's transition constraint is the identity (every register stays unchanged).

multilinear encoding

the padded trace (2^n rows × 2^4 columns) becomes a single multilinear polynomial f over n + 4 boolean variables. the encoding works by address:

  • variables x₁ through x_n encode the row index in binary
  • variables x_{n+1} through x_{n+4} encode the column index in binary

for any binary assignment (b₁, ..., b_n, c₁, ..., c₄):

f(b₁, ..., b_n, c₁, ..., c₄) = trace[row(b₁...b_n)][col(c₁...c₄)]

the polynomial f is the unique multilinear extension of this table. it agrees with the trace on all 2^{n+4} binary inputs and interpolates smoothly over the full Goldilocks field. this is the polynomial that WHIR commits to.

AIR constraints from nox patterns

each of nox's 16 patterns contributes a transition constraint — a polynomial equation that must hold between consecutive rows.

full constraint table

PATTERN → CONSTRAINT                                        │ DEGREE │ CONSTRAINTS
────────────────────────────────────────────────────────────┼────────┼────────────
0  axis     navigation through subject tree                │ 1      │ ~depth
1  quote    output = literal constant                       │ 1      │ 1
2  compose  chain: eval x, eval y, eval result on x's output│ 1      │ 2
3  cons     pair two sub-results                            │ 1      │ 2
4  branch   selector × (next − yes) + (1−sel) × (next − no)│ 2      │ 2
5  add      out = a + b mod p                               │ 1      │ 1
6  sub      out = a − b mod p                               │ 1      │ 1
7  mul      out = a × b mod p                               │ 2      │ 1
8  inv      out × input = 1 mod p (Fermat verification)    │ 2      │ 1
9  eq       (a − b) × inv = (a ≠ b), out = 1 − (a ≠ b)    │ 2      │ 1
10 lt       range decomposition into bits                   │ 1      │ ~64
11 xor      bit decomposition + XOR per bit                 │ 2      │ ~64
12 and      bit decomposition + AND per bit                 │ 2      │ ~64
13 not      bitwise complement                              │ 1      │ ~64
14 shl      shift via multiplication by 2^n                 │ 2      │ ~64
15 hash     Poseidon2 round function across rows            │ 7      │ ~300
16 hint     constraint check (Layer 1 verification)         │ varies │ varies

SuperSpartan handles AIR constraints of any degree via CCS. high-degree constraints (pattern 15: degree 7) cost only field operations in the prover — no cryptographic cost increase over degree-1 constraints. this is the CCS advantage: the Poseidon2 rounds inside the hash pattern are free in the IOP layer.

three examples spanning different degrees follow.

pattern 5: add (degree 1)

when r0_t = 5 (the add pattern fires at row t), the result at the next row must be the sum of the operands:

r5_{t+1} = r3_t + r4_t

this is a degree-1 constraint: a linear relation among register values at adjacent rows. the constraint polynomial is C₅(t) = r5_{t+1} - r3_t - r4_t, which equals zero on every row where pattern 5 fires.

pattern 7: mul (degree 2)

when r0_t = 7 (multiply), the result is the product:

r5_{t+1} = r3_t × r4_t

the constraint polynomial C₇(t) = r5_{t+1} - r3_t × r4_t is degree 2. the multiplication of two register values introduces one degree of non-linearity.

pattern 15: hash (degree 7)

when r0_t = 15, the row encodes one round of hemera (Poseidon2). the Poseidon2 round function applies the S-box x^7 to the state, then a linear layer. the constraint spans consecutive rows — the state after applying x^7 and the MDS matrix at row t must equal the state at row t+1.

state_{t+1} = MDS × (state_t)^7

the degree-7 S-box makes this a degree-7 transition constraint. in classical STARKs this would cause a 7x blowup in the quotient polynomial. in SuperSpartan, it costs a few extra field operations per sumcheck round — no cryptographic penalty.

boundary constraints

transition constraints govern consecutive rows. boundary constraints pin specific rows to known values.

the input boundary fixes row 0: the initial registers must match the program's input. if the computation adds 3 and 5, then r3_0 = 3 and r4_0 = 5.

the output boundary fixes the last active row: the result register must contain the program's output, and the status register must indicate clean halting.

boundary constraints are point evaluations. they assert that f, evaluated at specific binary coordinates, equals specific field elements. WHIR proves these directly as evaluation claims.

the combined constraint polynomial

the 16 pattern constraints must be combined into a single polynomial. the pattern selector handles this: at each row, only one pattern is active (the value in r0). the combined constraint is:

C(t) = Σ_{p=0}^{15} selector_p(r0_t) × C_p(t)

where selector_p(r0_t) equals 1 when r0_t = p and 0 otherwise. the selector is a polynomial in r0_t constructed via Lagrange interpolation over the 16 pattern values.

if the trace is valid — every pattern was executed correctly — then C(t) = 0 for every row t. the sumcheck protocol verifies this: the sum of C over all 2^n rows equals zero. SuperSpartan orchestrates this sumcheck, reducing the exponential sum to a single evaluation point, which WHIR opens.

focus accounting

every nox computation has a focus budget. focus is the resource that bounds computation — the analog of gas in other VMs, but deterministic and exact.

each row enforces the focus transition:

r7_t = r6_t - cost(r0_t)

focus_after equals focus_before minus the cost of the pattern that fired. the cost function is fixed per pattern: arithmetic patterns cost 1, hash rounds cost more. this constraint is part of every pattern's AIR — it is enforced universally, regardless of which pattern fires.

when focus reaches zero, the status register transitions to halted and the computation ends cleanly. the boundary constraint on the last row checks that r14 (status) indicates halted and r7 (focus_after) is zero or that r6 (focus_before) was insufficient for the next pattern's cost.

a concrete example

consider a simple program: add 3 and 5. nox executes this in one reduction step (plus padding). with initial focus of 10:

row  r0   r3   r4   r5   r6    r7   r14     description
───────────────────────────────────────────────────────
  0   5    3    5    0    10    9    run     add: r5 ← r3 + r4
  1   0    3    5    8     9    9    halt    result in r5, halted

the AIR constraint for row 0: r0 = 5 (add pattern), so C₅ applies. check: r5₁ = 8 = 3 + 5 = r3₀ + r4₀. the constraint is satisfied. focus: r7₀ = 9 = 10 - 1 = r6₀ - cost(5). satisfied.

this 2-row trace is padded to 2^1 = 2 rows (already a power of two). the multilinear polynomial f has 1 + 4 = 5 variables. WHIR commits to f. SuperSpartan runs the sumcheck over 2 rows. the verifier checks the sumcheck transcript and one WHIR evaluation proof. the entire proof attests that 3 + 5 = 8 — with cryptographic certainty, without revealing the trace.

from trace to trust

the pipeline recapitulates:

nox program → execution → trace table (2^n × 16)
    → pad to power of two
    → encode as multilinear polynomial f
    → WHIR_commit(f) → commitment C
    → SuperSpartan sumcheck over AIR constraints → point r
    → WHIR_open(f, r) → proof π
    → verifier checks transcript + evaluation proof

the trace is the witness. the polynomial is its algebraic encoding. the commitment binds the prover. the sumcheck verifies the constraints. the evaluation proof closes the loop. what enters as computation exits as evidence.

references

  • see whirlaway for how the architecture composes
  • see superspartan for the IOP that verifies constraints
  • see nox for the VM specification and pattern definitions
  • see hemera for the Poseidon2 hash used in pattern 15 and in WHIR commitments

Dimensions

trace-to-proof

Local Graph