You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The one-circuit parallel permutation path already recognizes its two sparse
product sets, but discarded their set indices before commitment. That forced
both products through generic 2,048-base Lagrange MSMs.
Every multi-circuit proof already takes prepare_batch, including both two-
and four-Action Orchard proofs. That path retains UnpreparedSet::Scheduled { set_index } and uses the key-specific difference
bases. This PR only closes the single-circuit routing omission: it carries the
private set index through product construction and calls the same existing
prepared-difference helper. It adds no cache.
The retained cache is independent of the circuit witness and circuit index.
Key generation derives it only from the proving key's fixed identity-cell
mapping, active-row schedule, Lagrange suffix sums, and blinding generator.
Each proof still derives the commitment scalars from its own product
polynomial.
Benchmarks
Rust 1.97.1, balanced alternating control/candidate pairs, first proof after
building and preparing a fresh proving key. Every pair produced identical
proof bytes and hashes. The benchmark base was 3729c32; the subsequently
merged #477 changes the disjoint multi-opening phase, and the rebased commit's
permutation byte-equivalence test passes on current main.
Apple M4 (Mac16,10), 10 Rayon workers, 160 one-Action pairs:
permutation phase: 2.120030 ms -> 1.528187 ms, -0.591843 ms;
paired bootstrap 95% CI [-0.621418, -0.562849] ms
complete proof: 43.546495 ms -> 42.866591 ms, -0.679904 ms;
95% CI [-0.802080, -0.560407] ms
x86-64 Linux, 6 Rayon workers, explicit x86_64-asm, 160 one-Action
pairs:
complete proof: 92.737180 ms -> 91.537239 ms, -1.199941 ms;
95% CI [-1.721505, -0.687688] ms
The multi-Action path already used the prepared difference commitments and is
unchanged. Its screens detected no regression: the M4 four-Action
permutation-phase CI was [-0.190372, +0.036528] ms across 64 pairs, and the
Linux complete-proof CI was [-1.629897, +0.620813] ms across 48 pairs.
Key generation, proving-key preparation, retained memory, RNG order,
transcript order, proof bytes, and public APIs are unchanged.
API surface: no pub, pub(crate), visibility, signature, trait, enum-variant,
alias, constant, constructor, or function-signature changes. The only new
field is private to the permutation prover module.
Zero common factor breaks sparse difference commitment
The single-circuit parallel permutation path now routes every sparse product set through commit_prepared_difference, whose precomputed bases only encode changes at suffix_rows = {0} ∪ {active.row+1} ∪ {fraction_rows+1..domain_size} derived from keygen's ActivePermutationSet. However, the single-circuit sparse product deliberately reproduces dense zero-denominator semantics: when an identity cell's common factor (beta*delta*omega^row + gamma + value) evaluates to zero, sparse_prefix_products zeroes the product from first_cancelled_zero + 1 through fraction_rows, and first_cancelled_zero can be an all-identity row that is not an active row (exactly the scenario unit-tested by sparse_product_preserves_common_zeros_at_boundaries, where all-identity rows carry the zero factor). The resulting change at index first_cancelled_zero + 1 is not in suffix_rows, so the difference-commitment scalars omit it and the commitment is computed to a different piecewise-constant polynomial than the actual product z used for the polynomial, coset, evaluations, and IPA argument. The invariant is only checked by a debug_assert! inside commit_prepared_difference (prover.rs:1421-1423), so release builds silently produce the wrong commitment. The multi-circuit batch path is immune because prepare_scheduled_fractions hard-codes first_cancelled_zero: None (prover.rs:833), making this a gap specific to the newly routed single-circuit path; before this PR that path committed the same product generically and correctly.
Confirmed. A cancelled common zero on an inactive row introduces a product transition at row + 1 that is absent from the keygen-prepared suffix support, so the release-only route could commit to a different polynomial. The PR now falls back to the generic Lagrange commitment for any sparse set with first_cancelled_zero.is_some(). The prepared path remains unchanged for ordinary challenges. Added cancelled_common_zero_disables_prepared_difference_commitment; all six permutation-prover tests pass in release mode. Keeping the PR in draft until the refreshed CI matrix is green.
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
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
The one-circuit parallel permutation path already recognizes its two sparse
product sets, but discarded their set indices before commitment. That forced
both products through generic 2,048-base Lagrange MSMs.
Every multi-circuit proof already takes
prepare_batch, including both two-and four-Action Orchard proofs. That path retains
UnpreparedSet::Scheduled { set_index }and uses the key-specific differencebases. This PR only closes the single-circuit routing omission: it carries the
private set index through product construction and calls the same existing
prepared-difference helper. It adds no cache.
The retained cache is independent of the circuit witness and circuit index.
Key generation derives it only from the proving key's fixed identity-cell
mapping, active-row schedule, Lagrange suffix sums, and blinding generator.
Each proof still derives the commitment scalars from its own product
polynomial.
Benchmarks
Rust 1.97.1, balanced alternating control/candidate pairs, first proof after
building and preparing a fresh proving key. Every pair produced identical
proof bytes and hashes. The benchmark base was
3729c32; the subsequentlymerged #477 changes the disjoint multi-opening phase, and the rebased commit's
permutation byte-equivalence test passes on current main.
Mac16,10), 10 Rayon workers, 160 one-Action pairs:paired bootstrap 95% CI [-0.621418, -0.562849] ms
95% CI [-0.802080, -0.560407] ms
x86_64-asm, 160 one-Actionpairs:
95% CI [-1.721505, -0.687688] ms
The multi-Action path already used the prepared difference commitments and is
unchanged. Its screens detected no regression: the M4 four-Action
permutation-phase CI was [-0.190372, +0.036528] ms across 64 pairs, and the
Linux complete-proof CI was [-1.629897, +0.620813] ms across 48 pairs.
Key generation, proving-key preparation, retained memory, RNG order,
transcript order, proof bytes, and public APIs are unchanged.
Tests
cargo fmt --all -- --check./scripts/changelog.py checkcargo +1.97.1 check --locked -p zakura-halo2-proofs --no-default-featurescargo +1.97.1 test --locked --release -p zakura-halo2-proofs --lib plonk::permutation::prover -- --nocaptureRAYON_NUM_THREADS=1 cargo +1.97.1 test --locked --release -p zakura-orchard --features prover-fingerprint --lib circuit::prover_fingerprint::prover_capture -- --exact --nocaptureRAYON_NUM_THREADS=1 cargo +1.97.1 test --locked --release -p zakura-orchard --features prover-fingerprint --lib circuit::prover_fingerprint::prover_capture_two_actions -- --exact --nocaptureAPI surface: no
pub,pub(crate), visibility, signature, trait, enum-variant,alias, constant, constructor, or function-signature changes. The only new
field is private to the permutation prover module.