arnaucube
arnaucube/nova-studyPublic Self-hosted repository
nova-study/src/circuits.rs
src/circuits.rsRaw
  1use ark_ec::{AffineRepr, CurveGroup, Group};
  2use ark_ff::{BigInteger, Field, PrimeField, ToConstraintField};
  3use ark_r1cs_std::{
  4    alloc::{AllocVar, AllocationMode},
  5    bits::uint8::UInt8,
  6    boolean::Boolean,
  7    eq::EqGadget,
  8    fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
  9    groups::GroupOpsBounds,
 10    prelude::CurveVar,
 11    ToBitsGadget,
 12    ToBytesGadget,
 13    ToConstraintFieldGadget,
 14    // groups::curves::short_weierstrass::ProjectiveVar,
 15};
 16use ark_serialize::CanonicalSerialize;
 17use ark_std::{One, Zero};
 18// use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar;
 19use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
 20
 21// use ark_crypto_primitives::crh::poseidon::{
 22//     constraints::{CRHGadget, CRHParametersVar},
 23//     CRH,
 24// };
 25// use ark_crypto_primitives::crh::{CRHScheme, CRHSchemeGadget};
 26// use ark_crypto_primitives::snark::{FromFieldElementsGadget, SNARKGadget, SNARK};
 27use ark_crypto_primitives::sponge::poseidon::{
 28    constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge,
 29};
 30use ark_crypto_primitives::sponge::{
 31    constraints::CryptographicSpongeVar, Absorb, CryptographicSponge,
 32};
 33
 34use core::{borrow::Borrow, marker::PhantomData};
 35use derivative::Derivative;
 36
 37use crate::nifs::Phi;
 38
 39pub type ConstraintF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
 40
 41#[derive(Debug, Derivative)]
 42#[derivative(Clone(bound = "C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>"))]
 43pub struct PhiVar<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
 44where
 45    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
 46{
 47    _c: PhantomData<C>,
 48    cmE: GC,
 49    u: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
 50    cmW: GC,
 51    x: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
 52}
 53
 54impl<C, GC> AllocVar<Phi<C>, ConstraintF<C>> for PhiVar<C, GC>
 55where
 56    C: CurveGroup,
 57    GC: CurveVar<C, ConstraintF<C>>,
 58    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
 59{
 60    fn new_variable<T: Borrow<Phi<C>>>(
 61        cs: impl Into<Namespace<ConstraintF<C>>>,
 62        f: impl FnOnce() -> Result<T, SynthesisError>,
 63        mode: AllocationMode,
 64    ) -> Result<Self, SynthesisError> {
 65        f().and_then(|val| {
 66            let cs = cs.into();
 67
 68            let u = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
 69                cs.clone(),
 70                || Ok(val.borrow().u),
 71                mode,
 72            )?;
 73            let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE.0), mode)?;
 74            let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW.0), mode)?;
 75
 76            let x = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
 77                cs,
 78                || Ok(val.borrow().x),
 79                mode,
 80            )?;
 81
 82            Ok(Self {
 83                _c: PhantomData,
 84                cmE,
 85                u,
 86                cmW,
 87                x,
 88            })
 89        })
 90    }
 91}
 92
 93pub struct NIFSGadget<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> {
 94    _c: PhantomData<C>,
 95    _gc: PhantomData<GC>,
 96}
 97
 98impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> NIFSGadget<C, GC>
 99where
