Separate prover and verifier keys in CompressedSNARK (#145) * checkpoint * simplify further * checkpoint * gens --> ck * update benches * address clippy * cleanup * update version
jump to
@@ -1,6 +1,6 @@
[package] name = "nova-snark" -version = "0.16.0" +version = "0.17.0" authors = ["Srinath Setty <srinath@microsoft.com>"] edition = "2021" description = "Recursive zkSNARKs without trusted setup"
@@ -49,6 +49,9 @@ NonTrivialTestCircuit::new(num_cons),
TrivialTestCircuit::default(), ); + // Produce prover and verifier keys for CompressedSNARK + let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp); + // produce a recursive SNARK let num_steps = 3; let mut recursive_snark: Option<RecursiveSNARK<G1, G2, C1, C2>> = None;@@ -84,12 +87,13 @@ group.bench_function("Prove", |b| {
b.iter(|| { assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove( black_box(&pp), + black_box(&pk), black_box(&recursive_snark) ) .is_ok()); }) }); - let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark); + let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); assert!(res.is_ok()); let compressed_snark = res.unwrap();@@ -98,7 +102,7 @@ group.bench_function("Verify", |b| {
b.iter(|| { assert!(black_box(&compressed_snark) .verify( - black_box(&pp), + black_box(&vk), black_box(num_steps), black_box(vec![<G1 as Group>::Scalar::from(2u64)]), black_box(vec![<G2 as Group>::Scalar::from(2u64)]),
@@ -256,13 +256,15 @@ assert!(res.is_ok());
// produce a compressed SNARK println!("Generating a CompressedSNARK using Spartan with IPA-PC..."); + let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp); + let start = Instant::now(); type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine<G1>; type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<G2>; type S1 = nova_snark::spartan::RelaxedR1CSSNARK<G1, EE1>; type S2 = nova_snark::spartan::RelaxedR1CSSNARK<G2, EE2>; - let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark); + let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); println!( "CompressedSNARK::prove: {:?}, took {:?}", res.is_ok(),@@ -282,7 +284,7 @@
// verify the compressed SNARK println!("Verifying a CompressedSNARK..."); let start = Instant::now(); - let res = compressed_snark.verify(&pp, num_steps, z0_primary, z0_secondary); + let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary); println!( "CompressedSNARK::verify: {:?}, took {:?}", res.is_ok(),
@@ -47,14 +47,14 @@ // First create the shape
let mut cs: ShapeCS<G> = ShapeCS::new(); let _ = synthesize_alloc_bit(&mut cs); let shape = cs.r1cs_shape(); - let gens = cs.r1cs_gens(); + let ck = cs.commitment_key(); // Now get the assignment let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new(); let _ = synthesize_alloc_bit(&mut cs); - let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); // Make sure that this is satisfiable - assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); + assert!(shape.is_sat(&ck, &inst, &witness).is_ok()); } }
@@ -3,23 +3,22 @@
#![allow(non_snake_case)] use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment}; -use bellperson::{Index, LinearCombination}; - -use ff::PrimeField; - use crate::{ errors::NovaError, - r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness}, + r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS}, traits::Group, + CommitmentKey, }; +use bellperson::{Index, LinearCombination}; +use ff::PrimeField; /// `NovaWitness` provide a method for acquiring an `R1CSInstance` and `R1CSWitness` from implementers. pub trait NovaWitness<G: Group> { - /// Return an instance and witness, given a shape and gens. + /// Return an instance and witness, given a shape and ck. fn r1cs_instance_and_witness( &self, shape: &R1CSShape<G>, - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, ) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError>; }@@ -27,8 +26,8 @@ /// `NovaShape` provides methods for acquiring `R1CSShape` and `R1CSGens` from implementers.
pub trait NovaShape<G: Group> { /// Return an appropriate `R1CSShape` struct. fn r1cs_shape(&self) -> R1CSShape<G>; - /// Return an appropriate `R1CSGens` struct. - fn r1cs_gens(&self) -> R1CSGens<G>; + /// Return an appropriate `CommitmentKey` struct. + fn commitment_key(&self) -> CommitmentKey<G>; } impl<G: Group> NovaWitness<G> for SatisfyingAssignment<G>@@ -38,12 +37,12 @@ {
fn r1cs_instance_and_witness( &self, shape: &R1CSShape<G>, - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, ) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError> { let W = R1CSWitness::<G>::new(shape, &self.aux_assignment)?; let X = &self.input_assignment[1..]; - let comm_W = W.commit(gens); + let comm_W = W.commit(ck); let instance = R1CSInstance::<G>::new(shape, &comm_W, X)?;@@ -88,8 +87,8 @@
S } - fn r1cs_gens(&self) -> R1CSGens<G> { - R1CSGens::<G>::new(self.num_constraints(), self.num_aux()) + fn commitment_key(&self) -> CommitmentKey<G> { + R1CS::<G>::commitment_key(self.num_constraints(), self.num_aux()) } }
@@ -3,7 +3,7 @@ //! Each of them is over a Pasta curve but
//! only the primary executes the next step of the computation. //! We have two running instances. Each circuit takes as input 2 hashes: one for each //! of the running instances. Each of these hashes is -//! H(params = H(shape, gens), i, z0, zi, U). Each circuit folds the last invocation of +//! H(params = H(shape, ck), i, z0, zi, U). Each circuit folds the last invocation of //! the other into the running instance use crate::{@@ -390,7 +390,7 @@ let params2 = NovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false);
let ro_consts1: ROConstantsCircuit<G2> = PoseidonConstantsCircuit::new(); let ro_consts2: ROConstantsCircuit<G1> = PoseidonConstantsCircuit::new(); - // Initialize the shape and gens for the primary + // Initialize the shape and ck for the primary let circuit1: NovaAugmentedCircuit<G2, TrivialTestCircuit<<G2 as Group>::Base>> = NovaAugmentedCircuit::new( params1.clone(),@@ -400,10 +400,10 @@ ro_consts1.clone(),
); let mut cs: ShapeCS<G1> = ShapeCS::new(); let _ = circuit1.synthesize(&mut cs); - let (shape1, gens1) = (cs.r1cs_shape(), cs.r1cs_gens()); + let (shape1, ck1) = (cs.r1cs_shape(), cs.commitment_key()); assert_eq!(cs.num_constraints(), 9815); - // Initialize the shape and gens for the secondary + // Initialize the shape and ck for the secondary let circuit2: NovaAugmentedCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> = NovaAugmentedCircuit::new( params2.clone(),@@ -413,7 +413,7 @@ ro_consts2.clone(),
); let mut cs: ShapeCS<G2> = ShapeCS::new(); let _ = circuit2.synthesize(&mut cs); - let (shape2, gens2) = (cs.r1cs_shape(), cs.r1cs_gens()); + let (shape2, ck2) = (cs.r1cs_shape(), cs.commitment_key()); assert_eq!(cs.num_constraints(), 10347); // Execute the base case for the primary@@ -436,9 +436,9 @@ TrivialTestCircuit::default(),
ro_consts1, ); let _ = circuit1.synthesize(&mut cs1); - let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &gens1).unwrap(); + let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &ck1).unwrap(); // Make sure that this is satisfiable - assert!(shape1.is_sat(&gens1, &inst1, &witness1).is_ok()); + assert!(shape1.is_sat(&ck1, &inst1, &witness1).is_ok()); // Execute the base case for the secondary let zero2 = <<G1 as Group>::Base as Field>::zero();@@ -460,8 +460,8 @@ TrivialTestCircuit::default(),
ro_consts2, ); let _ = circuit.synthesize(&mut cs2); - let (inst2, witness2) = cs2.r1cs_instance_and_witness(&shape2, &gens2).unwrap(); + let (inst2, witness2) = cs2.r1cs_instance_and_witness(&shape2, &ck2).unwrap(); // Make sure that it is satisfiable - assert!(shape2.is_sat(&gens2, &inst2, &witness2).is_ok()); + assert!(shape2.is_sat(&ck2, &inst2, &witness2).is_ok()); } }
@@ -976,12 +976,12 @@ let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize")); println!("Number of constraints: {}", cs.num_constraints()); let shape = cs.r1cs_shape(); - let gens = cs.r1cs_gens(); + let ck = cs.commitment_key(); // Then the satisfying assignment let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new(); let (a, e, s) = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize")); - let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); let a_p: Point<G1> = Point::new( a.x.get_value().unwrap(),@@ -996,7 +996,7 @@ );
let e_new = a_p.scalar_mul(&s); assert!(e_p.x == e_new.x && e_p.y == e_new.y); // Make sure that this is satisfiable - assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); + assert!(shape.is_sat(&ck, &inst, &witness).is_ok()); } fn synthesize_add_equal<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>)@@ -1018,12 +1018,12 @@ let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); let shape = cs.r1cs_shape(); - let gens = cs.r1cs_gens(); + let ck = cs.commitment_key(); // Then the satisfying assignment let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new(); let (a, e) = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal")); - let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); let a_p: Point<G1> = Point::new( a.x.get_value().unwrap(), a.y.get_value().unwrap(),@@ -1037,7 +1037,7 @@ );
let e_new = a_p.add(&a_p); assert!(e_p.x == e_new.x && e_p.y == e_new.y); // Make sure that it is satisfiable - assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); + assert!(shape.is_sat(&ck, &inst, &witness).is_ok()); } fn synthesize_add_negation<G, CS>(mut cs: CS) -> AllocatedPoint<G>@@ -1064,12 +1064,12 @@ let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); let shape = cs.r1cs_shape(); - let gens = cs.r1cs_gens(); + let ck = cs.commitment_key(); // Then the satisfying assignment let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new(); let e = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add negation")); - let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); let e_p: Point<G1> = Point::new( e.x.get_value().unwrap(), e.y.get_value().unwrap(),@@ -1077,6 +1077,6 @@ e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::one(),
); assert!(e_p.is_infinity); // Make sure that it is satisfiable - assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); + assert!(shape.is_sat(&ck, &inst, &witness).is_ok()); } }
@@ -38,9 +38,7 @@ use errors::NovaError;
use ff::Field; use gadgets::utils::scalar_as_base; use nifs::NIFS; -use r1cs::{ - R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, -}; +use r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness}; use serde::{Deserialize, Serialize}; use traits::{ circuit::StepCircuit,@@ -63,14 +61,12 @@ F_arity_primary: usize,
F_arity_secondary: usize, ro_consts_primary: ROConstants<G1>, ro_consts_circuit_primary: ROConstantsCircuit<G2>, - r1cs_gens_primary: R1CSGens<G1>, + ck_primary: CommitmentKey<G1>, r1cs_shape_primary: R1CSShape<G1>, - r1cs_shape_padded_primary: R1CSShape<G1>, ro_consts_secondary: ROConstants<G2>, ro_consts_circuit_secondary: ROConstantsCircuit<G1>, - r1cs_gens_secondary: R1CSGens<G2>, + ck_secondary: CommitmentKey<G2>, r1cs_shape_secondary: R1CSShape<G2>, - r1cs_shape_padded_secondary: R1CSShape<G2>, augmented_circuit_params_primary: NovaAugmentedCircuitParams, augmented_circuit_params_secondary: NovaAugmentedCircuitParams, _p_c1: PhantomData<C1>,@@ -101,7 +97,7 @@ // ro_consts_circuit_primart are parameterized by G2 because the type alias uses G2::Base = G1::Scalar
let ro_consts_circuit_primary: ROConstantsCircuit<G2> = ROConstantsCircuit::<G2>::new(); let ro_consts_circuit_secondary: ROConstantsCircuit<G1> = ROConstantsCircuit::<G1>::new(); - // Initialize gens for the primary + // Initialize ck for the primary let circuit_primary: NovaAugmentedCircuit<G2, C1> = NovaAugmentedCircuit::new( augmented_circuit_params_primary.clone(), None,@@ -110,10 +106,9 @@ ro_consts_circuit_primary.clone(),
); let mut cs: ShapeCS<G1> = ShapeCS::new(); let _ = circuit_primary.synthesize(&mut cs); - let (r1cs_shape_primary, r1cs_gens_primary) = (cs.r1cs_shape(), cs.r1cs_gens()); - let r1cs_shape_padded_primary = r1cs_shape_primary.pad(); + let (r1cs_shape_primary, ck_primary) = (cs.r1cs_shape(), cs.commitment_key()); - // Initialize gens for the secondary + // Initialize ck for the secondary let circuit_secondary: NovaAugmentedCircuit<G1, C2> = NovaAugmentedCircuit::new( augmented_circuit_params_secondary.clone(), None,@@ -122,22 +117,19 @@ ro_consts_circuit_secondary.clone(),
); let mut cs: ShapeCS<G2> = ShapeCS::new(); let _ = circuit_secondary.synthesize(&mut cs); - let (r1cs_shape_secondary, r1cs_gens_secondary) = (cs.r1cs_shape(), cs.r1cs_gens()); - let r1cs_shape_padded_secondary = r1cs_shape_secondary.pad(); + let (r1cs_shape_secondary, ck_secondary) = (cs.r1cs_shape(), cs.commitment_key()); Self { F_arity_primary, F_arity_secondary, ro_consts_primary, ro_consts_circuit_primary, - r1cs_gens_primary, + ck_primary, r1cs_shape_primary, - r1cs_shape_padded_primary, ro_consts_secondary, ro_consts_circuit_secondary, - r1cs_gens_secondary, + ck_secondary, r1cs_shape_secondary, - r1cs_shape_padded_secondary, augmented_circuit_params_primary, augmented_circuit_params_secondary, _p_c1: Default::default(),@@ -230,7 +222,7 @@ pp.ro_consts_circuit_primary.clone(),
); let _ = circuit_primary.synthesize(&mut cs_primary); let (u_primary, w_primary) = cs_primary - .r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.r1cs_gens_primary) + .r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary) .map_err(|_e| NovaError::UnSat)?; // base case for the secondary@@ -252,7 +244,7 @@ pp.ro_consts_circuit_secondary.clone(),
); let _ = circuit_secondary.synthesize(&mut cs_secondary); let (u_secondary, w_secondary) = cs_secondary - .r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.r1cs_gens_secondary) + .r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary) .map_err(|_e| NovaError::UnSat)?; // IVC proof for the primary circuit@@ -261,7 +253,7 @@ let l_u_primary = u_primary;
let r_W_primary = RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &l_w_primary); let r_U_primary = RelaxedR1CSInstance::from_r1cs_instance( - &pp.r1cs_gens_primary, + &pp.ck_primary, &pp.r1cs_shape_primary, &l_u_primary, );@@ -271,7 +263,7 @@ let l_w_secondary = w_secondary;
let l_u_secondary = u_secondary; let r_W_secondary = RelaxedR1CSWitness::<G2>::default(&pp.r1cs_shape_secondary); let r_U_secondary = - RelaxedR1CSInstance::<G2>::default(&pp.r1cs_gens_secondary, &pp.r1cs_shape_secondary); + RelaxedR1CSInstance::<G2>::default(&pp.ck_secondary, &pp.r1cs_shape_secondary); // Outputs of the two circuits thus far let zi_primary = c_primary.output(&z0_primary);@@ -300,7 +292,7 @@ }
Some(r_snark) => { // fold the secondary circuit's instance let (nifs_secondary, (r_U_secondary, r_W_secondary)) = NIFS::prove( - &pp.r1cs_gens_secondary, + &pp.ck_secondary, &pp.ro_consts_secondary, &pp.r1cs_shape_secondary, &r_snark.r_U_secondary,@@ -329,12 +321,12 @@ );
let _ = circuit_primary.synthesize(&mut cs_primary); let (l_u_primary, l_w_primary) = cs_primary - .r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.r1cs_gens_primary) + .r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary) .map_err(|_e| NovaError::UnSat)?; // fold the primary circuit's instance let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove( - &pp.r1cs_gens_primary, + &pp.ck_primary, &pp.ro_consts_primary, &pp.r1cs_shape_primary, &r_snark.r_U_primary,@@ -363,7 +355,7 @@ );
let _ = circuit_secondary.synthesize(&mut cs_secondary); let (l_u_secondary, l_w_secondary) = cs_secondary - .r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.r1cs_gens_secondary) + .r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary) .map_err(|_e| NovaError::UnSat)?; // update the running instances and witnesses@@ -464,17 +456,14 @@ || {
rayon::join( || { pp.r1cs_shape_primary.is_sat_relaxed( - &pp.r1cs_gens_primary, + &pp.ck_primary, &self.r_U_primary, &self.r_W_primary, ) }, || { - pp.r1cs_shape_primary.is_sat( - &pp.r1cs_gens_primary, - &self.l_u_primary, - &self.l_w_primary, - ) + pp.r1cs_shape_primary + .is_sat(&pp.ck_primary, &self.l_u_primary, &self.l_w_primary) }, ) },@@ -482,14 +471,14 @@ || {
rayon::join( || { pp.r1cs_shape_secondary.is_sat_relaxed( - &pp.r1cs_gens_secondary, + &pp.ck_secondary, &self.r_U_secondary, &self.r_W_secondary, ) }, || { pp.r1cs_shape_secondary.is_sat( - &pp.r1cs_gens_secondary, + &pp.ck_secondary, &self.l_u_secondary, &self.l_w_secondary, )@@ -508,8 +497,50 @@ Ok((self.zi_primary.clone(), self.zi_secondary.clone()))
} } +/// A type that holds the prover key for `CompressedSNARK` +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct ProverKey<G1, G2, C1, C2, S1, S2> +where + G1: Group<Base = <G2 as Group>::Scalar>, + G2: Group<Base = <G1 as Group>::Scalar>, + C1: StepCircuit<G1::Scalar>, + C2: StepCircuit<G2::Scalar>, + S1: RelaxedR1CSSNARKTrait<G1>, + S2: RelaxedR1CSSNARKTrait<G2>, +{ + pk_primary: S1::ProverKey, + pk_secondary: S2::ProverKey, + _p_c1: PhantomData<C1>, + _p_c2: PhantomData<C2>, +} + +/// A type that holds the verifier key for `CompressedSNARK` +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct VerifierKey<G1, G2, C1, C2, S1, S2> +where + G1: Group<Base = <G2 as Group>::Scalar>, + G2: Group<Base = <G1 as Group>::Scalar>, + C1: StepCircuit<G1::Scalar>, + C2: StepCircuit<G2::Scalar>, + S1: RelaxedR1CSSNARKTrait<G1>, + S2: RelaxedR1CSSNARKTrait<G2>, +{ + F_arity_primary: usize, + F_arity_secondary: usize, + ro_consts_primary: ROConstants<G1>, + ro_consts_secondary: ROConstants<G2>, + r1cs_shape_primary_digest: G1::Scalar, + r1cs_shape_secondary_digest: G2::Scalar, + vk_primary: S1::VerifierKey, + vk_secondary: S2::VerifierKey, + _p_c1: PhantomData<C1>, + _p_c2: PhantomData<C2>, +} + /// A SNARK that proves the knowledge of a valid `RecursiveSNARK` -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] #[serde(bound = "")] pub struct CompressedSNARK<G1, G2, C1, C2, S1, S2> where@@ -546,16 +577,50 @@ C2: StepCircuit<G2::Scalar>,
S1: RelaxedR1CSSNARKTrait<G1>, S2: RelaxedR1CSSNARKTrait<G2>, { + /// Creates prover and verifier keys for `CompressedSNARK` + pub fn setup( + pp: &PublicParams<G1, G2, C1, C2>, + ) -> ( + ProverKey<G1, G2, C1, C2, S1, S2>, + VerifierKey<G1, G2, C1, C2, S1, S2>, + ) { + let (pk_primary, vk_primary) = S1::setup(&pp.ck_primary, &pp.r1cs_shape_primary); + let (pk_secondary, vk_secondary) = S2::setup(&pp.ck_secondary, &pp.r1cs_shape_secondary); + + let pk = ProverKey { + pk_primary, + pk_secondary, + _p_c1: Default::default(), + _p_c2: Default::default(), + }; + + let vk = VerifierKey { + F_arity_primary: pp.F_arity_primary, + F_arity_secondary: pp.F_arity_secondary, + ro_consts_primary: pp.ro_consts_primary.clone(), + ro_consts_secondary: pp.ro_consts_secondary.clone(), + r1cs_shape_primary_digest: pp.r1cs_shape_primary.get_digest(), + r1cs_shape_secondary_digest: pp.r1cs_shape_secondary.get_digest(), + vk_primary, + vk_secondary, + _p_c1: Default::default(), + _p_c2: Default::default(), + }; + + (pk, vk) + } + /// Create a new `CompressedSNARK` pub fn prove( pp: &PublicParams<G1, G2, C1, C2>, + pk: &ProverKey<G1, G2, C1, C2, S1, S2>, recursive_snark: &RecursiveSNARK<G1, G2, C1, C2>, ) -> Result<Self, NovaError> { let (res_primary, res_secondary) = rayon::join( // fold the primary circuit's instance || { NIFS::prove( - &pp.r1cs_gens_primary, + &pp.ck_primary, &pp.ro_consts_primary, &pp.r1cs_shape_primary, &recursive_snark.r_U_primary,@@ -567,7 +632,7 @@ },
|| { // fold the secondary circuit's instance NIFS::prove( - &pp.r1cs_gens_secondary, + &pp.ck_secondary, &pp.ro_consts_secondary, &pp.r1cs_shape_secondary, &recursive_snark.r_U_secondary,@@ -581,26 +646,15 @@
let (nifs_primary, (f_U_primary, f_W_primary)) = res_primary?; let (nifs_secondary, (f_U_secondary, f_W_secondary)) = res_secondary?; - // produce a prover key for the SNARK - let (pk_primary, pk_secondary) = rayon::join( - || S1::prover_key(&pp.r1cs_gens_primary, &pp.r1cs_shape_padded_primary), - || S2::prover_key(&pp.r1cs_gens_secondary, &pp.r1cs_shape_padded_secondary), - ); - // create SNARKs proving the knowledge of f_W_primary and f_W_secondary let (f_W_snark_primary, f_W_snark_secondary) = rayon::join( - || { - S1::prove( - &pk_primary, - &f_U_primary, - &f_W_primary.pad(&pp.r1cs_shape_padded_primary), // pad the witness since shape was padded - ) - }, + || S1::prove(&pp.ck_primary, &pk.pk_primary, &f_U_primary, &f_W_primary), || { S2::prove( - &pk_secondary, + &pp.ck_secondary, + &pk.pk_secondary, &f_U_secondary, - &f_W_secondary.pad(&pp.r1cs_shape_padded_secondary), // pad the witness since the shape was padded + &f_W_secondary, ) }, );@@ -627,7 +681,7 @@
/// Verify the correctness of the `CompressedSNARK` pub fn verify( &self, - pp: &PublicParams<G1, G2, C1, C2>, + vk: &VerifierKey<G1, G2, C1, C2, S1, S2>, num_steps: usize, z0_primary: Vec<G1::Scalar>, z0_secondary: Vec<G2::Scalar>,@@ -649,10 +703,10 @@
// check if the output hashes in R1CS instances point to the right running instances let (hash_primary, hash_secondary) = { let mut hasher = <G2 as Group>::RO::new( - pp.ro_consts_secondary.clone(), - NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_primary, + vk.ro_consts_secondary.clone(), + NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_primary, ); - hasher.absorb(scalar_as_base::<G2>(pp.r1cs_shape_secondary.get_digest())); + hasher.absorb(scalar_as_base::<G2>(vk.r1cs_shape_secondary_digest)); hasher.absorb(G1::Scalar::from(num_steps as u64)); for e in z0_primary { hasher.absorb(e);@@ -663,10 +717,10 @@ }
self.r_U_secondary.absorb_in_ro(&mut hasher); let mut hasher2 = <G1 as Group>::RO::new( - pp.ro_consts_primary.clone(), - NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_secondary, + vk.ro_consts_primary.clone(), + NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_secondary, ); - hasher2.absorb(scalar_as_base::<G1>(pp.r1cs_shape_primary.get_digest())); + hasher2.absorb(scalar_as_base::<G1>(vk.r1cs_shape_primary_digest)); hasher2.absorb(G2::Scalar::from(num_steps as u64)); for e in z0_secondary { hasher2.absorb(e);@@ -690,31 +744,25 @@ }
// fold the running instance and last instance to get a folded instance let f_U_primary = self.nifs_primary.verify( - &pp.ro_consts_primary, - &pp.r1cs_shape_primary, + &vk.ro_consts_primary, + &vk.r1cs_shape_primary_digest, &self.r_U_primary, &self.l_u_primary, )?; let f_U_secondary = self.nifs_secondary.verify( - &pp.ro_consts_secondary, - &pp.r1cs_shape_secondary, + &vk.ro_consts_secondary, + &vk.r1cs_shape_secondary_digest, &self.r_U_secondary, &self.l_u_secondary, )?; - // produce a verifier key for the SNARK - let (vk_primary, vk_secondary) = rayon::join( - || S1::verifier_key(&pp.r1cs_gens_primary, &pp.r1cs_shape_padded_primary), - || S2::verifier_key(&pp.r1cs_gens_secondary, &pp.r1cs_shape_padded_secondary), - ); - // check the satisfiability of the folded instances using SNARKs proving the knowledge of their satisfying witnesses let (res_primary, res_secondary) = rayon::join( - || self.f_W_snark_primary.verify(&vk_primary, &f_U_primary), + || self.f_W_snark_primary.verify(&vk.vk_primary, &f_U_primary), || { self .f_W_snark_secondary - .verify(&vk_secondary, &f_U_secondary) + .verify(&vk.vk_secondary, &f_U_secondary) }, );@@ -725,7 +773,7 @@ Ok((self.zn_primary.clone(), self.zn_secondary.clone()))
} } -type CommitmentGens<G> = <<G as traits::Group>::CE as CommitmentEngineTrait<G>>::CommitmentGens; +type CommitmentKey<G> = <<G as traits::Group>::CE as CommitmentEngineTrait<G>>::CommitmentKey; type Commitment<G> = <<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment; type CompressedCommitment<G> = <<<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment; type CE<G> = <G as Group>::CE;@@ -962,14 +1010,17 @@ }
assert_eq!(zn_secondary, zn_secondary_direct); assert_eq!(zn_secondary, vec![<G2 as Group>::Scalar::from(2460515u64)]); + // produce the prover and verifier keys for compressed snark + let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp); + // produce a compressed SNARK - let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark); + let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); assert!(res.is_ok()); let compressed_snark = res.unwrap(); // verify the compressed SNARK let res = compressed_snark.verify( - &pp, + &vk, num_steps, vec![<G1 as Group>::Scalar::one()], vec![<G2 as Group>::Scalar::zero()],@@ -1110,13 +1161,16 @@ // verify the recursive SNARK
let res = recursive_snark.verify(&pp, num_steps, z0_primary.clone(), z0_secondary.clone()); assert!(res.is_ok()); + // produce the prover and verifier keys for compressed snark + let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp); + // produce a compressed SNARK - let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark); + let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); assert!(res.is_ok()); let compressed_snark = res.unwrap(); // verify the compressed SNARK - let res = compressed_snark.verify(&pp, num_steps, z0_primary, z0_secondary); + let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary); assert!(res.is_ok()); }
@@ -5,9 +5,10 @@
use crate::{ constants::{NUM_CHALLENGE_BITS, NUM_FE_FOR_RO}, errors::NovaError, - r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness}, + r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness}, + scalar_as_base, traits::{commitment::CommitmentTrait, AbsorbInROTrait, Group, ROTrait}, - Commitment, CompressedCommitment, + Commitment, CommitmentKey, CompressedCommitment, }; use core::marker::PhantomData; use serde::{Deserialize, Serialize};@@ -27,12 +28,12 @@
impl<G: Group> NIFS<G> { /// Takes as input a Relaxed R1CS instance-witness tuple `(U1, W1)` and /// an R1CS instance-witness tuple `(U2, W2)` with the same structure `shape` - /// and defined with respect to the same `gens`, and outputs + /// and defined with respect to the same `ck`, and outputs /// a folded Relaxed R1CS instance-witness tuple `(U, W)` of the same shape `shape`, /// with the guarantee that the folded witness `W` satisfies the folded instance `U` /// if and only if `W1` satisfies `U1` and `W2` satisfies `U2`. pub fn prove( - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, ro_consts: &ROConstants<G>, S: &R1CSShape<G>, U1: &RelaxedR1CSInstance<G>,@@ -51,7 +52,7 @@ U1.absorb_in_ro(&mut ro);
U2.absorb_in_ro(&mut ro); // compute a commitment to the cross-term - let (T, comm_T) = S.commit_T(gens, U1, W1, U2, W2)?; + let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2)?; // append `comm_T` to the transcript and obtain a challenge comm_T.absorb_in_ro(&mut ro);@@ -83,15 +84,15 @@ /// if and only if `U1` and `U2` are satisfiable.
pub fn verify( &self, ro_consts: &ROConstants<G>, - S: &R1CSShape<G>, + S_digest: &G::Scalar, U1: &RelaxedR1CSInstance<G>, U2: &R1CSInstance<G>, ) -> Result<RelaxedR1CSInstance<G>, NovaError> { // initialize a new RO let mut ro = G::RO::new(ro_consts.clone(), NUM_FE_FOR_RO); - // append S to the transcript - S.absorb_in_ro(&mut ro); + // append the digest of S to the transcript + ro.absorb(scalar_as_base::<G>(*S_digest)); // append U1 and U2 to transcript U1.absorb_in_ro(&mut ro);@@ -115,7 +116,10 @@
#[cfg(test)] mod tests { use super::*; - use crate::traits::{Group, ROConstantsTrait}; + use crate::{ + r1cs::R1CS, + traits::{Group, ROConstantsTrait}, + }; use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; use ff::{Field, PrimeField}; use rand::rngs::OsRng;@@ -168,32 +172,32 @@ // First create the shape
let mut cs: ShapeCS<G> = ShapeCS::new(); let _ = synthesize_tiny_r1cs_bellperson(&mut cs, None); let shape = cs.r1cs_shape(); - let gens = cs.r1cs_gens(); + let ck = cs.commitment_key(); let ro_consts = <<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new(); // Now get the instance and assignment for one instance let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new(); let _ = synthesize_tiny_r1cs_bellperson(&mut cs, Some(S::from(5))); - let (U1, W1) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (U1, W1) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); // Make sure that the first instance is satisfiable - assert!(shape.is_sat(&gens, &U1, &W1).is_ok()); + assert!(shape.is_sat(&ck, &U1, &W1).is_ok()); // Now get the instance and assignment for second instance let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new(); let _ = synthesize_tiny_r1cs_bellperson(&mut cs, Some(S::from(135))); - let (U2, W2) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); + let (U2, W2) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap(); // Make sure that the second instance is satisfiable - assert!(shape.is_sat(&gens, &U2, &W2).is_ok()); + assert!(shape.is_sat(&ck, &U2, &W2).is_ok()); // execute a sequence of folds - execute_sequence(&gens, &ro_consts, &shape, &U1, &W1, &U2, &W2); + execute_sequence(&ck, &ro_consts, &shape, &U1, &W1, &U2, &W2); } fn execute_sequence( - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, ro_consts: &<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants, shape: &R1CSShape<G>, U1: &R1CSInstance<G>,@@ -203,15 +207,15 @@ W2: &R1CSWitness<G>,
) { // produce a default running instance let mut r_W = RelaxedR1CSWitness::default(shape); - let mut r_U = RelaxedR1CSInstance::default(gens, shape); + let mut r_U = RelaxedR1CSInstance::default(ck, shape); // produce a step SNARK with (W1, U1) as the first incoming witness-instance pair - let res = NIFS::prove(gens, ro_consts, shape, &r_U, &r_W, U1, W1); + let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U1, W1); assert!(res.is_ok()); let (nifs, (_U, W)) = res.unwrap(); // verify the step SNARK with U1 as the first incoming instance - let res = nifs.verify(ro_consts, shape, &r_U, U1); + let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U1); assert!(res.is_ok()); let U = res.unwrap();@@ -222,12 +226,12 @@ r_W = W;
r_U = U; // produce a step SNARK with (W2, U2) as the second incoming witness-instance pair - let res = NIFS::prove(gens, ro_consts, shape, &r_U, &r_W, U2, W2); + let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U2, W2); assert!(res.is_ok()); let (nifs, (_U, W)) = res.unwrap(); // verify the step SNARK with U1 as the first incoming instance - let res = nifs.verify(ro_consts, shape, &r_U, U2); + let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U2); assert!(res.is_ok()); let U = res.unwrap();@@ -238,7 +242,7 @@ r_W = W;
r_U = U; // check if the running instance is satisfiable - assert!(shape.is_sat_relaxed(gens, &r_U, &r_W).is_ok()); + assert!(shape.is_sat_relaxed(ck, &r_U, &r_W).is_ok()); } #[test]@@ -301,12 +305,12 @@ res.unwrap()
}; // generate generators and ro constants - let gens = R1CSGens::new(num_cons, num_vars); + let ck = R1CS::<G>::commitment_key(num_cons, num_vars); let ro_consts = <<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new(); let rand_inst_witness_generator = - |gens: &R1CSGens<G>, I: &S| -> (S, R1CSInstance<G>, R1CSWitness<G>) { + |ck: &CommitmentKey<G>, I: &S| -> (S, R1CSInstance<G>, R1CSWitness<G>) { let i0 = *I; // compute a satisfying (vars, X) tuple@@ -328,24 +332,24 @@ assert!(res.is_ok());
res.unwrap() }; let U = { - let comm_W = W.commit(gens); + let comm_W = W.commit(ck); let res = R1CSInstance::new(&S, &comm_W, &X); assert!(res.is_ok()); res.unwrap() }; // check that generated instance is satisfiable - assert!(S.is_sat(gens, &U, &W).is_ok()); + assert!(S.is_sat(ck, &U, &W).is_ok()); (O, U, W) }; let mut csprng: OsRng = OsRng; let I = S::random(&mut csprng); // the first input is picked randomly for the first instance - let (O, U1, W1) = rand_inst_witness_generator(&gens, &I); - let (_O, U2, W2) = rand_inst_witness_generator(&gens, &O); + let (O, U1, W1) = rand_inst_witness_generator(&ck, &I); + let (_O, U2, W2) = rand_inst_witness_generator(&ck, &O); // execute a sequence of folds - execute_sequence(&gens, &ro_consts, &S, &U1, &W1, &U2, &W2); + execute_sequence(&ck, &ro_consts, &S, &U1, &W1, &U2, &W2); } }
@@ -2,14 +2,14 @@ //! This module implements `EvaluationEngine` using an IPA-based polynomial commitment scheme
#![allow(clippy::too_many_arguments)] use crate::{ errors::NovaError, - provider::pedersen::CommitmentGensExtTrait, + provider::pedersen::CommitmentKeyExtTrait, spartan::polynomial::EqPolynomial, traits::{ - commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait}, + commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait}, evaluation::EvaluationEngineTrait, AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait, }, - Commitment, CommitmentGens, CompressedCommitment, CE, + Commitment, CommitmentKey, CompressedCommitment, CE, }; use core::iter; use ff::Field;@@ -17,12 +17,19 @@ use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -/// Provides an implementation of generators for proving evaluations +/// Provides an implementation of the prover key #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] -pub struct EvaluationGens<G: Group> { - gens_v: CommitmentGens<G>, - gens_s: CommitmentGens<G>, +pub struct ProverKey<G: Group> { + ck_s: CommitmentKey<G>, +} + +/// Provides an implementation of the verifier key +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct VerifierKey<G: Group> { + ck_v: CommitmentKey<G>, + ck_s: CommitmentKey<G>, } /// Provides an implementation of a polynomial evaluation argument@@ -41,21 +48,31 @@
impl<G> EvaluationEngineTrait<G> for EvaluationEngine<G> where G: Group, - CommitmentGens<G>: CommitmentGensExtTrait<G, CE = G::CE>, + CommitmentKey<G>: CommitmentKeyExtTrait<G, CE = G::CE>, { type CE = G::CE; - type EvaluationGens = EvaluationGens<G>; + type ProverKey = ProverKey<G>; + type VerifierKey = VerifierKey<G>; type EvaluationArgument = EvaluationArgument<G>; - fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens { - EvaluationGens { - gens_v: gens.clone(), - gens_s: CommitmentGens::<G>::new(b"ipa", 1), - } + fn setup( + ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey, + ) -> (Self::ProverKey, Self::VerifierKey) { + let pk = ProverKey { + ck_s: CommitmentKey::<G>::new(b"ipa", 1), + }; + + let vk = VerifierKey { + ck_v: ck.clone(), + ck_s: CommitmentKey::<G>::new(b"ipa", 1), + }; + + (pk, vk) } fn prove( - gens: &Self::EvaluationGens, + ck: &CommitmentKey<G>, + pk: &Self::ProverKey, transcript: &mut G::TE, comm: &Commitment<G>, poly: &[G::Scalar],@@ -66,13 +83,13 @@ let u = InnerProductInstance::new(comm, &EqPolynomial::new(point.to_vec()).evals(), eval);
let w = InnerProductWitness::new(poly); Ok(EvaluationArgument { - ipa: InnerProductArgument::prove(&gens.gens_v, &gens.gens_s, &u, &w, transcript)?, + ipa: InnerProductArgument::prove(ck, &pk.ck_s, &u, &w, transcript)?, }) } /// A method to verify purported evaluations of a batch of polynomials fn verify( - gens: &Self::EvaluationGens, + vk: &Self::VerifierKey, transcript: &mut G::TE, comm: &Commitment<G>, point: &[G::Scalar],@@ -82,8 +99,8 @@ ) -> Result<(), NovaError> {
let u = InnerProductInstance::new(comm, &EqPolynomial::new(point.to_vec()).evals(), eval); arg.ipa.verify( - &gens.gens_v, - &gens.gens_s, + &vk.ck_v, + &vk.ck_s, (2_usize).pow(point.len() as u32), &u, transcript,@@ -147,15 +164,15 @@
impl<G> InnerProductArgument<G> where G: Group, - CommitmentGens<G>: CommitmentGensExtTrait<G, CE = G::CE>, + CommitmentKey<G>: CommitmentKeyExtTrait<G, CE = G::CE>, { fn protocol_name() -> &'static [u8] { b"inner product argument" } fn prove( - gens: &CommitmentGens<G>, - gens_c: &CommitmentGens<G>, + ck: &CommitmentKey<G>, + ck_c: &CommitmentKey<G>, U: &InnerProductInstance<G>, W: &InnerProductWitness<G>, transcript: &mut G::TE,@@ -171,12 +188,12 @@ <G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
// sample a random base for commiting to the inner product let r = G::Scalar::challenge(b"r", transcript)?; - let gens_c = gens_c.scale(&r); + let ck_c = ck_c.scale(&r); // a closure that executes a step of the recursive inner product argument let prove_inner = |a_vec: &[G::Scalar], b_vec: &[G::Scalar], - gens: &CommitmentGens<G>, + ck: &CommitmentKey<G>, transcript: &mut G::TE| -> Result< (@@ -184,18 +201,18 @@ CompressedCommitment<G>,
CompressedCommitment<G>, Vec<G::Scalar>, Vec<G::Scalar>, - CommitmentGens<G>, + CommitmentKey<G>, ), NovaError, > { let n = a_vec.len(); - let (gens_L, gens_R) = gens.split_at(n / 2); + let (ck_L, ck_R) = ck.split_at(n / 2); let c_L = inner_product(&a_vec[0..n / 2], &b_vec[n / 2..n]); let c_R = inner_product(&a_vec[n / 2..n], &b_vec[0..n / 2]); let L = CE::<G>::commit( - &gens_R.combine(&gens_c), + &ck_R.combine(&ck_c), &a_vec[0..n / 2] .iter() .chain(iter::once(&c_L))@@ -204,7 +221,7 @@ .collect::<Vec<G::Scalar>>(),
) .compress(); let R = CE::<G>::commit( - &gens_L.combine(&gens_c), + &ck_L.combine(&ck_c), &a_vec[n / 2..n] .iter() .chain(iter::once(&c_R))@@ -232,9 +249,9 @@ .zip(b_vec[n / 2..n].par_iter())
.map(|(b_L, b_R)| *b_L * r_inverse + r * *b_R) .collect::<Vec<G::Scalar>>(); - let gens_folded = gens.fold(&r_inverse, &r); + let ck_folded = ck.fold(&r_inverse, &r); - Ok((L, R, a_vec_folded, b_vec_folded, gens_folded)) + Ok((L, R, a_vec_folded, b_vec_folded, ck_folded)) }; // two vectors to hold the logarithmic number of group elements@@ -244,16 +261,16 @@
// we create mutable copies of vectors and generators let mut a_vec = W.a_vec.to_vec(); let mut b_vec = U.b_vec.to_vec(); - let mut gens = gens.clone(); + let mut ck = ck.clone(); for _i in 0..(U.b_vec.len() as f64).log2() as usize { - let (L, R, a_vec_folded, b_vec_folded, gens_folded) = - prove_inner(&a_vec, &b_vec, &gens, transcript)?; + let (L, R, a_vec_folded, b_vec_folded, ck_folded) = + prove_inner(&a_vec, &b_vec, &ck, transcript)?; L_vec.push(L); R_vec.push(R); a_vec = a_vec_folded; b_vec = b_vec_folded; - gens = gens_folded; + ck = ck_folded; } Ok(InnerProductArgument {@@ -266,8 +283,8 @@ }
fn verify( &self, - gens: &CommitmentGens<G>, - gens_c: &CommitmentGens<G>, + ck: &CommitmentKey<G>, + ck_c: &CommitmentKey<G>, n: usize, U: &InnerProductInstance<G>, transcript: &mut G::TE,@@ -286,9 +303,9 @@ <G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
// sample a random base for commiting to the inner product let r = G::Scalar::challenge(b"r", transcript)?; - let gens_c = gens_c.scale(&r); + let ck_c = ck_c.scale(&r); - let P = U.comm_a_vec + CE::<G>::commit(&gens_c, &[U.c]); + let P = U.comm_a_vec + CE::<G>::commit(&ck_c, &[U.c]); let batch_invert = |v: &[G::Scalar]| -> Result<Vec<G::Scalar>, NovaError> { let mut products = vec![G::Scalar::zero(); v.len()];@@ -354,23 +371,23 @@ }
s }; - let gens_hat = { - let c = CE::<G>::commit(gens, &s).compress(); - CommitmentGens::<G>::reinterpret_commitments_as_gens(&[c])? + let ck_hat = { + let c = CE::<G>::commit(ck, &s).compress(); + CommitmentKey::<G>::reinterpret_commitments_as_ck(&[c])? }; let b_hat = inner_product(&U.b_vec, &s); let P_hat = { - let gens_folded = { - let gens_L = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.L_vec)?; - let gens_R = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.R_vec)?; - let gens_P = CommitmentGens::<G>::reinterpret_commitments_as_gens(&[P.compress()])?; - gens_L.combine(&gens_R).combine(&gens_P) + let ck_folded = { + let ck_L = CommitmentKey::<G>::reinterpret_commitments_as_ck(&self.L_vec)?; + let ck_R = CommitmentKey::<G>::reinterpret_commitments_as_ck(&self.R_vec)?; + let ck_P = CommitmentKey::<G>::reinterpret_commitments_as_ck(&[P.compress()])?; + ck_L.combine(&ck_R).combine(&ck_P) }; CE::<G>::commit( - &gens_folded, + &ck_folded, &r_square .iter() .chain(r_inverse_square.iter())@@ -380,12 +397,7 @@ .collect::<Vec<G::Scalar>>(),
) }; - if P_hat - == CE::<G>::commit( - &gens_hat.combine(&gens_c), - &[self.a_hat, self.a_hat * b_hat], - ) - { + if P_hat == CE::<G>::commit(&ck_hat.combine(&ck_c), &[self.a_hat, self.a_hat * b_hat]) { Ok(()) } else { Err(NovaError::InvalidIPA)
@@ -105,7 +105,7 @@ let mut uniform_bytes = [0u8; 32];
reader.read_exact(&mut uniform_bytes).unwrap(); uniform_bytes_vec.push(uniform_bytes); } - let gens_proj: Vec<$name_curve> = (0..n) + let ck_proj: Vec<$name_curve> = (0..n) .collect::<Vec<usize>>() .into_par_iter() .map(|i| {@@ -115,22 +115,22 @@ })
.collect(); let num_threads = rayon::current_num_threads(); - if gens_proj.len() > num_threads { - let chunk = (gens_proj.len() as f64 / num_threads as f64).ceil() as usize; + if ck_proj.len() > num_threads { + let chunk = (ck_proj.len() as f64 / num_threads as f64).ceil() as usize; (0..num_threads) .collect::<Vec<usize>>() .into_par_iter() .map(|i| { let start = i * chunk; let end = if i == num_threads - 1 { - gens_proj.len() + ck_proj.len() } else { - core::cmp::min((i + 1) * chunk, gens_proj.len()) + core::cmp::min((i + 1) * chunk, ck_proj.len()) }; if end > start { - let mut gens = vec![$name_curve_affine::identity(); end - start]; - <Self as Curve>::batch_normalize(&gens_proj[start..end], &mut gens); - gens + let mut ck = vec![$name_curve_affine::identity(); end - start]; + <Self as Curve>::batch_normalize(&ck_proj[start..end], &mut ck); + ck } else { vec![] }@@ -140,9 +140,9 @@ .into_par_iter()
.flatten() .collect() } else { - let mut gens = vec![$name_curve_affine::identity(); n]; - <Self as Curve>::batch_normalize(&gens_proj, &mut gens); - gens + let mut ck = vec![$name_curve_affine::identity(); n]; + <Self as Curve>::batch_normalize(&ck_proj, &mut ck); + ck } }@@ -353,14 +353,14 @@ fn from_label_serial(label: &'static [u8], n: usize) -> Vec<EpAffine> {
let mut shake = Shake256::default(); shake.input(label); let mut reader = shake.xof_result(); - let mut gens = Vec::new(); + let mut ck = Vec::new(); for _ in 0..n { let mut uniform_bytes = [0u8; 32]; reader.read_exact(&mut uniform_bytes).unwrap(); let hash = Ep::hash_to_curve("from_uniform_bytes"); - gens.push(hash(&uniform_bytes).to_affine()); + ck.push(hash(&uniform_bytes).to_affine()); } - gens + ck } #[test]@@ -369,11 +369,11 @@ let label = b"test_from_label";
for n in [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1021, ] { - let gens_par = <G as Group>::from_label(label, n); - let gens_ser = from_label_serial(label, n); - assert_eq!(gens_par.len(), n); - assert_eq!(gens_ser.len(), n); - assert_eq!(gens_par, gens_ser); + let ck_par = <G as Group>::from_label(label, n); + let ck_ser = from_label_serial(label, n); + assert_eq!(ck_par.len(), n); + assert_eq!(ck_ser.len(), n); + assert_eq!(ck_par, ck_ser); } } }
@@ -2,7 +2,7 @@ //! This module provides an implementation of a commitment engine
use crate::{ errors::NovaError, traits::{ - commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait}, + commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait}, AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait, TranscriptEngineTrait, },@@ -18,8 +18,8 @@ use serde::{Deserialize, Serialize};
/// A type that holds commitment generators #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct CommitmentGens<G: Group> { - gens: Vec<G::PreprocessedGroupElement>, +pub struct CommitmentKey<G: Group> { + ck: Vec<G::PreprocessedGroupElement>, _p: PhantomData<G>, }@@ -37,24 +37,24 @@ pub struct CompressedCommitment<G: Group> {
comm: G::CompressedGroupElement, } -impl<G: Group> CommitmentGensTrait<G> for CommitmentGens<G> { +impl<G: Group> CommitmentKeyTrait<G> for CommitmentKey<G> { type Commitment = Commitment<G>; fn new(label: &'static [u8], n: usize) -> Self { - CommitmentGens { - gens: G::from_label(label, n.next_power_of_two()), + CommitmentKey { + ck: G::from_label(label, n.next_power_of_two()), _p: Default::default(), } } fn len(&self) -> usize { - self.gens.len() + self.ck.len() } fn commit(&self, v: &[G::Scalar]) -> Self::Commitment { - assert!(self.gens.len() >= v.len()); + assert!(self.ck.len() >= v.len()); Commitment { - comm: G::vartime_multiscalar_mul(v, &self.gens[..v.len()]), + comm: G::vartime_multiscalar_mul(v, &self.ck[..v.len()]), } } }@@ -209,15 +209,15 @@ _p: PhantomData<G>,
} impl<G: Group> CommitmentEngineTrait<G> for CommitmentEngine<G> { - type CommitmentGens = CommitmentGens<G>; + type CommitmentKey = CommitmentKey<G>; type Commitment = Commitment<G>; - fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment { - gens.commit(v) + fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { + ck.commit(v) } } -pub(crate) trait CommitmentGensExtTrait<G: Group>: CommitmentGensTrait<G> { +pub(crate) trait CommitmentKeyExtTrait<G: Group>: CommitmentKeyTrait<G> { type CE: CommitmentEngineTrait<G>; /// Splits the commitment key into two pieces at a specified point@@ -235,87 +235,87 @@ /// Scales the commitment key using the provided scalar
fn scale(&self, r: &G::Scalar) -> Self; /// Reinterprets commitments as commitment keys - fn reinterpret_commitments_as_gens( - c: &[<<<Self as CommitmentGensExtTrait<G>>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment], + fn reinterpret_commitments_as_ck( + c: &[<<<Self as CommitmentKeyExtTrait<G>>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment], ) -> Result<Self, NovaError> where Self: Sized; } -impl<G: Group> CommitmentGensExtTrait<G> for CommitmentGens<G> { +impl<G: Group> CommitmentKeyExtTrait<G> for CommitmentKey<G> { type CE = CommitmentEngine<G>; - fn split_at(&self, n: usize) -> (CommitmentGens<G>, CommitmentGens<G>) { + fn split_at(&self, n: usize) -> (CommitmentKey<G>, CommitmentKey<G>) { ( - CommitmentGens { - gens: self.gens[0..n].to_vec(), + CommitmentKey { + ck: self.ck[0..n].to_vec(), _p: Default::default(), }, - CommitmentGens { - gens: self.gens[n..].to_vec(), + CommitmentKey { + ck: self.ck[n..].to_vec(), _p: Default::default(), }, ) } - fn combine(&self, other: &CommitmentGens<G>) -> CommitmentGens<G> { - let gens = { - let mut c = self.gens.clone(); - c.extend(other.gens.clone()); + fn combine(&self, other: &CommitmentKey<G>) -> CommitmentKey<G> { + let ck = { + let mut c = self.ck.clone(); + c.extend(other.ck.clone()); c }; - CommitmentGens { - gens, + CommitmentKey { + ck, _p: Default::default(), } } // combines the left and right halves of `self` using `w1` and `w2` as the weights - fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentGens<G> { + fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentKey<G> { let w = vec![*w1, *w2]; let (L, R) = self.split_at(self.len() / 2); - let gens = (0..self.len() / 2) + let ck = (0..self.len() / 2) .into_par_iter() .map(|i| { - let bases = [L.gens[i].clone(), R.gens[i].clone()].to_vec(); + let bases = [L.ck[i].clone(), R.ck[i].clone()].to_vec(); G::vartime_multiscalar_mul(&w, &bases).preprocessed() }) .collect(); - CommitmentGens { - gens, + CommitmentKey { + ck, _p: Default::default(), } } /// Scales each element in `self` by `r` fn scale(&self, r: &G::Scalar) -> Self { - let gens_scaled = self - .gens + let ck_scaled = self + .ck .clone() .into_par_iter() .map(|g| G::vartime_multiscalar_mul(&[*r], &[g]).preprocessed()) .collect(); - CommitmentGens { - gens: gens_scaled, + CommitmentKey { + ck: ck_scaled, _p: Default::default(), } } /// reinterprets a vector of commitments as a set of generators - fn reinterpret_commitments_as_gens(c: &[CompressedCommitment<G>]) -> Result<Self, NovaError> { + fn reinterpret_commitments_as_ck(c: &[CompressedCommitment<G>]) -> Result<Self, NovaError> { let d = (0..c.len()) .into_par_iter() .map(|i| Commitment::<G>::decompress(&c[i])) .collect::<Result<Vec<Commitment<G>>, NovaError>>()?; - let gens = (0..d.len()) + let ck = (0..d.len()) .into_par_iter() .map(|i| d[i].comm.preprocessed()) .collect(); - Ok(CommitmentGens { - gens, + Ok(CommitmentKey { + ck, _p: Default::default(), }) }
@@ -8,12 +8,12 @@ nonnative::{bignat::nat_to_limbs, util::f_to_nat},
utils::scalar_as_base, }, traits::{ - commitment::{CommitmentEngineTrait, CommitmentGensTrait}, + commitment::{CommitmentEngineTrait, CommitmentKeyTrait}, AbsorbInROTrait, AppendToTranscriptTrait, Group, ROTrait, }, - Commitment, CommitmentGens, CE, + Commitment, CommitmentKey, CE, }; -use core::cmp::max; +use core::{cmp::max, marker::PhantomData}; use ff::Field; use flate2::{write::ZlibEncoder, Compression}; use itertools::concat;@@ -24,8 +24,8 @@
/// Public parameters for a given R1CS #[derive(Clone, Serialize, Deserialize)] #[serde(bound = "")] -pub struct R1CSGens<G: Group> { - pub(crate) gens: CommitmentGens<G>, +pub struct R1CS<G: Group> { + _p: PhantomData<G>, } /// A type that holds the shape of the R1CS matrices@@ -71,12 +71,10 @@ pub(crate) X: Vec<G::Scalar>,
pub(crate) u: G::Scalar, } -impl<G: Group> R1CSGens<G> { +impl<G: Group> R1CS<G> { /// Samples public parameters for the specified number of constraints and variables in an R1CS - pub fn new(num_cons: usize, num_vars: usize) -> R1CSGens<G> { - R1CSGens { - gens: CommitmentGens::<G>::new(b"gens", max(num_vars, num_cons)), - } + pub fn commitment_key(num_cons: usize, num_vars: usize) -> CommitmentKey<G> { + CommitmentKey::<G>::new(b"ck", max(num_vars, num_cons)) } }@@ -181,7 +179,7 @@
/// Checks if the Relaxed R1CS instance is satisfiable given a witness and its shape pub fn is_sat_relaxed( &self, - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, U: &RelaxedR1CSInstance<G>, W: &RelaxedR1CSWitness<G>, ) -> Result<(), NovaError> {@@ -206,10 +204,8 @@ };
// verify if comm_E and comm_W are commitments to E and W let res_comm: bool = { - let (comm_W, comm_E) = rayon::join( - || CE::<G>::commit(&gens.gens, &W.W), - || CE::<G>::commit(&gens.gens, &W.E), - ); + let (comm_W, comm_E) = + rayon::join(|| CE::<G>::commit(ck, &W.W), || CE::<G>::commit(ck, &W.E)); U.comm_W == comm_W && U.comm_E == comm_E };@@ -223,7 +219,7 @@
/// Checks if the R1CS instance is satisfiable given a witness and its shape pub fn is_sat( &self, - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, U: &R1CSInstance<G>, W: &R1CSWitness<G>, ) -> Result<(), NovaError> {@@ -246,7 +242,7 @@ res == 0
}; // verify if comm_W is a commitment to W - let res_comm: bool = U.comm_W == CE::<G>::commit(&gens.gens, &W.W); + let res_comm: bool = U.comm_W == CE::<G>::commit(ck, &W.W); if res_eq && res_comm { Ok(())@@ -259,7 +255,7 @@ /// A method to compute a commitment to the cross-term `T` given a
/// Relaxed R1CS instance-witness pair and an R1CS instance-witness pair pub fn commit_T( &self, - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, U1: &RelaxedR1CSInstance<G>, W1: &RelaxedR1CSWitness<G>, U2: &R1CSInstance<G>,@@ -300,7 +296,7 @@ .zip(&u_2_cdot_CZ_1)
.map(|(((a, b), c), d)| *a + *b - *c - *d) .collect::<Vec<G::Scalar>>(); - let comm_T = CE::<G>::commit(&gens.gens, &T); + let comm_T = CE::<G>::commit(ck, &T); Ok((T, comm_T)) }@@ -466,8 +462,8 @@ }
} /// Commits to the witness using the supplied generators - pub fn commit(&self, gens: &R1CSGens<G>) -> Commitment<G> { - CE::<G>::commit(&gens.gens, &self.W) + pub fn commit(&self, ck: &CommitmentKey<G>) -> Commitment<G> { + CE::<G>::commit(ck, &self.W) } }@@ -523,11 +519,8 @@ }
} /// Commits to the witness using the supplied generators - pub fn commit(&self, gens: &R1CSGens<G>) -> (Commitment<G>, Commitment<G>) { - ( - CE::<G>::commit(&gens.gens, &self.W), - CE::<G>::commit(&gens.gens, &self.E), - ) + pub fn commit(&self, ck: &CommitmentKey<G>) -> (Commitment<G>, Commitment<G>) { + (CE::<G>::commit(ck, &self.W), CE::<G>::commit(ck, &self.E)) } /// Folds an incoming R1CSWitness into the current one@@ -577,7 +570,7 @@ }
impl<G: Group> RelaxedR1CSInstance<G> { /// Produces a default RelaxedR1CSInstance given R1CSGens and R1CSShape - pub fn default(_gens: &R1CSGens<G>, S: &R1CSShape<G>) -> RelaxedR1CSInstance<G> { + pub fn default(_ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> RelaxedR1CSInstance<G> { let (comm_W, comm_E) = (Commitment::<G>::default(), Commitment::<G>::default()); RelaxedR1CSInstance { comm_W,@@ -589,11 +582,11 @@ }
/// Initializes a new RelaxedR1CSInstance from an R1CSInstance pub fn from_r1cs_instance( - gens: &R1CSGens<G>, + ck: &CommitmentKey<G>, S: &R1CSShape<G>, instance: &R1CSInstance<G>, ) -> RelaxedR1CSInstance<G> { - let mut r_instance = RelaxedR1CSInstance::default(gens, S); + let mut r_instance = RelaxedR1CSInstance::default(ck, S); r_instance.comm_W = instance.comm_W; r_instance.u = G::Scalar::one(); r_instance.X = instance.X.clone();
@@ -5,12 +5,12 @@ mod sumcheck;
use crate::{ errors::NovaError, - r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, + r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, traits::{ - evaluation::EvaluationEngineTrait, - snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait}, - AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait, + evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, AppendToTranscriptTrait, + ChallengeTrait, Group, TranscriptEngineTrait, }, + CommitmentKey, }; use ff::Field; use itertools::concat;@@ -23,38 +23,18 @@ /// A type that represents the prover's key
#[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> { - gens: EE::EvaluationGens, + pk_ee: EE::ProverKey, S: R1CSShape<G>, } -impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> ProverKeyTrait<G> for ProverKey<G, EE> { - fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self { - ProverKey { - gens: EE::setup(&gens.gens), - S: S.clone(), - } - } -} - /// A type that represents the verifier's key #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct VerifierKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> { - gens: EE::EvaluationGens, + vk_ee: EE::VerifierKey, S: R1CSShape<G>, } -impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> VerifierKeyTrait<G> - for VerifierKey<G, EE> -{ - fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self { - VerifierKey { - gens: EE::setup(&gens.gens), - S: S.clone(), - } - } -} - /// A succinct proof of knowledge of a witness to a relaxed R1CS instance /// The proof is produced using Spartan's combination of the sum-check and /// the commitment to a vector viewed as a polynomial commitment@@ -78,12 +58,22 @@ {
type ProverKey = ProverKey<G, EE>; type VerifierKey = VerifierKey<G, EE>; + fn setup(ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> (Self::ProverKey, Self::VerifierKey) { + let (pk_ee, vk_ee) = EE::setup(ck); + let pk = ProverKey { pk_ee, S: S.pad() }; + let vk = VerifierKey { vk_ee, S: S.pad() }; + + (pk, vk) + } + /// produces a succinct proof of satisfiability of a RelaxedR1CS instance fn prove( + ck: &CommitmentKey<G>, pk: &Self::ProverKey, U: &RelaxedR1CSInstance<G>, W: &RelaxedR1CSWitness<G>, ) -> Result<Self, NovaError> { + let W = W.pad(&pk.S); // pad the witness let mut transcript = G::TE::new(b"RelaxedR1CSSNARK"); // sanity check that R1CSShape has certain size characteristics@@ -275,7 +265,7 @@ .map(|(e, w)| *e + gamma * w)
.collect::<Vec<G::Scalar>>(); let eval = eval_E_prime + gamma * eval_W_prime; - let eval_arg = EE::prove(&pk.gens, &mut transcript, &comm, &poly, &r_z, &eval)?; + let eval_arg = EE::prove(ck, &pk.pk_ee, &mut transcript, &comm, &poly, &r_z, &eval)?; Ok(RelaxedR1CSSNARK { sc_proof_outer,@@ -428,7 +418,7 @@ let eval = self.eval_E_prime + gamma * self.eval_W_prime;
// verify eval_W and eval_E EE::verify( - &vk.gens, + &vk.vk_ee, &mut transcript, &comm, &r_z,
@@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
/// This trait defines the behavior of commitment key #[allow(clippy::len_without_is_empty)] -pub trait CommitmentGensTrait<G: Group>: +pub trait CommitmentKeyTrait<G: Group>: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// Holds the type of the commitment that can be produced@@ -99,11 +99,11 @@ pub trait CommitmentEngineTrait<G: Group>:
Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// Holds the type of the commitment key - type CommitmentGens: CommitmentGensTrait<G, Commitment = Self::Commitment>; + type CommitmentKey: CommitmentKeyTrait<G, Commitment = Self::Commitment>; /// Holds the type of the commitment type Commitment: CommitmentTrait<G>; /// Commits to the provided vector using the provided generators - fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment; + fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment; }
@@ -14,18 +14,24 @@ {
/// A type that holds the associated commitment engine type CE: CommitmentEngineTrait<G>; - /// A type that holds generators - type EvaluationGens: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; + /// A type that holds the prover key + type ProverKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; + + /// A type that holds the verifier key + type VerifierKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// A type that holds the evaluation argument type EvaluationArgument: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// A method to perform any additional setup needed to produce proofs of evaluations - fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens; + fn setup( + ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey, + ) -> (Self::ProverKey, Self::VerifierKey); /// A method to prove the evaluation of a multilinear polynomial fn prove( - gens: &Self::EvaluationGens, + ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey, + pk: &Self::ProverKey, transcript: &mut G::TE, comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment, poly: &[G::Scalar],@@ -35,7 +41,7 @@ ) -> Result<Self::EvaluationArgument, NovaError>;
/// A method to verify the purported evaluation of a multilinear polynomials fn verify( - gens: &Self::EvaluationGens, + vk: &Self::VerifierKey, transcript: &mut G::TE, comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment, point: &[G::Scalar],
@@ -1,46 +1,29 @@
//! This module defines a collection of traits that define the behavior of a zkSNARK for RelaxedR1CS use crate::{ errors::NovaError, - r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, + r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, traits::Group, + CommitmentKey, }; use serde::{Deserialize, Serialize}; -/// A trait that defines the behavior of a zkSNARK's prover key -pub trait ProverKeyTrait<G: Group>: Send + Sync { - /// Produces a new prover's key - fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self; -} - -/// A trait that defines the behavior of a zkSNARK's verifier key -pub trait VerifierKeyTrait<G: Group>: Send + Sync { - /// Produces a new verifier's key - fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self; -} - /// A trait that defines the behavior of a zkSNARK pub trait RelaxedR1CSSNARKTrait<G: Group>: Sized + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// A type that represents the prover's key - type ProverKey: ProverKeyTrait<G> + Serialize + for<'de> Deserialize<'de>; + type ProverKey: Send + Sync + Serialize + for<'de> Deserialize<'de>; /// A type that represents the verifier's key - type VerifierKey: VerifierKeyTrait<G> + Serialize + for<'de> Deserialize<'de>; + type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de>; - /// Produces a prover key - fn prover_key(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self::ProverKey { - Self::ProverKey::new(gens, S) - } - - /// Produces a verifier key - fn verifier_key(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self::VerifierKey { - Self::VerifierKey::new(gens, S) - } + /// Produces the keys for the prover and the verifier + fn setup(ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> (Self::ProverKey, Self::VerifierKey); /// Produces a new SNARK for a relaxed R1CS fn prove( + ck: &CommitmentKey<G>, pk: &Self::ProverKey, U: &RelaxedR1CSInstance<G>, W: &RelaxedR1CSWitness<G>,