-
Notifications
You must be signed in to change notification settings - Fork 17
BatchVerifier #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: batch-ring-proof
Are you sure you want to change the base?
BatchVerifier #66
Changes from 12 commits
06bbc1a
9af0789
3764010
237aa06
4472567
c771d38
0c3588f
75ecdce
ed6d7c4
29e47bc
c885dd7
2fbd0cb
5638cee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,12 +2,13 @@ use ark_ec::pairing::Pairing; | |
| use ark_ec::twisted_edwards::{Affine, TECurveConfig}; | ||
| use ark_ec::CurveGroup; | ||
| use ark_ff::PrimeField; | ||
| use ark_std::rand::RngCore; | ||
| use w3f_pcs::pcs::kzg::KZG; | ||
| use w3f_pcs::pcs::{RawVerifierKey, PCS}; | ||
| use w3f_plonk_common::kzg_acc::KzgAccumulator; | ||
| use w3f_plonk_common::piop::VerifierPiop; | ||
| use w3f_plonk_common::transcript::PlonkTranscript; | ||
| use w3f_plonk_common::verifier::PlonkVerifier; | ||
| use w3f_plonk_common::verifier::{Challenges, PlonkVerifier}; | ||
|
|
||
| use crate::piop::params::PiopParams; | ||
| use crate::piop::{FixedColumnsCommitted, PiopVerifier, VerifierKey}; | ||
|
|
@@ -89,40 +90,132 @@ where | |
| } | ||
| } | ||
|
|
||
| impl<E, Jubjub, T> RingVerifier<E::ScalarField, KZG<E>, Jubjub, T> | ||
| /// Accumulating batch verifier for ring proofs using KZG polynomial commitment scheme. | ||
| pub struct KzgBatchVerifier<E, J, T = ArkTranscript> | ||
| where | ||
| E: Pairing, | ||
| Jubjub: TECurveConfig<BaseField = E::ScalarField>, | ||
| J: TECurveConfig<BaseField = E::ScalarField>, | ||
| T: PlonkTranscript<E::ScalarField, KZG<E>>, | ||
| { | ||
| // Verifies a batch of proofs against the same ring. | ||
| pub fn verify_batch_kzg( | ||
| pub acc: KzgAccumulator<E>, | ||
| pub verifier: RingVerifier<E::ScalarField, KZG<E>, J, T>, | ||
| } | ||
|
|
||
| /// A ring proof that has been preprocessed for batch verification. | ||
| pub struct PreparedBatchItem<E, J> | ||
| where | ||
| E: Pairing, | ||
| J: TECurveConfig<BaseField = E::ScalarField>, | ||
| { | ||
| 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], | ||
| } | ||
|
|
||
| impl<E, J, T> KzgBatchVerifier<E, J, T> | ||
| where | ||
| E: Pairing, | ||
| J: TECurveConfig<BaseField = E::ScalarField>, | ||
| T: PlonkTranscript<E::ScalarField, KZG<E>>, | ||
| { | ||
| /// Prepares a ring proof for batch verification without accumulating it. | ||
| /// | ||
| /// Returns a `PreparedBatchItem` that can later be passed to `push_prepared`. | ||
| /// | ||
| /// This method is independent of the accumulator state, so multiple proofs can be | ||
| /// prepared in parallel (e.g., using `rayon`). Each prepared item is in the order | ||
| /// of a few KB, so for large batches you may want to prepare and push incrementally | ||
| /// rather than holding all prepared items in memory at once. | ||
| pub fn prepare( | ||
| &self, | ||
| proof: RingProof<E::ScalarField, KZG<E>>, | ||
| result: Affine<J>, | ||
| ) -> PreparedBatchItem<E, J> { | ||
| let (challenges, mut rng) = self.verifier.plonk_verifier.restore_challenges( | ||
| &result, | ||
| &proof, | ||
| // '1' accounts for the quotient polynomial that is aggregated together with the columns | ||
| PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<J>>::N_COLUMNS + 1, | ||
| PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<J>>::N_CONSTRAINTS, | ||
| ); | ||
| let seed = self.verifier.piop_params.seed; | ||
| let seed_plus_result = (seed + result).into_affine(); | ||
| let domain_at_zeta = self.verifier.piop_params.domain.evaluate(challenges.zeta); | ||
| let piop = PiopVerifier::<_, _, Affine<J>>::init( | ||
| domain_at_zeta, | ||
| self.verifier.fixed_columns_committed.clone(), | ||
| proof.column_commitments.clone(), | ||
| proof.columns_at_zeta.clone(), | ||
| (seed.x, seed.y), | ||
| (seed_plus_result.x, seed_plus_result.y), | ||
| ); | ||
davxy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Pick some entropy from plonk verifier for later usage | ||
| let mut entropy = [0_u8; 32]; | ||
| rng.fill_bytes(&mut entropy); | ||
|
|
||
| PreparedBatchItem { | ||
| piop, | ||
| proof, | ||
| challenges, | ||
| entropy, | ||
| } | ||
| } | ||
|
Comment on lines
+154
to
+164
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @swasilyev @burdges @drskalman Need some extra attention here. |
||
|
|
||
| /// Accumulates a previously prepared proof into the batch. | ||
| /// | ||
| /// This is the second step of the two-phase batch verification workflow: | ||
| /// 1. `prepare` - can be parallelized across multiple proofs | ||
| /// 2. `push_prepared` - must be called sequentially (mutates the accumulator) | ||
| /// | ||
| /// For simpler usage where parallelism isn't needed, use `push` instead. | ||
| pub fn push_prepared(&mut self, item: PreparedBatchItem<E, J>) { | ||
| let mut ts = self.verifier.plonk_verifier.transcript_prelude.clone(); | ||
| ts._add_serializable(b"batch-entropy", &item.entropy); | ||
| self.acc | ||
| .accumulate(item.piop, item.proof, item.challenges, &mut ts.to_rng()); | ||
| } | ||
|
Comment on lines
+173
to
+178
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @swasilyev @burdges @drskalman here I pick the randomness back to:
|
||
|
|
||
| /// Adds a ring proof to the batch, preparing and accumulating it immediately. | ||
| /// | ||
| /// The proof's pairing equation is aggregated into the internal accumulator. | ||
| /// Call `verify` after pushing all proofs to perform the batched verification. | ||
| pub fn push(&mut self, proof: RingProof<E::ScalarField, KZG<E>>, result: Affine<J>) { | ||
| let item = self.prepare(proof, result); | ||
| self.push_prepared(item); | ||
| } | ||
|
|
||
| /// Verifies all accumulated proofs in a single batched pairing check. | ||
| pub fn verify(&self) -> bool { | ||
| self.acc.verify() | ||
| } | ||
| } | ||
|
|
||
| impl<E, J, T> RingVerifier<E::ScalarField, KZG<E>, J, T> | ||
| where | ||
| E: Pairing, | ||
| J: TECurveConfig<BaseField = E::ScalarField>, | ||
| T: PlonkTranscript<E::ScalarField, KZG<E>>, | ||
| { | ||
| /// Build a new batch verifier. | ||
| pub fn kzg_batch_verifier(self) -> KzgBatchVerifier<E, J, T> { | ||
| KzgBatchVerifier { | ||
| acc: KzgAccumulator::<E>::new(self.plonk_verifier.pcs_vk.clone()), | ||
| verifier: self, | ||
| } | ||
| } | ||
|
|
||
| /// Verifies a batch of proofs against the same ring. | ||
| pub fn verify_batch_kzg( | ||
| self, | ||
| proofs: Vec<RingProof<E::ScalarField, KZG<E>>>, | ||
| results: Vec<Affine<Jubjub>>, | ||
| results: Vec<Affine<J>>, | ||
| ) -> bool { | ||
| let mut acc = KzgAccumulator::<E>::new(self.plonk_verifier.pcs_vk.clone()); | ||
| let mut batch = self.kzg_batch_verifier(); | ||
| for (proof, result) in proofs.into_iter().zip(results) { | ||
| let (challenges, mut rng) = self.plonk_verifier.restore_challenges( | ||
| &result, | ||
| &proof, | ||
| // '1' accounts for the quotient polynomial that is aggregated together with the columns | ||
| PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<Jubjub>>::N_COLUMNS + 1, | ||
| PiopVerifier::<E::ScalarField, <KZG<E> as PCS<_>>::C, Affine<Jubjub>>::N_CONSTRAINTS, | ||
| ); | ||
| let seed = self.piop_params.seed; | ||
| let seed_plus_result = (seed + result).into_affine(); | ||
| let domain_at_zeta = self.piop_params.domain.evaluate(challenges.zeta); | ||
| let piop = PiopVerifier::<_, _, Affine<Jubjub>>::init( | ||
| domain_at_zeta, | ||
| self.fixed_columns_committed.clone(), | ||
| proof.column_commitments.clone(), | ||
| proof.columns_at_zeta.clone(), | ||
| (seed.x, seed.y), | ||
| (seed_plus_result.x, seed_plus_result.y), | ||
| ); | ||
| acc.accumulate(piop, proof, challenges, &mut rng); | ||
| batch.push(proof, result); | ||
| } | ||
| acc.verify() | ||
| batch.verify() | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.