Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions w3f-plonk-common/src/kzg_acc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,24 @@ impl<E: Pairing> KzgAccumulator<E> {
// `Ci = ai_1.Ci_1 + ... + ai_ni.Ci_ni, i = 1,...,k`,
// `acc` is a `1+k+(n1+...+nk)`-MSM.

/// Accumulates
pub fn accumulate<F, Piop, Commitments, Evaluations, R: Rng>(
/// 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<F, Piop, Commitments, Evaluations>(
&mut self,
piop: Piop,
proof: Proof<F, KZG<E>, Commitments, Evaluations>,
challenges: Challenges<F>,
rng: &mut R,
r: F,
) where
F: PrimeField,
E: Pairing<ScalarField = F>,
Piop: VerifierPiop<F, <KZG<E> as PCS<F>>::C>,
Commitments: ColumnsCommited<F, <KZG<E> as PCS<F>>::C>,
Evaluations: ColumnsEvaluated<F>,
{
let r = F::rand(rng);
let r2 = r.square();
let zeta = challenges.zeta;

Expand Down Expand Up @@ -133,6 +136,23 @@ impl<E: Pairing> KzgAccumulator<E> {
self.randomizers.push(r2);
}

/// Accumulates a proof into the KZG opening batch, sampling the randomizer from `rng`.
pub fn accumulate<F, Piop, Commitments, Evaluations, R: Rng>(
&mut self,
piop: Piop,
proof: Proof<F, KZG<E>, Commitments, Evaluations>,
challenges: Challenges<F>,
rng: &mut R,
) where
F: PrimeField,
E: Pairing<ScalarField = F>,
Piop: VerifierPiop<F, <KZG<E> as PCS<F>>::C>,
Commitments: ColumnsCommited<F, <KZG<E> as PCS<F>>::C>,
Evaluations: ColumnsEvaluated<F>,
{
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()
Expand Down
5 changes: 1 addition & 4 deletions w3f-ring-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
40 changes: 13 additions & 27 deletions w3f-ring-proof/src/multi_ring_batch_verifier.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<E, J>
where
E: Pairing,
Expand All @@ -23,7 +22,7 @@ where
piop: PiopVerifier<E::ScalarField, <KZG<E> as PCS<E::ScalarField>>::C, Affine<J>>,
proof: RingProof<E::ScalarField, KZG<E>>,
challenges: Challenges<E::ScalarField>,
entropy: [u8; 32],
r: E::ScalarField,
}

impl<E, J> BatchItem<E, J>
Expand Down Expand Up @@ -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,
}
}
}
Expand All @@ -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<E: Pairing, T>
where
T: PlonkTranscript<E::ScalarField, KZG<E>>,
{
/// 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<E: Pairing> {
acc: KzgAccumulator<E>,
transcript: T,
}

impl<E: Pairing, T> BatchVerifier<E, T>
where
T: PlonkTranscript<E::ScalarField, KZG<E>>,
{
impl<E: Pairing> BatchVerifier<E> {
/// Creates a new multi-ring batch verifier.
pub fn new(kzg_vk: KzgVerifierKey<E>, transcript: T) -> Self {
pub fn new(kzg_vk: KzgVerifierKey<E>) -> Self {
Self {
acc: KzgAccumulator::<E>::new(kzg_vk),
transcript,
}
}

/// Adds a ring proof to the batch.
pub fn push<J>(
&mut self,
verifier: &RingVerifier<E::ScalarField, KZG<E>, J, T>,
verifier: &RingVerifier<E::ScalarField, KZG<E>, J>,
proof: RingProof<E::ScalarField, KZG<E>>,
result: Affine<J>,
) where
Expand All @@ -129,10 +117,8 @@ where
where
J: TECurveConfig<BaseField = E::ScalarField>,
{
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.
Expand Down
8 changes: 2 additions & 6 deletions w3f-ring-proof/src/ring_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,10 @@ where
}
}

impl<E, J, T> RingVerifier<E::ScalarField, KZG<E>, J, T>
impl<E, J> RingVerifier<E::ScalarField, KZG<E>, J>
where
E: Pairing,
J: TECurveConfig<BaseField = E::ScalarField>,
T: PlonkTranscript<E::ScalarField, KZG<E>>,
{
/// Verifies a batch of proofs against this ring in a single batched
/// pairing check, using a [`BatchVerifier`] under the hood.
Expand All @@ -107,10 +106,7 @@ where
proofs: Vec<RingProof<E::ScalarField, KZG<E>>>,
results: Vec<Affine<J>>,
) -> 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);
}
Expand Down
Loading