Repository navigation
Fix: Constrain table multiplicities - #1016
Conversation
|
/bench |
Benchmark — real block (
|
| Metric | main | PR | Δ |
|---|---|---|---|
| Peak heap | 47154 MB | 47177 MB | +23 MB (+0.0%) ⚪ |
| Prove time | 101.862s | 103.421s | +1.559s (+1.5%) ⚪ |
✅ No significant change.
Prove-time spread 0.6% (103.778s / 103.149s / 103.421s)
Commit: cc8a181 · Baseline: cached · Runner: self-hosted bench
|
/bench |
|
/bench |
|
/ai-review |
Codex Code ReviewNo actionable issues found in the PR changes. Reviewed statically; no builds or tests were run. |
Review summaryThe fix looks sound. I checked these points and found no problems:
Notes (Low / readability)
I left one inline comment, on the #977 guard exemption. |
AI ReviewPR #1016 · 36 changed files
Findings
Status column reflects the verdict from the verifier: deepseek-verifier (openrouter/deepseek/deepseek-v4-pro). AI-002: Stale bus-interaction counts in MaxRowsConfig comment table
Claim The comment table listing per-table bus-interaction counts and effective widths is now stale for tables whose bus interactions changed in this PR: LT went from 9→10, DVRM from 34→35, and SHIFT from 18→17 interactions, but the comment still lists the old values (9, 34, and 15 respectively). Evidence The mod.rs comment table (lines 71-93) lists 'LT | 15 | 9 | 42', 'DVRM | 34 | 34 | 136', and 'SHIFT | 27 | 15 | 72'. The actual bus_interactions() counts are now 10 for LT (added ARE_BYTES[μ,0]), 35 for DVRM (added ARE_BYTES[μ_q,μ_r]), and 17 for SHIFT (merged two ARE_BYTES into one). The eff-width column (main + 3×bus) is correspondingly wrong. The max_rows constants are hardcoded and not derived from this comment, so there is no functional impact, but the documentation is misleading for anyone sizing new tables from the formula. Suggested fix Update the comment table to reflect the new bus-interaction counts: LT→10, DVRM→35, SHIFT→17 (and recompute effective widths). Reviewer Lanes
Verification Lanes
Native Codex and Claude reviews run separately and post their own comments. They are not included in this structured provenance report. Discarded candidates (1) — rejected by the verifier
Raw lane outputs, candidates, final issues, and model metrics are uploaded as workflow artifacts. |
Resolve the two conflicts with #984 (COPY replaces COMMIT): - trace_builder.rs BITWISE collectors: keep COPY's collector from main and this branch's KECCAK_RND padding count (keccak_rnd::padding_are_bytes). - skip_empty_tables_tests.rs: COMMIT left the optional-table list (17 tables); keep this branch's ARE_BYTES exemption imports.
- dvrm.rs / trace_builder.rs: DVRM's MSB16 and NEG ZERO lookups are counted once per row, so an op split at MU_MAX sends them once per row. - trace_builder.rs: KECCAK_RND no longer sends HWSL. - continuations_design.md: LT and MUL bound their own mu with a constant-1 ARE_BYTES send.
Brings in main's #984 (COPY replaces COMMIT) through #1016's branch. Conflicts resolved by keeping both sides: - TableCounts / statement / VmAirs / Traces: drop commit, keep is_wh and copy. - BusId: IS_WH = 32 next to COPY's CopyNext = 33. 32 was one of the two IDs main's comment listed as unused; 29 and 34 stay unused. - RECURSION_INPUT_VERSION 5 with a v5 note: main's v4 already means the layout without commit, so is_wh needs its own number. - Tests: counts 20 / 18 / 6, the accelerator test renamed to a_run_without_accelerators_omits_all_five_and_is_wh, COMMIT's omission tests dropped as on main, and main's committed-output test kept with this branch's "dropping ..." message style.
Brings in #984 (COPY replaces COMMIT, x254 becomes two words) and #1016. Conflicts: - lib.rs: keep the pinned REGISTER commitment and add main's COPY AIR. - register.rs: keep the single OFFSET/INIT/FINI/IS_PC commitment; x254 is at 508-509 now. - trace_builder.rs: drop the COMMIT aux count; REGISTER takes final_pc_ts. - constraint-program tests: CPU with ts_base 0 plus main's COPY check. Changes the merge needs without a textual conflict: - cpu_start: COPY is a fixed table ahead of REGISTER and COMMIT is gone, so the first CPU sub-proof is at 5 + HALT + the five accelerators. The air_refs debug check and cpu_proof_start_matches_air_refs_layout (now 32 masks) follow. - collect_epoch_from_cpu_ops returns Result: main made collect_ops_from_cpu fallible. - multiplicity_forgery_poc: VmAirs::new takes the CPU heights and the REGISTER commitment; the prover commits to its own trace.
Motivation
Several AIR tables leave their multiplicity column
μunconstrained. Sinceμlives in the field, it can be set to−1, which flips a row's role on the bus: it starts receiving its range checks instead of sending them. This is exploitable: the bugs were proven end-to-end by a test where the verifier accepts a false statement against an unmodified ELF.Description
Follows the spec in #1017. Two fix shapes, by whether the table deduplicates rows:
μ ∈ [0, 256)with anIS_BYTEcheck sent with multiplicity 1, so noARE_BYTESsender carries a negative weight:LT, BYTEWISE:
ARE_BYTES[μ, 0].MUL, DVRM: one batched
ARE_BYTES[μ_a, μ_b].BRANCH: one batched
ARE_BYTES[μ, next_pc_low_1].next_pc_low_1was previously sent with weightμ, which let two BRANCH rows (μ = −2,μ = −1) cancel the bound of a forged LT row (branch_carrier_poc).Rows whose count exceeds 255 are split (
types::dedup_rows, anddedup_mul_rows/dedup_dvrm_rowsfor the two-count tables). The BITWISE collectors count one lookup per row, padding rows included (ARE_BYTES[0, 0]).Feat/skip empty tables #977 guard:
no_optional_table_uses_a_constant_multiplicitynow allowsMultiplicity::Oneonly onARE_BYTESsends whose values vanish on padding rows (a byte check on zero values is harmless). Every other bus still requires an empty table to send nothing.μ(μ·(1−μ) = 0, pluszbsfor SHIFT), and forceis_negative = 0on unsigned SHIFT rows.SHIFT:
IS_BYTE[shift[0]]andIS_BYTE[shift[1]]are batched into oneARE_BYTES[shift[0], shift[1]]with multiplicity 1, as in the spec.EQ no longer deduplicates rows (one row per op,
μis a bit, as in the spec).KECCAK_RND: its byte checks now use multiplicity 1 as in the spec, and padding is counted in the collector. The
Cxz_rightIS_BIT is no longer gated byμ, which lowers the table's max degree from 3 to 2.