Skip to content

perf(prover): run the first sumcheck round in the base field#471

Merged
shreyas-londhe merged 5 commits into
feat/base-field-witness-commitfrom
perf/first-sumcheck-round-in-base
Jul 13, 2026
Merged

perf(prover): run the first sumcheck round in the base field#471
shreyas-londhe merged 5 commits into
feat/base-field-witness-commitfrom
perf/first-sumcheck-round-in-base

Conversation

@BornPsych

@BornPsych BornPsych commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Runs the first Spartan sumcheck round over the base field. After the witness became base-committed (#470), the opening round still lifted the a, b, c mles into the extension before folding. This computes round 0's cubic evaluations directly on the base-field mles (one mixed base×ext multiply per point against the extension eq), then lifts into the extension only at the round-0 challenge. It also extracts the per-round message construction into a shared combined_round_message helper and adds the base-field sumcheck primitives it needs. A pair of #[ignore]d profiling probes are included so the win is reproducible in-tree.

Stacks on #470 (base-field witness commitment). Independent of the CI guard (#469).

Why

On the Goldilocks base-field path the witness mles are 64-bit Field64, but the sumcheck eq and challenges live in the degree-3 extension Field64_3. Lifting a, b, c to the extension before the first fold pays extension-width multiplies for data that is still base-valued. Doing round 0 in the base field removes one round's worth of extension multiplies — ~5% prove-time at 2^20 on the goldilocks base-field path. bn254 rides the identity embedding, so its path is a no-op (base == ext) and its proofs are unchanged.

What changed

  • provekit-commoncommon/src/utils/sumcheck.rs gains mixed_sumcheck_map_reduce and mixed_fold: reduce/fold the leading variable of base-field mles against an extension-field eq/challenge. Because the base→ext embedding map is a ring homomorphism, fold-then-lift is bit-identical to the old lift-then-fold — pinned by test_mixed_map_reduce_matches_lifted and test_explicit_mixed_fold_matches_fused_fold.
  • provekit-proverprover/src/whir_r1cs.rs: round 0 is hoisted out of the sumcheck loop and computed on the base-field mles (the loop now runs 1..m_0); the per-round coefficient combination (hhat + rho·g_poly, saved-value equality) is extracted verbatim into combined_round_message and shared by round 0 and the loop.
  • provekit-backend-bn254mavros_prove.rs passes the embedding (&Identity::new()) and the base-field mles into the prover; identity embedding ⇒ no-op, transcript unchanged.
  • Profiling (#[ignore]d)tooling/provekit-fixtures/tests/profile.rs: a size sweep (BF vs EF vs bn254, 2^14..2^20) and a 2^20 goldilocks-BF flamegraph + stage breakdown. Timing excludes scheme construction and harness clones. Dev-deps inferno / tracing-flame are scoped to provekit-fixtures only.

Transcript / soundness

The prover round messages, challenge draw order, and the separate ext blinding commitment are unchanged from #470 — the verifier is untouched and replays the identical Fiat-Shamir transcript. Round 0's base-field evaluations equal the old extension-lifted ones because map is a ring homomorphism (map(a·b − c) = map(a)·map(b) − map(c), map(0) = 0 for zero-padding). Both bn254 and goldilocks fixtures still prove→verify.

Out of scope (tracked separately)

Same as #470: this does not touch the Go recursive-verifier/ or the provekit-gnark bridge. The reported ~5% is from the local flamegraph probe, not a CI-enforced benchmark.

Verification

  • cargo fmt --all --check, cargo clippy --all-targets --all-features, cargo build --all-targets --all-features — all green, no new warnings.
  • cargo build --locked -p provekit-fixtures — merged Cargo.lock self-consistent with the new inferno/tracing-flame pins.
  • provekit-common 87 (incl. the base/ext parity tests), provekit-r1cs-compiler 41.
  • Fixtures over both fields: bn254 7 roundtrip + 6 soundness, goldilocks 7 + 6 — all pass. Profiling probes are #[ignore]d.

Commits

5 commits: profiling probes (ignored) · doc-comment rewrap · base-field sumcheck round helpers (common) · first sumcheck round in the base field (prover + bn254 call-site) · review follow-ups (hoist 1/2 inverse out of the per-round loop, move the profiling dev-deps to [workspace.dependencies], dedup the single-commit timed prove into the fixtures harness).

shreyas-londhe and others added 5 commits July 9, 2026 06:57
Two #[ignore] probes for manual profiling: a size sweep (BF vs EF vs bn254,
2^14..2^20) and a 2^20 goldilocks-BF flamegraph + stage breakdown. Timing
excludes scheme construction and harness clones (prove_setup builds inputs
outside the timer; time_prove_core measures only commit + prove_noir), and
the flame layer installs after fixture generation, so the numbers reflect
the true prove core. Profiling-only deps (inferno, tracing-flame).
cargo fmt rewrapping of comments trimmed in earlier commits; no code change.
Round 1 of the Spartan sumcheck can consume base-field a, b, c directly
(one mixed mul per point against the ext eq) instead of lifting them
first; the fold at the first challenge does the lift. These helpers
provide that round evaluation and fold, with parity against the
existing fused ext path pinned by tests.
The witness bounds a, b, c were lifted to the extension before the
sumcheck, paying ext arithmetic on base data for every round. The first
round (half the sumcheck work) now consumes them directly — base
products with one mixed mul per point against the ext eq — and the fold
at the first challenge does the lift. Transcript values are unchanged
(subfield arithmetic, same elements), so the verifier and proof format
are untouched; bn254 rides the same path via Identity.

~5% prove @2^20 goldilocks-BF, no bn254 regression.
- prover: precompute 1/2 once and pass it into combined_round_message
  instead of recomputing a field inverse every round (transcript-identical)
- deps: move inferno/tracing-flame to root [workspace.dependencies]
- fixtures: relocate the single-commit timed prove into harness.rs and
  point the flamegraph probe at target/profile/
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs-provekit-org Ready Ready Preview Jul 9, 2026 2:20am

Request Review

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

CSP benchmarks

Metric Value
Workflow status [PASS] success
Commit f126689344ca
Run #28989510584
Circuits benchmarked 21
Iterations averaged per circuit 3

Prover time, peak RSS, peak heap, and verifier time are arithmetic means across the iterations. Peak heap comes from the largest peak memory entry in provekit-cli prove's tracing output; peak RSS is reported by /usr/bin/time -v (max-resident-set-size).

Each metric cell shows the current value followed by the percentage delta against the latest successful main run #28917281870. (new) marks circuits absent from the baseline.

Results
Circuit Constraints Witnesses Prover time Peak RSS Peak heap Verifier time Proof size PKP size
ecdsa_p256 143,321 (±0.0%) 258,215 (±0.0%) 1.75 s (-33.6%) 226 MB (-11.8%) 188 MB (-16.5%) 90 ms (-73.8%) 301 KB (-89.5%) 811 KB (±0.0%)
keccak_1024 788,814 (±0.0%) 1,490,812 (±0.0%) 5.13 s (-18.9%) 897 MB (-7.9%) 874 MB (-6.9%) 460 ms (-44.4%) 371 KB (-88.5%) 5.88 MB (±0.0%)
keccak_128 157,522 (±0.0%) 304,529 (±0.0%) 1.22 s (-42.3%) 236 MB (-13.8%) 202 MB (-15.5%) 110 ms (-69.4%) 309 KB (-89.2%) 1.26 MB (±0.0%)
keccak_2048 1,507,374 (±0.0%) 2,840,532 (±0.0%) 10.09 s (-13.6%) 1.70 GB (-4.5%) 1.68 GB (-5.3%) 830 ms (-41.4%) 386 KB (-88.4%) 11.97 MB (±0.0%)
keccak_256 247,782 (±0.0%) 474,010 (±0.0%) 1.40 s (-39.5%) 290 MB (-10.9%) 249 MB (-13.1%) 150 ms (-62.8%) 330 KB (-88.6%) 1.88 MB (±0.0%)
keccak_512 428,126 (±0.0%) 812,944 (±0.0%) 2.62 s (-27.3%) 541 MB (-6.9%) 455 MB (-9.5%) 243 ms (-54.7%) 352 KB (-88.5%) 3.32 MB (±0.0%)
poseidon2_12 479 (±0.0%) 563 (±0.0%) 40 ms (-88.7%) 12.65 MB (-48.3%) 3.26 MB (-77.8%) 73.02 KB (-93.2%) 436 KB (±0.0%)
poseidon2_16 556 (±0.0%) 719 (±0.0%) 40 ms (-88.6%) 13.14 MB (-47.0%) 3.46 MB (-76.7%) 10 ms (-90.0%) 76.04 KB (-92.9%) 530 KB (±0.0%)
poseidon2_2 231 (±0.0%) 278 (±0.0%) 30 ms (-91.3%) 11.69 MB (-50.6%) 2.72 MB (-80.7%) 68.86 KB (-93.7%) 108 KB (±0.0%)
poseidon2_4 529 (±0.0%) 535 (±0.0%) 30 ms (-91.2%) 12.04 MB (-49.6%) 2.86 MB (-80.0%) 72.93 KB (-93.2%) 31.66 KB (±0.0%)
poseidon2_8 363 (±0.0%) 423 (±0.0%) 30 ms (-91.5%) 12.72 MB (-48.5%) 3.15 MB (-78.3%) 71.02 KB (-93.2%) 365 KB (±0.0%)
poseidon_12 504 (±0.0%) 524 (±0.0%) 37 ms (-89.7%) 13.14 MB (-47.0%) 3.53 MB (-76.3%) 10 ms (-90.0%) 75.24 KB (-93.1%) 569 KB (±0.0%)
poseidon_16 609 (±0.0%) 633 (±0.0%) 40 ms (-88.9%) 13.66 MB (-45.2%) 3.98 MB (-73.8%) 10 ms (-90.0%) 73.57 KB (-92.9%) 717 KB (±0.0%)
poseidon_2 240 (±0.0%) 249 (±0.0%) 30 ms (-91.3%) 11.78 MB (-49.9%) 2.68 MB (-80.9%) 66.10 KB (-93.7%) 59.18 KB (±0.0%)
poseidon_4 297 (±0.0%) 309 (±0.0%) 30 ms (-91.5%) 12.38 MB (-48.8%) 3.10 MB (-78.6%) 69.29 KB (-93.5%) 332 KB (±0.0%)
poseidon_8 402 (±0.0%) 418 (±0.0%) 30 ms (-91.4%) 12.56 MB (-48.6%) 3.29 MB (-77.6%) 71.92 KB (-93.2%) 448 KB (±0.0%)
sha256_1024 196,940 (±0.0%) 339,764 (±0.0%) 1.31 s (-40.9%) 270 MB (-12.4%) 236 MB (-13.8%) 160 ms (-61.6%) 315 KB (-89.1%) 1.91 MB (+3.0%)
sha256_128 46,398 (±0.0%) 80,974 (±0.0%) 320 ms (-70.6%) 76.66 MB (-24.4%) 55.50 MB (-33.6%) 40 ms (-84.6%) 298 KB (-88.6%) 512 KB (+1.4%)
sha256_2048 345,399 (±0.0%) 612,724 (±0.0%) 2.59 s (-28.2%) 515 MB (-6.0%) 436 MB (-9.9%) 297 ms (-50.8%) 342 KB (-88.6%) 3.02 MB (-0.5%)
sha256_256 67,904 (±0.0%) 117,944 (±0.0%) 560 ms (-59.7%) 123 MB (-17.9%) 98.23 MB (-24.6%) 60 ms (-79.3%) 278 KB (-89.7%) 726 KB (+2.1%)
sha256_512 110,916 (±0.0%) 191,884 (±0.0%) 683 ms (-54.9%) 150 MB (-16.3%) 126 MB (-20.2%) 90 ms (-72.5%) 293 KB (-89.3%) 1.10 MB (-1.1%)

@BornPsych BornPsych marked this pull request as ready for review July 10, 2026 11:48
@shreyas-londhe shreyas-londhe self-requested a review July 13, 2026 05:19
@BornPsych BornPsych requested a review from zkfriendly July 13, 2026 09:46

@shreyas-londhe shreyas-londhe left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zkfriendly zkfriendly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

alpha.push(alpha_0);

// Fold at the first challenge, lifting the mles into the extension.
let folded_a = mixed_fold(embedding, &a, alpha_0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mixed_fold breaks the prior fused fold/reduce path, adding four allocations and another scan. This is not a no-op for BN254 Identity. We can address this later since the focus is Goldilocks

@shreyas-londhe shreyas-londhe merged commit 100691c into feat/base-field-witness-commit Jul 13, 2026
11 checks passed
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.

3 participants