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