Skip to content

refactor(lfm,stark): delete the preprocessed round root and the mixed-height MMCS - #974

Merged
MauroToscano merged 1 commit into
per-table-gpufrom
pt/delete-prep-round
Sep 8, 2026
Merged

refactor(lfm,stark): delete the preprocessed round root and the mixed-height MMCS#974
MauroToscano merged 1 commit into
per-table-gpufrom
pt/delete-prep-round

Conversation

@MauroToscano

Copy link
Copy Markdown
Contributor

Deletes the preprocessed round root and the mixed-height MMCS that built it. With
#973 merged there is one proof format on this branch; this removes the last structure
that existed only to serve the other one.

+16 / −3,151 over 13 files, one signed commit. Figures are git diff --numstat
against the merge base at this head, and the table sums to them.

area +/− what goes
crypto/stark +0 / −2,234 batched/{mod,shape}.rs and pub mod batched;, fri/mmcs.rs and pub mod mmcs;, par::par_for_each_mut_indexed
prover/src/lfm +16 / −909 prep_root / prep_widths in both structs and their six entries, PREP_ROUND_SLOTS, prep_round_dims, prep_round_shape, pinned_prep_widths (method + free fn), slot_of_table, commit.rs's PrepRoundBuilder, and the tests whose subject they are
prover/src/bin +0 / −8 compute_lfm_registry stops emitting the two fields

Why it goes

prep_root was a SECOND commitment over the preprocessed matrices the per-slot roots
already commit individually, gathered into one mixed-height tree. The machine proves and
verifies a per-table MultiProof whose openings authenticate against roots, so nothing
read the round — verify_against_artifacts said exactly that in its own doc, under a
"What it does NOT do yet" heading. With no reader, the round was a pinned constant that
every build_artifacts call paid a tree for and that six registry entries carried.

Two things die with it because they existed only to serve it, and both were verified by
reading callers rather than by name:

  • slot_of_table mapped an epoch TABLE index back to a registry SLOT across the
    chunking and chip-mask shifts. Its only production caller was inside
    pinned_prep_widths, where the translation existed to index the round's width slice.
  • par::par_for_each_mut_indexed had exactly one caller, fri/mmcs.rs:776.

No blessed value is hand-edited

The six registry entries lose two FIELDS. Every root, program_id and height in them is
byte-identical: the deletion cut whole prep_root: [ … ], + prep_widths: [ … ], line
groups by matching structure, asserting exactly six matches, and touched no digit of any
value. lfm_program_id never took the round as an argument — the entry carried the pins,
the digest did not — so no digest moves and this is not a re-bless.

compute_lfm_registry is updated in the SAME commit. It printed prep_root: and
prep_widths: into the generated table, so left alone it would not have compiled, and had
it compiled it would have emitted a registry with fields the struct no longer has. That
matters beyond this PR: it is the step-8b regenerator, and a defect there surfaces during
the pin ceremony, which is the worst place in this campaign to find one.

Tests

Deleted: the seven M-6 prep-round tests in machine_tests.rs, the twelve drift assertions
that paired entry.prep_root / prep_widths against the artifacts (six identical pairs),
blake3_chip_tests::the_prep_round_expands_with_the_blake3_chunks, and fri/mmcs.rs's
fourteen, whose subject is the mixed-height tree itself. batched/shape.rs carried none.

verify_against_artifacts_agrees_with_the_registry_path STAYS. It sat inside the same
// The batched preprocessed round (M-6) banner, which ran to end of file, but it is M-7's
honest-path control for a function that stays. The banner is not the criterion — each
of the seven was confirmed by reading that it touches prep_root / prep_round_* /
pinned_prep_widths. The same check is why
the_slot_to_table_map_is_not_the_identity_beyond_one_chunk DOES go: it reads as a
survivor by name, and its subject dies with pinned_prep_widths.

Bycatch, not churn

