Repository navigation
Fix: pin final PC to halt - #1020
Conversation
…nue past the exit ecall
… the halted state
|
/bench |
Benchmark — real block (
|
| Metric | main | PR | Δ |
|---|---|---|---|
| Peak heap | 47154 MB | 47797 MB | +643 MB (+1.4%) ⚪ |
| Prove time | 101.862s | 102.077s | +0.215s (+0.2%) ⚪ |
✅ No significant change.
Prove-time spread 0.7% (102.521s / 102.077s / 101.832s)
Commit: 92ebfbb · Baseline: cached · Runner: self-hosted bench
|
/ai-review |
Codex Code ReviewNo actionable issues found in the PR changes. The final-register commitments and continuation checks are consistent with HALT trace generation and cumulative output counts. Reviewed statically; no builds or tests run. |
ReviewI found no blocking issues. The fix closes the hole the PR describes, and I checked the soundness argument it relies on. What I checked
Minor
The extra commitment work per prove/verify is negligible: an LDE plus a Merkle tree over 128 rows. |
AI ReviewPR #1020 · 15 changed files Findings
Status column reflects the verdict from the verifier: deepseek-verifier (openrouter/deepseek/deepseek-v4-pro). AI-001: Prover panics when public output exceeds u32
Claim The monolithic prover uses Evidence In Suggested fix Replace the 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. Raw lane outputs, candidates, final issues, and model metrics are uploaded as workflow artifacts. |
* Preprocess the CPU timestamp as the spec defines it * Fix some low findings * Pin the PoC verifier to the halted register commitment
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.
After the final-register pin, COPY's commit index cannot carry into x254's high word in a proof that verifies: FINI fixes it to 0 and the verifier refuses an output of 2^32 bytes or more.
Conflict: lib.rs, VmAirs::new builds both the IS_WH AIRs and the pinned REGISTER AIR. Changes the merge needs without a textual conflict: - cpu_start counts the IS_WH sub-proofs, which air_refs places after the accelerators and before the CPU tables; without it the verifier would read CPU heights one sub-proof early in every proof that ships IS_WH. The air_refs debug check and cpu_proof_start_matches_air_refs_layout (64 masks, is_wh included) follow. - is_wh_tests: VmAirs::new takes the CPU heights and the REGISTER commitment; the prover commits to its own trace.
- copy.rs: COPY keeps the commit index non-decreasing but does not force x254's high word to zero; the halted final register file does. The executor's 1 MiB cap only keeps honest runs provable. - prove_elfs_tests.rs: the forged high word is refused by COPY's dst_res ADD and the MEMW bus, not by REGISTER. - auto_storage.rs: the CPU table's TIMESTAMP is preprocessed, so the prover builds two Merkle trees for it; the RAM estimate counts both. - tables/mod.rs: CPU is 37 columns, effective width 97. - prove_with_options_and_inputs: an oversized public output is an error, not a panic; the layout test calls its masks optional tables.
Motivation
HALT's
pccolumn is unconstrained. A prover can set it to1, so HALT's consume and emit of the PC token cancel each other. The realnext_pcof the exit ecall is then left free on thememorybus, more CPU rows can execute after the exit, and the chain closes through REGISTER's final token, which nothing checks. For example, a program that callsexit(1)can be proven asexit(0). This affects both monolithic and continuation proofs.Description
FINI, now preprocessed) to the halted state: x1-x31 = 0, x254 = committed bytes, PC = 1 (register::halted_fini). Real rows never writenext_pc = 1, so the PC chain can only end through HALT.reg_finito equal the halted state.halt_pc_forgery_poc(monolithic) andhalt_continuation_poc(continuations). The attack verifies onmainand is rejected here.