feat: commit the R1CS witness over the base field (proof format 2.0)#470
Open
BornPsych wants to merge 10 commits into
Open
feat: commit the R1CS witness over the base field (proof format 2.0)#470BornPsych wants to merge 10 commits into
BornPsych wants to merge 10 commits into
Conversation
FIELD_ID tags each field's on-disk proof so one field's proof is rejected by another field's verifier; bn254 reserves 0 for legacy byte-identity. The 2.0 major bump makes an incompatible WhirR1CSScheme/WHIR payload fail fast on read instead of mis-deserializing.
…per field Commit the witness over the base field (whir_witness: GenericWhirConfig <P::Embedding>) and move the Spartan blinding polynomial g to a separate extension-field commitment (whir_blinding). g masks ext-valued sumcheck rounds, so it needs ext randomness and cannot be embedded in a base witness vector; sizing it to 4*m_0 coefficients drops the old m-padding. Make the covector eval helpers embedding-aware (base×ext mixed arithmetic) since the polynomial is now base while eval points are ext. Fold ProofField::FIELD_ID into the .np magic (bn254 id 0 unchanged) so a proof from one field fails another field's format check.
Mirror the scheme split: commit the base-field witness with the non-ZK whir_witness config (no more base->ext lift) and commit the Spartan blinding g with the separate ext whir_blinding config. BlindingState carries g's flattened vector plus its own WHIR witness instead of an offset into the witness padding. The sumcheck sources blinding_eval from the standalone g vector (offset 0), and g is opened by a dedicated whir_blinding.prove after all witness opens, replacing the OffsetCovector-into-the-witness-open. Eval helpers take the embedding for base x ext mixed products.
Receive the ext blinding commitment right after the witness commitment (before challenge sampling), matching the prover's transcript order. Verify the witness with the two-step whir::Config API (verify -> final-claim check) and drop the blinding covector that was mixed into the witness open. Verify g by a dedicated whir_blinding open at the end, against the power covector at offset 0.
GoldilocksField switches its embedding from Identity<Field64_3> to Basefield<Field64_3> (FIELD_ID 1): the witness commits in Field64, with Field64_3 only for challenges and sumcheck — the base-commit path. Add GoldilocksEfField (Identity<Field64_3>, FIELD_ID 2) as a stand-in for challenge-bearing fixtures whose witness holds ext values a base witness can't. Its distinct FIELD_ID reflects the different base byte layout, and its TODO records the concrete removal path (base transcript codec + k-fold repetition for 128-bit soundness). Factor the shared FieldHash glue into a macro over both fields.
Drop the zkWHIR config (WhirZkConfig) — bn254 now uses the same non-ZK base-commit path as every field, with Identity<Fr> so base == ext (no actual base savings, no witness hiding). FIELD_ID 0 keeps the .np format magic byte-identical. mavros_prove sources blinding_eval from the separate g vector, matching the prover.
cli and verifier-server pass whir_witness + whir_blinding to the gnark parameter writer instead of the removed zkWHIR blinded/blinding commitments. The r1cs-compiler security tests check the two new configs (new_witness_config_for_size + new_blinding_config_for_size), and the dimension test drops to m=13 (the blinding-room padding bump is gone).
WhirR1CSProver now requires Standard: Distribution<Base<P>>; add it to the harness runners that prove.
Split the roundtrip/soundness macros into base-compatible and challenge-bearing suites. GoldilocksField runs the base suites (real base-leaf commitment); GoldilocksEfField runs the challenge suites (ext witness holds challenge values). bn254 runs both on itself. Thread the base-sampling bound through the shared helpers.
Complete the base-sampling bound on `tampered_public_input_is_rejected` with `Distribution<Base<P>>` — the merge left it with only the ext bound, but the generic test body commits in the base field via `prove`. Rewrap the `np_format` doc comment to satisfy rustfmt. Reuse the `next_power_of_two` helper for `nv_blind` instead of a re-implemented ceil-log2, and describe `GoldilocksEfField` by its purpose (identity-embedding Goldilocks for challenge-bearing circuits).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
CSP benchmarks
Prover time, peak RSS, peak heap, and verifier time are arithmetic means across the iterations. Peak heap comes from the largest Each metric cell shows the current value followed by the percentage delta against the latest successful Results
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Commits the R1CS witness over the base field and moves the Spartan blinding
polynomial
gto a separate extension-field commitment, instead of committing thewhole witness (padded with the blinding coefficients) in the extension field. The proof
format is bumped to 2.0 and tagged per field so one field's proof is rejected by
another field's verifier. bn254 and Goldilocks both ride the new uniform non-ZK
base-commit path.
Builds on the field-generic spine + two-backend work (#458/#459/#460). Independent of the
CI guard PR (#469).
Why
Goldilocks is a 64-bit prime: its whole value is that committed data (witness, matrix
coefficients) stays in the base field
Field64, with only challenges/sumcheck in thedegree-3 extension
Field64_3. The old scheme committed the witness in the extension andpadded
w1with room for the blinding polynomial — that forces base data throughextension-width commitments and couples witness sizing to blinding room. Splitting the two
commitments lets the witness commit natively in the base field and sizes the blinding
commitment to just its
4 * m_0cubic coefficients.What changed
provekit-common—WhirR1CSSchemegainswhir_witness: GenericWhirConfig<P::Embedding>(base-field, non-ZK) and a separate
whir_blinding: GenericWhirConfig<Identity<Ext<P>>>;new
new_witness_config_for_size/new_blinding_config_for_size/whir_protocol_params;the old
4 * m_0w1-padding is gone..npformat magic is derived fromProofField::FIELD_ID(np_format); all format versions bump to2.0(major must matchon read). Covector eval helpers are embedding-aware (base × ext).
provekit-prover— commits the base-field witness withwhir_witness(no base→extlift) and commits
gwith the separatewhir_blinding;BlindingStatecarriesg's ownvector + WHIR witness;
gis opened by a dedicatedwhir_blinding.proveafter the witnessopens.
provekit-verifier— receives the ext blinding commitment right after the witnesscommitment (matching prover transcript order), verifies the witness with the two-step
whir::ConfigAPI, and verifiesgby a dedicated open at the end.Identity<Fr>,FIELD_ID 0,.npmagic byte-identical); Goldilocks switches toBasefield<Field64_3>(
FIELD_ID 1). AddsGoldilocksEfField(Identity<Field64_3>,FIELD_ID 2) as a stand-infor challenge-bearing fixtures.
whir_witness+whir_blindingto thegnark writer; r1cs-compiler security tests check the two new configs (dimension test drops
to
m = 13); fixtures route base vs challenge suites to the right field.Caveats
GoldilocksEfFieldis a stand-in. A singleField64challenge is only ~64-bit sound,so challenge-bearing fixtures run on the ext-leaf field until a base transcript codec +
k-fold repetition land (see the
TODOingoldilocks/src/field.rs).sumcheck ZK only, not witness ZK (
whir_witnessTODO).Out of scope (tracked separately)
This PR changes only the Rust WHIR proving/verifying path. It intentionally does not touch:
recursive-verifier/(which still parses the old fused zkWHIR commitment layout), orprovekit-gnarkbridge / Groth16 prover path.Consequence: the WHIR →
recursive-verifier(Go) → Groth16 on-chain route will not verify2.0 proofs until a paired Go update lands, tracked as follow-up. The direct Groth16+BSB22
backend (#427 / #447) is a separate crate and is unaffected by this change (the two only share
a few tooling files). This keeps the PR focused on the Rust proof-system change; the
recursive-verifier port is deliberately left for a coordinated follow-up.
Verification
cargo fmt --all --check,cargo clippy --all-targets --all-features(no new errors),cargo check --all-targets --all-featuresgreen.6 soundness — all pass.
provekit-r1cs-compiler41 tests pass (security + dimension, split config).Commits
9 authored commits (base-field split across common / prover / verifier / backends / tooling /
fixtures) plus one commit reconciling the base-sampling bound and rustfmt onto current
main.