Repository navigation
Bound-check quotient VM operands at build time and harden the interpreter (QVM-01) - #12
Merged
Merged
Conversation
Size the pre-first-squeeze transcript run from every advice phase up to and including the first challenge-bearing phase, not just phase 0, so the valid "advice in an early phase, challenge in a later phase" shape no longer under-sizes the buffer and overruns VK_MPTR. In the quotient VM limb-decomposition and product-add peepholes, re-check that fused opcode coefficients still fit their one-byte constant slots after intervening residue/base emission, falling back to generic ops instead of panicking in the u8::try_from(...).expect(...). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eter
Addresses audit finding QVM-01 ("Quotient-VM operand fields are
bound-checked neither at run time nor by the byte validator").
Build time (fail closed): every emitted memory pointer must be aligned
and inside a window the verifier populates before the VM runs, and
constant slots, selector buckets, y-power gaps and stack depth must be
in range. The check runs from `validate_generator_invariants` and uses
one operand model shared with the interpreter guards.
Run time: folds require exactly one live value, pops cannot go below
the stack floor, spills cannot pass the planned ceiling, native
callbacks require an empty stack instead of resetting it, bucket and
gap operands and MODARITH7 flags are range-checked, the epilogue also
requires the stack back at its base, and u16 constant slots are
clamped to the table length.
Runtime pointer and u8 constant clamps were measured and left out: on
the Moonlight wrap they cost about 56k and 31k gas per verification,
and in a 400-mutation experiment they still let 261 wrong in-range
operands through, so exact build-time checks plus the VK codehash pin
are the stronger layer. The remaining runtime checks cost about 1.5k
gas; the VK output is unchanged.
Ported from misc-fixes 86b262e, 580a912 (MF-3), b680bf2 and
20766cb, without their typed errors or unrelated changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses audit finding QVM-01: "Quotient-VM operand fields are bound-checked neither at run time nor by the byte validator".
Build time (fails closed) —
validate_quotient_program_operands, run fromLoweringPlan::validate_generator_invariants:The walker is total over the opcode table; a test pins this, so a new opcode that forgets it fails the render. The interpreter guards read their bounds from the same operand model.
Run time (plain
revert(0, 0); rendered only inside the opcode arms that are rendered):q_sp == base, alongsideq_pc == q_endandq_has_top == 0;Measured and left out: runtime pointer clamps and u8 constant clamps.
docs/reference/QUOTIENT_NUMERATOR_EVALUATOR.md("Interpreter Bounds Checks (QVM-01)").Ported from
misc-fixes: 86b262e (clamps and stack floor), 580a912 (MF-3 only), b680bf2 (epilogueq_spcheck) and 20766cb (build-time pointer windows). Their typed errors, the alpha/vk_digest binding and the precompile error split are not included.Measurements
Moonlight wrap (Nightfall
fee_12345), rendered from the committed production VKs. Settings: solc 0.8.35 via-IR, runs 200, cancun; anvil prague with the default size limit.main(same codehash), so only the verifier changes.Fixtures (pinned solc 0.8.30):
Tests
cargo test --release --lib: 148 passed. Withevm,rust-verifier-traceandHALO2_SOLIDITY_RUN_EVM_TESTS=1: 185 passed.Notes
vm/mod.rs, so whichever merges second needs a small rebase.6b3d2096, which is not yet onmain(the same base as Add opt-in direct quotient lowering for the Solidity verifier #10).🤖 Generated with Claude Code