diff --git a/w3f-plonk-common/src/kzg_acc.rs b/w3f-plonk-common/src/kzg_acc.rs index 0b7bbeb..e26506d 100644 --- a/w3f-plonk-common/src/kzg_acc.rs +++ b/w3f-plonk-common/src/kzg_acc.rs @@ -62,13 +62,17 @@ impl KzgAccumulator { // `Ci = ai_1.Ci_1 + ... + ai_ni.Ci_ni, i = 1,...,k`, // `acc` is a `1+k+(n1+...+nk)`-MSM. - /// Accumulates - pub fn accumulate( + /// Accumulates a proof into the KZG opening batch using the given randomizer `r`. + /// + /// Like [`accumulate`](Self::accumulate), but takes an explicit randomizer + /// instead of sampling one internally. Useful when `r` is derived from an + /// external source (e.g. a Fiat-Shamir transcript managed by the caller). + pub fn accumulate_with_r( &mut self, piop: Piop, proof: Proof, Commitments, Evaluations>, challenges: Challenges, - rng: &mut R, + r: F, ) where F: PrimeField, E: Pairing, @@ -76,7 +80,6 @@ impl KzgAccumulator { Commitments: ColumnsCommited as PCS>::C>, Evaluations: ColumnsEvaluated, { - let r = F::rand(rng); let r2 = r.square(); let zeta = challenges.zeta; @@ -133,6 +136,23 @@ impl KzgAccumulator { self.randomizers.push(r2); } + /// Accumulates a proof into the KZG opening batch, sampling the randomizer from `rng`. + pub fn accumulate( + &mut self, + piop: Piop, + proof: Proof, Commitments, Evaluations>, + challenges: Challenges, + rng: &mut R, + ) where + F: PrimeField, + E: Pairing, + Piop: VerifierPiop as PCS>::C>, + Commitments: ColumnsCommited as PCS>::C>, + Evaluations: ColumnsEvaluated, + { + self.accumulate_with_r(piop, proof, challenges, F::rand(rng)); + } + pub fn verify(&self) -> bool { let proof = E::G1::msm(&self.kzg_proofs, &self.randomizers) .unwrap() diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 738a845..7ed01b5 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -262,10 +262,7 @@ mod tests { // Multi-ring batch verification use crate::multi_ring_batch_verifier::BatchVerifier; - let mut batch = BatchVerifier::new( - verifier_a.pcs_vk().clone(), - verifier_a.plonk_verifier.transcript_prelude.clone(), - ); + let mut batch = BatchVerifier::new(verifier_a.pcs_vk().clone()); for (result, proof) in claims_a { batch.push(&verifier_a, proof, result); } diff --git a/w3f-ring-proof/src/multi_ring_batch_verifier.rs b/w3f-ring-proof/src/multi_ring_batch_verifier.rs index a21679b..6cfcb94 100644 --- a/w3f-ring-proof/src/multi_ring_batch_verifier.rs +++ b/w3f-ring-proof/src/multi_ring_batch_verifier.rs @@ -1,7 +1,6 @@ use ark_ec::pairing::Pairing; use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::CurveGroup; -use ark_std::rand::RngCore; use w3f_pcs::pcs::kzg::params::KzgVerifierKey; use w3f_pcs::pcs::kzg::KZG; use w3f_pcs::pcs::PCS; @@ -14,7 +13,7 @@ use crate::piop::PiopVerifier; use crate::ring_verifier::RingVerifier; use crate::RingProof; -/// A ring proof preprocessed for multi-ring batch verification. +/// A prepared batch item. pub struct BatchItem where E: Pairing, @@ -23,7 +22,7 @@ where piop: PiopVerifier as PCS>::C, Affine>, proof: RingProof>, challenges: Challenges, - entropy: [u8; 32], + r: E::ScalarField, } impl BatchItem @@ -62,14 +61,14 @@ where (seed_plus_result.x, seed_plus_result.y), ); - let mut entropy = [0_u8; 32]; - rng.fill_bytes(&mut entropy); + use ark_std::UniformRand; + let r = E::ScalarField::rand(&mut rng); Self { piop, proof, challenges, - entropy, + r, } } } @@ -79,36 +78,25 @@ where /// Accumulates proofs from one or more rings (keysets) into a single batched /// pairing check. All rings must share the same KZG SRS. /// -/// Holds its own transcript instance, cloned on each `push_prepared` call so -/// the per-proof entropy can be folded in without touching the originating -/// `RingVerifier`. Per-proof independence is ensured by the entropy derived -/// during preparation (which absorbs the full proof via the per-ring -/// transcript), so the base transcript only needs to be deterministic, not -/// proof-specific. -pub struct BatchVerifier -where - T: PlonkTranscript>, -{ +/// Per-proof independence is ensured by the accumulation randomizer derived +/// during [`BatchItem`] preparation (which replays the full proof transcript +/// via the per-ring verifier). +pub struct BatchVerifier { acc: KzgAccumulator, - transcript: T, } -impl BatchVerifier -where - T: PlonkTranscript>, -{ +impl BatchVerifier { /// Creates a new multi-ring batch verifier. - pub fn new(kzg_vk: KzgVerifierKey, transcript: T) -> Self { + pub fn new(kzg_vk: KzgVerifierKey) -> Self { Self { acc: KzgAccumulator::::new(kzg_vk), - transcript, } } /// Adds a ring proof to the batch. pub fn push( &mut self, - verifier: &RingVerifier, J, T>, + verifier: &RingVerifier, J>, proof: RingProof>, result: Affine, ) where @@ -129,10 +117,8 @@ where where J: TECurveConfig, { - let mut ts = self.transcript.clone(); - ts._add_serializable(b"batch-entropy", &item.entropy); self.acc - .accumulate(item.piop, item.proof, item.challenges, &mut ts.to_rng()); + .accumulate_with_r(item.piop, item.proof, item.challenges, item.r); } /// Verifies all accumulated proofs in a single batched pairing check. diff --git a/w3f-ring-proof/src/ring_verifier.rs b/w3f-ring-proof/src/ring_verifier.rs index 7244d02..2abf340 100644 --- a/w3f-ring-proof/src/ring_verifier.rs +++ b/w3f-ring-proof/src/ring_verifier.rs @@ -94,11 +94,10 @@ where } } -impl RingVerifier, J, T> +impl RingVerifier, J> where E: Pairing, J: TECurveConfig, - T: PlonkTranscript>, { /// Verifies a batch of proofs against this ring in a single batched /// pairing check, using a [`BatchVerifier`] under the hood. @@ -107,10 +106,7 @@ where proofs: Vec>>, results: Vec>, ) -> bool { - let mut batch = BatchVerifier::new( - self.plonk_verifier.pcs_vk.clone(), - self.plonk_verifier.transcript_prelude.clone(), - ); + let mut batch = BatchVerifier::new(self.plonk_verifier.pcs_vk.clone()); for (proof, result) in proofs.into_iter().zip(results) { batch.push(self, proof, result); }