The Full Protocol, Rolled Out#
This section presents the complete OpenVM STARK protocol as a single self-contained reference covering the multi-AIR setting. The proof covers \(n\) AIRs, each with its own trace height \(N_a\), constraint set, and optional bus interactions. All notation follows Primitives.
Prover |
Verifier |
|
|---|---|---|
Setup: Transcript seeding ( |
||
Create fresh transcript \(\mathcal{T}\) (Poseidon2 duplex sponge).
|
Create fresh \(\mathcal{T}\); identical observations ( |
|
Round 1: Witness commitment ( |
||
For each AIR \(a\) (\(a = 0, \ldots, n-1\)):
|
||
Preprocessed traces (per-AIR, committed individually):
|
||
\(\mathcal{T}.\text{observe}(\text{pv}_a)\) for each AIR \(a\).
|
\(=\) |
Identical observations of \(\text{pv}_a\), preprocessed commits, main commits, \(\log_2 N_a\). |
Round 2: After-challenge trace (LogUp) ( |
(only if any AIR has bus interactions) |
|
Grind for LogUp PoW witness \(\eta_{\text{lu}}\). |
||
\(\eta_{\text{lu}}\) |
\(\longrightarrow\) |
Check: PoW witness valid (). |
\((\alpha_{\text{lu}}, \beta_{\text{lu}})\) |
\(\longleftarrow\) |
\(\alpha_{\text{lu}} \leftarrow \mathcal{T}.\text{sample\_ext}()\), \(\beta_{\text{lu}} \leftarrow \mathcal{T}.\text{sample\_ext}()\). |
For each AIR \(a\) with interactions ( |
||
\(\mathcal{T}.\text{observe}(\text{exposed values per AIR})\) (each is FF4: 4 base elements).
|
\(=\) |
Observe exposed values, \(r_2\).
|
Round Q: Quotient polynomial ( |
||
\(\alpha\) |
\(\longleftarrow\) |
\(\alpha \leftarrow \mathcal{T}.\text{sample\_ext}()\) (constraint folding challenge). |
For each AIR \(a\) ( |
||
Collect all quotient chunks across AIRs, each at its own height.
|
\(=\) |
\(\mathcal{T}.\text{observe}(r_Q)\). |
DEEP Proof-of-Work |
||
Grind for DEEP PoW witness \(\eta_{\text{deep}}\). |
||
\(\eta_{\text{deep}}\) |
\(\longrightarrow\) |
Check: PoW witness valid. |
Evaluation stage ( |
||
\(\zeta\) |
\(\longleftarrow\) |
\(\zeta \leftarrow \mathcal{T}.\text{sample\_ext}()\) (OOD evaluation point). |
For each committed matrix, evaluate columns at \(\zeta\) and \(\zeta\omega_a\)
( |
||
\(\{e_{p,o}\}\) |
\(\longrightarrow\) |
\(\{e_{p,o}\}\); \(\mathcal{T}.\text{observe}(\{e_{p,o}\})\). |
PCS batch opening ( |
||
\(\alpha_{\text{pcs}}\) |
\(\longleftarrow\) |
\(\alpha_{\text{pcs}} \leftarrow \mathcal{T}.\text{sample\_ext}()\) (batch combination challenge). |
Reduced polynomial per height ( |
||
FRI commit phase ( |
||
Collect reduced polynomials keyed by \(\log_2(\text{height})\).
|
||
Pair evaluations as leaves, \(r_0^{\text{FRI}} = \MT(F_0)\) ( |
\(\longrightarrow\) |
\(r_0^{\text{FRI}}\); \(\mathcal{T}.\text{observe}(r_0^{\text{FRI}})\). |
PoW grind per round (if configured). |
\(\longrightarrow\) |
|
\(\beta_0\) |
\(\longleftarrow\) |
\(\beta_0 \leftarrow \mathcal{T}.\text{sample\_ext}()\). |
\(\Fold\): \(F_1 = \Fold(F_0, \beta_0)\) ( |
||
\(\vdots\) (repeat for \(K\) rounds; at each fold, roll in any \(\text{ro}_h\) at that height) |
\(\vdots\) |
|
Final polynomial \(F_K\) (truncated, bit-reversed, IDFT to coefficients). |
\(\longrightarrow\) |
\(F_K\); \(\mathcal{T}.\text{observe}(F_K)\). |
Query-phase PoW |
||
PoW witness for query phase. |
\(\longrightarrow\) |
Check: PoW valid. |
Query phase ( |
||
For each query \(i = 1, \ldots, Q_{\text{queries}}\): |
\(=\) |
\(q_i \leftarrow \mathcal{T}.\text{sample\_bits}(\log_2 N_{\text{ext}})\). |
Merkle openings at \(q_i\) for every committed tree.
|
\(\longrightarrow\) |
For each query \(q\): |
Merkle check: verify opening proofs for all committed trees
( |
||
Reduced opening ( |
||
FRI fold verification ( |
||
Final polynomial check: evaluate \(F_K\) at folded domain point, verify \(= \text{folded}\). |
||
Constraint check ( |
||
For each AIR \(a\), with domain \(D_a\) and constraint set \(\{C_{a,i}\}\)
( |
||
Accept iff all checks pass for all \(n\) AIRs. |
Proof Structure#
Multi-AIR Key Points#
Different heights. AIR traces may have different numbers of rows (\(N_a \ne N_b\)). This propagates through the entire protocol: domain selectors are per-AIR, the vanishing polynomial \(Z_{H_a}\) is per-AIR, and \(\omega_a\) (the next-row step in the “next” opening) differs per AIR.
MMCS commitments.
When multiple matrices of different heights are committed together
(common main trace, quotient chunks), they share a single Merkle tree
via the mixed-matrix commitment scheme (pcs.py#build-mmcs-tree).
Shorter matrices are injected at higher tree levels.
Per-height alpha tracking.
During PCS opening, the \(\alpha_{\text{pcs}}\) power accumulator is maintained
separately for each distinct \(\log_2(\text{height})\)
(pcs.py#per-height-alpha).
Using a single global accumulator works for single-height proofs but produces
incorrect results for multi-height cases.
FRI roll-in. Reduced openings from shorter matrices enter the FRI polynomial at the folding round where the FRI domain size matches their height. At each fold: \(F_{k+1} \mathrel{+}= \beta_k^2 \cdot \text{ro}_h\).
Error precedence. OodEvaluationMismatch (constraint check failure) takes
priority over ChallengePhaseError (LogUp cumulative sum nonzero). The verifier
raises the LogUp error only after the constraint check succeeds.