diff --git a/folding-schemes/src/folding/circuits/nonnative.rs b/folding-schemes/src/folding/circuits/nonnative.rs index 943a243..67ca365 100644 --- a/folding-schemes/src/folding/circuits/nonnative.rs +++ b/folding-schemes/src/folding/circuits/nonnative.rs @@ -2,16 +2,54 @@ use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, + boolean::Boolean, fields::{ fp::FpVar, - nonnative::{params::OptimizationType, AllocatedNonNativeFieldVar, NonNativeFieldVar}, + nonnative::{ + params::{get_params, OptimizationType}, + AllocatedNonNativeFieldVar, NonNativeFieldVar, + }, FieldVar, }, - ToBitsGadget, + ToBitsGadget, ToConstraintFieldGadget, }; -use ark_relations::r1cs::{Namespace, SynthesisError}; +use ark_relations::r1cs::{ConstraintSystemRef, Namespace, OptimizationGoal, SynthesisError}; use ark_std::Zero; use core::borrow::Borrow; +use std::marker::PhantomData; + +/// Compose a vector boolean into a `NonNativeFieldVar` +pub fn nonnative_field_var_from_le_bits( + cs: ConstraintSystemRef, + bits: &[Boolean], +) -> Result, SynthesisError> { + let params = get_params( + TargetField::MODULUS_BIT_SIZE as usize, + BaseField::MODULUS_BIT_SIZE as usize, + match cs.optimization_goal() { + OptimizationGoal::None => OptimizationType::Constraints, + OptimizationGoal::Constraints => OptimizationType::Constraints, + OptimizationGoal::Weight => OptimizationType::Weight, + }, + ); + + // push the lower limbs first + let mut limbs = bits + .chunks(params.bits_per_limb) + .map(Boolean::le_bits_to_fp_var) + .collect::, _>>()?; + limbs.resize(params.num_limbs, FpVar::zero()); + limbs.reverse(); + + Ok(AllocatedNonNativeFieldVar { + cs, + limbs, + num_of_additions_over_normal_form: BaseField::one(), + is_in_the_normal_form: false, + target_phantom: PhantomData, + } + .into()) +} /// A more efficient version of `NonNativeFieldVar::to_constraint_field` pub fn nonnative_field_var_to_constraint_field( @@ -112,23 +150,63 @@ where } } -/// Wrapper on top of [`point_to_nonnative_limbs_custom_opt`] which always uses -/// [`OptimizationType::Weight`]. +impl ToConstraintFieldGadget for NonNativeAffineVar +where + ::BaseField: ark_ff::PrimeField, +{ + // A more efficient version of `point_to_nonnative_limbs_custom_opt`. + // Used for converting `NonNativeAffineVar` to a vector of `FpVar` with minimum length in + // the circuit. + fn to_constraint_field(&self) -> Result>, SynthesisError> { + let x = nonnative_field_var_to_constraint_field(&self.x)?; + let y = nonnative_field_var_to_constraint_field(&self.y)?; + Ok([x, y].concat()) + } +} + +/// The out-circuit counterpart of `NonNativeAffineVar::to_constraint_field` #[allow(clippy::type_complexity)] -pub fn point_to_nonnative_limbs( +pub fn nonnative_affine_to_field_elements( p: C, ) -> Result<(Vec, Vec), SynthesisError> where ::BaseField: ark_ff::PrimeField, { - point_to_nonnative_limbs_custom_opt(p, OptimizationType::Weight) + let affine = p.into_affine(); + if affine.is_zero() { + let x = nonnative_field_to_field_elements(&C::BaseField::zero()); + let y = nonnative_field_to_field_elements(&C::BaseField::zero()); + return Ok((x, y)); + } + + let (x, y) = affine.xy().unwrap(); + let x = nonnative_field_to_field_elements(x); + let y = nonnative_field_to_field_elements(y); + Ok((x, y)) +} + +impl NonNativeAffineVar +where + ::BaseField: ark_ff::PrimeField, +{ + // A wrapper of `point_to_nonnative_limbs_custom_opt` with constraints-focused optimization + // type (which is the default optimization type for arkworks' Groth16). + // Used for extracting a list of field elements of type `C::ScalarField` from the public input + // `p`, in exactly the same way as how `NonNativeAffineVar` is represented as limbs of type + // `FpVar` in-circuit. + #[allow(clippy::type_complexity)] + pub fn inputize(p: C) -> Result<(Vec, Vec), SynthesisError> { + point_to_nonnative_limbs_custom_opt(p, OptimizationType::Constraints) + } } -/// Used to compute (outside the circuit) the limbs representation of a point that matches the one -/// used in-circuit, and in particular this method allows to specify which [`OptimizationType`] to -/// use. +// Used to compute (outside the circuit) the limbs representation of a point. +// For `OptimizationType::Constraints`, the result matches the one used in-circuit. +// For `OptimizationType::Weight`, the result vector is more dense and is suitable for hashing. +// It is possible to further optimize the length of the result vector (see +// `nonnative_affine_to_field_elements`) #[allow(clippy::type_complexity)] -pub fn point_to_nonnative_limbs_custom_opt( +fn point_to_nonnative_limbs_custom_opt( p: C, optimization_type: OptimizationType, ) -> Result<(Vec, Vec), SynthesisError> @@ -166,24 +244,63 @@ where mod tests { use super::*; use ark_pallas::{Fr, Projective}; - use ark_r1cs_std::{alloc::AllocVar, R1CSVar, ToConstraintFieldGadget}; + use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::ConstraintSystem; - use ark_std::{UniformRand, Zero}; + use ark_std::UniformRand; #[test] - fn test_alloc_nonnativeaffinevar() { + fn test_alloc_zero() { let cs = ConstraintSystem::::new_ref(); // dealing with the 'zero' point should not panic when doing the unwrap let p = Projective::zero(); - NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).unwrap(); + assert!(NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).is_ok()); + } + + #[test] + fn test_arkworks_to_constraint_field() { + let cs = ConstraintSystem::::new_ref(); // check that point_to_nonnative_limbs returns the expected values let mut rng = ark_std::test_rng(); let p = Projective::rand(&mut rng); let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).unwrap(); - let (x, y) = point_to_nonnative_limbs(p).unwrap(); + let (x, y) = point_to_nonnative_limbs_custom_opt(p, OptimizationType::Weight).unwrap(); assert_eq!(pVar.x.to_constraint_field().unwrap().value().unwrap(), x); assert_eq!(pVar.y.to_constraint_field().unwrap().value().unwrap(), y); } + + #[test] + fn test_improved_to_constraint_field() { + let cs = ConstraintSystem::::new_ref(); + + // check that point_to_nonnative_limbs returns the expected values + let mut rng = ark_std::test_rng(); + let p = Projective::rand(&mut rng); + let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).unwrap(); + let (x, y) = nonnative_affine_to_field_elements(p).unwrap(); + assert_eq!( + pVar.to_constraint_field().unwrap().value().unwrap(), + [x, y].concat() + ); + } + + #[test] + fn test_inputize() { + let cs = ConstraintSystem::::new_ref(); + + // check that point_to_nonnative_limbs returns the expected values + let mut rng = ark_std::test_rng(); + let p = Projective::rand(&mut rng); + let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).unwrap(); + let (x, y) = NonNativeAffineVar::inputize(p).unwrap(); + + match (pVar.x, pVar.y) { + (NonNativeFieldVar::Var(p_x), NonNativeFieldVar::Var(p_y)) => { + assert_eq!(p_x.limbs.value().unwrap(), x); + assert_eq!(p_y.limbs.value().unwrap(), y); + } + _ => unreachable!(), + } + } } diff --git a/folding-schemes/src/folding/nova/circuits.rs b/folding-schemes/src/folding/nova/circuits.rs index 3c35532..b80093f 100644 --- a/folding-schemes/src/folding/nova/circuits.rs +++ b/folding-schemes/src/folding/nova/circuits.rs @@ -17,11 +17,10 @@ use ark_r1cs_std::{ fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar}, groups::GroupOpsBounds, prelude::CurveVar, - ToBitsGadget, ToConstraintFieldGadget, + R1CSVar, ToConstraintFieldGadget, }; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError}; -use ark_std::fmt::Debug; -use ark_std::Zero; +use ark_std::{fmt::Debug, Zero}; use core::{borrow::Borrow, marker::PhantomData}; use super::{ @@ -30,9 +29,9 @@ use super::{ }, CommittedInstance, }; -use crate::constants::N_BITS_RO; -use crate::folding::circuits::nonnative::{point_to_nonnative_limbs, NonNativeAffineVar}; +use crate::folding::circuits::nonnative::{nonnative_affine_to_field_elements, NonNativeAffineVar}; use crate::frontend::FCircuit; +use crate::{constants::N_BITS_RO, folding::circuits::nonnative::nonnative_field_var_from_le_bits}; /// CF1 represents the ConstraintField used for the main Nova circuit which is over E1::Fr, where /// E1 is the main curve where we do the folding. @@ -106,10 +105,8 @@ where let U_vec = [ vec![self.u], self.x, - self.cmE.x.to_constraint_field()?, - self.cmE.y.to_constraint_field()?, - self.cmW.x.to_constraint_field()?, - self.cmW.y.to_constraint_field()?, + self.cmE.to_constraint_field()?, + self.cmW.to_constraint_field()?, ] .concat(); let input = [vec![i], z_0, z_i, U_vec.clone()].concat(); @@ -132,6 +129,26 @@ where C: CurveGroup, ::BaseField: ark_ff::PrimeField, { + pub fn fold_committed_instance( + r: FpVar>, + ci1: CommittedInstanceVar, // U_i + ci2: CommittedInstanceVar, // u_i + ) -> Result, SynthesisError> { + Ok(CommittedInstanceVar { + cmE: NonNativeAffineVar::new_constant(ConstraintSystemRef::None, C::zero())?, + cmW: NonNativeAffineVar::new_constant(ConstraintSystemRef::None, C::zero())?, + // ci3.u = ci1.u + r * ci2.u + u: ci1.u + &r * ci2.u, + // ci3.x = ci1.x + r * ci2.x + x: ci1 + .x + .iter() + .zip(ci2.x) + .map(|(a, b)| a + &r * &b) + .collect::>>>(), + }) + } + /// Implements the constraints for NIFS.V for u and x, since cm(E) and cm(W) are delegated to /// the CycleFold circuit. pub fn verify( @@ -139,20 +156,13 @@ where ci1: CommittedInstanceVar, // U_i ci2: CommittedInstanceVar, // u_i ci3: CommittedInstanceVar, // U_{i+1} - ) -> Result>, SynthesisError> { - // ensure that: ci3.u == ci1.u + r * ci2.u - let first_check = ci3.u.is_eq(&(ci1.u + r.clone() * ci2.u))?; - - // ensure that: ci3.x == ci1.x + r * ci2.x - let x_rlc = ci1 - .x - .iter() - .zip(ci2.x) - .map(|(a, b)| a + &r * &b) - .collect::>>>(); - let second_check = x_rlc.is_eq(&ci3.x)?; - - first_check.and(&second_check) + ) -> Result<(), SynthesisError> { + let ci = Self::fold_committed_instance(r, ci1, ci2)?; + + ci.u.enforce_equal(&ci3.u)?; + ci.x.enforce_equal(&ci3.x)?; + + Ok(()) } } @@ -173,11 +183,11 @@ where u_i: CommittedInstance, cmT: C, ) -> Result, SynthesisError> { - let (U_cmE_x, U_cmE_y) = point_to_nonnative_limbs::(U_i.cmE)?; - let (U_cmW_x, U_cmW_y) = point_to_nonnative_limbs::(U_i.cmW)?; - let (u_cmE_x, u_cmE_y) = point_to_nonnative_limbs::(u_i.cmE)?; - let (u_cmW_x, u_cmW_y) = point_to_nonnative_limbs::(u_i.cmW)?; - let (cmT_x, cmT_y) = point_to_nonnative_limbs::(cmT)?; + let (U_cmE_x, U_cmE_y) = nonnative_affine_to_field_elements::(U_i.cmE)?; + let (U_cmW_x, U_cmW_y) = nonnative_affine_to_field_elements::(U_i.cmW)?; + let (u_cmE_x, u_cmE_y) = nonnative_affine_to_field_elements::(u_i.cmE)?; + let (u_cmW_x, u_cmW_y) = nonnative_affine_to_field_elements::(u_i.cmW)?; + let (cmT_x, cmT_y) = nonnative_affine_to_field_elements::(cmT)?; let mut sponge = PoseidonSponge::::new(poseidon_config); let input = vec![ @@ -212,16 +222,13 @@ where ) -> Result>, SynthesisError> { let mut sponge = PoseidonSpongeVar::::new(cs, poseidon_config); - let input: Vec> = vec![ + let input: Vec> = [ U_i_vec, vec![u_i.u.clone()], u_i.x.clone(), - u_i.cmE.x.to_constraint_field()?, - u_i.cmE.y.to_constraint_field()?, - u_i.cmW.x.to_constraint_field()?, - u_i.cmW.y.to_constraint_field()?, - cmT.x.to_constraint_field()?, - cmT.y.to_constraint_field()?, + u_i.cmE.to_constraint_field()?, + u_i.cmW.to_constraint_field()?, + cmT.to_constraint_field()?, ] .concat(); sponge.absorb(&input)?; @@ -248,10 +255,10 @@ pub struct AugmentedFCircuit< pub i_usize: Option, pub z_0: Option>, pub z_i: Option>, - pub u_i: Option>, + pub u_i_cmW: Option, pub U_i: Option>, - pub U_i1: Option>, - pub r_nonnat: Option>, + pub U_i1_cmE: Option, + pub U_i1_cmW: Option, pub cmT: Option, pub F: FC, // F circuit pub x: Option>, // public input (u_{i+1}.x[0]) @@ -259,15 +266,11 @@ pub struct AugmentedFCircuit< // cyclefold verifier on C1 // Here 'cf1, cf2' are for each of the CycleFold circuits, corresponding to the fold of cmW and // cmE respectively - pub cf1_u_i: Option>, // input - pub cf2_u_i: Option>, // input - pub cf_U_i: Option>, // input - pub cf1_U_i1: Option>, // intermediate - pub cf_U_i1: Option>, // output + pub cf1_u_i_cmW: Option, // input + pub cf2_u_i_cmW: Option, // input + pub cf_U_i: Option>, // input pub cf1_cmT: Option, pub cf2_cmT: Option, - pub cf1_r_nonnat: Option, - pub cf2_r_nonnat: Option, pub cf_x: Option>, // public input (u_{i+1}.x[1]) } @@ -284,23 +287,19 @@ where i_usize: None, z_0: None, z_i: None, - u_i: None, + u_i_cmW: None, U_i: None, - U_i1: None, - r_nonnat: None, + U_i1_cmE: None, + U_i1_cmW: None, cmT: None, F: F_circuit, x: None, // cyclefold values - cf1_u_i: None, - cf2_u_i: None, + cf1_u_i_cmW: None, + cf2_u_i_cmW: None, cf_U_i: None, - cf1_U_i1: None, - cf_U_i1: None, cf1_cmT: None, cf2_cmT: None, - cf1_r_nonnat: None, - cf2_r_nonnat: None, cf_x: None, } } @@ -334,24 +333,26 @@ where .unwrap_or(vec![CF1::::zero(); self.F.state_len()])) })?; - let u_dummy_native = CommittedInstance::::dummy(2); - let u_i = CommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.u_i.unwrap_or(u_dummy_native.clone())) - })?; + let u_dummy = CommittedInstance::dummy(2); let U_i = CommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.U_i.unwrap_or(u_dummy_native.clone())) + Ok(self.U_i.unwrap_or(u_dummy.clone())) })?; - let U_i1 = CommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.U_i1.unwrap_or(u_dummy_native.clone())) + let U_i1_cmE = NonNativeAffineVar::new_witness(cs.clone(), || { + Ok(self.U_i1_cmE.unwrap_or_else(C1::zero)) })?; - let r_nonnat = - NonNativeFieldVar::::new_witness(cs.clone(), || { - Ok(self.r_nonnat.unwrap_or_else(CF2::::zero)) - })?; + let U_i1_cmW = NonNativeAffineVar::new_witness(cs.clone(), || { + Ok(self.U_i1_cmW.unwrap_or_else(C1::zero)) + })?; + let cmT = NonNativeAffineVar::new_witness(cs.clone(), || Ok(self.cmT.unwrap_or_else(C1::zero)))?; - let x = - FpVar::>::new_input(cs.clone(), || Ok(self.x.unwrap_or_else(CF1::::zero)))?; + + let cf_u_dummy = CommittedInstance::dummy(CF_IO_LEN); + let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone())) + })?; + let cf1_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf1_cmT.unwrap_or_else(C2::zero)))?; + let cf2_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf2_cmT.unwrap_or_else(C2::zero)))?; let crh_params = CRHParametersVar::::new_constant( cs.clone(), @@ -364,22 +365,33 @@ where .F .generate_step_constraints(cs.clone(), i_usize, z_i.clone())?; - let zero = FpVar::>::new_constant(cs.clone(), CF1::::zero())?; - let is_not_basecase = i.is_neq(&zero)?; + let is_basecase = i.is_zero()?; - // 1.a u_i.x[0] == H(i, z_0, z_i, U_i) + // Primary Part + // P.1. Compute u_i.x + // u_i.x[0] = H(i, z_0, z_i, U_i) let (u_i_x, U_i_vec) = U_i.clone() .hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?; - // check that h == u_i.x[0] - (u_i.x[0]).conditional_enforce_equal(&u_i_x, &is_not_basecase)?; + // u_i.x[1] = H(cf_U_i) + let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&crh_params)?; + + // P.2. Construct u_i + let u_i = CommittedInstanceVar { + // u_i.cmE = cm(0) + cmE: NonNativeAffineVar::new_constant(cs.clone(), C1::zero())?, + // u_i.u = 1 + u: FpVar::one(), + // u_i.cmW is provided by the prover as witness + cmW: NonNativeAffineVar::new_witness(cs.clone(), || { + Ok(self.u_i_cmW.unwrap_or(C1::zero())) + })?, + // u_i.x is computed in step 1 + x: vec![u_i_x, cf_u_i_x], + }; - // 2. u_i.cmE==cm(0), u_i.u==1 - (u_i.cmE.x.is_zero()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - (u_i.cmE.y.is_zero()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - (u_i.u.is_one()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; + // P.3. nifs.verify, obtains U_{i+1} by folding u_i & U_i . - // 3. nifs.verify, checks that folding u_i & U_i obtains U_{i+1}. // compute r = H(u_i, U_i, cmT) let r_bits = ChallengeGadget::::get_challenge_gadget( cs.clone(), @@ -389,60 +401,38 @@ where cmT.clone(), )?; let r = Boolean::le_bits_to_fp_var(&r_bits)?; - - // enforce that the input r_nonnat as bits matches the in-circuit computed r_bits - let r_nonnat_bits: Vec> = - r_nonnat.to_bits_le()?.into_iter().take(N_BITS_RO).collect(); - r_nonnat_bits.enforce_equal(&r_bits)?; - - // Notice that NIFSGadget::verify is not checking the folding of cmE & cmW, since it will - // be done on the other curve. - let nifs_check = NIFSGadget::::verify(r, U_i.clone(), u_i.clone(), U_i1.clone())?; - nifs_check.conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - - // 4.a u_{i+1}.x[0] = H(i+1, z_0, z_i+1, U_{i+1}), this is the first output of F' + // Also convert r_bits to a `NonNativeFieldVar` + let r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &r_bits)?; + + // Notice that NIFSGadget::fold_committed_instance does not fold cmE & cmW. + // We set `U_i1.cmE` and `U_i1.cmW` to unconstrained witnesses `U_i1_cmE` and `U_i1_cmW` + // respectively. + // The correctness of them will be checked on the other curve. + let mut U_i1 = NIFSGadget::::fold_committed_instance(r, U_i.clone(), u_i.clone())?; + U_i1.cmE = U_i1_cmE; + U_i1.cmW = U_i1_cmW; + + // P.4.a compute and check the first output of F' + // Base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{\bot}) + // Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1}) let (u_i1_x, _) = U_i1.clone().hash( &crh_params, i + FpVar::>::one(), z_0.clone(), z_i1.clone(), )?; - - u_i1_x.enforce_equal(&x)?; + let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash( + &crh_params, + FpVar::>::one(), + z_0.clone(), + z_i1.clone(), + )?; + let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?; + x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?; // CycleFold part - let cf_u_dummy_native = CommittedInstance::::dummy(CF_IO_LEN); - // cf W circuit data - let cf1_u_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.cf1_u_i.unwrap_or_else(|| cf_u_dummy_native.clone())) - })?; - let cf2_u_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.cf2_u_i.unwrap_or_else(|| cf_u_dummy_native.clone())) - })?; - let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone())) - })?; - let cf1_U_i1 = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.cf1_U_i1.unwrap_or_else(|| cf_u_dummy_native.clone())) - })?; - let cf_U_i1 = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(self.cf_U_i1.unwrap_or_else(|| cf_u_dummy_native.clone())) - })?; - let cf1_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf1_cmT.unwrap_or_else(C2::zero)))?; - let cf2_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf2_cmT.unwrap_or_else(C2::zero)))?; - let cf1_r_nonnat = - NonNativeFieldVar::::new_witness(cs.clone(), || { - Ok(self.cf1_r_nonnat.unwrap_or_else(C2::ScalarField::zero)) - })?; - let cf2_r_nonnat = - NonNativeFieldVar::::new_witness(cs.clone(), || { - Ok(self.cf2_r_nonnat.unwrap_or_else(C2::ScalarField::zero)) - })?; - let cf_x = FpVar::>::new_input(cs.clone(), || { - Ok(self.cf_x.unwrap_or_else(C1::ScalarField::zero)) - })?; - - let cfW_x: Vec> = vec![ + // C.1. Compute cf1_u_i.x and cf2_u_i.x + let cfW_x = vec![ r_nonnat.clone(), U_i.cmW.x, U_i.cmW.y, @@ -451,78 +441,86 @@ where U_i1.cmW.x, U_i1.cmW.y, ]; - let cfE_x: Vec> = vec![ + let cfE_x = vec![ r_nonnat, U_i.cmE.x, U_i.cmE.y, cmT.x, cmT.y, U_i1.cmE.x, U_i1.cmE.y, ]; - // 1.b u_i.x[1] == H(cf_U_i) - let (cf_u_i_x, _) = cf_U_i.clone().hash(&crh_params)?; - // check that h == u_i.x[1] - (u_i.x[1]).conditional_enforce_equal(&cf_u_i_x, &is_not_basecase)?; - - // 4.b u_{i+1}.x[1] = H(cf_U_{i+1}), this is the second output of F' - let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params)?; - cf_u_i1_x.enforce_equal(&cf_x)?; - // ensure that cf1_u & cf2_u have as public inputs the cmW & cmE from main instances U_i, // u_i, U_i+1 coordinates of the commitments - cf1_u_i - .x - .conditional_enforce_equal(&cfW_x, &is_not_basecase)?; - cf2_u_i - .x - .conditional_enforce_equal(&cfE_x, &is_not_basecase)?; + // C.2. Construct `cf1_u_i` and `cf2_u_i` + let cf1_u_i = CycleFoldCommittedInstanceVar { + // cf1_u_i.cmE = 0 + cmE: GC2::zero(), + // cf1_u_i.u = 1 + u: NonNativeFieldVar::one(), + // cf1_u_i.cmW is provided by the prover as witness + cmW: GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?, + // cf1_u_i.x is computed in step 1 + x: cfW_x, + }; + let cf2_u_i = CycleFoldCommittedInstanceVar { + // cf2_u_i.cmE = 0 + cmE: GC2::zero(), + // cf2_u_i.u = 1 + u: NonNativeFieldVar::one(), + // cf2_u_i.cmW is provided by the prover as witness + cmW: GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?, + // cf2_u_i.x is computed in step 1 + x: cfE_x, + }; + // C.3. nifs.verify, obtains cf1_U_{i+1} by folding cf1_u_i & cf_U_i, and then cf_U_{i+1} + // by folding cf2_u_i & cf1_U_{i+1}. + + // compute cf1_r = H(cf1_u_i, cf_U_i, cf1_cmT) // cf_r_bits is denoted by rho* in the paper. - // assert that cf_r_bits == cf_r_nonnat converted to bits. cf_r_nonnat is just an auxiliary - // value used to compute RLC of NonNativeFieldVar values, since we can convert - // NonNativeFieldVar into Vec, but not in the other direction. let cf1_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( cs.clone(), &self.poseidon_config, - cf_U_i.clone(), + cf_U_i_vec, cf1_u_i.clone(), cf1_cmT.clone(), )?; - let cf1_r_nonnat_bits = cf1_r_nonnat.to_bits_le()?; - cf1_r_bits.conditional_enforce_equal(&cf1_r_nonnat_bits[..N_BITS_RO], &is_not_basecase)?; + // Convert cf1_r_bits to a `NonNativeFieldVar` + let cf1_r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &cf1_r_bits)?; + // Fold cf1_u_i & cf_U_i into cf1_U_{i+1} + let cf1_U_i1 = NIFSFullGadget::::fold_committed_instance( + cf1_r_bits, + cf1_r_nonnat, + cf1_cmT, + cf_U_i, + cf1_u_i, + )?; + // same for cf2_r: let cf2_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( cs.clone(), &self.poseidon_config, - cf1_U_i1.clone(), + cf1_U_i1.to_constraint_field()?, cf2_u_i.clone(), cf2_cmT.clone(), )?; - let cf2_r_nonnat_bits = cf2_r_nonnat.to_bits_le()?; - cf2_r_bits.conditional_enforce_equal(&cf2_r_nonnat_bits[..N_BITS_RO], &is_not_basecase)?; - - // check cf_u_i.cmE=0, cf_u_i.u=1 - (cf1_u_i.cmE.is_zero()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - (cf1_u_i.u.is_one()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - (cf2_u_i.cmE.is_zero()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - (cf2_u_i.u.is_one()?).conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - - // check the fold of all the parameters of the CycleFold instances, where the elliptic - // curve points relations are checked natively in Curve1 circuit (this one) - let v1 = NIFSFullGadget::::verify( - cf1_r_bits, - cf1_r_nonnat, - cf1_cmT, - cf_U_i, - cf1_u_i, - cf1_U_i1.clone(), - )?; - v1.conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; - let v2 = NIFSFullGadget::::verify( + let cf2_r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &cf2_r_bits)?; + let cf_U_i1 = NIFSFullGadget::::fold_committed_instance( cf2_r_bits, cf2_r_nonnat, cf2_cmT, cf1_U_i1, // the output from NIFS.V(cf1_r, cf_U, cfE_u) cf2_u_i, - cf_U_i1, )?; - v2.conditional_enforce_equal(&Boolean::TRUE, &is_not_basecase)?; + + // Back to Primary Part + // P.4.b compute and check the second output of F' + // Base case: u_{i+1}.x[1] == H(cf_U_{\bot}) + // Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1}) + let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params)?; + let (cf_u_i1_x_base, _) = + CycleFoldCommittedInstanceVar::new_constant(cs.clone(), cf_u_dummy)? + .hash(&crh_params)?; + let cf_x = FpVar::new_input(cs.clone(), || { + Ok(self.cf_x.unwrap_or(cf_u_i1_x_base.value()?)) + })?; + cf_x.enforce_equal(&is_basecase.select(&cf_u_i1_x_base, &cf_u_i1_x)?)?; Ok(()) } @@ -533,7 +531,6 @@ pub mod tests { use super::*; use ark_bn254::{Fr, G1Projective as Projective}; use ark_ff::BigInteger; - use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; @@ -583,14 +580,13 @@ pub mod tests { CommittedInstanceVar::::new_witness(cs.clone(), || Ok(ci3.clone())) .unwrap(); - let nifs_check = NIFSGadget::::verify( + NIFSGadget::::verify( rVar.clone(), ci1Var.clone(), ci2Var.clone(), ci3Var.clone(), ) .unwrap(); - nifs_check.enforce_equal(&Boolean::::TRUE).unwrap(); assert!(cs.is_satisfied().unwrap()); } @@ -675,10 +671,8 @@ pub mod tests { let U_iVar_vec = [ vec![U_iVar.u.clone()], U_iVar.x.clone(), - U_iVar.cmE.x.to_constraint_field().unwrap(), - U_iVar.cmE.y.to_constraint_field().unwrap(), - U_iVar.cmW.x.to_constraint_field().unwrap(), - U_iVar.cmW.y.to_constraint_field().unwrap(), + U_iVar.cmE.to_constraint_field().unwrap(), + U_iVar.cmW.to_constraint_field().unwrap(), ] .concat(); let r_bitsVar = ChallengeGadget::::get_challenge_gadget( diff --git a/folding-schemes/src/folding/nova/cyclefold.rs b/folding-schemes/src/folding/nova/cyclefold.rs index e04e234..7bc87bb 100644 --- a/folding-schemes/src/folding/nova/cyclefold.rs +++ b/folding-schemes/src/folding/nova/cyclefold.rs @@ -42,7 +42,6 @@ pub struct CycleFoldCommittedInstanceVar>> where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - _c: PhantomData, pub cmE: GC, pub u: NonNativeFieldVar>, pub cmW: GC, @@ -76,13 +75,7 @@ where mode, )?; - Ok(Self { - _c: PhantomData, - cmE, - u, - cmW, - x, - }) + Ok(Self { cmE, u, cmW, x }) }) } } @@ -189,6 +182,7 @@ pub struct NIFSFullGadget>> { _c: PhantomData, _gc: PhantomData, } + impl>> NIFSFullGadget where C: CurveGroup, @@ -196,42 +190,46 @@ where ::BaseField: ark_ff::PrimeField, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { + pub fn fold_committed_instance( + // assumes that r_bits is equal to r_nonnat just that in a different format + r_bits: Vec>>, + r_nonnat: NonNativeFieldVar>, + cmT: GC, + ci1: CycleFoldCommittedInstanceVar, + // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) + ci2: CycleFoldCommittedInstanceVar, + ) -> Result, SynthesisError> { + Ok(CycleFoldCommittedInstanceVar { + cmE: cmT.scalar_mul_le(r_bits.iter())? + ci1.cmE, + cmW: ci1.cmW + ci2.cmW.scalar_mul_le(r_bits.iter())?, + u: ci1.u + r_nonnat.clone(), + x: ci1 + .x + .iter() + .zip(ci2.x) + .map(|(a, b)| a + &r_nonnat * &b) + .collect::>(), + }) + } + pub fn verify( // assumes that r_bits is equal to r_nonnat just that in a different format r_bits: Vec>>, r_nonnat: NonNativeFieldVar>, cmT: GC, - // ci1 is assumed to be always with cmE=0, u=1 (checks done previous to this method) ci1: CycleFoldCommittedInstanceVar, + // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) ci2: CycleFoldCommittedInstanceVar, ci3: CycleFoldCommittedInstanceVar, - ) -> Result>, SynthesisError> { - // cm(E) check: ci3.cmE == ci1.cmE + r * cmT (ci2.cmE=0) - let first_check = ci3 - .cmE - .is_eq(&(cmT.scalar_mul_le(r_bits.iter())? + ci1.cmE))?; - - // cm(W) check: ci3.cmW == ci1.cmW + r * ci2.cmW - let second_check = ci3 - .cmW - .is_eq(&(ci1.cmW + ci2.cmW.scalar_mul_le(r_bits.iter())?))?; - - let u_rlc: NonNativeFieldVar> = ci1.u + r_nonnat.clone(); - let third_check = u_rlc.is_eq(&ci3.u)?; - - // ensure that: ci3.x == ci1.x + r * ci2.x - let x_rlc: Vec>> = ci1 - .x - .iter() - .zip(ci2.x) - .map(|(a, b)| a + &r_nonnat * &b) - .collect::>>>(); - let fourth_check = x_rlc.is_eq(&ci3.x)?; - - first_check - .and(&second_check)? - .and(&third_check)? - .and(&fourth_check) + ) -> Result<(), SynthesisError> { + let ci = Self::fold_committed_instance(r_bits, r_nonnat, cmT, ci1, ci2)?; + + ci.cmE.enforce_equal(&ci3.cmE)?; + ci.u.enforce_equal(&ci3.u)?; + ci.cmW.enforce_equal(&ci3.cmW)?; + ci.x.enforce_equal(&ci3.x)?; + + Ok(()) } } @@ -285,25 +283,24 @@ where pub fn get_challenge_gadget( cs: ConstraintSystemRef, poseidon_config: &PoseidonConfig, - U_i: CycleFoldCommittedInstanceVar, + mut U_i_vec: Vec>, u_i: CycleFoldCommittedInstanceVar, cmT: GC, ) -> Result>, SynthesisError> { let mut sponge = PoseidonSpongeVar::::new(cs, poseidon_config); - let mut U_vec = U_i.to_constraint_field()?; - let mut u_vec = u_i.to_constraint_field()?; + let mut u_i_vec = u_i.to_constraint_field()?; let mut cmT_vec = cmT.to_constraint_field()?; - let U_cm_is_inf = U_vec.pop().unwrap(); - let u_cm_is_inf = u_vec.pop().unwrap(); + let U_cm_is_inf = U_i_vec.pop().unwrap(); + let u_cm_is_inf = u_i_vec.pop().unwrap(); let cmT_is_inf = cmT_vec.pop().unwrap(); // Concatenate `U_i.cmE_is_inf`, `U_i.cmW_is_inf`, `u_i.cmE_is_inf`, `u_i.cmW_is_inf`, `cmT_is_inf` // to save constraints for sponge.squeeze_bits let is_inf = U_cm_is_inf * CF2::::from(8u8) + u_cm_is_inf.double()? + cmT_is_inf; - let input = [U_vec, u_vec, cmT_vec, vec![is_inf]].concat(); + let input = [U_i_vec, u_i_vec, cmT_vec, vec![is_inf]].concat(); sponge.absorb(&input)?; let bits = sponge.squeeze_bits(N_BITS_RO)?; Ok(bits) @@ -486,7 +483,7 @@ pub mod tests { .unwrap(); let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT)).unwrap(); - let nifs_check = NIFSFullGadget::::verify( + NIFSFullGadget::::verify( r_bitsVar, r_nonnatVar, cmTVar, @@ -495,7 +492,6 @@ pub mod tests { ci3Var, ) .unwrap(); - nifs_check.enforce_equal(&Boolean::::TRUE).unwrap(); assert!(cs.is_satisfied().unwrap()); } @@ -547,7 +543,7 @@ pub mod tests { let r_bitsVar = CycleFoldChallengeGadget::::get_challenge_gadget( cs.clone(), &poseidon_config, - U_iVar, + U_iVar.to_constraint_field().unwrap(), u_iVar, cmTVar, ) diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index 5f8cb00..1ae68c5 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -2,7 +2,6 @@ use ark_crypto_primitives::sponge::Absorb; use ark_ec::{CurveGroup, Group}; use ark_ff::PrimeField; -use ark_r1cs_std::fields::nonnative::params::OptimizationType; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_snark::SNARK; use ark_std::rand::{CryptoRng, RngCore}; @@ -14,7 +13,7 @@ use super::{circuits::CF2, nifs::NIFS, CommittedInstance, Nova}; use crate::commitment::{ kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, }; -use crate::folding::circuits::nonnative::point_to_nonnative_limbs_custom_opt; +use crate::folding::circuits::nonnative::NonNativeAffineVar; use crate::frontend::FCircuit; use crate::Error; use crate::{Decider as DeciderTrait, FoldingScheme}; @@ -151,12 +150,9 @@ where // compute U = U_{d+1}= NIFS.V(U_d, u_d, cmT) let U = NIFS::::verify(proof.r, running_instance, incoming_instance, &proof.cmT); - let (cmE_x, cmE_y) = - point_to_nonnative_limbs_custom_opt::(U.cmE, OptimizationType::Constraints)?; - let (cmW_x, cmW_y) = - point_to_nonnative_limbs_custom_opt::(U.cmW, OptimizationType::Constraints)?; - let (cmT_x, cmT_y) = - point_to_nonnative_limbs_custom_opt::(proof.cmT, OptimizationType::Constraints)?; + let (cmE_x, cmE_y) = NonNativeAffineVar::inputize(U.cmE)?; + let (cmW_x, cmW_y) = NonNativeAffineVar::inputize(U.cmW)?; + let (cmT_x, cmT_y) = NonNativeAffineVar::inputize(proof.cmT)?; let public_input: Vec = vec![ vec![i], diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index 0a00e05..335eb28 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -22,7 +22,7 @@ use core::{borrow::Borrow, marker::PhantomData}; use super::{circuits::ChallengeGadget, nifs::NIFS}; use crate::ccs::r1cs::R1CS; use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme}; -use crate::folding::circuits::nonnative::{point_to_nonnative_limbs, NonNativeAffineVar}; +use crate::folding::circuits::nonnative::{nonnative_affine_to_field_elements, NonNativeAffineVar}; use crate::folding::nova::{ circuits::{CommittedInstanceVar, CF1, CF2}, CommittedInstance, Nova, Witness, @@ -560,10 +560,8 @@ where poseidon_config: &PoseidonConfig, U_i: CommittedInstance, ) -> Result<(C::ScalarField, C::ScalarField), Error> { - let (cmE_x_limbs, cmE_y_limbs): (Vec, Vec) = - point_to_nonnative_limbs::(U_i.cmE)?; - let (cmW_x_limbs, cmW_y_limbs): (Vec, Vec) = - point_to_nonnative_limbs::(U_i.cmW)?; + let (cmE_x_limbs, cmE_y_limbs) = nonnative_affine_to_field_elements(U_i.cmE)?; + let (cmW_x_limbs, cmW_y_limbs) = nonnative_affine_to_field_elements(U_i.cmW)?; let transcript = &mut PoseidonTranscript::::new(poseidon_config); // compute the KZG challenges, which are computed in-circuit and checked that it matches @@ -586,16 +584,10 @@ where let mut transcript = PoseidonTranscriptVar::>::new(cs.clone(), &poseidon_config.clone()); - let cmW_x_limbs = U_i.cmW.x.to_constraint_field()?; - let cmW_y_limbs = U_i.cmW.y.to_constraint_field()?; - transcript.absorb_vec(&cmW_x_limbs)?; - transcript.absorb_vec(&cmW_y_limbs)?; + transcript.absorb_vec(&U_i.cmW.to_constraint_field()?[..])?; let challenge_W = transcript.get_challenge()?; - let cmE_x_limbs = U_i.cmE.x.to_constraint_field()?; - let cmE_y_limbs = U_i.cmE.y.to_constraint_field()?; - transcript.absorb_vec(&cmE_x_limbs)?; - transcript.absorb_vec(&cmE_y_limbs)?; + transcript.absorb_vec(&U_i.cmE.to_constraint_field()?[..])?; let challenge_E = transcript.get_challenge()?; Ok((challenge_W, challenge_E)) diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index dab6632..b6cc2d7 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -16,7 +16,7 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use crate::ccs::r1cs::{extract_r1cs, extract_w_x, R1CS}; use crate::commitment::CommitmentScheme; use crate::folding::circuits::nonnative::{ - nonnative_field_to_field_elements, point_to_nonnative_limbs, + nonnative_affine_to_field_elements, nonnative_field_to_field_elements, }; use crate::frontend::FCircuit; use crate::utils::vec::is_zero_vec; @@ -73,8 +73,8 @@ where z_0: Vec, z_i: Vec, ) -> Result { - let (cmE_x, cmE_y) = point_to_nonnative_limbs::(self.cmE)?; - let (cmW_x, cmW_y) = point_to_nonnative_limbs::(self.cmW)?; + let (cmE_x, cmE_y) = nonnative_affine_to_field_elements::(self.cmE)?; + let (cmW_x, cmW_y) = nonnative_affine_to_field_elements::(self.cmW)?; CRH::::evaluate( poseidon_config, @@ -342,7 +342,7 @@ where fn prove_step(&mut self) -> Result<(), Error> { let augmented_F_circuit: AugmentedFCircuit; - if self.i > C1::ScalarField::from_le_bytes_mod_order(&std::usize::MAX.to_le_bytes()) { + if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) { return Err(Error::MaxStep); } let mut i_bytes: [u8; 8] = [0; 8]; @@ -392,22 +392,18 @@ where i_usize: Some(0), z_0: Some(self.z_0.clone()), // = z_i z_i: Some(self.z_i.clone()), - u_i: Some(self.u_i.clone()), // = dummy + u_i_cmW: Some(self.u_i.cmW), // = dummy U_i: Some(self.U_i.clone()), // = dummy - U_i1: Some(U_i1.clone()), - r_nonnat: Some(r_Fq), + U_i1_cmE: Some(U_i1.cmE), + U_i1_cmW: Some(U_i1.cmW), cmT: Some(cmT), F: self.F.clone(), x: Some(u_i1_x), - cf1_u_i: None, - cf2_u_i: None, + cf1_u_i_cmW: None, + cf2_u_i_cmW: None, cf_U_i: None, - cf1_U_i1: None, - cf_U_i1: None, cf1_cmT: None, cf2_cmT: None, - cf1_r_nonnat: None, - cf2_r_nonnat: None, cf_x: Some(cf_u_i1_x), }; @@ -451,15 +447,14 @@ where }; // fold self.cf_U_i + cfW_U -> folded running with cfW - let (_cfW_w_i, cfW_u_i, cfW_W_i1, cfW_U_i1, cfW_cmT, cfW_r1_Fq) = self - .fold_cyclefold_circuit( - self.cf_W_i.clone(), // CycleFold running instance witness - self.cf_U_i.clone(), // CycleFold running instance - cfW_u_i_x, - cfW_circuit, - )?; + let (_cfW_w_i, cfW_u_i, cfW_W_i1, cfW_U_i1, cfW_cmT, _) = self.fold_cyclefold_circuit( + self.cf_W_i.clone(), // CycleFold running instance witness + self.cf_U_i.clone(), // CycleFold running instance + cfW_u_i_x, + cfW_circuit, + )?; // fold [the output from folding self.cf_U_i + cfW_U] + cfE_U = folded_running_with_cfW + cfE - let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, cf_r2_Fq) = + let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = self.fold_cyclefold_circuit(cfW_W_i1, cfW_U_i1.clone(), cfE_u_i_x, cfE_circuit)?; cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config)?; @@ -471,23 +466,19 @@ where i_usize: Some(i_usize), z_0: Some(self.z_0.clone()), z_i: Some(self.z_i.clone()), - u_i: Some(self.u_i.clone()), + u_i_cmW: Some(self.u_i.cmW), U_i: Some(self.U_i.clone()), - U_i1: Some(U_i1.clone()), - r_nonnat: Some(r_Fq), + U_i1_cmE: Some(U_i1.cmE), + U_i1_cmW: Some(U_i1.cmW), cmT: Some(cmT), F: self.F.clone(), x: Some(u_i1_x), // cyclefold values - cf1_u_i: Some(cfW_u_i.clone()), - cf2_u_i: Some(cfE_u_i.clone()), + cf1_u_i_cmW: Some(cfW_u_i.cmW), + cf2_u_i_cmW: Some(cfE_u_i.cmW), cf_U_i: Some(self.cf_U_i.clone()), - cf1_U_i1: Some(cfW_U_i1.clone()), - cf_U_i1: Some(cf_U_i1.clone()), cf1_cmT: Some(cfW_cmT), cf2_cmT: Some(cf_cmT), - cf1_r_nonnat: Some(cfW_r1_Fq), - cf2_r_nonnat: Some(cf_r2_Fq), cf_x: Some(cf_u_i1_x), }; @@ -523,11 +514,11 @@ where // set values for next iteration self.i += C1::ScalarField::one(); - self.z_i = z_i1.clone(); + self.z_i = z_i1; self.w_i = Witness::::new(w_i1, self.r1cs.A.n_rows); self.u_i = self.w_i.commit::(&self.cs_params, x_i1)?; - self.W_i = W_i1.clone(); - self.U_i = U_i1.clone(); + self.W_i = W_i1; + self.U_i = U_i1; #[cfg(test)] { diff --git a/folding-schemes/src/folding/nova/nifs.rs b/folding-schemes/src/folding/nova/nifs.rs index d2bcc65..20d4f58 100644 --- a/folding-schemes/src/folding/nova/nifs.rs +++ b/folding-schemes/src/folding/nova/nifs.rs @@ -203,14 +203,13 @@ pub mod tests { use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; use ark_ff::{BigInteger, PrimeField}; use ark_pallas::{Fr, Projective}; - use ark_std::{ops::Mul, UniformRand, Zero}; + use ark_std::{ops::Mul, UniformRand}; use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z}; use crate::commitment::pedersen::{Params as PedersenParams, Pedersen}; use crate::folding::nova::circuits::ChallengeGadget; use crate::folding::nova::traits::NovaR1CS; use crate::transcript::poseidon::{poseidon_test_config, PoseidonTranscript}; - use crate::utils::vec::vec_scalar_mul; #[allow(clippy::type_complexity)] pub(crate) fn prepare_simple_fold_inputs() -> (