Skip to content

feat: add initial OOD sampling to BitZ commitments - #76

Merged
zkfriendly merged 7 commits into
mainfrom
sl/initial-ood
Sep 30, 2026
Merged

zkfriendly merged 7 commits into
mainfrom
sl/initial-ood

Conversation

@shreyas-londhe

Copy link
Copy Markdown
Collaborator

Add an initial out-of-domain (OOD) evaluation of the committed packed witness before the Spartan and BitZ challenges. Batch that claim into the existing Ligerito opening.

  • Derive OOD grinding from the PCS profile; UDR omits the OOD round.
  • Extend CommitScheme with transcript-aware commitment and verification methods. Retain the same OOD claim for dense and succinct openings.
  • Return CommittedWitness from circuit commitment and consume it during proving, preserving the transcript that sampled the OOD point. Verification receives the claim before replaying circuit proof challenges.

This changes the BitZ and circuit proof transcripts and the circuit commitment API. Raw Pcs::commit remains available without OOD; callers using the OOD path must continue the commitment transcript through opening.

Regression tests cover altered, missing, and truncated OOD values, invalid grinding nonces, and dense/succinct round trips. Focused PCS, BitZ, and circuit tests, Clippy, formatting, and Rustdoc checks passed locally; the all-shapes test reaching m28 was not completed. Byte-for-byte transcript equivalence with BitZ-PoC remains unverified.

@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.

Thanks for the PR, I checked OOD algebra, batching, transcript order, and circuit integration, and all looked good. Left some comments.

Comment thread crates/pcs/src/ood.rs Outdated
Comment on lines +89 to +93
for (chunk, &scale) in basis.chunks_exact_mut(block).zip(&head) {
for (basis, &weight) in chunk.iter_mut().zip(&tail) {
*basis += as_flock_f128(coefficient * scale * weight);
}
}

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.

We can parallelize this for larger inputs, it can be improve by ~7x, based on some experiments:

Packed elements Current Eight threads
2^22 2.964 ms 0.442 ms
2^24 11.911 ms 1.656 ms

Comment thread crates/tests/examples/dump_bitz.rs Outdated

let started = std::time::Instant::now();
let mut transcript = prover_transcript();
let (_, data) = instance

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.

The prove timer now includes commitment creation but before it was not included.

Comment thread crates/tests/tests/prove.rs Outdated

fn prove(instance: &Instance) -> Proof {
let mut transcript = prover_transcript();
let (_, data) = instance

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.

The fixture already commits in benchmark/crates/tests/src/lib.rs line 83. This duplicate commitment can be removed; similar to how CircuitProofSystem already does, we can create one OOD commitment and retain the its transcript. This can free ~80mb during proving.

Comment thread crates/pcs/src/lib.rs Outdated
///
/// Call before witness-dependent challenges and continue with the same transcript.
/// Profiles without initial OOD sampling omit that round.
fn commit_with_ood(

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.

Do we need both commit and commit_with_ood, and both verification methods, in the public API? Could the normal methods handle OOD automatically based on the selected security profile?

This would give callers one standard way to create and verify proofs. We would still keep receive_commitment separate, because circuits need the OOD claim before Spartan starts.

Is there a use case that requires both paths? If so, could we document it? Otherwise, I suggest keeping one main interface to make it easier for callers to use correctly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I agree with exposing the developer with the option to choose the security profile than OOD sampling, and we can consolidate the APIs. Thanks for flagging this!

@zkfriendly
zkfriendly added this pull request to stack #139 September 29, 2026 11:03
@zkfriendly

Copy link
Copy Markdown
Collaborator

The newly added VerifierData associated type can also be avoided. See stacked draft PR: #138

@shreyas-londhe

Copy link
Copy Markdown
Collaborator Author

The newly added VerifierData associated type can also be avoided.

I'll use a shared Commitment for the root and retained OOD claim, as in #138, and remove VerifierData. receive_commitment will construct that state before circuit challenges, and verify_lin will authenticate the claim during opening.

@zkfriendly
zkfriendly merged commit 5cdfbba into main Sep 30, 2026
3 checks passed
@zkfriendly
zkfriendly deleted the sl/initial-ood branch September 30, 2026 09:13
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.

2 participants