arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/crypto-primitives/src/nizk/groth16/constraints.rs
crypto-primitives/src/nizk/groth16/constraints.rsRaw
  1use crate::{
  2    nizk::{groth16::Groth16, NIZKVerifierGadget},
  3    Vec,
  4};
  5use algebra_core::{AffineCurve, PairingEngine, ToConstraintField};
  6use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError};
  7use r1cs_std::prelude::*;
  8
  9use core::{borrow::Borrow, marker::PhantomData};
 10use groth16::{PreparedVerifyingKey, Proof, VerifyingKey};
 11
 12#[derive(Derivative)]
 13#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))]
 14pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> {
 15    pub a: P::G1Var,
 16    pub b: P::G2Var,
 17    pub c: P::G1Var,
 18}
 19
 20#[derive(Derivative)]
 21#[derivative(
 22    Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
 23    P::G2PreparedVar: Clone, ")
 24)]
 25pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
 26    pub alpha_g1: P::G1Var,
 27    pub beta_g2: P::G2Var,
 28    pub gamma_g2: P::G2Var,
 29    pub delta_g2: P::G2Var,
 30    pub gamma_abc_g1: Vec<P::G1Var>,
 31}
 32
 33impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> {
 34    pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> {
 35        let alpha_g1_pc = P::prepare_g1(&self.alpha_g1)?;
 36        let beta_g2_pc = P::prepare_g2(&self.beta_g2)?;
 37
 38        let alpha_g1_beta_g2 = P::pairing(alpha_g1_pc, beta_g2_pc)?;
 39        let gamma_g2_neg_pc = P::prepare_g2(&self.gamma_g2.negate()?)?;
 40        let delta_g2_neg_pc = P::prepare_g2(&self.delta_g2.negate()?)?;
 41
 42        Ok(PreparedVerifyingKeyVar {
 43            alpha_g1_beta_g2,
 44            gamma_g2_neg_pc,
 45            delta_g2_neg_pc,
 46            gamma_abc_g1: self.gamma_abc_g1.clone(),
 47        })
 48    }
 49}
 50
 51#[derive(Derivative)]
 52#[derivative(
 53    Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
 54    P::G2PreparedVar: Clone, ")
 55)]
 56pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
 57    pub alpha_g1_beta_g2: P::GTVar,
 58    pub gamma_g2_neg_pc: P::G2PreparedVar,
 59    pub delta_g2_neg_pc: P::G2PreparedVar,
 60    pub gamma_abc_g1: Vec<P::G1Var>,
 61}
 62
 63pub struct Groth16VerifierGadget<E, P>
 64where
 65    E: PairingEngine,
 66
 67    P: PairingVar<E>,
 68{
 69    _pairing_engine: PhantomData<E>,
 70    _pairing_gadget: PhantomData<P>,
 71}
 72
 73impl<E, P, C, V> NIZKVerifierGadget<Groth16<E, C, V>, E::Fq> for Groth16VerifierGadget<E, P>
 74where
 75    E: PairingEngine,
 76    C: ConstraintSynthesizer<E::Fr>,
 77    V: ToConstraintField<E::Fr>,
 78    P: PairingVar<E>,
 79{
 80    type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>;
 81    type VerificationKeyVar = VerifyingKeyVar<E, P>;
 82    type ProofVar = ProofVar<E, P>;
 83
 84    /// Allocates `N::Proof` in `cs` without performing
 85    /// subgroup checks.
 86    fn new_proof_unchecked<T: Borrow<Proof<E>>>(
 87        cs: impl Into<Namespace<E::Fq>>,
 88        f: impl FnOnce() -> Result<T, SynthesisError>,
 89        mode: AllocationMode,
 90    ) -> Result<Self::ProofVar, SynthesisError> {
 91        let ns = cs.into();
 92        let cs = ns.cs();
 93        f().and_then(|proof| {
 94            let proof = proof.borrow();
 95            let a = CurveVar::new_variable_omit_prime_order_check(
 96                cs.ns("Proof.a"),
 97                || Ok(proof.a.into_projective()),
 98                mode,
 99            )?;
100            let b = CurveVar::new_variable_omit_prime_order_check(
101                cs.ns("Proof.b"),
102                || Ok(proof.b.into_projective()),
103                mode,
104            )?;
105            let c = CurveVar::new_variable_omit_prime_order_check(
106                cs.ns("Proof.c"),
107                || Ok(proof.c.into_projective()),
108                mode,
109            )?;
110            Ok(ProofVar { a, b, c })
111        })
112    }
113
114    /// Allocates `N::Proof` in `cs` without performing
115    /// subgroup checks.
116    fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
117        cs: impl Into<Namespace<E::Fq>>,
118        f: impl FnOnce() -> Result<T, SynthesisError>,
119        mode: AllocationMode,
120    ) -> Result<Self::VerificationKeyVar, SynthesisError> {
121        let ns = cs.into();
122        let cs = ns.cs();
123        f().and_then(|vk| {
124            let vk = vk.borrow();
125            let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
126                cs.ns("alpha_g1"),
127                || Ok(vk.alpha_g1.into_projective()),
128                mode,
129            )?;
130            let beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
131                cs.ns("beta_g2"),
132                || Ok(vk.beta_g2.into_projective()),
133                mode,
134            )?;
135            let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
136                cs.ns("gamma_g2"),
137                || Ok(vk.gamma_g2.into_projective()),
138                mode,
139            )?;
140            let delta_g2 = P::G2Var::new_variable_omit_prime_order_check(
141                cs.ns("delta_g2"),
142                || Ok(vk.delta_g2.into_projective()),
143                mode,
144            )?;
145
146            let gamma_abc_g1 = vk
147                .gamma_abc_g1
148                .iter()
149                .map(|g| {
150                    P::G1Var::new_variable_omit_prime_order_check(
151                        cs.ns("g"),
152                        || Ok(g.into_projective()),
153                        mode,
154                    )
155                })
156                .collect::<Result<Vec<_>, _>>()?;
157            Ok(VerifyingKeyVar {
158                alpha_g1,
159                beta_g2,
160                gamma_g2,
161                delta_g2,
162                gamma_abc_g1,
163            })
164        })
165    }
166
167    fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
168        vk: &Self::VerificationKeyVar,
169        input: impl Iterator<Item = &'a T>,
170        proof: &Self::ProofVar,
171        condition: &Boolean<E::Fq>,
172    ) -> Result<(), SynthesisError> {
173        let pvk = vk.prepare()?;
174        <Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::conditional_verify_prepared(
175            &pvk, input, proof, condition,
176        )
177    }
178
179    fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
180        pvk: &Self::PreparedVerificationKeyVar,
181        mut public_inputs: impl Iterator<Item = &'a T>,
182        proof: &Self::ProofVar,
183        condition: &Boolean<E::Fq>,
184    ) -> Result<(), SynthesisError> {
185        let pvk = pvk.clone();
186
187        let g_ic = {
188            let mut g_ic: P::G1Var = pvk.gamma_abc_g1[0].clone();
189            let mut input_len = 1;
190            for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) {
191                let encoded_input_i: P::G1Var = b.mul_bits(input.to_bits()?.iter())?;
192                g_ic += encoded_input_i;
193                input_len += 1;
194            }
195            // Check that the input and the query in the verification are of the
196            // same length.
197            assert!(input_len == pvk.gamma_abc_g1.len() && public_inputs.next().is_none());
198            g_ic
199        };
200
201        let test_exp = {
202            let proof_a_prep = P::prepare_g1(&proof.a)?;
203            let proof_b_prep = P::prepare_g2(&proof.b)?;
204            let proof_c_prep = P::prepare_g1(&proof.c)?;
205
206            let g_ic_prep = P::prepare_g1(&g_ic)?;
207
208            P::miller_loop(
209                &[proof_a_prep, g_ic_prep, proof_c_prep],
210                &[
211                    proof_b_prep,
212                    pvk.gamma_g2_neg_pc.clone(),
213                    pvk.delta_g2_neg_pc.clone(),
214                ],
215            )?
216        };
217
218        let test = P::final_exponentiation(&test_exp).unwrap();
219
220        test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?;
221        Ok(())
222    }
223}
224
225impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
226where
227    E: PairingEngine,
228    P: PairingVar<E>,
229{
230    fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
231        cs: impl Into<Namespace<E::Fq>>,
232        f: impl FnOnce() -> Result<T, SynthesisError>,
233        mode: AllocationMode,
234    ) -> Result<Self, SynthesisError> {
235        let ns = cs.into();
236        let cs = ns.cs();
237
238        f().and_then(|pvk| {
239            let pvk = pvk.borrow();
240            let alpha_g1_beta_g2 = P::GTVar::new_variable(
241                cs.ns("alpha_g1_beta_g2"),
242                || Ok(pvk.alpha_g1_beta_g2),
243                mode,
244            )?;
245
246            let gamma_g2_neg_pc = P::G2PreparedVar::new_variable(
247                cs.ns("gamma_g2_neg_pc"),
248                || Ok(pvk.gamma_g2_neg_pc.clone()),
249                mode,
250            )?;
251
252            let delta_g2_neg_pc = P::G2PreparedVar::new_variable(
253                cs.ns("delta_g2_neg_pc"),
254                || Ok(pvk.delta_g2_neg_pc.clone()),
255                mode,
256            )?;
257
258            let gamma_abc_g1 =
259                Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?;
260
261            Ok(Self {
262                alpha_g1_beta_g2,
263                gamma_g2_neg_pc,
264                delta_g2_neg_pc,
265                gamma_abc_g1,
266            })
267        })
268    }
269}
270
271impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
272where
273    E: PairingEngine,
274
275    P: PairingVar<E>,
276{
277    fn new_variable<T: Borrow<VerifyingKey<E>>>(
278        cs: impl Into<Namespace<E::Fq>>,
279        f: impl FnOnce() -> Result<T, SynthesisError>,
280        mode: AllocationMode,
281    ) -> Result<Self, SynthesisError> {
282        let ns = cs.into();
283        let cs = ns.cs();
284
285        f().and_then(|vk| {
286            let VerifyingKey {
287                alpha_g1,
288                beta_g2,
289                gamma_g2,
290                delta_g2,
291                gamma_abc_g1,
292            } = vk.borrow().clone();
293            let alpha_g1 = P::G1Var::new_variable(cs.ns("alpha_g1"), || Ok(alpha_g1), mode)?;
294            let beta_g2 = P::G2Var::new_variable(cs.ns("beta_g2"), || Ok(beta_g2), mode)?;
295            let gamma_g2 = P::G2Var::new_variable(cs.ns("gamma_g2"), || Ok(gamma_g2), mode)?;
296            let delta_g2 = P::G2Var::new_variable(cs.ns("delta_g2"), || Ok(delta_g2), mode)?;
297
298            let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
299            Ok(Self {
300                alpha_g1,
301                beta_g2,
302                gamma_g2,
303                delta_g2,
304                gamma_abc_g1,
305            })
306        })
307    }
308}
309
310impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
311where
312    E: PairingEngine,
313    P: PairingVar<E>,
314{
315    fn new_variable<T: Borrow<Proof<E>>>(
316        cs: impl Into<Namespace<E::Fq>>,
317        f: impl FnOnce() -> Result<T, SynthesisError>,
318        mode: AllocationMode,
319    ) -> Result<Self, SynthesisError> {
320        let ns = cs.into();
321        let cs = ns.cs();
322
323        f().and_then(|proof| {
324            let Proof { a, b, c } = proof.borrow().clone();
325            let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?;
326            let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?;
327            let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?;
328            Ok(Self { a, b, c })
329        })
330    }
331}
332
333impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
334where
335    E: PairingEngine,
336    P: PairingVar<E>,
337{
338    #[inline]
339    fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
340        let mut bytes = Vec::new();
341        bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
342        bytes.extend_from_slice(&self.beta_g2.to_bytes()?);
343        bytes.extend_from_slice(&self.gamma_g2.to_bytes()?);
344        bytes.extend_from_slice(&self.delta_g2.to_bytes()?);
345        for g in &self.gamma_abc_g1 {
346            bytes.extend_from_slice(&g.to_bytes()?);
347        }
348        Ok(bytes)
349    }
350}
351
352#[cfg(test)]
353mod test {
354    use groth16::*;
355    use r1cs_core::{
356        lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
357    };
358
359    use super::*;
360    use algebra::{
361        bls12_377::{Bls12_377, Fq, Fr},
362        test_rng, BitIterator, Field, PrimeField,
363    };
364    use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
365    use rand::Rng;
366
367    type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
368    type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>;
369    type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
370    type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
371
372    struct Bench<F: Field> {
373        inputs: Vec<Option<F>>,
374        num_constraints: usize,
375    }
376
377    impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
378        fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
379            assert!(self.inputs.len() >= 2);
380            assert!(self.num_constraints >= self.inputs.len());
381
382            let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
383            for input in self.inputs {
384                let input_var = cs.new_input_variable(|| input.get())?;
385                variables.push((input, input_var));
386            }
387
388            for i in 0..self.num_constraints {
389                let new_entry = {
390                    let (input_1_val, input_1_var) = variables[i];
391                    let (input_2_val, input_2_var) = variables[i + 1];
392                    let result_val = input_1_val
393                        .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
394                    let result_var = cs.new_witness_variable(|| {
395                        result_val.ok_or(SynthesisError::AssignmentMissing)
396                    })?;
397                    cs.enforce_named_constraint(
398                        format!("Enforce constraint {}", i),
399                        lc!() + input_1_var,
400                        lc!() + input_2_var,
401                        lc!() + result_var,
402                    )
403                    .unwrap();
404                    (result_val, result_var)
405                };
406                variables.push(new_entry);
407            }
408            Ok(())
409        }
410    }
411
412    #[test]
413    fn groth16_verifier_test() {
414        let num_inputs = 100;
415        let num_constraints = num_inputs;
416        let rng = &mut test_rng();
417        let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
418        for _ in 0..num_inputs {
419            inputs.push(Some(rng.gen()));
420        }
421        let params = {
422            let c = Bench::<Fr> {
423                inputs: vec![None; num_inputs],
424                num_constraints,
425            };
426
427            generate_random_parameters(c, rng).unwrap()
428        };
429
430        {
431            let proof = {
432                // Create an instance of our circuit (with the
433                // witness)
434                let c = Bench {
435                    inputs: inputs.clone(),
436                    num_constraints,
437                };
438                // Create a groth16 proof with our parameters.
439                create_random_proof(c, &params, rng).unwrap()
440            };
441
442            // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
443            let cs = ConstraintSystem::<Fq>::new_ref();
444
445            let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
446            let mut input_gadgets = Vec::new();
447
448            {
449                for (i, input) in inputs.into_iter().enumerate() {
450                    let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>();
451                    // Input must be in little-endian, but BitIterator outputs in big-endian.
452                    input_bits.reverse();
453
454                    let input_bits =
455                        Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || {
456                            Ok(input_bits)
457                        })
458                        .unwrap();
459                    input_gadgets.push(input_bits);
460                }
461            }
462
463            let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
464            let proof_gadget =
465                TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
466            println!("Time to verify!\n\n\n\n");
467            <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
468                &vk_gadget,
469                input_gadgets.iter(),
470                &proof_gadget,
471            )
472            .unwrap();
473            if !cs.is_satisfied().unwrap() {
474                println!("=========================================================");
475                println!("Unsatisfied constraints:");
476                println!("{:?}", cs.which_is_unsatisfied().unwrap());
477                println!("=========================================================");
478            }
479
480            // cs.print_named_objects();
481            assert!(cs.is_satisfied().unwrap());
482        }
483    }
484}
485
486#[cfg(test)]
487mod test_recursive {
488    use groth16::*;
489    use r1cs_core::{
490        lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
491    };
492
493    use super::*;
494    use algebra::{
495        fields::{FftParameters, FpParameters},
496        mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
497        mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
498        test_rng, BigInteger, Field, PrimeField,
499    };
500    use r1cs_std::{
501        fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
502        mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
503    };
504    use rand::Rng;
505
506    type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
507    type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>;
508    type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
509    type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
510
511    type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
512    type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>;
513    type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
514    type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
515
516    #[derive(Clone)]
517    struct Bench<F: Field> {
518        inputs: Vec<Option<F>>,
519        num_constraints: usize,
520    }
521
522    impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
523        fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
524            assert!(self.inputs.len() >= 2);
525            assert!(self.num_constraints >= self.inputs.len());
526
527            let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
528            for input in self.inputs {
529                let input_var = cs.new_input_variable(|| input.get())?;
530                variables.push((input, input_var));
531            }
532
533            for i in 0..self.num_constraints {
534                let new_entry = {
535                    let (input_1_val, input_1_var) = variables[i];
536                    let (input_2_val, input_2_var) = variables[i + 1];
537                    let result_val = input_1_val
538                        .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
539                    let result_var = cs.new_witness_variable(|| {
540                        result_val.ok_or(SynthesisError::AssignmentMissing)
541                    })?;
542                    cs.enforce_named_constraint(
543                        format!("Enforce constraint {}", i),
544                        lc!() + input_1_var,
545                        lc!() + input_2_var,
546                        lc!() + result_var,
547                    )
548                    .unwrap();
549                    (result_val, result_var)
550                };
551                variables.push(new_entry);
552            }
553            Ok(())
554        }
555    }
556
557    struct Wrapper {
558        inputs: Vec<Option<MNT4Fq>>,
559        params: Parameters<MNT6_298>,
560        proof: Proof<MNT6_298>,
561    }
562
563    impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
564        fn generate_constraints(
565            self,
566            cs: ConstraintSystemRef<MNT6Fq>,
567        ) -> Result<(), SynthesisError> {
568            let params = self.params;
569            let proof = self.proof;
570            let inputs: Vec<_> = self
571                .inputs
572                .into_iter()
573                .map(|input| input.unwrap())
574                .collect();
575            let input_gadgets;
576
577            {
578                // Chain all input values in one large byte array.
579                let input_bytes = inputs
580                    .clone()
581                    .into_iter()
582                    .flat_map(|input| {
583                        input
584                            .into_repr()
585                            .as_ref()
586                            .iter()
587                            .flat_map(|l| l.to_le_bytes().to_vec())
588                            .collect::<Vec<_>>()
589                    })
590                    .collect::<Vec<_>>();
591
592                // Allocate this byte array as input packed into field elements.
593                let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?;
594                // 40 byte
595                let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
596                input_gadgets = input_bytes
597                    .chunks(element_size)
598                    .map(|chunk| {
599                        chunk
600                            .iter()
601                            .flat_map(|byte| byte.into_bits_le())
602                            .collect::<Vec<_>>()
603                    })
604                    .collect::<Vec<_>>();
605            }
606
607            let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(&params.vk))?;
608            let proof_gadget =
609                TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
610            <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
611                &vk_gadget,
612                input_gadgets.iter(),
613                &proof_gadget,
614            )?;
615            Ok(())
616        }
617    }
618
619    #[test]
620    fn groth16_recursive_verifier_test() {
621        let num_inputs = 5;
622        let num_constraints = num_inputs;
623        let rng = &mut test_rng();
624        let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
625        for _ in 0..num_inputs {
626            inputs.push(Some(rng.gen()));
627        }
628
629        // Generate inner params and proof.
630        let inner_params = {
631            let c = Bench::<MNT4Fq> {
632                inputs: vec![None; num_inputs],
633                num_constraints,
634            };
635
636            generate_random_parameters(c, rng).unwrap()
637        };
638
639        let inner_proof = {
640            // Create an instance of our circuit (with the
641            // witness)
642            let c = Bench {
643                inputs: inputs.clone(),
644                num_constraints,
645            };
646            // Create a groth16 proof with our parameters.
647            create_random_proof(c, &inner_params, rng).unwrap()
648        };
649
650        // Generate outer params and proof.
651        let params = {
652            let c = Wrapper {
653                inputs: inputs.clone(),
654                params: inner_params.clone(),
655                proof: inner_proof.clone(),
656            };
657
658            generate_random_parameters(c, rng).unwrap()
659        };
660
661        {
662            let proof = {
663                // Create an instance of our circuit (with the
664                // witness)
665                let c = Wrapper {
666                    inputs: inputs.clone(),
667                    params: inner_params.clone(),
668                    proof: inner_proof.clone(),
669                };
670                // Create a groth16 proof with our parameters.
671                create_random_proof(c, &params, rng).unwrap()
672            };
673
674            let cs = ConstraintSystem::<MNT4Fq>::new_ref();
675
676            let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
677            let mut input_gadgets = Vec::new();
678
679            {
680                let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
681                let mut input_bits = Vec::new();
682                for (i, input) in inputs.into_iter().enumerate() {
683                    let input_gadget =
684                        FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap();
685                    let mut fp_bits = input_gadget.to_bits().unwrap();
686
687                    // FpVar::to_bits outputs a big-endian binary representation of
688                    // fe_gadget's value, so we have to reverse it to get the little-endian
689                    // form.
690                    fp_bits.reverse();
691
692                    // Use 320 bits per element.
693                    for _ in fp_bits.len()..bigint_size {
694                        fp_bits.push(Boolean::constant(false));
695                    }
696                    input_bits.extend_from_slice(&fp_bits);
697                }
698
699                // Pack input bits into field elements of the underlying circuit.
700                let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
701                let max_size = max_size as usize;
702                let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
703                for chunk in input_bits.chunks(max_size) {
704                    let mut chunk = chunk.to_vec();
705                    let len = chunk.len();
706                    for _ in len..bigint_size {
707                        chunk.push(Boolean::constant(false));
708                    }
709                    input_gadgets.push(chunk);
710                }
711                // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
712            }
713
714            let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(&params.vk)).unwrap();
715            let proof_gadget =
716                TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
717            println!("Time to verify!\n\n\n\n");
718            <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
719                &vk_gadget,
720                input_gadgets.iter(),
721                &proof_gadget,
722            )
723            .unwrap();
724            if !cs.is_satisfied().unwrap() {
725                println!("=========================================================");
726                println!("Unsatisfied constraints:");
727                println!("{:?}", cs.which_is_unsatisfied().unwrap());
728                println!("=========================================================");
729            }
730
731            // cs.print_named_objects();
732            assert!(cs.is_satisfied().unwrap());
733        }
734    }
735}