Skip to content

perf(prover): collapse R1CS row-covectors into one before WHIR#446

Draft
BornPsych wants to merge 3 commits into
worldfnd:v1from
BornPsych:perf/direct-rlc-r1cs-covectors
Draft

perf(prover): collapse R1CS row-covectors into one before WHIR#446
BornPsych wants to merge 3 commits into
worldfnd:v1from
BornPsych:perf/direct-rlc-r1cs-covectors

Conversation

@BornPsych
Copy link
Copy Markdown

@BornPsych BornPsych commented May 22, 2026

Summary

R1CS row-covectors a, b, c (~32 MB each at m=20) were each wrapped in their own PrefixCovector and passed to whir.prove as three separate linear forms. WHIR's prepare_and_sumcheck then sampled one FS challenge and folded them into a single covector internally. The three intermediate dense vectors stayed resident across the setup until WHIR consumed them, even though only the combined linear form had any
downstream use.

This PR moves the row-RLC into provekit: sample inner_rlc from the prover transcript right after the three matrix evaluations are sent, fold a, b, c into a single PrefixCovector via the new build_combined_prefix_covector helper, and pass one LF to whir.prove instead of three. Verifier mirrors at the same transcript position; soundness follows from inner_rlc being bound to all three evals before being drawn.

Same direct-RLC applies to the dual-commit path with one shared inner_rlc across both commitments.

WHIR itself is unchanged — the LF count it receives just shrinks from three to one. geometric_challenge(1) short-circuits to [ONE] with no extra FS sample, so the only transcript-level change is the new inner_rlc sample on the provekit side.

Measured impact

Single run, complete_age_check. Baseline used was v1 + the perf(prover): drop R1CS after sumcheck … commit (raised separately). Numbers are for the eventual merged state of both PRs.

Metric baseline this PR Δ
Run peak memory 816 MB 766 MB −50 MB / −6.1%
prove_with_toml duration 1.96 s 1.93 s within noise
Allocations 3.56M 3.56M 0

Removes three now-dead helpers from prover/src/whir_r1cs.rs (create_weights_and_evaluations, compute_evaluations, compute_public_weight_evaluation), and refactors the public-inputs-hash absorption into read_public_inputs_challenge so the public-weight covector is built lazily only when needed.

Test plan

  • cargo test -p provekit-bench --test compiler --release — 16 passed (incl. complete_age_check, test_public_input_binding_exploit)
  • provekit-cli proveprovekit-cli verify round-trip on complete_age_check
  • Dual-commit circuits (small-sha, read_write_memory, etc.) round-trip
  • Bench additional circuits (t_add_dsc_1850, t_add_id_data_1850) to confirm percentage scales

Rollback

Revert the single commit. The protocol modification is local: one
extra verifier_message() sample in provekit's prover/verifier, no
WHIR-side changes.

WhirR1CSScheme::prove computes three dense row-covectors a, b, c via
calculate_external_row_of_r1cs_matrices and previously wrapped each
in its own PrefixCovector before passing the trio to whir.prove. WHIR
then sampled a single FS challenge (constraint_rlc_coeffs) and folded
the three covectors into one inside prepare_and_sumcheck.

The three intermediate dense vectors (~32 MB each at m=20) stayed
resident through the entire setup until WHIR consumed them, even
though only the combined linear form had any downstream use.

Sample inner_rlc in the provekit transcript right after the three
matrix evaluations are sent, fold a, b, c into a single PrefixCovector
via the new build_combined_prefix_covector helper, and pass one LF to
whir.prove instead of three. Verifier mirrors the same sample order
so the FS state matches; soundness follows from inner_rlc being bound
to all three evals before being drawn.

Same direct-RLC applies to the dual-commit path with one shared
inner_rlc across both commitments; sampled after every alpha eval and
optional public/challenge eval is absorbed.

Measured on complete_age_check (v1 baseline e599840, single-commit):

  - run peak memory:    816 MB -> 766 MB (-50 MB, -6.1%)
  - prove_with_toml:    1.96 s -> 1.93 s (within noise)
  - allocations:        3.56M -> 3.56M  (no change)
  - 16/16 integration tests pass, including
    test_public_input_binding_exploit

Removes three now-dead helpers from prover/src/whir_r1cs.rs:
create_weights_and_evaluations, compute_evaluations,
compute_public_weight_evaluation.
@BornPsych BornPsych force-pushed the perf/direct-rlc-r1cs-covectors branch from 55b3263 to 5d13860 Compare May 22, 2026 17:34
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