Three comments in registry.rs's build leg became false when the LDE stopped being
consumed twice, and one of them said commit_group "used to do its own expansion" —
a migration reference with a shelf life of weeks. All three are rewritten in present tense
to describe what the code does now. lde_columns' doc loses the same paragraph for the
same reason, along with an intra-doc link to prep_round_root — a name that, checked
across the whole tree, never named an item.
#973 also left two references to a_batched_lfm_epoch_is_refused_for_the_round_coverage_gap,
a test it had itself deleted; both sat inside text this PR removes.

Evidence

Laptop, at this head:

cargo fmt --all                                 no changes
cargo check -p lambda-vm-prover --all-targets   exit 0
make lint                                       exit 0

Box gate at this head, on a 32-core box, preconditions asserted before a test ran:

HEAD_ASSERT expected=1a82b97c… got=1a82b97c…    TREE_CLEAN yes
TOOLCHAIN cargo 1.94.0 (85eff7c80 2026-01-15) · git version 2.43.0
ARTIFACT_BUILD_EXIT=0        ARTIFACTS expected=264 missing=0

cargo test --release -p lambda-vm-prover --lib
  test result: FAILED. 1088 passed; 8 failed; 43 ignored; 0 measured; 0 filtered out;
  finished in 2441.14s
  -- --list: 1139 tests, 0 benchmarks
cargo test --release -p stark          (four result lines: lib, two integration, doc-tests)
  test result: ok. 271 passed; 0 failed; 0 ignored;  finished in 0.06s   <- src/lib.rs
  test result: ok.   0 passed; 0 failed; 0 ignored;  finished in 0.00s   <- tests/gpu_constraint_interp.rs
  test result: ok.   0 passed; 0 failed; 0 ignored;  finished in 0.00s   <- tests/r4_denoms_parity.rs
  test result: ok.   0 passed; 0 failed; 3 ignored;  finished in 0.00s   <- doc-tests
  summed: 271 passed; 0 failed; 3 ignored = 274      (--lib --list: 271 tests)
cargo test --release -p math-cuda      171 passed; 0 failed
make lint                              LINT_EXIT=0

Predicted 1088 / 8 / 43 = 1139 before the run; measured 1088 / 8 / 43, with --list
independently returning 1139. Stark was predicted at 271 / 0 / 3 = 274 and measured
there.
math-cuda unchanged at 171 / 0, as predicted — this PR touches no math-cuda file.

