diff --git a/Cargo.toml b/Cargo.toml index 1948e8f0..b0fa43ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nova-snark" -version = "0.16.0" +version = "0.17.0" authors = ["Srinath Setty "] edition = "2021" description = "Recursive zkSNARKs without trusted setup" diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index 63101b77..11bf46b0 100644 --- a/benches/compressed-snark.rs +++ b/benches/compressed-snark.rs @@ -49,6 +49,9 @@ fn bench_compressed_snark(c: &mut Criterion) { 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> = None; @@ -84,12 +87,13 @@ fn bench_compressed_snark(c: &mut Criterion) { 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 @@ fn bench_compressed_snark(c: &mut Criterion) { b.iter(|| { assert!(black_box(&compressed_snark) .verify( - black_box(&pp), + black_box(&vk), black_box(num_steps), black_box(vec![::Scalar::from(2u64)]), black_box(vec![::Scalar::from(2u64)]), diff --git a/examples/minroot.rs b/examples/minroot.rs index 25259f10..6599fead 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -256,13 +256,15 @@ fn main() { // 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; type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine; type S1 = nova_snark::spartan::RelaxedR1CSSNARK; type S2 = nova_snark::spartan::RelaxedR1CSSNARK; - 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 @@ fn main() { // 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(), diff --git a/src/bellperson/mod.rs b/src/bellperson/mod.rs index a31e8752..666cab82 100644 --- a/src/bellperson/mod.rs +++ b/src/bellperson/mod.rs @@ -47,14 +47,14 @@ mod tests { let mut cs: ShapeCS = 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 = 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()); } } diff --git a/src/bellperson/r1cs.rs b/src/bellperson/r1cs.rs index c3851a82..c46892ee 100644 --- a/src/bellperson/r1cs.rs +++ b/src/bellperson/r1cs.rs @@ -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 { - /// 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, - gens: &R1CSGens, + ck: &CommitmentKey, ) -> Result<(R1CSInstance, R1CSWitness), NovaError>; } @@ -27,8 +26,8 @@ pub trait NovaWitness { pub trait NovaShape { /// Return an appropriate `R1CSShape` struct. fn r1cs_shape(&self) -> R1CSShape; - /// Return an appropriate `R1CSGens` struct. - fn r1cs_gens(&self) -> R1CSGens; + /// Return an appropriate `CommitmentKey` struct. + fn commitment_key(&self) -> CommitmentKey; } impl NovaWitness for SatisfyingAssignment @@ -38,12 +37,12 @@ where fn r1cs_instance_and_witness( &self, shape: &R1CSShape, - gens: &R1CSGens, + ck: &CommitmentKey, ) -> Result<(R1CSInstance, R1CSWitness), NovaError> { let W = R1CSWitness::::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::::new(shape, &comm_W, X)?; @@ -88,8 +87,8 @@ where S } - fn r1cs_gens(&self) -> R1CSGens { - R1CSGens::::new(self.num_constraints(), self.num_aux()) + fn commitment_key(&self) -> CommitmentKey { + R1CS::::commitment_key(self.num_constraints(), self.num_aux()) } } diff --git a/src/circuit.rs b/src/circuit.rs index 30d11f71..a9e9d04f 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -3,7 +3,7 @@ //! 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 @@ mod tests { let ro_consts1: ROConstantsCircuit = PoseidonConstantsCircuit::new(); let ro_consts2: ROConstantsCircuit = PoseidonConstantsCircuit::new(); - // Initialize the shape and gens for the primary + // Initialize the shape and ck for the primary let circuit1: NovaAugmentedCircuit::Base>> = NovaAugmentedCircuit::new( params1.clone(), @@ -400,10 +400,10 @@ mod tests { ); let mut cs: ShapeCS = 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::Base>> = NovaAugmentedCircuit::new( params2.clone(), @@ -413,7 +413,7 @@ mod tests { ); let mut cs: ShapeCS = 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 @@ mod tests { 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 = <::Base as Field>::zero(); @@ -460,8 +460,8 @@ mod tests { 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()); } } diff --git a/src/gadgets/ecc.rs b/src/gadgets/ecc.rs index 95c681e1..3616f86c 100644 --- a/src/gadgets/ecc.rs +++ b/src/gadgets/ecc.rs @@ -976,12 +976,12 @@ mod tests { let _ = synthesize_smul::(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 = SatisfyingAssignment::new(); let (a, e, s) = synthesize_smul::(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 = Point::new( a.x.get_value().unwrap(), @@ -996,7 +996,7 @@ mod tests { 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(mut cs: CS) -> (AllocatedPoint, AllocatedPoint) @@ -1018,12 +1018,12 @@ mod tests { let _ = synthesize_add_equal::(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 = SatisfyingAssignment::new(); let (a, e) = synthesize_add_equal::(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 = Point::new( a.x.get_value().unwrap(), a.y.get_value().unwrap(), @@ -1037,7 +1037,7 @@ mod tests { 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(mut cs: CS) -> AllocatedPoint @@ -1064,12 +1064,12 @@ mod tests { let _ = synthesize_add_negation::(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 = SatisfyingAssignment::new(); let e = synthesize_add_negation::(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 = Point::new( e.x.get_value().unwrap(), e.y.get_value().unwrap(), @@ -1077,6 +1077,6 @@ mod tests { ); 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()); } } diff --git a/src/lib.rs b/src/lib.rs index 3dd5e0ed..54572eec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 @@ where F_arity_secondary: usize, ro_consts_primary: ROConstants, ro_consts_circuit_primary: ROConstantsCircuit, - r1cs_gens_primary: R1CSGens, + ck_primary: CommitmentKey, r1cs_shape_primary: R1CSShape, - r1cs_shape_padded_primary: R1CSShape, ro_consts_secondary: ROConstants, ro_consts_circuit_secondary: ROConstantsCircuit, - r1cs_gens_secondary: R1CSGens, + ck_secondary: CommitmentKey, r1cs_shape_secondary: R1CSShape, - r1cs_shape_padded_secondary: R1CSShape, augmented_circuit_params_primary: NovaAugmentedCircuitParams, augmented_circuit_params_secondary: NovaAugmentedCircuitParams, _p_c1: PhantomData, @@ -101,7 +97,7 @@ where let ro_consts_circuit_primary: ROConstantsCircuit = ROConstantsCircuit::::new(); let ro_consts_circuit_secondary: ROConstantsCircuit = ROConstantsCircuit::::new(); - // Initialize gens for the primary + // Initialize ck for the primary let circuit_primary: NovaAugmentedCircuit = NovaAugmentedCircuit::new( augmented_circuit_params_primary.clone(), None, @@ -110,10 +106,9 @@ where ); let mut cs: ShapeCS = 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 = NovaAugmentedCircuit::new( augmented_circuit_params_secondary.clone(), None, @@ -122,22 +117,19 @@ where ); let mut cs: ShapeCS = 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 @@ where ); 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 @@ where ); 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 @@ where 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 @@ where let l_u_secondary = u_secondary; let r_W_secondary = RelaxedR1CSWitness::::default(&pp.r1cs_shape_secondary); let r_U_secondary = - RelaxedR1CSInstance::::default(&pp.r1cs_gens_secondary, &pp.r1cs_shape_secondary); + RelaxedR1CSInstance::::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 @@ where 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 @@ where 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 @@ where 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 @@ where 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 @@ where 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,9 +497,51 @@ where } } -/// A SNARK that proves the knowledge of a valid `RecursiveSNARK` +/// A type that holds the prover key for `CompressedSNARK` #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] +pub struct ProverKey +where + G1: Group::Scalar>, + G2: Group::Scalar>, + C1: StepCircuit, + C2: StepCircuit, + S1: RelaxedR1CSSNARKTrait, + S2: RelaxedR1CSSNARKTrait, +{ + pk_primary: S1::ProverKey, + pk_secondary: S2::ProverKey, + _p_c1: PhantomData, + _p_c2: PhantomData, +} + +/// A type that holds the verifier key for `CompressedSNARK` +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct VerifierKey +where + G1: Group::Scalar>, + G2: Group::Scalar>, + C1: StepCircuit, + C2: StepCircuit, + S1: RelaxedR1CSSNARKTrait, + S2: RelaxedR1CSSNARKTrait, +{ + F_arity_primary: usize, + F_arity_secondary: usize, + ro_consts_primary: ROConstants, + ro_consts_secondary: ROConstants, + r1cs_shape_primary_digest: G1::Scalar, + r1cs_shape_secondary_digest: G2::Scalar, + vk_primary: S1::VerifierKey, + vk_secondary: S2::VerifierKey, + _p_c1: PhantomData, + _p_c2: PhantomData, +} + +/// A SNARK that proves the knowledge of a valid `RecursiveSNARK` +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound = "")] pub struct CompressedSNARK where G1: Group::Scalar>, @@ -546,16 +577,50 @@ where S1: RelaxedR1CSSNARKTrait, S2: RelaxedR1CSSNARKTrait, { + /// Creates prover and verifier keys for `CompressedSNARK` + pub fn setup( + pp: &PublicParams, + ) -> ( + ProverKey, + VerifierKey, + ) { + 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, + pk: &ProverKey, recursive_snark: &RecursiveSNARK, ) -> Result { 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 @@ where || { // 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 @@ where 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 @@ where /// Verify the correctness of the `CompressedSNARK` pub fn verify( &self, - pp: &PublicParams, + vk: &VerifierKey, num_steps: usize, z0_primary: Vec, z0_secondary: Vec, @@ -649,10 +703,10 @@ where // check if the output hashes in R1CS instances point to the right running instances let (hash_primary, hash_secondary) = { let mut hasher = ::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::(pp.r1cs_shape_secondary.get_digest())); + hasher.absorb(scalar_as_base::(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 @@ where self.r_U_secondary.absorb_in_ro(&mut hasher); let mut hasher2 = ::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::(pp.r1cs_shape_primary.get_digest())); + hasher2.absorb(scalar_as_base::(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 @@ where // 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 @@ where } } -type CommitmentGens = <::CE as CommitmentEngineTrait>::CommitmentGens; +type CommitmentKey = <::CE as CommitmentEngineTrait>::CommitmentKey; type Commitment = <::CE as CommitmentEngineTrait>::Commitment; type CompressedCommitment = <<::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment; type CE = ::CE; @@ -962,14 +1010,17 @@ mod tests { assert_eq!(zn_secondary, zn_secondary_direct); assert_eq!(zn_secondary, vec![::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![::Scalar::one()], vec![::Scalar::zero()], @@ -1110,13 +1161,16 @@ mod tests { 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()); } diff --git a/src/nifs.rs b/src/nifs.rs index 632acb9f..a2608e5a 100644 --- a/src/nifs.rs +++ b/src/nifs.rs @@ -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 @@ type ROConstants = impl NIFS { /// 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, + ck: &CommitmentKey, ro_consts: &ROConstants, S: &R1CSShape, U1: &RelaxedR1CSInstance, @@ -51,7 +52,7 @@ impl NIFS { 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 @@ impl NIFS { pub fn verify( &self, ro_consts: &ROConstants, - S: &R1CSShape, + S_digest: &G::Scalar, U1: &RelaxedR1CSInstance, U2: &R1CSInstance, ) -> Result, 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::(*S_digest)); // append U1 and U2 to transcript U1.absorb_in_ro(&mut ro); @@ -115,7 +116,10 @@ impl NIFS { #[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 @@ mod tests { let mut cs: ShapeCS = 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 = <::RO as ROTrait<::Base, ::Scalar>>::Constants::new(); // Now get the instance and assignment for one instance let mut cs: SatisfyingAssignment = 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 = 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, + ck: &CommitmentKey, ro_consts: &<::RO as ROTrait<::Base, ::Scalar>>::Constants, shape: &R1CSShape, U1: &R1CSInstance, @@ -203,15 +207,15 @@ mod tests { ) { // 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { }; // generate generators and ro constants - let gens = R1CSGens::new(num_cons, num_vars); + let ck = R1CS::::commitment_key(num_cons, num_vars); let ro_consts = <::RO as ROTrait<::Base, ::Scalar>>::Constants::new(); let rand_inst_witness_generator = - |gens: &R1CSGens, I: &S| -> (S, R1CSInstance, R1CSWitness) { + |ck: &CommitmentKey, I: &S| -> (S, R1CSInstance, R1CSWitness) { let i0 = *I; // compute a satisfying (vars, X) tuple @@ -328,24 +332,24 @@ mod tests { 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); } } diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 87a76281..5cfb0bfa 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -2,14 +2,14 @@ #![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 { - gens_v: CommitmentGens, - gens_s: CommitmentGens, +pub struct ProverKey { + ck_s: CommitmentKey, +} + +/// Provides an implementation of the verifier key +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct VerifierKey { + ck_v: CommitmentKey, + ck_s: CommitmentKey, } /// Provides an implementation of a polynomial evaluation argument @@ -41,21 +48,31 @@ pub struct EvaluationEngine { impl EvaluationEngineTrait for EvaluationEngine where G: Group, - CommitmentGens: CommitmentGensExtTrait, + CommitmentKey: CommitmentKeyExtTrait, { type CE = G::CE; - type EvaluationGens = EvaluationGens; + type ProverKey = ProverKey; + type VerifierKey = VerifierKey; type EvaluationArgument = EvaluationArgument; - fn setup(gens: &>::CommitmentGens) -> Self::EvaluationGens { - EvaluationGens { - gens_v: gens.clone(), - gens_s: CommitmentGens::::new(b"ipa", 1), - } + fn setup( + ck: &>::CommitmentKey, + ) -> (Self::ProverKey, Self::VerifierKey) { + let pk = ProverKey { + ck_s: CommitmentKey::::new(b"ipa", 1), + }; + + let vk = VerifierKey { + ck_v: ck.clone(), + ck_s: CommitmentKey::::new(b"ipa", 1), + }; + + (pk, vk) } fn prove( - gens: &Self::EvaluationGens, + ck: &CommitmentKey, + pk: &Self::ProverKey, transcript: &mut G::TE, comm: &Commitment, poly: &[G::Scalar], @@ -66,13 +83,13 @@ where 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, point: &[G::Scalar], @@ -82,8 +99,8 @@ where 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 @@ struct InnerProductArgument { impl InnerProductArgument where G: Group, - CommitmentGens: CommitmentGensExtTrait, + CommitmentKey: CommitmentKeyExtTrait, { fn protocol_name() -> &'static [u8] { b"inner product argument" } fn prove( - gens: &CommitmentGens, - gens_c: &CommitmentGens, + ck: &CommitmentKey, + ck_c: &CommitmentKey, U: &InnerProductInstance, W: &InnerProductWitness, transcript: &mut G::TE, @@ -171,12 +188,12 @@ where // 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, + ck: &CommitmentKey, transcript: &mut G::TE| -> Result< ( @@ -184,18 +201,18 @@ where CompressedCommitment, Vec, Vec, - CommitmentGens, + CommitmentKey, ), 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::::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 @@ where ) .compress(); let R = CE::::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 @@ where .map(|(b_L, b_R)| *b_L * r_inverse + r * *b_R) .collect::>(); - 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 @@ where // 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 @@ where fn verify( &self, - gens: &CommitmentGens, - gens_c: &CommitmentGens, + ck: &CommitmentKey, + ck_c: &CommitmentKey, n: usize, U: &InnerProductInstance, transcript: &mut G::TE, @@ -286,9 +303,9 @@ where // 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::::commit(&gens_c, &[U.c]); + let P = U.comm_a_vec + CE::::commit(&ck_c, &[U.c]); let batch_invert = |v: &[G::Scalar]| -> Result, NovaError> { let mut products = vec![G::Scalar::zero(); v.len()]; @@ -354,23 +371,23 @@ where s }; - let gens_hat = { - let c = CE::::commit(gens, &s).compress(); - CommitmentGens::::reinterpret_commitments_as_gens(&[c])? + let ck_hat = { + let c = CE::::commit(ck, &s).compress(); + CommitmentKey::::reinterpret_commitments_as_ck(&[c])? }; let b_hat = inner_product(&U.b_vec, &s); let P_hat = { - let gens_folded = { - let gens_L = CommitmentGens::::reinterpret_commitments_as_gens(&self.L_vec)?; - let gens_R = CommitmentGens::::reinterpret_commitments_as_gens(&self.R_vec)?; - let gens_P = CommitmentGens::::reinterpret_commitments_as_gens(&[P.compress()])?; - gens_L.combine(&gens_R).combine(&gens_P) + let ck_folded = { + let ck_L = CommitmentKey::::reinterpret_commitments_as_ck(&self.L_vec)?; + let ck_R = CommitmentKey::::reinterpret_commitments_as_ck(&self.R_vec)?; + let ck_P = CommitmentKey::::reinterpret_commitments_as_ck(&[P.compress()])?; + ck_L.combine(&ck_R).combine(&ck_P) }; CE::::commit( - &gens_folded, + &ck_folded, &r_square .iter() .chain(r_inverse_square.iter()) @@ -380,12 +397,7 @@ where ) }; - if P_hat - == CE::::commit( - &gens_hat.combine(&gens_c), - &[self.a_hat, self.a_hat * b_hat], - ) - { + if P_hat == CE::::commit(&ck_hat.combine(&ck_c), &[self.a_hat, self.a_hat * b_hat]) { Ok(()) } else { Err(NovaError::InvalidIPA) diff --git a/src/provider/pasta.rs b/src/provider/pasta.rs index 5b32ea81..8f4d773e 100644 --- a/src/provider/pasta.rs +++ b/src/provider/pasta.rs @@ -105,7 +105,7 @@ macro_rules! impl_traits { 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::>() .into_par_iter() .map(|i| { @@ -115,22 +115,22 @@ macro_rules! impl_traits { .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::>() .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]; - ::batch_normalize(&gens_proj[start..end], &mut gens); - gens + let mut ck = vec![$name_curve_affine::identity(); end - start]; + ::batch_normalize(&ck_proj[start..end], &mut ck); + ck } else { vec![] } @@ -140,9 +140,9 @@ macro_rules! impl_traits { .flatten() .collect() } else { - let mut gens = vec![$name_curve_affine::identity(); n]; - ::batch_normalize(&gens_proj, &mut gens); - gens + let mut ck = vec![$name_curve_affine::identity(); n]; + ::batch_normalize(&ck_proj, &mut ck); + ck } } @@ -353,14 +353,14 @@ mod tests { 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 @@ mod tests { 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 = ::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 = ::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); } } } diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index 7a32b3e5..c2cb3811 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -2,7 +2,7 @@ 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 { - gens: Vec, +pub struct CommitmentKey { + ck: Vec, _p: PhantomData, } @@ -37,24 +37,24 @@ pub struct CompressedCommitment { comm: G::CompressedGroupElement, } -impl CommitmentGensTrait for CommitmentGens { +impl CommitmentKeyTrait for CommitmentKey { type Commitment = Commitment; 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 @@ pub struct CommitmentEngine { } impl CommitmentEngineTrait for CommitmentEngine { - type CommitmentGens = CommitmentGens; + type CommitmentKey = CommitmentKey; type Commitment = Commitment; - 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: CommitmentGensTrait { +pub(crate) trait CommitmentKeyExtTrait: CommitmentKeyTrait { type CE: CommitmentEngineTrait; /// Splits the commitment key into two pieces at a specified point @@ -235,87 +235,87 @@ pub(crate) trait CommitmentGensExtTrait: CommitmentGensTrait { fn scale(&self, r: &G::Scalar) -> Self; /// Reinterprets commitments as commitment keys - fn reinterpret_commitments_as_gens( - c: &[<<>::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment], + fn reinterpret_commitments_as_ck( + c: &[<<>::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment], ) -> Result where Self: Sized; } -impl CommitmentGensExtTrait for CommitmentGens { +impl CommitmentKeyExtTrait for CommitmentKey { type CE = CommitmentEngine; - fn split_at(&self, n: usize) -> (CommitmentGens, CommitmentGens) { + fn split_at(&self, n: usize) -> (CommitmentKey, CommitmentKey) { ( - 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) -> CommitmentGens { - let gens = { - let mut c = self.gens.clone(); - c.extend(other.gens.clone()); + fn combine(&self, other: &CommitmentKey) -> CommitmentKey { + 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 { + fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentKey { 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]) -> Result { + fn reinterpret_commitments_as_ck(c: &[CompressedCommitment]) -> Result { let d = (0..c.len()) .into_par_iter() .map(|i| Commitment::::decompress(&c[i])) .collect::>, 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(), }) } diff --git a/src/r1cs.rs b/src/r1cs.rs index 7dfad589..7d06a7d7 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -8,12 +8,12 @@ use crate::{ 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 @@ use sha3::{Digest, Sha3_256}; /// Public parameters for a given R1CS #[derive(Clone, Serialize, Deserialize)] #[serde(bound = "")] -pub struct R1CSGens { - pub(crate) gens: CommitmentGens, +pub struct R1CS { + _p: PhantomData, } /// A type that holds the shape of the R1CS matrices @@ -71,12 +71,10 @@ pub struct RelaxedR1CSInstance { pub(crate) u: G::Scalar, } -impl R1CSGens { +impl R1CS { /// Samples public parameters for the specified number of constraints and variables in an R1CS - pub fn new(num_cons: usize, num_vars: usize) -> R1CSGens { - R1CSGens { - gens: CommitmentGens::::new(b"gens", max(num_vars, num_cons)), - } + pub fn commitment_key(num_cons: usize, num_vars: usize) -> CommitmentKey { + CommitmentKey::::new(b"ck", max(num_vars, num_cons)) } } @@ -181,7 +179,7 @@ impl R1CSShape { /// Checks if the Relaxed R1CS instance is satisfiable given a witness and its shape pub fn is_sat_relaxed( &self, - gens: &R1CSGens, + ck: &CommitmentKey, U: &RelaxedR1CSInstance, W: &RelaxedR1CSWitness, ) -> Result<(), NovaError> { @@ -206,10 +204,8 @@ impl R1CSShape { // 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::::commit(&gens.gens, &W.W), - || CE::::commit(&gens.gens, &W.E), - ); + let (comm_W, comm_E) = + rayon::join(|| CE::::commit(ck, &W.W), || CE::::commit(ck, &W.E)); U.comm_W == comm_W && U.comm_E == comm_E }; @@ -223,7 +219,7 @@ impl R1CSShape { /// Checks if the R1CS instance is satisfiable given a witness and its shape pub fn is_sat( &self, - gens: &R1CSGens, + ck: &CommitmentKey, U: &R1CSInstance, W: &R1CSWitness, ) -> Result<(), NovaError> { @@ -246,7 +242,7 @@ impl R1CSShape { }; // verify if comm_W is a commitment to W - let res_comm: bool = U.comm_W == CE::::commit(&gens.gens, &W.W); + let res_comm: bool = U.comm_W == CE::::commit(ck, &W.W); if res_eq && res_comm { Ok(()) @@ -259,7 +255,7 @@ impl R1CSShape { /// Relaxed R1CS instance-witness pair and an R1CS instance-witness pair pub fn commit_T( &self, - gens: &R1CSGens, + ck: &CommitmentKey, U1: &RelaxedR1CSInstance, W1: &RelaxedR1CSWitness, U2: &R1CSInstance, @@ -300,7 +296,7 @@ impl R1CSShape { .map(|(((a, b), c), d)| *a + *b - *c - *d) .collect::>(); - let comm_T = CE::::commit(&gens.gens, &T); + let comm_T = CE::::commit(ck, &T); Ok((T, comm_T)) } @@ -466,8 +462,8 @@ impl R1CSWitness { } /// Commits to the witness using the supplied generators - pub fn commit(&self, gens: &R1CSGens) -> Commitment { - CE::::commit(&gens.gens, &self.W) + pub fn commit(&self, ck: &CommitmentKey) -> Commitment { + CE::::commit(ck, &self.W) } } @@ -523,11 +519,8 @@ impl RelaxedR1CSWitness { } /// Commits to the witness using the supplied generators - pub fn commit(&self, gens: &R1CSGens) -> (Commitment, Commitment) { - ( - CE::::commit(&gens.gens, &self.W), - CE::::commit(&gens.gens, &self.E), - ) + pub fn commit(&self, ck: &CommitmentKey) -> (Commitment, Commitment) { + (CE::::commit(ck, &self.W), CE::::commit(ck, &self.E)) } /// Folds an incoming R1CSWitness into the current one @@ -577,7 +570,7 @@ impl RelaxedR1CSWitness { impl RelaxedR1CSInstance { /// Produces a default RelaxedR1CSInstance given R1CSGens and R1CSShape - pub fn default(_gens: &R1CSGens, S: &R1CSShape) -> RelaxedR1CSInstance { + pub fn default(_ck: &CommitmentKey, S: &R1CSShape) -> RelaxedR1CSInstance { let (comm_W, comm_E) = (Commitment::::default(), Commitment::::default()); RelaxedR1CSInstance { comm_W, @@ -589,11 +582,11 @@ impl RelaxedR1CSInstance { /// Initializes a new RelaxedR1CSInstance from an R1CSInstance pub fn from_r1cs_instance( - gens: &R1CSGens, + ck: &CommitmentKey, S: &R1CSShape, instance: &R1CSInstance, ) -> RelaxedR1CSInstance { - 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(); diff --git a/src/spartan/mod.rs b/src/spartan/mod.rs index 9eb50d50..8089c366 100644 --- a/src/spartan/mod.rs +++ b/src/spartan/mod.rs @@ -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 @@ use sumcheck::SumcheckProof; #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct ProverKey> { - gens: EE::EvaluationGens, + pk_ee: EE::ProverKey, S: R1CSShape, } -impl> ProverKeyTrait for ProverKey { - fn new(gens: &R1CSGens, S: &R1CSShape) -> 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> { - gens: EE::EvaluationGens, + vk_ee: EE::VerifierKey, S: R1CSShape, } -impl> VerifierKeyTrait - for VerifierKey -{ - fn new(gens: &R1CSGens, S: &R1CSShape) -> 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 @@ impl> RelaxedR1CSSNARKTrait; type VerifierKey = VerifierKey; + fn setup(ck: &CommitmentKey, S: &R1CSShape) -> (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, pk: &Self::ProverKey, U: &RelaxedR1CSInstance, W: &RelaxedR1CSWitness, ) -> Result { + 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 @@ impl> RelaxedR1CSSNARKTrait>(); 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 @@ impl> RelaxedR1CSSNARKTrait: +pub trait CommitmentKeyTrait: 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: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// Holds the type of the commitment key - type CommitmentGens: CommitmentGensTrait; + type CommitmentKey: CommitmentKeyTrait; /// Holds the type of the commitment type Commitment: CommitmentTrait; /// 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; } diff --git a/src/traits/evaluation.rs b/src/traits/evaluation.rs index 1840462a..3f1fba61 100644 --- a/src/traits/evaluation.rs +++ b/src/traits/evaluation.rs @@ -14,18 +14,24 @@ pub trait EvaluationEngineTrait: /// A type that holds the associated commitment engine type CE: CommitmentEngineTrait; - /// 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: &>::CommitmentGens) -> Self::EvaluationGens; + fn setup( + ck: &>::CommitmentKey, + ) -> (Self::ProverKey, Self::VerifierKey); /// A method to prove the evaluation of a multilinear polynomial fn prove( - gens: &Self::EvaluationGens, + ck: &>::CommitmentKey, + pk: &Self::ProverKey, transcript: &mut G::TE, comm: &>::Commitment, poly: &[G::Scalar], @@ -35,7 +41,7 @@ pub trait EvaluationEngineTrait: /// A method to verify the purported evaluation of a multilinear polynomials fn verify( - gens: &Self::EvaluationGens, + vk: &Self::VerifierKey, transcript: &mut G::TE, comm: &>::Commitment, point: &[G::Scalar], diff --git a/src/traits/snark.rs b/src/traits/snark.rs index ff5d7c7b..20289f00 100644 --- a/src/traits/snark.rs +++ b/src/traits/snark.rs @@ -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: Send + Sync { - /// Produces a new prover's key - fn new(gens: &R1CSGens, S: &R1CSShape) -> Self; -} - -/// A trait that defines the behavior of a zkSNARK's verifier key -pub trait VerifierKeyTrait: Send + Sync { - /// Produces a new verifier's key - fn new(gens: &R1CSGens, S: &R1CSShape) -> Self; -} - /// A trait that defines the behavior of a zkSNARK pub trait RelaxedR1CSSNARKTrait: Sized + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// A type that represents the prover's key - type ProverKey: ProverKeyTrait + 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 + Serialize + for<'de> Deserialize<'de>; - - /// Produces a prover key - fn prover_key(gens: &R1CSGens, S: &R1CSShape) -> Self::ProverKey { - Self::ProverKey::new(gens, S) - } + type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de>; - /// Produces a verifier key - fn verifier_key(gens: &R1CSGens, S: &R1CSShape) -> Self::VerifierKey { - Self::VerifierKey::new(gens, S) - } + /// Produces the keys for the prover and the verifier + fn setup(ck: &CommitmentKey, S: &R1CSShape) -> (Self::ProverKey, Self::VerifierKey); /// Produces a new SNARK for a relaxed R1CS fn prove( + ck: &CommitmentKey, pk: &Self::ProverKey, U: &RelaxedR1CSInstance, W: &RelaxedR1CSWitness,