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}