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