100    C: CurveGroup,
101    GC: CurveVar<C, ConstraintF<C>>,
102    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
103{
104    // implements the constraints for NIFS.V
105    pub fn verify(
106        r: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
107        cmT: GC,
108        phi1: PhiVar<C, GC>,
109        phi2: PhiVar<C, GC>,
110        phi3: PhiVar<C, GC>,
111    ) -> Result<(), SynthesisError> {
112        let r2 = r.square()?;
113
114        phi3.cmE.enforce_equal(
115            &(phi1.cmE
116                + cmT.scalar_mul_le(r.to_bits_le()?.iter())?
117                + phi2.cmE.scalar_mul_le(r2.to_bits_le()?.iter())?),
118        )?;
119        phi3.u.enforce_equal(&(phi1.u + r.clone() * phi2.u))?;
120        phi3.cmW
121            .enforce_equal(&(phi1.cmW + phi2.cmW.scalar_mul_le(r.to_bits_le()?.iter())?))?;
122
123        // wip x's check
124        phi3.x.enforce_equal(&(phi1.x + r * phi2.x))?;
125        Ok(())
126    }
127}
128
129pub trait FCircuit<F: PrimeField>: ConstraintSynthesizer<F> + Copy {
130    // method that returns z_i (input), z_i1 (output)
131    fn public(self) -> (F, F);
132}
133
134pub struct AugmentedFCircuit<
135    C: CurveGroup,
136    GC: CurveVar<C, ConstraintF<C>>,
137    FC: FCircuit<ConstraintF<C>>,
138> where
139    <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
140{
141    pub _c: PhantomData<C>,
142    pub _gc: PhantomData<GC>,
143
144    // pub poseidon_native: PoseidonSponge<ConstraintF<C>>,
145    pub poseidon_config: PoseidonConfig<ConstraintF<C>>,
146    pub i: Option<C::BaseField>, // TODO rm Option in all params
147    pub z_0: Option<C::BaseField>,
148    pub z_i: Option<C::BaseField>,
149    pub z_i1: Option<C::BaseField>, // z_{i+1}
150    pub phi: Option<Phi<C>>, // phi_i in the paper sometimes appears as phi (φ_i) and others as 𝗎
151    pub phiBig: Option<Phi<C>>, // ϕ_i
152    pub phiBigOut: Option<Phi<C>>, // ϕ_{i+1}
153    pub cmT: Option<C>,
154    pub r: Option<C::ScalarField>, // This will not be an input and derived from a hash internally in the circuit (poseidon transcript)
155    pub F: FC,                     // F circuit
156    pub x: ConstraintF<C>,         // pub input (φ_{i+1}.x)
157}
158
159impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>, FC: FCircuit<ConstraintF<C>>>
160    ConstraintSynthesizer<ConstraintF<C>> for AugmentedFCircuit<C, GC, FC>
161where
162    C: CurveGroup,
163    GC: CurveVar<C, ConstraintF<C>>,
164    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
165    <C as CurveGroup>::BaseField: PrimeField,
166    <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
167{
168    fn generate_constraints(
169        self,
170        cs: ConstraintSystemRef<ConstraintF<C>>,
171    ) -> Result<(), SynthesisError> {
172        let i = FpVar::<ConstraintF<C>>::new_input(cs.clone(), || Ok(self.i.unwrap()))?;
173        let z_0 = FpVar::<ConstraintF<C>>::new_input(cs.clone(), || Ok(self.z_0.unwrap()))?;
174        let z_i = FpVar::<ConstraintF<C>>::new_input(cs.clone(), || Ok(self.z_i.unwrap()))?;
175        let z_i1 = FpVar::<ConstraintF<C>>::new_input(cs.clone(), || Ok(self.z_i1.unwrap()))?;
176
177        let phi = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phi.unwrap()))?;
178        let phiBig = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiBig.unwrap()))?;
179        let phiBigOut = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiBigOut.unwrap()))?;
180
181        let cmT = GC::new_witness(cs.clone(), || Ok(self.cmT.unwrap()))?;
182        let r =
183            NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_witness(cs.clone(), || {
184                Ok(self.r.unwrap())
185            })?; // r will come from transcript
186
187        // if i=0, output H(vk_nifs, 1, z_0, z_i1, phi)
188        let phiOut_x = AugmentedFCircuit::<C, GC, FC>::phi_x_hash_var(
189            cs.clone(),
190            self.poseidon_config.clone(),
191            FpVar::<ConstraintF<C>>::one(),
192            z_0.clone(),
193            z_i1.clone(),
194            phi.clone(),
195        )?;
196        // TODO WIP: x is the output when i=0
197
198        // 1. phi.x == H(vk_nifs, i, z_0, z_i, phiBig)
199        let h = AugmentedFCircuit::<C, GC, FC>::phi_x_hash_var(
200            cs.clone(),
201            self.poseidon_config.clone(),
202            i.clone(),
203            z_0.clone(),
204            z_i.clone(),
205            phiBig.clone(),
206        )?;
207        let x_CF = phi.x.to_constraint_field()?; // phi.x on the ConstraintF<C>
208                                                 // x_CF[0].enforce_equal(&h)?; // review
209
210        // 2. phi.cmE==cm(0), phi.u==1
211        // (phi.cmE.is_zero()?).enforce_equal(&Boolean::TRUE)?; // TODO check that cmE = cm(0)
212        (phi.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
213
214        // 3. nifs.verify, checks that folding phi & phiBig obtains phiBigOut
215        NIFSGadget::<C, GC>::verify(r, cmT, phi, phiBig, phiBigOut.clone())?;
216
217        // 4. zksnark.V(vk_snark, phi_new, proof_phi)
218        // 5. phi.x == H(i+1, z_0, z_i+1, phiBigOut)
219        let h = AugmentedFCircuit::<C, GC, FC>::phi_x_hash_var(
220            cs.clone(),
221            self.poseidon_config.clone(),
222            i + FpVar::<ConstraintF<C>>::one(),
223            z_0.clone(),
224            z_i1.clone(),
225            phiBigOut.clone(),
226        )?;
227        // WIP
228        let x_CF = phiBigOut.x.to_constraint_field()?; // phi.x on the ConstraintF<C>
229                                                       // x_CF[0].enforce_equal(&h)?; // TODO review
230
231        // WIP assert that z_i1 == F(z_i).z_i1
232        // self.F.generate_constraints(cs.clone())?;
233
234        Ok(())
235    }
236}
237
238impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>, FC: FCircuit<ConstraintF<C>>>
239    AugmentedFCircuit<C, GC, FC>
240where
241    C: CurveGroup,
242    GC: CurveVar<C, ConstraintF<C>>,
243    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
244    <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
245    <C as CurveGroup>::BaseField: Absorb,
246{
247    fn phi_x_hash_var(
248        cs: ConstraintSystemRef<ConstraintF<C>>,
249        poseidon_config: PoseidonConfig<ConstraintF<C>>,
250        i: FpVar<ConstraintF<C>>,
251        z_0: FpVar<ConstraintF<C>>,
252        z_i: FpVar<ConstraintF<C>>,
253        phi: PhiVar<C, GC>,
254    ) -> Result<FpVar<ConstraintF<C>>, SynthesisError> {
255        // note: this method can be optimized if instead of bytes representations we hash finite
256        // field elements (in the constraint field)
257        let mut sponge = PoseidonSpongeVar::<ConstraintF<C>>::new(cs.clone(), &poseidon_config);
258
259        let input = vec![i, z_0, z_i];
260        sponge.absorb(&input)?;
261
262        let input: Vec<Vec<UInt8<ConstraintF<C>>>> = vec![phi.u.to_bytes()?, phi.x.to_bytes()?];
263        sponge.absorb(&input)?;
264
265        let input = vec![phi.cmE.to_bytes()?, phi.cmW.to_bytes()?];
266        sponge.absorb(&input)?;
267
268        let h = sponge.squeeze_field_elements(1).unwrap();
269        Ok(h[0].clone())
270    }
271    fn phi_x_hash(
272        poseidon_config: PoseidonConfig<ConstraintF<C>>,
273        i: ConstraintF<C>,
274        z_0: ConstraintF<C>,
275        z_i: ConstraintF<C>,
276        phi: Phi<C>,
277    ) -> ConstraintF<C> {
278        let mut sponge = PoseidonSponge::<ConstraintF<C>>::new(&poseidon_config);
279
280        let input: Vec<ConstraintF<C>> = vec![i, z_0, z_i];
281        sponge.absorb(&input);
282
283        let input: Vec<Vec<u8>> = vec![
284            phi.u.into_bigint().to_bytes_le(),
285            phi.x.into_bigint().to_bytes_le(),
286        ];
287        sponge.absorb(&input);
288
289        let cmE_bytes = Self::to_bytes_cs_compat(phi.cmE.0);
290        let cmW_bytes = Self::to_bytes_cs_compat(phi.cmW.0);
291        let input = vec![cmE_bytes, cmW_bytes];
292        sponge.absorb(&input);
293
294        let h = sponge.squeeze_field_elements(1);
295        h[0]
296    }
297
298    fn to_bytes_cs_compat(c: C) -> Vec<u8> {
299        // note: this method has been implemented to be compatible with the arkworks/r1cs-std
300        // short_weierstrass/ProjectiveVar ToBytesGadget implementation, as the
301        // arkworks/algebra/serialize/SWCurveConfig version is not compatible.
302        let a = c.into_affine();
303        let x = a.x().unwrap();
304        let y = a.y().unwrap();
305        let mut x_bytes = Vec::new();
306        x.serialize_uncompressed(&mut x_bytes).unwrap();
307        let mut y_bytes = Vec::new();
308        y.serialize_uncompressed(&mut y_bytes).unwrap();
309
310        x_bytes.append(&mut vec![0, 0]);
311        y_bytes.append(&mut vec![0, 0]);
312        x_bytes.append(&mut y_bytes);
313        x_bytes.push(0);
314        x_bytes
315    }
316}
317
318//////////
319
320// pub struct Nova<MainField: PrimeField, SecondField: PrimeField, C1: CurveGroup, C2: CurveGroup> {}
321// pub trait SNARKs<MainField: PrimeField, SecondField: PrimeField> {
322//     type AugmentedFunctionSNARK: SNARK<MainField>;
323//     // type FunctionSNARK: ConstraintSynthesizer<Fr>; // F
324//     type DummyStepSNARK: SNARK<SecondField>;
325//
326//     type AugmentedFunctionCircuit: SNARKGadget<MainField, SecondField, Self::AugmentedFunctionSNARK>; // F'
327//     type FunctionCircuit: ConstraintSynthesizer<MainField>; // F
328//     type DummyStepCircuit: SNARKGadget<SecondField, MainField, Self::DummyStepSNARK>;
329// }
330// pub struct TS<
331//     MainField: PrimeField,
332//     SecondField: PrimeField,
333//     Config: SNARKs<MainField, SecondField>,
334// > {
335//     augmentedF_pk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::ProvingKey,
336//     augmentedF_vk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::VerifyingKey,
337//
338//     dummy_pk: <Config::DummyStepSNARK as SNARK<SecondField>>::ProvingKey,
339//     dummy_vk: <Config::DummyStepSNARK as SNARK<SecondField>>::VerifyingKey,
340// }
341
342#[derive(Clone, Copy, Debug)]
343pub struct TestFCircuit<F: PrimeField> {
344    z_i: F,  // z_i
345    z_i1: F, // z_{i+1}
346}
347impl<F: PrimeField> FCircuit<F> for TestFCircuit<F> {
348    fn public(self) -> (F, F) {
349        (self.z_i, self.z_i1)
350    }
351}
352impl<F: PrimeField> ConstraintSynthesizer<F> for TestFCircuit<F> {
353    fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
354        let z_i = FpVar::<F>::new_input(cs.clone(), || Ok(self.z_i))?;
355        let z_i1 = FpVar::<F>::new_input(cs.clone(), || Ok(self.z_i1))?;
356        let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
357
358        let y = &z_i * &z_i * &z_i + &z_i + &five;
359        y.enforce_equal(&z_i1)?;
360        Ok(())
361    }
362}
363
364#[cfg(test)]
365mod test {
366    use super::*;
367
368    use crate::transcript::Transcript;
369    use ark_r1cs_std::R1CSVar;
370    use ark_relations::r1cs::ConstraintSystem;
371    use ark_std::UniformRand;
372
373    use crate::nifs;
374    use crate::pedersen;
375    use crate::transcript::poseidon_test_config;
376    use ark_ec::Group;
377    // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
378    use crate::pedersen::Commitment;
379    use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, Fq, Fr, G1Projective as MNT4G1Projective};
380    use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective};
381    use ark_std::One;
382
383    // mnt4's Fr is the Constraint Field,
384    // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1
385
386    #[test]
387    fn test_phi_var() {
388        let phi = Phi::<MNT6G1Projective> {
389            cmE: Commitment(MNT6G1Projective::generator()),
390            u: Fq::one(),
391            cmW: Commitment(MNT6G1Projective::generator()),
392            x: Fq::one(),
393        };
394
395        let cs = ConstraintSystem::<Fr>::new_ref();
396        let _phiVar =
397            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
398        // println!("num_constraints={:?}", cs.num_constraints());
399    }
400
401    #[test]
402    fn test_phi_x_hash() {
403        let mut rng = ark_std::test_rng();
404        let poseidon_config = poseidon_test_config::<Fr>();
405
406        let z_0 = Fr::from(0_u32);
407        let z_i = Fr::from(3_u32);
408        let phi = Phi::<MNT6G1Projective> {
409            // cmE: Commitment(MNT6G1Projective::generator()),
410            cmE: Commitment(MNT6G1Projective::rand(&mut rng)),
411            u: Fq::one(),
412            cmW: Commitment(MNT6G1Projective::generator()),
413            x: Fq::one(),
414        };
415        let x = AugmentedFCircuit::<MNT6G1Projective, MNT6G1Var, TestFCircuit<Fr>>::phi_x_hash(
416            poseidon_config.clone(),
417            Fr::one(),
418            z_0.clone(),
419            z_i.clone(),
420            phi.clone(),
421        );
422
423        let cs = ConstraintSystem::<Fr>::new_ref();
424        let z_0Var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(z_0)).unwrap();
425        let z_iVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(z_i)).unwrap();
426        let phiVar =
427            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
428
429        let xVar =
430            AugmentedFCircuit::<MNT6G1Projective, MNT6G1Var, TestFCircuit<Fr>>::phi_x_hash_var(
431                cs.clone(),
432                poseidon_config.clone(),
433                FpVar::<Fr>::one(),
434                z_0Var,
435                z_iVar,
436                phiVar,
437            )
438            .unwrap();
439        println!("num_constraints={:?}", cs.num_constraints());
440
441        assert_eq!(x, xVar.value().unwrap());
442    }
443
444    #[test]
445    fn test_nifs_gadget() {
446        let mut rng = ark_std::test_rng();
447        let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
448        let poseidon_config = poseidon_test_config::<Fq>();
449
450        let cs = ConstraintSystem::<Fr>::new_ref();
451
452        let (r1cs, ws, _) = nifs::gen_test_values::<Fq>(2);
453        let (A, _, _) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
454
455        let r = Fq::rand(&mut rng); // this would come from the transcript
456
457        let fw1 = nifs::FWit::<MNT6G1Projective>::new(ws[0].clone(), A.len());
458        let fw2 = nifs::FWit::<MNT6G1Projective>::new(ws[1].clone(), A.len());
459
460        let mut transcript_p = Transcript::<Fq, MNT6G1Projective>::new(&poseidon_config);
461
462        let (_fw3, phi1, phi2, _T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
463            &mut transcript_p,
464            &pedersen_params,
465            r,
466            &r1cs,
467            fw1,
468            fw2,
469        );
470        let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
471
472        let phi1Var =
473            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi1)).unwrap();
474        let phi2Var =
475            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi2)).unwrap();
476        let phi3Var =
477            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi3)).unwrap();
478
479        let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap();
480        let rVar = NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
481
482        NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(rVar, cmTVar, phi1Var, phi2Var, phi3Var)
483            .unwrap();
484        // println!("num_constraints={:?}", cs.num_constraints());
485        assert!(cs.is_satisfied().unwrap());
486    }
487
488    #[test]
489    fn test_augmented_f_circuit() {
490        let mut rng = ark_std::test_rng();
491        let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
492        let poseidon_config_Fq = poseidon_test_config::<Fq>();
493        let poseidon_config_Fr = poseidon_test_config::<Fr>();
494
495        let cs = ConstraintSystem::<Fr>::new_ref();
496
497        let (r1cs, ws, _) = nifs::gen_test_values::<Fq>(2);
498        let A = r1cs.A.clone();
499
500        let r = Fq::rand(&mut rng); // this would come from the transcript
501
502        let fw1 = nifs::FWit::<MNT6G1Projective>::new(ws[0].clone(), A.len());
503        let fw2 = nifs::FWit::<MNT6G1Projective>::new(ws[1].clone(), A.len());
504
505        let mut transcript_p = Transcript::<Fq, MNT6G1Projective>::new(&poseidon_config_Fq);
506
507        let (_fw3, phi1, phi2, _T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
508            &mut transcript_p,
509            &pedersen_params,
510            r,
511            &r1cs,
512            fw1,
513            fw2,
514        );
515        let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
516        println!("phi1 {:?}", phi1.cmE);
517
518        let i = Fr::from(1_u32);
519        let z_0 = Fr::from(0_u32);
520        let z_i = Fr::from(3_u32);
521        let z_i1 = Fr::from(35_u32);
522        let test_F_circuit = TestFCircuit::<Fr> { z_i, z_i1 };
523
524        let x = AugmentedFCircuit::<MNT6G1Projective, MNT6G1Var, TestFCircuit<Fr>>::phi_x_hash(
525            poseidon_config_Fr.clone(),
526            i + Fr::one(),
527            z_0.clone(),
528            z_i1.clone(),
529            phi3.clone(),
530        );
531
532        let augmentedF = AugmentedFCircuit::<MNT6G1Projective, MNT6G1Var, TestFCircuit<Fr>> {
533            _c: PhantomData,
534            _gc: PhantomData,
535            poseidon_config: poseidon_config_Fr.clone(),
536            i: Some(i),
537            z_0: Some(z_0),
538            z_i: Some(z_i),
539            z_i1: Some(z_i1),
540            phi: Some(phi1),
541            phiBig: Some(phi2),
542            phiBigOut: Some(phi3.clone()),
543            cmT: Some(cmT.0),
544            r: Some(r),
545            F: test_F_circuit,
546            x,
547        };
548        augmentedF.generate_constraints(cs.clone()).unwrap();
549        println!("num_constraints={:?}", cs.num_constraints());
550
551        assert!(cs.is_satisfied().unwrap());
552    }
553}