From 6999eb87b793832e4b83d4ce3fe6b4352ff0819e Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 17 Oct 2024 02:08:47 +0100 Subject: [PATCH 1/4] load preprocessed as witness --- snark-verifier-sdk/src/aggregation.rs | 40 ++++++++++++++----- .../src/aggregation/aggregation_circuit.rs | 2 +- .../aggregation/multi_aggregation_circuit.rs | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/snark-verifier-sdk/src/aggregation.rs b/snark-verifier-sdk/src/aggregation.rs index bbf9cde0..11cb40ff 100644 --- a/snark-verifier-sdk/src/aggregation.rs +++ b/snark-verifier-sdk/src/aggregation.rs @@ -10,13 +10,16 @@ use ark_std::start_timer; use halo2_base::{ halo2_proofs::{ circuit::Value, - halo2curves::bn256::{Fr, G1Affine}, + halo2curves::bn256::{Fq, Fr, G1Affine}, }, AssignedValue, }; use itertools::Itertools; use snark_verifier::{ - loader::halo2::EccInstructions, + loader::halo2::{ + halo2_ecc::{ecc::EccChip, fields::fp::FpConfig}, + EcPoint, EccInstructions, Scalar, + }, pcs::{ kzg::{KzgAccumulator, KzgAs}, AccumulationScheme, MultiOpenScheme, PolynomialCommitmentScheme, @@ -58,21 +61,24 @@ pub fn flatten_accumulator<'a>( .collect() } -#[allow(clippy::type_complexity)] +type AssignedInstances<'a> = + Vec>::AssignedScalar>>; +type KzgAcc<'a> = KzgAccumulator>>; +type LoadedEcPoints<'a> = Vec>>>>; +type LoadedScalars<'a> = Vec>>>>; + /// Core function used in `synthesize` to aggregate multiple `snarks`. /// /// Returns the assigned instances of previous snarks and the new final pair that needs to be verified in a pairing check. /// For each previous snark, we concatenate all instances into a single vector. We return a vector of vectors, /// one vector per snark, for convenience. +#[allow(clippy::type_complexity)] pub fn aggregate<'a, PCS>( svk: &PCS::SuccinctVerifyingKey, loader: &Rc>, snarks: &[SnarkWitness], as_proof: Value<&'_ [u8]>, -) -> ( - Vec>::AssignedScalar>>, - KzgAccumulator>>, -) +) -> (AssignedInstances<'a>, KzgAcc<'a>, LoadedEcPoints<'a>, LoadedScalars<'a>) where PCS: PolynomialCommitmentScheme< G1Affine, @@ -89,18 +95,28 @@ where .collect_vec() }; - // TODO pre-allocate capacity better - let mut previous_instances = Vec::with_capacity(snarks.len()); let mut transcript = PoseidonTranscript::>, _>::from_spec( loader, Value::unknown(), POSEIDON_SPEC.clone(), ); + let mut previous_instances = Vec::with_capacity(snarks.len()); + let mut preprocessed_polys = Vec::with_capacity(snarks.len()); + let mut transcript_init_states = Vec::with_capacity(snarks.len()); let mut accumulators = snarks .iter() .flat_map(|snark| { - let protocol = snark.protocol.loaded(loader); + // The SNARK protocol's preprocessed polynomials and the initial state of the + // prover/verifier's transcripts are loaded as witnesses. + // + // This allows us to aggregate SNARKs that may have been generated using one or more + // circuits. + // + // Note: Its important to further constrain the assigned preprocessed polynomial commitments + // and the assigned transcript initial state to belong to a fixed expected set. + let protocol = snark.protocol.loaded_preprocessed_as_witness(loader); + // TODO use 1d vector let instances = assign_instances(&snark.instances); @@ -113,6 +129,8 @@ where previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), ); + preprocessed_polys.push(protocol.preprocessed); + transcript_init_states.push(protocol.transcript_initial_state); accumulator }) @@ -127,5 +145,5 @@ where accumulators.pop().unwrap() }; - (previous_instances, accumulator) + (previous_instances, accumulator, preprocessed_polys, transcript_init_states) } diff --git a/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs b/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs index 51c43e06..3166d821 100644 --- a/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs +++ b/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs @@ -181,7 +181,7 @@ impl Circuit for AggregationCircuit { let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let (_, acc) = + let (_, acc, _, _) = aggregate::(&self.svk, &loader, &self.snarks, self.as_proof()); instances.extend( diff --git a/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs b/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs index 054aec96..c8d345b6 100644 --- a/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs +++ b/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs @@ -129,7 +129,7 @@ impl Circuit for PublicAggregationCircuit { let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let (prev_instances, acc) = aggregate::>( + let (prev_instances, acc, _, _) = aggregate::>( &self.aggregation.svk, &loader, &self.aggregation.snarks, From 7d9868ee25edc1b3e882f60c8f065e801f49f039 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 17 Oct 2024 02:14:17 +0100 Subject: [PATCH 2/4] change fn name --- snark-verifier-sdk/src/aggregation.rs | 71 ++++++++++++++++++- .../src/aggregation/aggregation_circuit.rs | 2 +- .../aggregation/multi_aggregation_circuit.rs | 2 +- snark-verifier-sdk/src/lib.rs | 2 +- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/snark-verifier-sdk/src/aggregation.rs b/snark-verifier-sdk/src/aggregation.rs index 11cb40ff..358aa5b1 100644 --- a/snark-verifier-sdk/src/aggregation.rs +++ b/snark-verifier-sdk/src/aggregation.rs @@ -73,7 +73,7 @@ type LoadedScalars<'a> = Vec( +pub fn aggregate_hybrid<'a, PCS>( svk: &PCS::SuccinctVerifyingKey, loader: &Rc>, snarks: &[SnarkWitness], @@ -147,3 +147,72 @@ where (previous_instances, accumulator, preprocessed_polys, transcript_init_states) } + +#[allow(clippy::type_complexity)] +/// Core function used in `synthesize` to aggregate multiple `snarks`. +/// +/// Returns the assigned instances of previous snarks and the new final pair that needs to be verified in a pairing check. +/// For each previous snark, we concatenate all instances into a single vector. We return a vector of vectors, +/// one vector per snark, for convenience. +pub fn aggregate<'a, PCS>( + svk: &PCS::SuccinctVerifyingKey, + loader: &Rc>, + snarks: &[SnarkWitness], + as_proof: Value<&'_ [u8]>, +) -> (AssignedInstances<'a>, KzgAcc<'a>) +where + PCS: PolynomialCommitmentScheme< + G1Affine, + Rc>, + Accumulator = KzgAccumulator>>, + > + MultiOpenScheme>>, +{ + let assign_instances = |instances: &[Vec>]| { + instances + .iter() + .map(|instances| { + instances.iter().map(|instance| loader.assign_scalar(*instance)).collect_vec() + }) + .collect_vec() + }; + + // TODO pre-allocate capacity better + let mut previous_instances = Vec::with_capacity(snarks.len()); + let mut transcript = PoseidonTranscript::>, _>::from_spec( + loader, + Value::unknown(), + POSEIDON_SPEC.clone(), + ); + + let mut accumulators = snarks + .iter() + .flat_map(|snark| { + let protocol = snark.protocol.loaded(loader); + // TODO use 1d vector + let instances = assign_instances(&snark.instances); + + // read the transcript and perform Fiat-Shamir + // run through verification computation and produce the final pair `succinct` + transcript.new_stream(snark.proof()); + let proof = Plonk::::read_proof(svk, &protocol, &instances, &mut transcript); + let accumulator = Plonk::::succinct_verify(svk, &protocol, &instances, &proof); + + previous_instances.push( + instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), + ); + + accumulator + }) + .collect_vec(); + + let accumulator = if accumulators.len() > 1 { + transcript.new_stream(as_proof); + let proof = + KzgAs::::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); + KzgAs::::verify(&Default::default(), &accumulators, &proof).unwrap() + } else { + accumulators.pop().unwrap() + }; + + (previous_instances, accumulator) +} diff --git a/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs b/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs index 3166d821..51c43e06 100644 --- a/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs +++ b/snark-verifier-sdk/src/aggregation/aggregation_circuit.rs @@ -181,7 +181,7 @@ impl Circuit for AggregationCircuit { let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let (_, acc, _, _) = + let (_, acc) = aggregate::(&self.svk, &loader, &self.snarks, self.as_proof()); instances.extend( diff --git a/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs b/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs index c8d345b6..054aec96 100644 --- a/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs +++ b/snark-verifier-sdk/src/aggregation/multi_aggregation_circuit.rs @@ -129,7 +129,7 @@ impl Circuit for PublicAggregationCircuit { let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let (prev_instances, acc, _, _) = aggregate::>( + let (prev_instances, acc) = aggregate::>( &self.aggregation.svk, &loader, &self.aggregation.snarks, diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index 439924dc..2a873e58 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -18,7 +18,7 @@ pub mod types; pub use aggregation::aggregation_circuit::AggregationCircuit; pub use aggregation::load_verify_circuit_degree; pub use aggregation::multi_aggregation_circuit::PublicAggregationCircuit; -pub use aggregation::{aggregate, flatten_accumulator}; +pub use aggregation::{aggregate, aggregate_hybrid, flatten_accumulator}; pub use circuit_ext::CircuitExt; pub use param::{BITS, LIMBS}; pub use snark::gen_dummy_snark; From 0d7c3ae2ea12b864fe8e361c1a2662039ac6c626 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 14:59:43 +0100 Subject: [PATCH 3/4] return assigned values (so that loader's rc is not still borrowed) --- snark-verifier-sdk/src/aggregation.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/snark-verifier-sdk/src/aggregation.rs b/snark-verifier-sdk/src/aggregation.rs index 358aa5b1..0c052f35 100644 --- a/snark-verifier-sdk/src/aggregation.rs +++ b/snark-verifier-sdk/src/aggregation.rs @@ -18,7 +18,7 @@ use itertools::Itertools; use snark_verifier::{ loader::halo2::{ halo2_ecc::{ecc::EccChip, fields::fp::FpConfig}, - EcPoint, EccInstructions, Scalar, + EccInstructions, }, pcs::{ kzg::{KzgAccumulator, KzgAs}, @@ -44,8 +44,8 @@ pub fn load_verify_circuit_degree() -> u32 { params.degree } -pub fn flatten_accumulator<'a>( - accumulator: KzgAccumulator>>, +pub fn flatten_accumulator( + accumulator: KzgAccumulator>, ) -> Vec> { let KzgAccumulator { lhs, rhs } = accumulator; let lhs = lhs.into_assigned(); @@ -55,17 +55,19 @@ pub fn flatten_accumulator<'a>( .truncation .limbs .into_iter() - .chain(lhs.y.truncation.limbs.into_iter()) - .chain(rhs.x.truncation.limbs.into_iter()) - .chain(rhs.y.truncation.limbs.into_iter()) + .chain(lhs.y.truncation.limbs) + .chain(rhs.x.truncation.limbs) + .chain(rhs.y.truncation.limbs) .collect() } type AssignedInstances<'a> = Vec>::AssignedScalar>>; type KzgAcc<'a> = KzgAccumulator>>; -type LoadedEcPoints<'a> = Vec>>>>; -type LoadedScalars<'a> = Vec>>>>; +type AssignedEcPoints<'a> = + Vec> as EccInstructions<'a, G1Affine>>::AssignedEcPoint>>; +type AssignedScalars<'a> = + Vec> as EccInstructions<'a, G1Affine>>::AssignedScalar>>; /// Core function used in `synthesize` to aggregate multiple `snarks`. /// @@ -78,7 +80,7 @@ pub fn aggregate_hybrid<'a, PCS>( loader: &Rc>, snarks: &[SnarkWitness], as_proof: Value<&'_ [u8]>, -) -> (AssignedInstances<'a>, KzgAcc<'a>, LoadedEcPoints<'a>, LoadedScalars<'a>) +) -> (AssignedInstances<'a>, KzgAcc<'a>, AssignedEcPoints<'a>, AssignedScalars<'a>) where PCS: PolynomialCommitmentScheme< G1Affine, @@ -129,8 +131,10 @@ where previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), ); - preprocessed_polys.push(protocol.preprocessed); - transcript_init_states.push(protocol.transcript_initial_state); + preprocessed_polys + .push(protocol.preprocessed.into_iter().map(|ec| ec.into_assigned()).collect()); + transcript_init_states + .push(protocol.transcript_initial_state.map(|s| s.into_assigned())); accumulator }) From 5bfda265224ecc0555f263b15fef259211db67e9 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 5 Nov 2024 08:19:10 +0000 Subject: [PATCH 4/4] chore: rename function --- snark-verifier-sdk/src/aggregation.rs | 9 +++++++-- snark-verifier-sdk/src/lib.rs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/snark-verifier-sdk/src/aggregation.rs b/snark-verifier-sdk/src/aggregation.rs index 0c052f35..2afe4e5b 100644 --- a/snark-verifier-sdk/src/aggregation.rs +++ b/snark-verifier-sdk/src/aggregation.rs @@ -74,8 +74,13 @@ type AssignedScalars<'a> = /// Returns the assigned instances of previous snarks and the new final pair that needs to be verified in a pairing check. /// For each previous snark, we concatenate all instances into a single vector. We return a vector of vectors, /// one vector per snark, for convenience. +/// +/// The difference between [`aggregate_as_witness`] and [`aggregate`] is that `aggregate` loads +/// the [`Protocol`][snark_verifier::Protocol] of all SNARKs as constants. Whereas in +/// [`aggregate_as_witness`] we load them as witness and return the preprocessed polynomials and +/// the transcript initial states. #[allow(clippy::type_complexity)] -pub fn aggregate_hybrid<'a, PCS>( +pub fn aggregate_as_witness<'a, PCS>( svk: &PCS::SuccinctVerifyingKey, loader: &Rc>, snarks: &[SnarkWitness], @@ -152,12 +157,12 @@ where (previous_instances, accumulator, preprocessed_polys, transcript_init_states) } -#[allow(clippy::type_complexity)] /// Core function used in `synthesize` to aggregate multiple `snarks`. /// /// Returns the assigned instances of previous snarks and the new final pair that needs to be verified in a pairing check. /// For each previous snark, we concatenate all instances into a single vector. We return a vector of vectors, /// one vector per snark, for convenience. +#[allow(clippy::type_complexity)] pub fn aggregate<'a, PCS>( svk: &PCS::SuccinctVerifyingKey, loader: &Rc>, diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index 2a873e58..d691246a 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -18,7 +18,7 @@ pub mod types; pub use aggregation::aggregation_circuit::AggregationCircuit; pub use aggregation::load_verify_circuit_degree; pub use aggregation::multi_aggregation_circuit::PublicAggregationCircuit; -pub use aggregation::{aggregate, aggregate_hybrid, flatten_accumulator}; +pub use aggregation::{aggregate, aggregate_as_witness, flatten_accumulator}; pub use circuit_ext::CircuitExt; pub use param::{BITS, LIMBS}; pub use snark::gen_dummy_snark;