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