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