The stark run's three ignored are doc-tests, which is why they survive a commit that
deletes fourteen unit tests: crypto/stark/src carries exactly three ```ignore fenced
blocks before and after, and none of the three deleted files carried one.

The eight failures are the RPX pin's, byte-identical to the set #973 gated and named; none
is in this PR's deletion set. That they are unchanged across a tree with prep_root,
prep_widths, PrepRoundBuilder, slot_of_table and the mixed-height MMCS all removed is
the evidence that nothing read the preprocessed round back — compiling clean would only
have shown that nothing REFERENCES it.

Two independent derivations for the prover figure, both pre-registered:

  1. Forward from the measured head. refactor: delete the batched proof format, per-table only #973 gated 1096 / 8 / 43 = 1147. This commit removes
    exactly eight #[test]s — seven M-6 plus one blake3_chip — all in plain #[cfg(test)]
    modules, none #[ignore]d, and none among the eight known-red (the four red
    machine_tests are the register-derivation trio and transcript_replay_cell_counts,
    all outside the M-6 banner). 1096 − 8 = 1088.
  2. Through the cfg-gate gap. prover/src carries 1,161 #[test] attributes against
    1,147 measured runnable — a gap of exactly 14, and it was 14 at the previous head too
    (1,160 / 1,146), so it is stable. This commit takes attributes to 1,153 and removes
    nothing from a gated module, so the gap holds: 1,153 − 14 = 1,139. The gate's own
    --list returned 1,139.

One counting note, and one measurement note

An #[test] ATTRIBUTE count is not a count of what RUNS, and it errs in BOTH directions.
prover/src over-counts (1,161 against 1,147 runnable — cfg-gated modules), while
crypto/stark UNDER-counts: at the previous head src + tests carried 219 attributes
against 288 measured runnable, in a crate where an earlier attribute-derived prediction of
307 missed that same 288. So the stark prediction above rested on ONE route — 285 passing at the previous head with
zero failures, minus fourteen non-ignored passing tests, giving 271 — and this PR does not
manufacture a second. The gate command instead runs
cargo test --release -p stark --lib -- --list, so the run carries its own count rather
than a derived one. It returned 271, and the four test result: lines sum to
271 / 0 / 3 = 274 — the predicted figure exactly.

The same lines correct a stale description worth writing down: stark's suite is the lib
binary, TWO integration binaries and doc-tests, not the "lib plus three integration
binaries" an earlier characterisation recorded. Four result lines, three Running headers
— the fourth is doc-tests, which prints no Running tests/… line — so anyone
reconstructing the split from the older wording attributes the ignored three to the wrong
place.

★ The measurement note is worth more than the counting one. A previous gate on this lane
returned 900 passed; 204 failed; 43 ignored — it parsed cleanly, printed every expected
line, and every figure in it was meaningless: a fresh worktree had no guest ELFs, so every
suite that executes a guest program failed on a missing file. What caught it was a
prediction written down beforehand, and specifically that the total matched to the unit
while the split did not
— 900 + 204 + 43 = 1,147 exactly. A real regression moves both.
Pre-registration is not ceremony here; it is the only instrument that distinguishes a
broken run from a broken branch.

…-height MMCS

`prep_root` and `prep_widths` leave `LfmRegistryEntry` and `LfmArtifacts`, and
the machinery behind them goes with them: `PREP_ROUND_SLOTS`, `prep_round_dims`,
`pinned_prep_widths` (method and free function), `prep_round_shape`,
`slot_of_table`, `commit.rs`'s `PrepRoundBuilder`, `stark::batched` (`shape.rs`
and its `mod.rs`) and `stark::fri::mmcs`.

They were one thing: a SECOND commitment over the preprocessed matrices the
per-slot `roots` already commit individually, gathered into one mixed-height
tree. The machine proves and verifies a per-table `MultiProof` whose openings
authenticate against `roots`, so nothing read the round — `verify_against_
artifacts` said so in its own doc. With no reader, the round was a pinned
constant that every `build_artifacts` call paid a tree for and six registry
entries carried.

`slot_of_table` goes because `pinned_prep_widths` was its only caller: it mapped
an epoch TABLE index back to a registry SLOT across the chunking and chip-mask
shifts, and that translation existed to index the round's width slice.
`par::par_for_each_mut_indexed` goes for the same reason — its only caller was
`fri/mmcs.rs:776`.

No blessed value is hand-edited. The six entries lose two FIELDS; every root,
`program_id` and height in them is byte-identical, and `lfm_program_id` never
took the round as an argument, so no digest moves. `compute_lfm_registry` stops
emitting the two fields, so a regenerated table matches the struct.

Tests: the seven M-6 prep-round tests in `machine_tests.rs` and the twelve
drift assertions that paired `entry.prep_root`/`prep_widths` against the
artifacts, plus `blake3_chip_tests::the_prep_round_expands_with_the_blake3_
chunks`. `verify_against_artifacts_agrees_with_the_registry_path` sits inside
the same banner and STAYS — it is M-7's honest-path control for a function that
stays. `stark::batched::shape` carried no tests; `fri/mmcs.rs` carried fourteen,
whose subject was the mixed-height tree itself.
@MauroToscano
MauroToscano merged commit 1d92fea into per-table-gpu Sep 8, 2026
9 checks passed
@MauroToscano
MauroToscano deleted the pt/delete-prep-round branch September 8, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant