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}