reorganize traits into a module; cut boilerplate code (#91) use a default implementation for step circuit
@@ -1,45 +1,18 @@
#![allow(non_snake_case)] +use criterion::*; use nova_snark::{ - traits::{Group, StepCircuit}, + traits::{circuit::TrivialTestCircuit, Group}, CompressedSNARK, PublicParams, RecursiveSNARK, }; +use std::time::Duration; type G1 = pasta_curves::pallas::Point; type G2 = pasta_curves::vesta::Point; type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>; type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>; - -#[derive(Clone, Debug)] -struct TrivialTestCircuit<F: PrimeField> { - _p: PhantomData<F>, -} - -impl<F> StepCircuit<F> for TrivialTestCircuit<F> -where - F: PrimeField, -{ - fn synthesize<CS: ConstraintSystem<F>>( - &self, - _cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError> { - Ok(z) - } - - fn compute(&self, z: &F) -> F { - *z - } -} - type C1 = TrivialTestCircuit<<G1 as Group>::Scalar>; type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>; - -use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; -use core::marker::PhantomData; -use criterion::*; -use ff::PrimeField; -use std::time::Duration; fn compressed_snark_benchmark(c: &mut Criterion) { let num_samples = 10;@@ -64,12 +37,8 @@ group.sample_size(num_samples);
// Produce public parameters let pp = PublicParams::<G1, G2, C1, C2>::setup( - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + TrivialTestCircuit::default(), ); // produce a recursive SNARK@@ -80,12 +49,8 @@ for i in 0..num_steps {
let res = RecursiveSNARK::prove_step( &pp, recursive_snark, - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + TrivialTestCircuit::default(), <G1 as Group>::Scalar::one(), <G2 as Group>::Scalar::zero(), );
@@ -1,44 +1,17 @@
#![allow(non_snake_case)] +use criterion::*; use nova_snark::{ - traits::{Group, StepCircuit}, + traits::{circuit::TrivialTestCircuit, Group}, PublicParams, RecursiveSNARK, }; +use std::time::Duration; type G1 = pasta_curves::pallas::Point; type G2 = pasta_curves::vesta::Point; - -#[derive(Clone, Debug)] -struct TrivialTestCircuit<F: PrimeField> { - _p: PhantomData<F>, -} - -impl<F> StepCircuit<F> for TrivialTestCircuit<F> -where - F: PrimeField, -{ - fn synthesize<CS: ConstraintSystem<F>>( - &self, - _cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError> { - Ok(z) - } - - fn compute(&self, z: &F) -> F { - *z - } -} - type C1 = TrivialTestCircuit<<G1 as Group>::Scalar>; type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>; -use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; -use core::marker::PhantomData; -use criterion::*; -use ff::PrimeField; -use std::time::Duration; - fn recursive_snark_benchmark(c: &mut Criterion) { let num_samples = 10; bench_recursive_snark(c, num_samples);@@ -62,12 +35,8 @@ group.sample_size(num_samples);
// Produce public parameters let pp = PublicParams::<G1, G2, C1, C2>::setup( - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + TrivialTestCircuit::default(), ); // Bench time to produce a recursive SNARK;@@ -81,12 +50,8 @@ for i in 0..num_warmup_steps {
let res = RecursiveSNARK::prove_step( &pp, recursive_snark, - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + TrivialTestCircuit::default(), <G1 as Group>::Scalar::one(), <G2 as Group>::Scalar::zero(), );@@ -112,12 +77,8 @@ // produce a recursive SNARK for a step of the recursion
assert!(RecursiveSNARK::prove_step( black_box(&pp), black_box(recursive_snark.clone()), - black_box(TrivialTestCircuit { - _p: Default::default(), - }), - black_box(TrivialTestCircuit { - _p: Default::default(), - }), + black_box(TrivialTestCircuit::default()), + black_box(TrivialTestCircuit::default()), black_box(<G1 as Group>::Scalar::zero()), black_box(<G2 as Group>::Scalar::zero()), )
@@ -12,11 +12,13 @@ poseidon::{Poseidon, PoseidonConstants},
Strength, }; use nova_snark::{ - traits::{Group, StepCircuit}, + traits::{ + circuit::{StepCircuit, TrivialTestCircuit}, + Group, + }, CompressedSNARK, PublicParams, RecursiveSNARK, }; use num_bigint::BigUint; -use std::marker::PhantomData; use std::time::Instant; #[derive(Clone, Debug)]@@ -183,9 +185,7 @@ ],
pc: pc.clone(), }; - let circuit_secondary = TrivialTestCircuit { - _p: Default::default(), - }; + let circuit_secondary = TrivialTestCircuit::default(); println!("Nova-based VDF with MinRoot delay function"); println!("==========================================");@@ -299,26 +299,3 @@ start.elapsed()
); assert!(res.is_ok()); } - -// A trivial test circuit that we use on the secondary curve -#[derive(Clone, Debug)] -struct TrivialTestCircuit<F: PrimeField> { - _p: PhantomData<F>, -} - -impl<F> StepCircuit<F> for TrivialTestCircuit<F> -where - F: PrimeField, -{ - fn synthesize<CS: ConstraintSystem<F>>( - &self, - _cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError> { - Ok(z) - } - - fn compute(&self, z: &F) -> F { - *z - } -}
@@ -16,7 +16,7 @@ alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select, le_bits_to_num,
}, }, r1cs::{R1CSInstance, RelaxedR1CSInstance}, - traits::{Group, HashFuncCircuitTrait, HashFuncConstantsCircuit, StepCircuit}, + traits::{circuit::StepCircuit, Group, HashFuncCircuitTrait, HashFuncConstantsCircuit}, }; use bellperson::{ gadgets::{@@ -355,32 +355,8 @@ use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
use crate::{ bellperson::r1cs::{NovaShape, NovaWitness}, poseidon::PoseidonConstantsCircuit, - traits::HashFuncConstantsTrait, + traits::{circuit::TrivialTestCircuit, HashFuncConstantsTrait}, }; - use ff::PrimeField; - use std::marker::PhantomData; - - #[derive(Clone)] - struct TestCircuit<F: PrimeField> { - _p: PhantomData<F>, - } - - impl<F> StepCircuit<F> for TestCircuit<F> - where - F: PrimeField, - { - fn synthesize<CS: ConstraintSystem<F>>( - &self, - _cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError> { - Ok(z) - } - - fn compute(&self, z: &F) -> F { - *z - } - } #[test] fn test_verification_circuit() {@@ -391,13 +367,11 @@ let ro_consts1: HashFuncConstantsCircuit<G2> = PoseidonConstantsCircuit::new();
let ro_consts2: HashFuncConstantsCircuit<G1> = PoseidonConstantsCircuit::new(); // Initialize the shape and gens for the primary - let circuit1: NIFSVerifierCircuit<G2, TestCircuit<<G2 as Group>::Base>> = + let circuit1: NIFSVerifierCircuit<G2, TrivialTestCircuit<<G2 as Group>::Base>> = NIFSVerifierCircuit::new( params1.clone(), None, - TestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), ro_consts1.clone(), ); let mut cs: ShapeCS<G1> = ShapeCS::new();@@ -406,13 +380,11 @@ let (shape1, gens1) = (cs.r1cs_shape(), cs.r1cs_gens());
assert_eq!(cs.num_constraints(), 20584); // Initialize the shape and gens for the secondary - let circuit2: NIFSVerifierCircuit<G1, TestCircuit<<G1 as Group>::Base>> = + let circuit2: NIFSVerifierCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> = NIFSVerifierCircuit::new( params2.clone(), None, - TestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), ro_consts2.clone(), ); let mut cs: ShapeCS<G2> = ShapeCS::new();@@ -425,13 +397,11 @@ let zero1 = <<G2 as Group>::Base as Field>::zero();
let mut cs1: SatisfyingAssignment<G1> = SatisfyingAssignment::new(); let inputs1: NIFSVerifierCircuitInputs<G2> = NIFSVerifierCircuitInputs::new(shape2.get_digest(), zero1, zero1, None, None, None, None); - let circuit1: NIFSVerifierCircuit<G2, TestCircuit<<G2 as Group>::Base>> = + let circuit1: NIFSVerifierCircuit<G2, TrivialTestCircuit<<G2 as Group>::Base>> = NIFSVerifierCircuit::new( params1, Some(inputs1), - TestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), ro_consts1, ); let _ = circuit1.synthesize(&mut cs1);@@ -451,13 +421,11 @@ None,
Some(inst1), None, ); - let circuit: NIFSVerifierCircuit<G1, TestCircuit<<G1 as Group>::Base>> = + let circuit: NIFSVerifierCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> = NIFSVerifierCircuit::new( params2, Some(inputs2), - TestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), ro_consts2, ); let _ = circuit.synthesize(&mut cs2);
@@ -16,7 +16,6 @@ // public modules
pub mod errors; pub mod gadgets; pub mod pasta; -pub mod snark; pub mod spartan_with_ipa_pc; pub mod traits;@@ -36,10 +35,9 @@ use nifs::NIFS;
use r1cs::{ R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, }; -use snark::RelaxedR1CSSNARKTrait; use traits::{ - AbsorbInROTrait, Group, HashFuncConstants, HashFuncConstantsCircuit, HashFuncConstantsTrait, - HashFuncTrait, StepCircuit, + circuit::StepCircuit, snark::RelaxedR1CSSNARKTrait, AbsorbInROTrait, Group, HashFuncConstants, + HashFuncConstantsCircuit, HashFuncConstantsTrait, HashFuncTrait, }; /// A type that holds public parameters of Nova@@ -665,32 +663,11 @@ type G2 = pasta_curves::vesta::Point;
type S1 = spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>; type S2 = spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>; use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; + use core::marker::PhantomData; use ff::PrimeField; - use std::marker::PhantomData; - - #[derive(Clone, Debug)] - struct TrivialTestCircuit<F: PrimeField> { - _p: PhantomData<F>, - } - - impl<F> StepCircuit<F> for TrivialTestCircuit<F> - where - F: PrimeField, - { - fn synthesize<CS: ConstraintSystem<F>>( - &self, - _cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError> { - Ok(z) - } - - fn compute(&self, z: &F) -> F { - *z - } - } + use traits::circuit::TrivialTestCircuit; - #[derive(Clone, Debug)] + #[derive(Clone, Debug, Default)] struct CubicCircuit<F: PrimeField> { _p: PhantomData<F>, }@@ -743,14 +720,7 @@ G1,
G2, TrivialTestCircuit<<G1 as Group>::Scalar>, TrivialTestCircuit<<G2 as Group>::Scalar>, - >::setup( - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, - ); + >::setup(TrivialTestCircuit::default(), TrivialTestCircuit::default()); let num_steps = 1;@@ -758,12 +728,8 @@ // produce a recursive SNARK
let res = RecursiveSNARK::prove_step( &pp, None, - TrivialTestCircuit { - _p: Default::default(), - }, - TrivialTestCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + TrivialTestCircuit::default(), <G1 as Group>::Scalar::zero(), <G2 as Group>::Scalar::zero(), );@@ -782,12 +748,8 @@ }
#[test] fn test_ivc_nontrivial() { - let circuit_primary = TrivialTestCircuit { - _p: Default::default(), - }; - let circuit_secondary = CubicCircuit { - _p: Default::default(), - }; + let circuit_primary = TrivialTestCircuit::default(); + let circuit_secondary = CubicCircuit::default(); // produce public parameters let pp = PublicParams::<@@ -852,10 +814,7 @@ // sanity: check the claimed output with a direct computation of the same
assert_eq!(zn_primary, <G1 as Group>::Scalar::one()); let mut zn_secondary_direct = <G2 as Group>::Scalar::zero(); for _i in 0..num_steps { - zn_secondary_direct = CubicCircuit { - _p: Default::default(), - } - .compute(&zn_secondary_direct); + zn_secondary_direct = CubicCircuit::default().compute(&zn_secondary_direct); } assert_eq!(zn_secondary, zn_secondary_direct); assert_eq!(zn_secondary, <G2 as Group>::Scalar::from(2460515u64));@@ -863,12 +822,8 @@ }
#[test] fn test_ivc_nontrivial_with_compression() { - let circuit_primary = TrivialTestCircuit { - _p: Default::default(), - }; - let circuit_secondary = CubicCircuit { - _p: Default::default(), - }; + let circuit_primary = TrivialTestCircuit::default(); + let circuit_secondary = CubicCircuit::default(); // produce public parameters let pp = PublicParams::<@@ -921,10 +876,7 @@ // sanity: check the claimed output with a direct computation of the same
assert_eq!(zn_primary, <G1 as Group>::Scalar::one()); let mut zn_secondary_direct = <G2 as Group>::Scalar::zero(); for _i in 0..num_steps { - zn_secondary_direct = CubicCircuit { - _p: Default::default(), - } - .compute(&zn_secondary_direct); + zn_secondary_direct = CubicCircuit::default().compute(&zn_secondary_direct); } assert_eq!(zn_secondary, zn_secondary_direct); assert_eq!(zn_secondary, <G2 as Group>::Scalar::from(2460515u64));@@ -1027,9 +979,7 @@ let circuit_primary = FifthRootCheckingCircuit {
y: <G1 as Group>::Scalar::zero(), }; - let circuit_secondary = TrivialTestCircuit { - _p: Default::default(), - }; + let circuit_secondary = TrivialTestCircuit::default(); // produce public parameters let pp = PublicParams::<@@ -1093,14 +1043,7 @@ G1,
G2, TrivialTestCircuit<<G1 as Group>::Scalar>, CubicCircuit<<G2 as Group>::Scalar>, - >::setup( - TrivialTestCircuit { - _p: Default::default(), - }, - CubicCircuit { - _p: Default::default(), - }, - ); + >::setup(TrivialTestCircuit::default(), CubicCircuit::default()); let num_steps = 1;@@ -1108,12 +1051,8 @@ // produce a recursive SNARK
let res = RecursiveSNARK::prove_step( &pp, None, - TrivialTestCircuit { - _p: Default::default(), - }, - CubicCircuit { - _p: Default::default(), - }, + TrivialTestCircuit::default(), + CubicCircuit::default(), <G1 as Group>::Scalar::one(), <G2 as Group>::Scalar::zero(), );
@@ -8,7 +8,7 @@ use super::r1cs::{
R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, }; use super::traits::{AbsorbInROTrait, Group, HashFuncTrait}; -use std::marker::PhantomData; +use core::marker::PhantomData; /// A SNARK that holds the proof of a step of an incremental computation #[allow(clippy::upper_case_acronyms)]
@@ -1,5 +1,5 @@
-//! A collection of traits that define the behavior of a zkSNARK for RelaxedR1CS -use super::{ +//! 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}, traits::Group,
@@ -8,8 +8,10 @@ use super::{
commitments::CommitGens, errors::NovaError, r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, - snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait}, - traits::{AppendToTranscriptTrait, ChallengeTrait, Group}, + traits::{ + snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait}, + AppendToTranscriptTrait, ChallengeTrait, Group, + }, }; use core::cmp::max; use ff::Field;
@@ -175,20 +175,6 @@ /// A helper trait for references implementing group scalar multiplication.
pub trait ScalarMulOwned<Rhs, Output = Self>: for<'r> ScalarMul<&'r Rhs, Output> {} impl<T, Rhs, Output> ScalarMulOwned<Rhs, Output> for T where T: for<'r> ScalarMul<&'r Rhs, Output> {} -/// A helper trait for a step of the incremental computation (i.e., circuit for F) -pub trait StepCircuit<F: PrimeField>: Send + Sync + Clone { - /// Sythesize the circuit for a computation step and return variable - /// that corresponds to the output of the step z_{i+1} - fn synthesize<CS: ConstraintSystem<F>>( - &self, - cs: &mut CS, - z: AllocatedNum<F>, - ) -> Result<AllocatedNum<F>, SynthesisError>; - - /// Execute the circuit for a computation step and return output - fn compute(&self, z: &F) -> F; -} - impl<F: PrimeField> AppendToTranscriptTrait for F { fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) { transcript.append_message(label, self.to_repr().as_ref());@@ -202,3 +188,6 @@ s.append_to_transcript(label, transcript);
} } } + +pub mod circuit; +pub mod snark;
@@ -0,0 +1,41 @@
+//! This module defines traits that a step function must implement +use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; +use core::marker::PhantomData; +use ff::PrimeField; + +/// A helper trait for a step of the incremental computation (i.e., circuit for F) +pub trait StepCircuit<F: PrimeField>: Send + Sync + Clone { + /// Sythesize the circuit for a computation step and return variable + /// that corresponds to the output of the step z_{i+1} + fn synthesize<CS: ConstraintSystem<F>>( + &self, + cs: &mut CS, + z: AllocatedNum<F>, + ) -> Result<AllocatedNum<F>, SynthesisError>; + + /// Execute the circuit for a computation step and return output + fn compute(&self, z: &F) -> F; +} + +/// A trivial step circuit that simply returns the input +#[derive(Clone, Debug, Default)] +pub struct TrivialTestCircuit<F: PrimeField> { + _p: PhantomData<F>, +} + +impl<F> StepCircuit<F> for TrivialTestCircuit<F> +where + F: PrimeField, +{ + fn synthesize<CS: ConstraintSystem<F>>( + &self, + _cs: &mut CS, + z: AllocatedNum<F>, + ) -> Result<AllocatedNum<F>, SynthesisError> { + Ok(z) + } + + fn compute(&self, z: &F) -> F { + *z + } +}