Skip to content

refactor(stark): share what the multilinear path needs - #997

Draft
ColoCarletti wants to merge 1 commit into
mainfrom
whir-pr/01-shared-from-stark
Draft

ColoCarletti wants to merge 1 commit into
mainfrom
whir-pr/01-shared-from-stark

Conversation

@ColoCarletti

@ColoCarletti ColoCarletti commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Rearranges code both provers use so a second one can reach it. No new
behaviour, no new callers.

  • grinding moves from stark to crypto, unchanged. It lived where only
    one prover could reach it; stark::grinding re-exports what it defined,
    and the GPU dispatch counter moves with it.
  • A preprocessed commitment is computed on first use instead of always. On
    the univariate path something always asks, so nothing changes but when.
  • AIR gains bus_interactions() and max_constraint_degree() — both were
    already computed inside composition_poly_degree_bound, which now calls
    them — and precomputed_columns(), which the five preprocessed tables
    supply from the code that already built those columns to hash them.
  • Table::columns and in_place_bit_reverse_permute go parallel. Same
    values, same places.

Checked: every preprocessed commitment root of a continuation proof is
byte-identical to main's, across all tables of all epochs.

… here

Five changes to shared code, none of which move a univariate proof.

**The grind moves to `crypto`.** Both provers do the same proof-of-work search,
and only one of them could reach it while it lived in `stark`. The algorithm,
the prefix and the validity predicate come over unchanged; `stark::grinding`
re-exports what it used to define, and the device dispatch counter moves with
it, so `gpu_lde::gpu_grind_calls` now reads the counter where the dispatch
happens.

**A preprocessed commitment is computed when someone asks for it.** It used to
be computed whether or not anything read it. On the univariate path something
always does — the verifier compares it against the proof's root — but the
multilinear one has no separate root and checks the columns instead, so on that
path nobody ever asks, and on a real program the ones that are not compiled-in
constants are an LDE and a Merkle tree each, two dozen times over.
`with_preprocessed` keeps its meaning and its signature.

**The AIR says three things it already knew.** `bus_interactions()` and
`max_constraint_degree()` were computed inside
`composition_poly_degree_bound`; they are now methods, and that function calls
them. `precomputed_columns()` is new and defaults to empty: it is what replaces
comparing a root, and what generates it is the same work that recomputing the
commitment costs. The five preprocessed tables supply it through
`with_preprocessed_columns`, extracted from the `compute_*_commitment` that
already built those columns to hash them.

**Two passes go wide.** `Table::columns` transposes one column per worker, and
`in_place_bit_reverse_permute` takes the row-major path it already had for a
power-of-two length. A permutation is a permutation and a transpose is a
transpose: same values, same places.

What was checked, and what could not be: every **preprocessed** commitment root
of a continuation proof is identical to what the parent produces, which is the
part this touches — the deferred commitment and the extracted columns. The trace
roots cannot be compared across runs at all, on this commit or on its parent:
six tables lay their deduplicated rows out in `HashMap` order, so two runs of
the same binary already disagree on twenty of seventy-nine roots.

557 tests in the prover — main's number — 51 in crypto, 223 in stark, 182 in math.
@ColoCarletti ColoCarletti changed the title refactor(stark): what the multilinear path needs from what is already… refactor(stark): share what the multilinear path needs Sep 18, 2026
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