diff --git a/src/circuit.rs b/src/circuit.rs index f4a1724..002a7c2 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,36 +1,31 @@ -//! There are two Verification Circuits. Each of them is over a Pasta curve but -//! only one of them executes the next step of the computation by applying the inner function F. -//! There are also two running relaxed r1cs instances. -//! -//! When we build a circuit we denote u1 the running relaxed r1cs instance of -//! the circuit and u2 the running relaxed r1cs instance of the other circuit. -//! The circuit takes as input two hashes h1 and h2. -//! If the circuit applies the inner function F, then -//! h1 = H(params = H(shape, gens), u2, i, z0, zi) and h2 = H(u1, i) -//! otherwise -//! h1 = H(u2, i) and h2 = H(params = H(shape, gens), u1, i, z0, zi) +//! There are two Verification Circuits. The primary and the secondary. +//! Each of them is over a Pasta curve but +//! only the primary executes the next step of the computation. +//! TODO: The base case is different for the primary and the secondary. +//! 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 +//! the other into the running instance use super::{ commitments::Commitment, gadgets::{ ecc::AllocatedPoint, - utils::{ - alloc_bignat_constant, alloc_num_equals, alloc_one, alloc_zero, conditionally_select, - conditionally_select_bignat, le_bits_to_num, - }, + r1cs::{AllocatedR1CSInstance, AllocatedRelaxedR1CSInstance}, + utils::{alloc_num_equals, alloc_zero, conditionally_select, le_bits_to_num}, }, poseidon::{NovaPoseidonConstants, PoseidonROGadget}, - r1cs::RelaxedR1CSInstance, + r1cs::{R1CSInstance, RelaxedR1CSInstance}, traits::{Group, StepCircuit}, }; use bellperson::{ - gadgets::{boolean::Boolean, num::AllocatedNum, Assignment}, + gadgets::{ + boolean::{AllocatedBit, Boolean}, + num::AllocatedNum, + Assignment, + }, Circuit, ConstraintSystem, SynthesisError, }; -use bellperson_nonnative::{ - mp::bignat::BigNat, - util::{convert::f_to_nat, num::Num}, -}; use ff::{Field, PrimeField, PrimeFieldBits}; #[derive(Debug, Clone)] @@ -53,15 +48,13 @@ pub struct NIFSVerifierCircuitInputs where G: Group, { - h1: G::Base, - h2: G::Base, - u2: RelaxedR1CSInstance, + params: G::Base, // Hash(Shape of u2, Gens for u2). Needed for computing the challenge. i: G::Base, z0: G::Base, zi: G::Base, - params: G::Base, // Hash(Shape of u2, Gens for u2). Needed for computing the challenge. + U: RelaxedR1CSInstance, + u: R1CSInstance, T: Commitment, - w: Commitment, // The commitment to the witness of the fresh r1cs instance } impl NIFSVerifierCircuitInputs @@ -71,26 +64,22 @@ where /// Create new inputs/witness for the verification circuit #[allow(dead_code, clippy::too_many_arguments)] pub fn new( - h1: G::Base, - u2: RelaxedR1CSInstance, + params: G::Base, i: G::Base, z0: G::Base, zi: G::Base, - h2: G::Base, - params: G::Base, + U: RelaxedR1CSInstance, + u: R1CSInstance, T: Commitment, - w: Commitment, ) -> Self { Self { - h1, - u2, + params, i, z0, zi, - h2, - params, + U, + u, T, - w, } } } @@ -111,7 +100,8 @@ where impl NIFSVerifierCircuit where G: Group, - ::Base: ff::PrimeField, + ::Base: PrimeField + PrimeFieldBits, + ::Scalar: PrimeField + PrimeFieldBits, SC: StepCircuit, { /// Create a new verification circuit for the input relaxed r1cs instances @@ -132,133 +122,56 @@ where poseidon_constants, } } -} - -impl Circuit<::Base> for NIFSVerifierCircuit -where - G: Group, - ::Base: PrimeField + PrimeFieldBits, - ::Scalar: PrimeFieldBits, - SC: StepCircuit, -{ - fn synthesize::Base>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - /***********************************************************************/ - // Allocate h1 - /***********************************************************************/ - - let h1 = AllocatedNum::alloc(cs.namespace(|| "allocate h1"), || Ok(self.inputs.get()?.h1))?; - let h1_bn = BigNat::from_num( - cs.namespace(|| "allocate h1_bn"), - Num::from(h1.clone()), - self.params.limb_width, - self.params.n_limbs, - )?; - /***********************************************************************/ - // This circuit does not modify h2 but it outputs it. - // Allocate it and output it. - /***********************************************************************/ + /// Allocate all witnesses and return + fn alloc_witness::Base>>( + &self, + mut cs: CS, + ) -> Result< + ( + AllocatedNum, + AllocatedNum, + AllocatedNum, + AllocatedNum, + AllocatedRelaxedR1CSInstance, + AllocatedR1CSInstance, + AllocatedPoint, + ), + SynthesisError, + > { + // Allocate the params + let params = AllocatedNum::alloc(cs.namespace(|| "params"), || Ok(self.inputs.get()?.params))?; - // Allocate h2 as a big number with 8 limbs - let h2 = AllocatedNum::alloc(cs.namespace(|| "allocate h2"), || Ok(self.inputs.get()?.h2))?; - let h2_bn = BigNat::from_num( - cs.namespace(|| "allocate h2_bn"), - Num::from(h2.clone()), - self.params.limb_width, - self.params.n_limbs, - )?; + // Allocate i + let i = AllocatedNum::alloc(cs.namespace(|| "i"), || Ok(self.inputs.get()?.i))?; - let _ = h2.inputize(cs.namespace(|| "Output 1"))?; + // Allocate z0 + let z_0 = AllocatedNum::alloc(cs.namespace(|| "z0"), || Ok(self.inputs.get()?.z0))?; - /***********************************************************************/ - // Allocate u2 by allocating W_r, E_r, u_r, X_r - /***********************************************************************/ + // Allocate zi + let z_i = AllocatedNum::alloc(cs.namespace(|| "zi"), || Ok(self.inputs.get()?.zi))?; - // W_r = (x, y, infinity) - let W_r = AllocatedPoint::alloc( - cs.namespace(|| "allocate W_r"), + // Allocate the running instance + let U: AllocatedRelaxedR1CSInstance = AllocatedRelaxedR1CSInstance::alloc( + cs.namespace(|| "Allocate U"), self .inputs .get() - .map_or(None, |inputs| Some(inputs.u2.comm_W.comm.to_coordinates())), + .map_or(None, |inputs| Some(inputs.U.clone())), + self.params.limb_width, + self.params.n_limbs, )?; - // E_r = (x, y, infinity) - let E_r = AllocatedPoint::alloc( - cs.namespace(|| "allocate E_r"), + // Allocate the instance to be folded in + let u = AllocatedR1CSInstance::alloc( + cs.namespace(|| "allocate instance u to fold"), self .inputs .get() - .map_or(None, |inputs| Some(inputs.u2.comm_E.comm.to_coordinates())), + .map_or(None, |inputs| Some(inputs.u.clone())), )?; - // u_r << |G::Base| despite the fact that u_r is a scalar. - // So we parse all of its bytes as a G::Base element - let u_r = AllocatedNum::alloc(cs.namespace(|| "u_r"), || { - let u_bits = self.inputs.get()?.u2.u.to_le_bits(); - let mut mult = G::Base::one(); - let mut u = G::Base::zero(); - for bit in u_bits { - if bit { - u += mult; - } - mult = mult + mult; - } - Ok(u) - })?; - - // The running X is two items! the running h1 and the running h2 - let Xr0 = BigNat::alloc_from_nat( - cs.namespace(|| "allocate X_r[0]"), - || Ok(f_to_nat(&self.inputs.get()?.u2.X[0])), - self.params.limb_width, - self.params.n_limbs, - )?; - - // Analyze Xr0 as limbs to use later - let Xr0_bn = Xr0 - .as_limbs::() - .iter() - .enumerate() - .map(|(i, limb)| { - limb - .as_sapling_allocated_num(cs.namespace(|| format!("convert limb {} of X_r[0] to num", i))) - }) - .collect::>, _>>()?; - - let Xr1 = BigNat::alloc_from_nat( - cs.namespace(|| "allocate X_r[1]"), - || Ok(f_to_nat(&self.inputs.get()?.u2.X[1])), - self.params.limb_width, - self.params.n_limbs, - )?; - - // Analyze Xr1 as limbs to use later - let Xr1_bn = Xr1 - .as_limbs::() - .iter() - .enumerate() - .map(|(i, limb)| { - limb - .as_sapling_allocated_num(cs.namespace(|| format!("convert limb {} of X_r[1] to num", i))) - }) - .collect::>, _>>()?; - - /***********************************************************************/ - // Allocate i - /***********************************************************************/ - - let i = AllocatedNum::alloc(cs.namespace(|| "i"), || Ok(self.inputs.get()?.i))?; - - /***********************************************************************/ // Allocate T - /***********************************************************************/ - - // T = (x, y, infinity) - let T = AllocatedPoint::alloc( cs.namespace(|| "allocate T"), self @@ -267,200 +180,125 @@ where .map_or(None, |inputs| Some(inputs.T.comm.to_coordinates())), )?; - /***********************************************************************/ - // Allocate params - /***********************************************************************/ - - let params = AllocatedNum::alloc(cs.namespace(|| "params"), || Ok(self.inputs.get()?.params))?; - - /***********************************************************************/ - // Allocate W - /***********************************************************************/ - - // W = (x, y, infinity) - let W = AllocatedPoint::alloc( - cs.namespace(|| "allocate W"), - self - .inputs - .get() - .map_or(None, |inputs| Some(inputs.w.comm.to_coordinates())), - )?; - - /***********************************************************************/ - // U2' = default if i == 0, otherwise NIFS.V(pp, u_new, U, T) - /***********************************************************************/ - - // Allocate 0 and 1 - let zero = alloc_zero(cs.namespace(|| "zero"))?; - let one = alloc_one(cs.namespace(|| "one"))?; - - // Compute default values of U2': - // W_default and E_default are a commitment to zero - let W_default = AllocatedPoint::new(zero.clone(), zero.clone(), one); - let E_default = W_default.clone(); - - // u_default = 0 - let u_default = zero.clone(); - - // X_default = 0 - let X0_default = BigNat::alloc_from_nat( - cs.namespace(|| "allocate x_default[0]"), - || Ok(f_to_nat(&G::Scalar::zero())), - self.params.limb_width, - self.params.n_limbs, - )?; + Ok((params, i, z_0, z_i, U, u, T)) + } - let X1_default = BigNat::alloc_from_nat( - cs.namespace(|| "allocate x_default[1]"), - || Ok(f_to_nat(&G::Scalar::zero())), + /// Synthesizes base case and returns the new relaxed R1CSInstance + fn synthesize_base_case::Base>>( + &self, + mut cs: CS, + ) -> Result, SynthesisError> { + let U_default: AllocatedRelaxedR1CSInstance = AllocatedRelaxedR1CSInstance::default( + cs.namespace(|| "Allocate U_default"), self.params.limb_width, self.params.n_limbs, )?; + Ok(U_default) + } - // Compute r: - + /// Synthesizes non base case and returns the new relaxed R1CSInstance + /// And a boolean indicating if all checks pass + #[allow(clippy::too_many_arguments)] + fn synthesize_non_base_case::Base>>( + &self, + mut cs: CS, + params: AllocatedNum, + i: AllocatedNum, + z_0: AllocatedNum, + z_i: AllocatedNum, + U: AllocatedRelaxedR1CSInstance, + u: AllocatedR1CSInstance, + T: AllocatedPoint, + ) -> Result<(AllocatedRelaxedR1CSInstance, AllocatedBit), SynthesisError> { + // Check that u.x[0] = Hash(params, U,i,z0,zi) let mut ro: PoseidonROGadget = PoseidonROGadget::new(self.poseidon_constants.clone()); + ro.absorb(params); + ro.absorb(i); + ro.absorb(z_0); + ro.absorb(z_i); + let _ = U.absorb_in_ro(cs.namespace(|| "absorb U"), &mut ro)?; - ro.absorb(h1.clone()); - ro.absorb(h2); - ro.absorb(W.x.clone()); - ro.absorb(W.y.clone()); - ro.absorb(W.is_infinity.clone()); - ro.absorb(T.x.clone()); - ro.absorb(T.y.clone()); - ro.absorb(T.is_infinity.clone()); - // absorb each of the limbs of X_r[0] - for limb in Xr0_bn.clone().into_iter() { - ro.absorb(limb); - } - - // absorb each of the limbs of X_r[1] - for limb in Xr1_bn.clone().into_iter() { - ro.absorb(limb); - } - - let r_bits = ro.get_challenge(cs.namespace(|| "r bits"))?; - let r = le_bits_to_num(cs.namespace(|| "r"), r_bits.clone())?; - - // W_fold = W_r + r * W - let rW = W.scalar_mul(cs.namespace(|| "r * W"), r_bits.clone())?; - let W_fold = W_r.add(cs.namespace(|| "W_r + r * W"), &rW)?; - - // E_fold = E_r + r * T - let rT = T.scalar_mul(cs.namespace(|| "r * T"), r_bits)?; - let E_fold = E_r.add(cs.namespace(|| "E_r + r * T"), &rT)?; - - // u_fold = u_r + r - let u_fold = AllocatedNum::alloc(cs.namespace(|| "u_fold"), || { - Ok(*u_r.get_value().get()? + r.get_value().get()?) - })?; - cs.enforce( - || "Check u_fold", - |lc| lc, - |lc| lc, - |lc| lc + u_fold.get_variable() - u_r.get_variable() - r.get_variable(), - ); - - // Fold the IO: - // Analyze r into limbs - let r_bn = BigNat::from_num( - cs.namespace(|| "allocate r_bn"), - Num::from(r.clone()), - self.params.limb_width, - self.params.n_limbs, + let hash_bits = ro.get_hash(cs.namespace(|| "Input hash"))?; + let hash = le_bits_to_num(cs.namespace(|| "bits to hash"), hash_bits)?; + let check_pass = alloc_num_equals( + cs.namespace(|| "check consistency of u.X[0] with H(params, U, i, z0, zi)"), + u.X0.clone(), + hash, )?; - // Allocate the order of the non-native field as a constant - let m_bn = alloc_bignat_constant( - cs.namespace(|| "alloc m"), - &G::get_order(), + // Run NIFS Verifier + let U_fold = U.fold_with_r1cs( + cs.namespace(|| "compute fold of U and u"), + u, + T, + self.poseidon_constants.clone(), self.params.limb_width, self.params.n_limbs, )?; - // First the fold h1 with X_r[0]; - let (_, r_0) = h1_bn.mult_mod(cs.namespace(|| "r*h1"), &r_bn, &m_bn)?; - // add X_r[0] - let r_new_0 = Xr0.add::(&r_0)?; - // Now reduce - let Xr0_fold = r_new_0.red_mod(cs.namespace(|| "reduce folded X_r[0]"), &m_bn)?; - - // First the fold h2 with X_r[1]; - let (_, r_1) = h2_bn.mult_mod(cs.namespace(|| "r*h2"), &r_bn, &m_bn)?; - // add X_r[1] - let r_new_1 = Xr1.add::(&r_1)?; - // Now reduce - let Xr1_fold = r_new_1.red_mod(cs.namespace(|| "reduce folded X_r[1]"), &m_bn)?; - - // Now select the default values if i == 0 otherwise the fold values - let is_base_case = Boolean::from(alloc_num_equals( - cs.namespace(|| "Check if base case"), - i.clone(), - zero, - )?); + Ok((U_fold, check_pass)) + } +} - let W_new = AllocatedPoint::conditionally_select( - cs.namespace(|| "W_new"), - &W_default, - &W_fold, - &is_base_case, - )?; +impl Circuit<::Base> for NIFSVerifierCircuit +where + G: Group, + ::Base: PrimeField + PrimeFieldBits, + ::Scalar: PrimeFieldBits, + SC: StepCircuit, +{ + fn synthesize::Base>>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + // Allocate all witnesses + let (params, i, z_0, z_i, U, u, T) = + self.alloc_witness(cs.namespace(|| "allocate the circuit witness"))?; - let E_new = AllocatedPoint::conditionally_select( - cs.namespace(|| "E_new"), - &E_default, - &E_fold, - &is_base_case, - )?; + // Compute variable indicating if this is the base case + let zero = alloc_zero(cs.namespace(|| "zero"))?; + let is_base_case = alloc_num_equals(cs.namespace(|| "Check if base case"), i.clone(), zero)?; //TODO: maybe optimize this? - let u_new = conditionally_select(cs.namespace(|| "u_new"), &u_default, &u_fold, &is_base_case)?; + // Synthesize the circuit for the base case and get the new running instance + let Unew_base = self.synthesize_base_case(cs.namespace(|| "base case"))?; - let Xr0_new = conditionally_select_bignat( - cs.namespace(|| "X_r_new[0]"), - &X0_default, - &Xr0_fold, - &is_base_case, + // Synthesize the circuit for the non-base case and get the new running + // instance along with a boolean indicating if all checks have passed + let (Unew_non_base, check_non_base_pass) = self.synthesize_non_base_case( + cs.namespace(|| "synthesize non base case"), + params.clone(), + i.clone(), + z_0.clone(), + z_i.clone(), + U, + u.clone(), + T, )?; - // Analyze Xr0_new as limbs to use later - let Xr0_new_bn = Xr0_new - .as_limbs::() - .iter() - .enumerate() - .map(|(i, limb)| { - limb.as_sapling_allocated_num( - cs.namespace(|| format!("convert limb {} of X_r_new[0] to num", i)), - ) - }) - .collect::>, _>>()?; - - let Xr1_new = conditionally_select_bignat( - cs.namespace(|| "X_r_new[1]"), - &X1_default, - &Xr1_fold, + // Either check_non_base_pass=true or we are in the base case + let should_be_false = AllocatedBit::nor( + cs.namespace(|| "check_non_base_pass nor base_case"), + &check_non_base_pass, &is_base_case, )?; + cs.enforce( + || "check_non_base_pass nor base_case = false", + |lc| lc + should_be_false.get_variable(), + |lc| lc + CS::one(), + |lc| lc, + ); - // Analyze Xr1_new as limbs to use later - let Xr1_new_bn = Xr1_new - .as_limbs::() - .iter() - .enumerate() - .map(|(i, limb)| { - limb.as_sapling_allocated_num( - cs.namespace(|| format!("convert limb {} of X_r_new[1] to num", i)), - ) - }) - .collect::>, _>>()?; - - /***********************************************************************/ - // Compute i + 1 - /***********************************************************************/ + // Compute the U_new + let Unew = Unew_base.conditionally_select( + cs.namespace(|| "compute U_new"), + Unew_non_base, + &Boolean::from(is_base_case.clone()), + )?; + // Compute i + 1 let i_new = AllocatedNum::alloc(cs.namespace(|| "i + 1"), || { Ok(*i.get_value().get()? + G::Base::one()) })?; - cs.enforce( || "check i + 1", |lc| lc, @@ -468,113 +306,32 @@ where |lc| lc + i_new.get_variable() - CS::one() - i.get_variable(), ); - /***********************************************************************/ - // Allocate z0 - /***********************************************************************/ - - let z_0 = AllocatedNum::alloc(cs.namespace(|| "z0"), || Ok(self.inputs.get()?.z0))?; - - /***********************************************************************/ - // Allocate zi - /***********************************************************************/ - - let z_i = AllocatedNum::alloc(cs.namespace(|| "zi"), || Ok(self.inputs.get()?.zi))?; - - /***********************************************************************/ - //Check that if i == 0, z0 = zi, that is (i == 0) AND (z0 != zi) = false - /***********************************************************************/ - - let z0_is_zi = Boolean::from(alloc_num_equals( - cs.namespace(|| "z0 = zi"), - z_0.clone(), - z_i.clone(), - )?); - - cs.enforce( - || "i == 0 and z0 != zi = false", - |_| is_base_case.lc(CS::one(), G::Base::one()), - |_| z0_is_zi.not().lc(CS::one(), G::Base::one()), - |lc| lc, - ); - - /***********************************************************************/ - // Check that h1 = Hash(params, u2,i,z0,zi) - /***********************************************************************/ - - let mut h1_hash: PoseidonROGadget = - PoseidonROGadget::new(self.poseidon_constants.clone()); - - h1_hash.absorb(params.clone()); - h1_hash.absorb(W_r.x); - h1_hash.absorb(W_r.y); - h1_hash.absorb(W_r.is_infinity); - h1_hash.absorb(E_r.x); - h1_hash.absorb(E_r.y); - h1_hash.absorb(E_r.is_infinity); - h1_hash.absorb(u_r.clone()); - - // absorb each of the limbs of X_r[0] - for limb in Xr0_bn.into_iter() { - h1_hash.absorb(limb); - } - - // absorb each of the limbs of X_r[1] - for limb in Xr1_bn.into_iter() { - h1_hash.absorb(limb); - } - - h1_hash.absorb(i.clone()); - h1_hash.absorb(z_0.clone()); - h1_hash.absorb(z_i.clone()); - - let hash_bits = h1_hash.get_challenge(cs.namespace(|| "Input hash"))?; // TODO: use get_hash method - let hash = le_bits_to_num(cs.namespace(|| "bits to hash"), hash_bits)?; - - cs.enforce( - || "check h1", - |lc| lc, - |lc| lc, - |lc| lc + h1.get_variable() - hash.get_variable(), - ); - - /***********************************************************************/ // Compute z_{i+1} - /***********************************************************************/ - + let z_input = conditionally_select( + cs.namespace(|| "select input to F"), + &z_0, + &z_i, + &Boolean::from(is_base_case), + )?; let z_next = self .step_circuit - .synthesize(&mut cs.namespace(|| "F"), z_i)?; - - /***********************************************************************/ - // Compute the new hash H(params, u2_new, i+1, z0, z_{i+1}) - /***********************************************************************/ - - h1_hash.flush_state(); - h1_hash.absorb(params); - h1_hash.absorb(W_new.x.clone()); - h1_hash.absorb(W_new.y.clone()); - h1_hash.absorb(W_new.is_infinity); - h1_hash.absorb(E_new.x.clone()); - h1_hash.absorb(E_new.y.clone()); - h1_hash.absorb(E_new.is_infinity); - h1_hash.absorb(u_new); - - // absorb each of the limbs of X_r_new[0] - for limb in Xr0_new_bn.into_iter() { - h1_hash.absorb(limb); - } - - // absorb each of the limbs of X_r_new[1] - for limb in Xr1_new_bn.into_iter() { - h1_hash.absorb(limb); - } - - h1_hash.absorb(i_new.clone()); - h1_hash.absorb(z_0); - h1_hash.absorb(z_next); - let h1_new_bits = h1_hash.get_challenge(cs.namespace(|| "h1_new bits"))?; // TODO: use get_hash method - let h1_new = le_bits_to_num(cs.namespace(|| "h1_new"), h1_new_bits)?; - let _ = h1_new.inputize(cs.namespace(|| "output h1_new"))?; + .synthesize(&mut cs.namespace(|| "F"), z_input)?; + + // Compute the new hash H(params, Unew, i+1, z0, z_{i+1}) + let mut ro: PoseidonROGadget = PoseidonROGadget::new(self.poseidon_constants); + ro.absorb(params); + ro.absorb(i_new.clone()); + ro.absorb(z_0); + ro.absorb(z_next); + let _ = Unew.absorb_in_ro(cs.namespace(|| "absorb U_new"), &mut ro)?; + let hash_bits = ro.get_hash(cs.namespace(|| "output hash bits"))?; + let hash = le_bits_to_num(cs.namespace(|| "convert hash to num"), hash_bits)?; + + // Outputs the computed hash and u.X[1] that corresponds to the hash of the other circuit + let _ = hash.inputize(cs.namespace(|| "output new hash of this circuit"))?; + let _ = u + .X1 + .inputize(cs.namespace(|| "Output unmodified hash of the other circuit"))?; Ok(()) } @@ -628,6 +385,7 @@ mod tests { }, poseidon_constants1.clone(), ); + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit1.synthesize(&mut cs); @@ -658,27 +416,20 @@ mod tests { cs.num_constraints() ); - // TODO: We need to hardwire default hash or give it as input - let default_hash = <::Base as ff::PrimeField>::from_str_vartime( - "332553638888022689042501686561503049809", - ) - .unwrap(); - + let zero = <::Base as Field>::zero(); + let zero_fq = <::Scalar as Field>::zero(); let T = vec![::Scalar::zero()].commit(&gens2.gens_E); let w = vec![::Scalar::zero()].commit(&gens2.gens_E); - // Now get an assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let inputs: NIFSVerifierCircuitInputs = NIFSVerifierCircuitInputs::new( - default_hash, - RelaxedR1CSInstance::default(&gens2, &shape2), <::Base as Field>::zero(), // TODO: provide real inputs - <::Base as Field>::zero(), // TODO: provide real inputs - <::Base as Field>::zero(), // TODO: provide real inputs - <::Base as Field>::zero(), // TODO: provide real inputs - <::Base as Field>::zero(), // TODO: provide real inputs - T, // TODO: provide real inputs - w, + zero, // TODO: provide real inputs + zero, // TODO: provide real inputs + zero, // TODO: provide real inputs + RelaxedR1CSInstance::default(&gens2, &shape2), + R1CSInstance::new(&shape2, &w, &[zero_fq, zero_fq]).unwrap(), + T, // TODO: provide real inputs ); let circuit: NIFSVerifierCircuit::Base>> = diff --git a/src/gadgets/mod.rs b/src/gadgets/mod.rs index c845d83..b8f53e0 100644 --- a/src/gadgets/mod.rs +++ b/src/gadgets/mod.rs @@ -1,2 +1,3 @@ pub mod ecc; +pub mod r1cs; pub mod utils; diff --git a/src/gadgets/r1cs.rs b/src/gadgets/r1cs.rs new file mode 100644 index 0000000..4d92dd0 --- /dev/null +++ b/src/gadgets/r1cs.rs @@ -0,0 +1,363 @@ +use crate::{ + gadgets::{ + ecc::AllocatedPoint, + utils::{ + alloc_bignat_constant, alloc_one, alloc_scalar_as_base, alloc_zero, conditionally_select, + conditionally_select_bignat, le_bits_to_num, + }, + }, + poseidon::{NovaPoseidonConstants, PoseidonROGadget}, + r1cs::{R1CSInstance, RelaxedR1CSInstance}, + traits::Group, +}; +use bellperson::{ + gadgets::{boolean::Boolean, num::AllocatedNum, Assignment}, + ConstraintSystem, SynthesisError, +}; +use bellperson_nonnative::{ + mp::bignat::BigNat, + util::{convert::f_to_nat, num::Num}, +}; +use ff::{Field, PrimeField, PrimeFieldBits}; + +/// An Allocated R1CS Instance +#[derive(Clone)] +pub struct AllocatedR1CSInstance +where + G: Group, +{ + pub(crate) W: AllocatedPoint, + pub(crate) X0: AllocatedNum, + pub(crate) X1: AllocatedNum, +} + +impl AllocatedR1CSInstance +where + G: Group, + ::Base: PrimeField + PrimeFieldBits, + ::Scalar: PrimeFieldBits, +{ + /// Takes the r1cs instance and creates a new allocated r1cs instance + pub fn alloc::Base>>( + mut cs: CS, + u: Option>, + ) -> Result { + // Check that the incoming instance has exactly 2 io + let W = AllocatedPoint::alloc( + cs.namespace(|| "allocate W"), + u.get() + .map_or(None, |u| Some(u.comm_W.comm.to_coordinates())), + )?; + + let X0 = alloc_scalar_as_base::( + cs.namespace(|| "allocate X[0]"), + u.get().map_or(None, |u| Some(u.X[0])), + )?; + let X1 = alloc_scalar_as_base::( + cs.namespace(|| "allocate X[1]"), + u.get().map_or(None, |u| Some(u.X[1])), + )?; + + Ok(AllocatedR1CSInstance { W, X0, X1 }) + } + + pub fn absorb_in_ro(&self, ro: &mut PoseidonROGadget) { + ro.absorb(self.W.x.clone()); + ro.absorb(self.W.y.clone()); + ro.absorb(self.W.is_infinity.clone()); + ro.absorb(self.X0.clone()); + ro.absorb(self.X1.clone()); + } +} + +/// An Allocated Relaxed R1CS Instance +pub struct AllocatedRelaxedR1CSInstance +where + G: Group, + ::Base: PrimeField + PrimeFieldBits, + ::Scalar: PrimeFieldBits, +{ + pub(crate) W: AllocatedPoint, + pub(crate) E: AllocatedPoint, + pub(crate) u: AllocatedNum, + pub(crate) X0: BigNat, + pub(crate) X1: BigNat, +} + +impl AllocatedRelaxedR1CSInstance +where + G: Group, + ::Base: PrimeField + PrimeFieldBits, + ::Scalar: PrimeFieldBits, +{ + /// Allocates the given RelaxedR1CSInstance as a witness of the circuit + pub fn alloc::Base>>( + mut cs: CS, + inst: Option>, + limb_width: usize, + n_limbs: usize, + ) -> Result { + let W = AllocatedPoint::alloc( + cs.namespace(|| "allocate W"), + inst + .get() + .map_or(None, |inst| Some(inst.comm_W.comm.to_coordinates())), + )?; + + let E = AllocatedPoint::alloc( + cs.namespace(|| "allocate E"), + inst + .get() + .map_or(None, |inst| Some(inst.comm_E.comm.to_coordinates())), + )?; + + // u << |G::Base| despite the fact that u is a scalar. + // So we parse all of its bytes as a G::Base element + let u = alloc_scalar_as_base::( + cs.namespace(|| "allocate u"), + inst.get().map_or(None, |inst| Some(inst.u)), + )?; + + let X0 = BigNat::alloc_from_nat( + cs.namespace(|| "allocate X[0]"), + || Ok(f_to_nat(&inst.get()?.X[0])), + limb_width, + n_limbs, + )?; + + let X1 = BigNat::alloc_from_nat( + cs.namespace(|| "allocate X[1]"), + || Ok(f_to_nat(&inst.get()?.X[1])), + limb_width, + n_limbs, + )?; + + Ok(AllocatedRelaxedR1CSInstance { W, E, u, X0, X1 }) + } + + /// Allocates the hardcoded default RelaxedR1CSInstance in the circuit. + /// W = E = 0, u = 1, X0 = X1 = 0 + pub fn default::Base>>( + mut cs: CS, + limb_width: usize, + n_limbs: usize, + ) -> Result { + let zero = alloc_zero(cs.namespace(|| "zero"))?; + let one = alloc_one(cs.namespace(|| "one"))?; + + let W_default = AllocatedPoint::new(zero.clone(), zero.clone(), one); + let E_default = W_default.clone(); + + let u_default = zero; + + let X0_default = BigNat::alloc_from_nat( + cs.namespace(|| "allocate x_default[0]"), + || Ok(f_to_nat(&G::Scalar::zero())), + limb_width, + n_limbs, + )?; + + let X1_default = BigNat::alloc_from_nat( + cs.namespace(|| "allocate x_default[1]"), + || Ok(f_to_nat(&G::Scalar::zero())), + limb_width, + n_limbs, + )?; + Ok(AllocatedRelaxedR1CSInstance { + W: W_default, + E: E_default, + u: u_default, + X0: X0_default, + X1: X1_default, + }) + } + + pub fn absorb_in_ro::Base>>( + &self, + mut cs: CS, + ro: &mut PoseidonROGadget, + ) -> Result<(), SynthesisError> { + ro.absorb(self.W.x.clone()); + ro.absorb(self.W.y.clone()); + ro.absorb(self.W.is_infinity.clone()); + ro.absorb(self.E.x.clone()); + ro.absorb(self.E.y.clone()); + ro.absorb(self.E.is_infinity.clone()); + ro.absorb(self.u.clone()); + + // Analyze X0 as limbs + let X0_bn = self + .X0 + .as_limbs::() + .iter() + .enumerate() + .map(|(i, limb)| { + limb + .as_sapling_allocated_num(cs.namespace(|| format!("convert limb {} of X_r[0] to num", i))) + }) + .collect::>, _>>()?; + + // absorb each of the limbs of X[0] + for limb in X0_bn.into_iter() { + ro.absorb(limb); + } + + // Analyze X1 as limbs + let X1_bn = self + .X1 + .as_limbs::() + .iter() + .enumerate() + .map(|(i, limb)| { + limb + .as_sapling_allocated_num(cs.namespace(|| format!("convert limb {} of X_r[1] to num", i))) + }) + .collect::>, _>>()?; + + // absorb each of the limbs of X[1] + for limb in X1_bn.into_iter() { + ro.absorb(limb); + } + + Ok(()) + } + + /// Folds self with a relaxed r1cs instance and returns the result + pub fn fold_with_r1cs::Base>>( + &self, + mut cs: CS, + u: AllocatedR1CSInstance, + T: AllocatedPoint, + poseidon_constants: NovaPoseidonConstants, + limb_width: usize, + n_limbs: usize, + ) -> Result, SynthesisError> { + // Compute r: + let mut ro: PoseidonROGadget = PoseidonROGadget::new(poseidon_constants); + u.absorb_in_ro(&mut ro); + ro.absorb(T.x.clone()); + ro.absorb(T.y.clone()); + ro.absorb(T.is_infinity.clone()); + let r_bits = ro.get_challenge(cs.namespace(|| "r bits"))?; + let r = le_bits_to_num(cs.namespace(|| "r"), r_bits.clone())?; + + // W_fold = self.W + r * u.W + let rW = u.W.scalar_mul(cs.namespace(|| "r * u.W"), r_bits.clone())?; + let W_fold = self.W.add(cs.namespace(|| "self.W + r * u.W"), &rW)?; + + // E_fold = self.E + r * T + let rT = T.scalar_mul(cs.namespace(|| "r * T"), r_bits)?; + let E_fold = self.E.add(cs.namespace(|| "self.E + r * T"), &rT)?; + + // u_fold = u_r + r + let u_fold = AllocatedNum::alloc(cs.namespace(|| "u_fold"), || { + Ok(*self.u.get_value().get()? + r.get_value().get()?) + })?; + cs.enforce( + || "Check u_fold", + |lc| lc, + |lc| lc, + |lc| lc + u_fold.get_variable() - self.u.get_variable() - r.get_variable(), + ); + + // Fold the IO: + // Analyze r into limbs + let r_bn = BigNat::from_num( + cs.namespace(|| "allocate r_bn"), + Num::from(r.clone()), + limb_width, + n_limbs, + )?; + + // Allocate the order of the non-native field as a constant + let m_bn = alloc_bignat_constant( + cs.namespace(|| "alloc m"), + &G::get_order(), + limb_width, + n_limbs, + )?; + + // Analyze X0 to bignat + let X0_bn = BigNat::from_num( + cs.namespace(|| "allocate X0_bn"), + Num::from(u.X0.clone()), + limb_width, + n_limbs, + )?; + + // Fold self.X[0] + r * X[0] + let (_, r_0) = X0_bn.mult_mod(cs.namespace(|| "r*X[0]"), &r_bn, &m_bn)?; + // add X_r[0] + let r_new_0 = self.X0.add::(&r_0)?; + // Now reduce + let X0_fold = r_new_0.red_mod(cs.namespace(|| "reduce folded X[0]"), &m_bn)?; + + // Analyze X1 to bignat + let X1_bn = BigNat::from_num( + cs.namespace(|| "allocate X1_bn"), + Num::from(u.X1.clone()), + limb_width, + n_limbs, + )?; + + // Fold self.X[1] + r * X[1] + let (_, r_1) = X1_bn.mult_mod(cs.namespace(|| "r*X[1]"), &r_bn, &m_bn)?; + // add X_r[1] + let r_new_1 = self.X1.add::(&r_1)?; + // Now reduce + let X1_fold = r_new_1.red_mod(cs.namespace(|| "reduce folded X[1]"), &m_bn)?; + + Ok(Self { + W: W_fold, + E: E_fold, + u: u_fold, + X0: X0_fold, + X1: X1_fold, + }) + } + + /// If the condition is true then returns this otherwise it returns the other + pub fn conditionally_select::Base>>( + &self, + mut cs: CS, + other: AllocatedRelaxedR1CSInstance, + condition: &Boolean, + ) -> Result, SynthesisError> { + let W = AllocatedPoint::conditionally_select( + cs.namespace(|| "W = cond ? self.W : other.W"), + &self.W, + &other.W, + condition, + )?; + + let E = AllocatedPoint::conditionally_select( + cs.namespace(|| "E = cond ? self.E : other.E"), + &self.E, + &other.E, + condition, + )?; + + let u = conditionally_select( + cs.namespace(|| "u = cond ? self.u : other.u"), + &self.u, + &other.u, + condition, + )?; + + let X0 = conditionally_select_bignat( + cs.namespace(|| "X[0] = cond ? self.X[0] : other.X[0]"), + &self.X0, + &other.X0, + condition, + )?; + + let X1 = conditionally_select_bignat( + cs.namespace(|| "X[1] = cond ? self.X[1] : other.X[1]"), + &self.X1, + &other.X1, + condition, + )?; + + Ok(AllocatedRelaxedR1CSInstance { W, E, u, X0, X1 }) + } +} diff --git a/src/gadgets/utils.rs b/src/gadgets/utils.rs index 54a742c..fea1ef0 100644 --- a/src/gadgets/utils.rs +++ b/src/gadgets/utils.rs @@ -1,3 +1,4 @@ +use crate::traits::Group; use bellperson::{ gadgets::{ boolean::{AllocatedBit, Boolean}, @@ -7,7 +8,7 @@ use bellperson::{ ConstraintSystem, LinearCombination, SynthesisError, }; use bellperson_nonnative::mp::bignat::{nat_to_limbs, BigNat}; -use ff::{PrimeField, PrimeFieldBits}; +use ff::{Field, PrimeField, PrimeFieldBits}; use rug::Integer; /// Gets as input the little indian representation of a number and spits out the number @@ -73,6 +74,30 @@ pub fn alloc_one>( Ok(one) } +/// Allocate a scalar as a base. Only to be used is the scalar fits in base! +pub fn alloc_scalar_as_base( + mut cs: CS, + input: Option, +) -> Result, SynthesisError> +where + G: Group, + ::Scalar: PrimeFieldBits, + CS: ConstraintSystem<::Base>, +{ + AllocatedNum::alloc(cs.namespace(|| "allocate scalar as base"), || { + let input_bits = input.get()?.clone().to_le_bits(); + let mut mult = G::Base::one(); + let mut val = G::Base::zero(); + for bit in input_bits { + if bit { + val += mult; + } + mult = mult + mult; + } + Ok(val) + }) +} + /// Allocate bignat a constant pub fn alloc_bignat_constant>( mut cs: CS, @@ -109,7 +134,6 @@ pub fn alloc_num_equals>( ) -> Result { // Allocate and constrain `r`: result boolean bit. // It equals `true` if `a` equals `b`, `false` otherwise - let r_value = match (a.get_value(), b.get_value()) { (Some(a), Some(b)) => Some(a == b), _ => None, @@ -147,7 +171,6 @@ pub fn alloc_num_equals>( // Allocate `t = delta * delta_inv` // If `delta` is non-zero (a != b), `t` will equal 1 // If `delta` is zero (a == b), `t` cannot equal 1 - let t = AllocatedNum::alloc(cs.namespace(|| "t"), || { let mut tmp = *delta.get_value().get()?; tmp.mul_assign(&(*delta_inv.get_value().get()?)); @@ -215,7 +238,6 @@ pub fn conditionally_select>( // a * condition + b*(1-condition) = c -> // a * condition - b*condition = c - b - cs.enforce( || "conditional select constraint", |lc| lc + a.get_variable() - b.get_variable(), @@ -278,7 +300,6 @@ pub fn conditionally_select2>( // a * condition + b*(1-condition) = c -> // a * condition - b*condition = c - b - cs.enforce( || "conditional select constraint", |lc| lc + a.get_variable() - b.get_variable(), diff --git a/src/lib.rs b/src/lib.rs index 2d0c2cc..8035469 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,6 @@ impl StepSNARK { NovaError, > { // append the protocol name to the transcript - //transcript.append_protocol_name(StepSNARK::protocol_name()); transcript.append_message(b"protocol-name", StepSNARK::::protocol_name()); // compute a commitment to the cross-term diff --git a/src/poseidon.rs b/src/poseidon.rs index 9a8672c..d9d89c5 100644 --- a/src/poseidon.rs +++ b/src/poseidon.rs @@ -7,7 +7,7 @@ use bellperson::{ ConstraintSystem, SynthesisError, }; use ff::{PrimeField, PrimeFieldBits}; -use generic_array::typenum::{U24, U25, U27, U31}; +use generic_array::typenum::{U25, U27, U31, U8}; use neptune::{ circuit::poseidon_hash, poseidon::{Poseidon, PoseidonConstants}, @@ -22,7 +22,7 @@ pub struct NovaPoseidonConstants where F: PrimeField, { - constants24: PoseidonConstants, + constants8: PoseidonConstants, constants25: PoseidonConstants, constants27: PoseidonConstants, constants31: PoseidonConstants, @@ -35,12 +35,12 @@ where { /// Generate Poseidon constants for the arities that Nova uses pub fn new() -> Self { - let constants24 = PoseidonConstants::::new_with_strength(Strength::Strengthened); + let constants8 = PoseidonConstants::::new_with_strength(Strength::Strengthened); let constants25 = PoseidonConstants::::new_with_strength(Strength::Strengthened); let constants27 = PoseidonConstants::::new_with_strength(Strength::Strengthened); let constants31 = PoseidonConstants::::new_with_strength(Strength::Strengthened); Self { - constants24, + constants8, constants25, constants27, constants31, @@ -71,12 +71,6 @@ where } } - #[allow(dead_code)] - /// Flush the state of the RO - pub fn flush_state(&mut self) { - self.state = Vec::new(); - } - /// Absorb a new number into the state of the oracle #[allow(dead_code)] pub fn absorb(&mut self, e: Scalar) { @@ -85,8 +79,8 @@ where fn hash_inner(&mut self) -> Scalar { match self.state.len() { - 24 => { - Poseidon::::new_with_preimage(&self.state, &self.constants.constants24).hash() + 8 => { + Poseidon::::new_with_preimage(&self.state, &self.constants.constants8).hash() } 25 => { Poseidon::::new_with_preimage(&self.state, &self.constants.constants25).hash() @@ -160,11 +154,6 @@ where } } - /// Flush the state of the RO - pub fn flush_state(&mut self) { - self.state = Vec::new(); - } - /// Absorb a new number into the state of the oracle #[allow(dead_code)] pub fn absorb(&mut self, e: AllocatedNum) { @@ -176,10 +165,10 @@ where CS: ConstraintSystem, { let out = match self.state.len() { - 24 => poseidon_hash( + 8 => poseidon_hash( cs.namespace(|| "Posideon hash"), self.state.clone(), - &self.constants.constants24, + &self.constants.constants8, )?, 25 => poseidon_hash( cs.namespace(|| "Poseidon hash"), diff --git a/src/r1cs.rs b/src/r1cs.rs index d3d9e7d..3ac1469 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -36,8 +36,8 @@ pub struct R1CSWitness { /// A type that holds an R1CS instance #[derive(Clone, Debug, PartialEq, Eq)] pub struct R1CSInstance { - comm_W: Commitment, - X: Vec, + pub(crate) comm_W: Commitment, + pub(crate) X: Vec, } /// A type that holds a witness for a given Relaxed R1CS instance diff --git a/tests/bit.rs b/tests/bit.rs index 7c29305..65bc1ba 100644 --- a/tests/bit.rs +++ b/tests/bit.rs @@ -9,7 +9,7 @@ use nova_snark::bellperson::{ fn synthesize_alloc_bit>( cs: &mut CS, ) -> Result<(), SynthesisError> { - //get two bits as input and check that they are indeed bits + // get two bits as input and check that they are indeed bits let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::one()))?; let _ = a.inputize(cs.namespace(|| "a is input")); cs.enforce( @@ -33,18 +33,18 @@ fn synthesize_alloc_bit>( fn test_alloc_bit() { type G = pasta_curves::pallas::Point; - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_alloc_bit(&mut cs); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); println!("Mult mod constraint no: {}", cs.num_constraints()); - //Now get the assignment + // 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(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } diff --git a/tests/nonnative.rs b/tests/nonnative.rs index 007839b..d71c624 100644 --- a/tests/nonnative.rs +++ b/tests/nonnative.rs @@ -169,7 +169,7 @@ fn synthesize_add_mod>( fn test_mult_mod() { type G = pasta_curves::pallas::Point; - //Set the inputs + // Set the inputs let a_val = Integer::from_str_radix( "11572336752428856981970994795408771577024165681374400871001196932361466228192", 10, @@ -196,19 +196,19 @@ fn test_mult_mod() { ) .unwrap(); - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_mult_mod(&mut cs, &a_val, &b_val, &m_val, &q_val, &r_val, 32, 8); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); println!("Mult mod constraint no: {}", cs.num_constraints()); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_mult_mod(&mut cs, &a_val, &b_val, &m_val, &q_val, &r_val, 32, 8); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } @@ -216,7 +216,7 @@ fn test_mult_mod() { fn test_add() { type G = pasta_curves::pallas::Point; - //Set the inputs + // Set the inputs let a_val = Integer::from_str_radix( "11572336752428856981970994795408771577024165681374400871001196932361466228192", 10, @@ -229,19 +229,19 @@ fn test_add() { ) .unwrap(); - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_add(&mut cs, &a_val, &b_val, &c_val, 32, 8); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); println!("Add mod constraint no: {}", cs.num_constraints()); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_add(&mut cs, &a_val, &b_val, &c_val, 32, 8); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } @@ -249,7 +249,7 @@ fn test_add() { fn test_add_mod() { type G = pasta_curves::pallas::Point; - //Set the inputs + // Set the inputs let a_val = Integer::from_str_radix( "11572336752428856981970994795408771577024165681374400871001196932361466228192", 10, @@ -267,19 +267,19 @@ fn test_add_mod() { ) .unwrap(); - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_add_mod(&mut cs, &a_val, &b_val, &c_val, &m_val, 32, 8); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); println!("Add mod constraint no: {}", cs.num_constraints()); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_add_mod(&mut cs, &a_val, &b_val, &c_val, &m_val, 32, 8); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } @@ -287,21 +287,21 @@ fn test_add_mod() { fn test_equal() { type G = pasta_curves::pallas::Point; - //Set the inputs + // Set the inputs let a_val = Integer::from_str_radix("1157233675242885698197099479540877", 10).unwrap(); - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_is_equal(&mut cs, &a_val, 32, 8); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); println!("Equal constraint no: {}", cs.num_constraints()); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_is_equal(&mut cs, &a_val, 32, 8); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } diff --git a/tests/num.rs b/tests/num.rs index a0f5b5a..55b58d1 100644 --- a/tests/num.rs +++ b/tests/num.rs @@ -42,18 +42,18 @@ fn synthesize_use_cs_one_after_inputize fn test_use_cs_one() { type G = pasta_curves::pallas::Point; - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_use_cs_one(&mut cs); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_use_cs_one(&mut cs); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); } @@ -61,17 +61,17 @@ fn test_use_cs_one() { fn test_use_cs_one_after_inputize() { type G = pasta_curves::pallas::Point; - //First create the shape + // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_use_cs_one_after_inputize(&mut cs); let shape = cs.r1cs_shape(); let gens = cs.r1cs_gens(); - //Now get the assignment + // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); let _ = synthesize_use_cs_one_after_inputize(&mut cs); let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap(); - //Make sure that this is satisfiable + // Make sure that this is satisfiable assert!(shape.is_sat(&gens, &inst, &witness).is_ok()); }