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::nizk::{gm17::Gm17, NIZKVerifierGadget};
  2use algebra::{AffineCurve, Field, PairingEngine, ToConstraintField};
  3use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
  4use r1cs_std::prelude::*;
  5
  6use gm17::{Proof, VerifyingKey};
  7use std::{borrow::Borrow, marker::PhantomData};
  8
  9#[derive(Derivative)]
 10#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))]
 11pub struct ProofGadget<
 12    PairingE: PairingEngine,
 13    ConstraintF: Field,
 14    P: PairingGadget<PairingE, ConstraintF>,
 15> {
 16    pub a: P::G1Gadget,
 17    pub b: P::G2Gadget,
 18    pub c: P::G1Gadget,
 19}
 20
 21#[derive(Derivative)]
 22#[derivative(Clone(
 23    bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \
 24             P::G2PreparedGadget: Clone, "
 25))]
 26pub struct VerifyingKeyGadget<
 27    PairingE: PairingEngine,
 28    ConstraintF: Field,
 29    P: PairingGadget<PairingE, ConstraintF>,
 30> {
 31    pub h_g2:       P::G2Gadget,
 32    pub g_alpha_g1: P::G1Gadget,
 33    pub h_beta_g2:  P::G2Gadget,
 34    pub g_gamma_g1: P::G1Gadget,
 35    pub h_gamma_g2: P::G2Gadget,
 36    pub query:      Vec<P::G1Gadget>,
 37}
 38
 39impl<PairingE: PairingEngine, ConstraintF: Field, P: PairingGadget<PairingE, ConstraintF>>
 40    VerifyingKeyGadget<PairingE, ConstraintF, P>
 41{
 42    pub fn prepare<CS: ConstraintSystem<ConstraintF>>(
 43        &self,
 44        mut cs: CS,
 45    ) -> Result<PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>, SynthesisError> {
 46        let mut cs = cs.ns(|| "Preparing verifying key");
 47        let g_alpha_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_alpha_g1"), &self.g_alpha_g1)?;
 48        let h_beta_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_beta_g2"), &self.h_beta_g2)?;
 49        let g_gamma_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_gamma_pc"), &self.g_gamma_g1)?;
 50        let h_gamma_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_gamma_pc"), &self.h_gamma_g2)?;
 51        let h_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_pc"), &self.h_g2)?;
 52        Ok(PreparedVerifyingKeyGadget {
 53            g_alpha: self.g_alpha_g1.clone(),
 54            h_beta: self.h_beta_g2.clone(),
 55            g_alpha_pc,
 56            h_beta_pc,
 57            g_gamma_pc,
 58            h_gamma_pc,
 59            h_pc,
 60            query: self.query.clone(),
 61        })
 62    }
 63}
 64
 65#[derive(Derivative)]
 66#[derivative(Clone(
 67    bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \
 68             P::G2PreparedGadget: Clone, "
 69))]
 70pub struct PreparedVerifyingKeyGadget<
 71    PairingE: PairingEngine,
 72    ConstraintF: Field,
 73    P: PairingGadget<PairingE, ConstraintF>,
 74> {
 75    pub g_alpha:    P::G1Gadget,
 76    pub h_beta:     P::G2Gadget,
 77    pub g_alpha_pc: P::G1PreparedGadget,
 78    pub h_beta_pc:  P::G2PreparedGadget,
 79    pub g_gamma_pc: P::G1PreparedGadget,
 80    pub h_gamma_pc: P::G2PreparedGadget,
 81    pub h_pc:       P::G2PreparedGadget,
 82    pub query:      Vec<P::G1Gadget>,
 83}
 84
 85pub struct Gm17VerifierGadget<PairingE, ConstraintF, P>
 86where
 87    PairingE: PairingEngine,
 88    ConstraintF: Field,
 89    P: PairingGadget<PairingE, ConstraintF>,
 90{
 91    _pairing_engine: PhantomData<PairingE>,
 92    _engine:         PhantomData<ConstraintF>,
 93    _pairing_gadget: PhantomData<P>,
 94}
 95
 96impl<PairingE, ConstraintF, P, C, V> NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF>
 97    for Gm17VerifierGadget<PairingE, ConstraintF, P>
 98where
 99    PairingE: PairingEngine,
100    ConstraintF: Field,
101    C: ConstraintSynthesizer<PairingE::Fr>,
102    V: ToConstraintField<PairingE::Fr>,
103    P: PairingGadget<PairingE, ConstraintF>,
104{
105    type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>;
106    type ProofGadget = ProofGadget<PairingE, ConstraintF, P>;
107
108    fn check_verify<'a, CS, I, T>(
109        mut cs: CS,
110        vk: &Self::VerificationKeyGadget,
111        mut public_inputs: I,
112        proof: &Self::ProofGadget,
113    ) -> Result<(), SynthesisError>
114    where
115        CS: ConstraintSystem<ConstraintF>,
116        I: Iterator<Item = &'a T>,
117        T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
118    {
119        let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?;
120        // e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) *
121        // e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i]
122
123        let g_psi = {
124            let mut cs = cs.ns(|| "Process input");
125            let mut g_psi = pvk.query[0].clone();
126            let mut input_len = 1;
127            for (i, (input, b)) in public_inputs
128                .by_ref()
129                .zip(pvk.query.iter().skip(1))
130                .enumerate()
131            {
132                let input_bits = input.to_bits(cs.ns(|| format!("Input {}", i)))?;
133                g_psi = b.mul_bits(cs.ns(|| format!("Mul {}", i)), &g_psi, input_bits.iter())?;
134                input_len += 1;
135            }
136            // Check that the input and the query in the verification are of the
137            // same length.
138            assert!(input_len == pvk.query.len() && public_inputs.next().is_none());
139            g_psi
140        };
141
142        let mut test1_a_g_alpha = proof.a.add(cs.ns(|| "A * G^{alpha}"), &pvk.g_alpha)?;
143        let test1_b_h_beta = proof.b.add(cs.ns(|| "B * H^{beta}"), &pvk.h_beta)?;
144
145        let test1_exp = {
146            test1_a_g_alpha = test1_a_g_alpha.negate(cs.ns(|| "neg 1"))?;
147            let test1_a_g_alpha_prep = P::prepare_g1(cs.ns(|| "First prep"), &test1_a_g_alpha)?;
148            let test1_b_h_beta_prep = P::prepare_g2(cs.ns(|| "Second prep"), &test1_b_h_beta)?;
149
150            let g_psi_prep = P::prepare_g1(cs.ns(|| "Third prep"), &g_psi)?;
151
152            let c_prep = P::prepare_g1(cs.ns(|| "Fourth prep"), &proof.c)?;
153
154            P::miller_loop(
155                cs.ns(|| "Miller loop 1"),
156                &[
157                    test1_a_g_alpha_prep,
158                    g_psi_prep,
159                    c_prep,
160                    pvk.g_alpha_pc.clone(),
161                ],
162                &[
163                    test1_b_h_beta_prep,
164                    pvk.h_gamma_pc.clone(),
165                    pvk.h_pc.clone(),
166                    pvk.h_beta_pc.clone(),
167                ],
168            )?
169        };
170
171        let test1 = P::final_exponentiation(cs.ns(|| "Final Exp 1"), &test1_exp).unwrap();
172
173        // e(A, H^{gamma}) = e(G^{gamma}, B)
174        let test2_exp = {
175            let a_prep = P::prepare_g1(cs.ns(|| "Fifth prep"), &proof.a)?;
176            // pvk.h_gamma_pc
177            //&pvk.g_gamma_pc
178            let proof_b = proof.b.negate(cs.ns(|| "Negate b"))?;
179            let b_prep = P::prepare_g2(cs.ns(|| "Sixth prep"), &proof_b)?;
180            P::miller_loop(
181                cs.ns(|| "Miller loop 4"),
182                &[a_prep, pvk.g_gamma_pc.clone()],
183                &[pvk.h_gamma_pc.clone(), b_prep],
184            )?
185        };
186        let test2 = P::final_exponentiation(cs.ns(|| "Final Exp 2"), &test2_exp)?;
187
188        let one = P::GTGadget::one(cs.ns(|| "GT One"))?;
189        test1.enforce_equal(cs.ns(|| "Test 1"), &one)?;
190        test2.enforce_equal(cs.ns(|| "Test 2"), &one)?;
191        Ok(())
192    }
193}
194
195impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF>
196    for VerifyingKeyGadget<PairingE, ConstraintF, P>
197where
198    PairingE: PairingEngine,
199    ConstraintF: Field,
200    P: PairingGadget<PairingE, ConstraintF>,
201{
202    #[inline]
203    fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
204        mut cs: CS,
205        value_gen: FN,
206    ) -> Result<Self, SynthesisError>
207    where
208        FN: FnOnce() -> Result<T, SynthesisError>,
209        T: Borrow<VerifyingKey<PairingE>>,
210    {
211        value_gen().and_then(|vk| {
212            let VerifyingKey {
213                h_g2,
214                g_alpha_g1,
215                h_beta_g2,
216                g_gamma_g1,
217                h_gamma_g2,
218                query,
219            } = vk.borrow().clone();
220            let h_g2 = P::G2Gadget::alloc(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?;
221            let g_alpha_g1 =
222                P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?;
223            let h_beta_g2 =
224                P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?;
225            let g_gamma_g1 =
226                P::G1Gadget::alloc(cs.ns(|| "g_gamma_g1"), || Ok(g_gamma_g1.into_projective()))?;
227            let h_gamma_g2 =
228                P::G2Gadget::alloc(cs.ns(|| "h_gamma_g2"), || Ok(h_gamma_g2.into_projective()))?;
229
230            let query = query
231                .into_iter()
232                .enumerate()
233                .map(|(i, query_i)| {
234                    P::G1Gadget::alloc(cs.ns(|| format!("query_{}", i)), || {
235                        Ok(query_i.into_projective())
236                    })
237                })
238                .collect::<Vec<_>>()
239                .into_iter()
240                .collect::<Result<_, _>>()?;
241            Ok(Self {
242                h_g2,
243                g_alpha_g1,
244                h_beta_g2,
245                g_gamma_g1,
246                h_gamma_g2,
247                query,
248            })
249        })
250    }
251
252    #[inline]
253    fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
254        mut cs: CS,
255        value_gen: FN,
256    ) -> Result<Self, SynthesisError>
257    where
258        FN: FnOnce() -> Result<T, SynthesisError>,
259        T: Borrow<VerifyingKey<PairingE>>,
260    {
261        value_gen().and_then(|vk| {
262            let VerifyingKey {
263                h_g2,
264                g_alpha_g1,
265                h_beta_g2,
266                g_gamma_g1,
267                h_gamma_g2,
268                query,
269            } = vk.borrow().clone();
270            let h_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?;
271            let g_alpha_g1 =
272                P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?;
273            let h_beta_g2 =
274                P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?;
275            let g_gamma_g1 = P::G1Gadget::alloc_input(cs.ns(|| "g_gamma_g1"), || {
276                Ok(g_gamma_g1.into_projective())
277            })?;
278            let h_gamma_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_gamma_g2"), || {
279                Ok(h_gamma_g2.into_projective())
280            })?;
281
282            let query = query
283                .into_iter()
284                .enumerate()
285                .map(|(i, query_i)| {
286                    P::G1Gadget::alloc_input(cs.ns(|| format!("query_{}", i)), || {
287                        Ok(query_i.into_projective())
288                    })
289                })
290                .collect::<Vec<_>>()
291                .into_iter()
292                .collect::<Result<_, _>>()?;
293            Ok(Self {
294                h_g2,
295                g_alpha_g1,
296                h_beta_g2,
297                g_gamma_g1,
298                h_gamma_g2,
299                query,
300            })
301        })
302    }
303}
304
305impl<PairingE, ConstraintF, P> AllocGadget<Proof<PairingE>, ConstraintF>
306    for ProofGadget<PairingE, ConstraintF, P>
307where
308    PairingE: PairingEngine,
309    ConstraintF: Field,
310    P: PairingGadget<PairingE, ConstraintF>,
311{
312    #[inline]
313    fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
314        mut cs: CS,
315        value_gen: FN,
316    ) -> Result<Self, SynthesisError>
317    where
318        FN: FnOnce() -> Result<T, SynthesisError>,
319        T: Borrow<Proof<PairingE>>,
320    {
321        value_gen().and_then(|proof| {
322            let Proof { a, b, c } = proof.borrow().clone();
323            let a = P::G1Gadget::alloc_checked(cs.ns(|| "a"), || Ok(a.into_projective()))?;
324            let b = P::G2Gadget::alloc_checked(cs.ns(|| "b"), || Ok(b.into_projective()))?;
325            let c = P::G1Gadget::alloc_checked(cs.ns(|| "c"), || Ok(c.into_projective()))?;
326            Ok(Self { a, b, c })
327        })
328    }
329
330    #[inline]
331    fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
332        mut cs: CS,
333        value_gen: FN,
334    ) -> Result<Self, SynthesisError>
335    where
336        FN: FnOnce() -> Result<T, SynthesisError>,
337        T: Borrow<Proof<PairingE>>,
338    {
339        value_gen().and_then(|proof| {
340            let Proof { a, b, c } = proof.borrow().clone();
341            // We don't need to check here because the prime order check can be performed
342            // in plain.
343            let a = P::G1Gadget::alloc_input(cs.ns(|| "a"), || Ok(a.into_projective()))?;
344            let b = P::G2Gadget::alloc_input(cs.ns(|| "b"), || Ok(b.into_projective()))?;
345            let c = P::G1Gadget::alloc_input(cs.ns(|| "c"), || Ok(c.into_projective()))?;
346            Ok(Self { a, b, c })
347        })
348    }
349}
350
351impl<PairingE, ConstraintF, P> ToBytesGadget<ConstraintF>
352    for VerifyingKeyGadget<PairingE, ConstraintF, P>
353where
354    PairingE: PairingEngine,
355    ConstraintF: Field,
356    P: PairingGadget<PairingE, ConstraintF>,
357{
358    #[inline]
359    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
360        &self,
361        mut cs: CS,
362    ) -> Result<Vec<UInt8>, SynthesisError> {
363        let mut bytes = Vec::new();
364        bytes.extend_from_slice(&self.h_g2.to_bytes(&mut cs.ns(|| "h_g2 to bytes"))?);
365        bytes.extend_from_slice(
366            &self
367                .g_alpha_g1
368                .to_bytes(&mut cs.ns(|| "g_alpha_g1 to bytes"))?,
369        );
370        bytes.extend_from_slice(
371            &self
372                .h_beta_g2
373                .to_bytes(&mut cs.ns(|| "h_beta_g2 to bytes"))?,
374        );
375        bytes.extend_from_slice(
376            &self
377                .g_gamma_g1
378                .to_bytes(&mut cs.ns(|| "g_gamma_g1 to bytes"))?,
379        );
380        bytes.extend_from_slice(
381            &self
382                .h_gamma_g2
383                .to_bytes(&mut cs.ns(|| "h_gamma_g2 to bytes"))?,
384        );
385        for (i, q) in self.query.iter().enumerate() {
386            let mut cs = cs.ns(|| format!("Iteration {}", i));
387            bytes.extend_from_slice(&q.to_bytes(&mut cs.ns(|| "q"))?);
388        }
389        Ok(bytes)
390    }
391
392    fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
393        &self,
394        cs: CS,
395    ) -> Result<Vec<UInt8>, SynthesisError> {
396        self.to_bytes(cs)
397    }
398}
399
400#[cfg(test)]
401mod test {
402    use gm17::*;
403    use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
404
405    use super::*;
406    use algebra::{
407        curves::bls12_377::Bls12_377,
408        fields::bls12_377::{Fq, Fr},
409        BitIterator, PrimeField,
410    };
411    use r1cs_std::{
412        boolean::Boolean, pairing::bls12_377::PairingGadget as Bls12_377PairingGadget,
413        test_constraint_system::TestConstraintSystem,
414    };
415    use rand::{thread_rng, Rng};
416
417    type TestProofSystem = Gm17<Bls12_377, Bench<Fr>, Fr>;
418    type TestVerifierGadget = Gm17VerifierGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
419    type TestProofGadget = ProofGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
420    type TestVkGadget = VerifyingKeyGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
421
422    struct Bench<F: Field> {
423        inputs:          Vec<Option<F>>,
424        num_constraints: usize,
425    }
426
427    impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
428        fn generate_constraints<CS: ConstraintSystem<F>>(
429            self,
430            cs: &mut CS,
431        ) -> Result<(), SynthesisError> {
432            assert!(self.inputs.len() >= 2);
433            assert!(self.num_constraints >= self.inputs.len());
434
435            let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
436            for (i, input) in self.inputs.into_iter().enumerate() {
437                let input_var = cs.alloc_input(
438                    || format!("Input {}", i),
439                    || input.ok_or(SynthesisError::AssignmentMissing),
440                )?;
441                variables.push((input, input_var));
442            }
443
444            for i in 0..self.num_constraints {
445                let new_entry = {
446                    let (input_1_val, input_1_var) = variables[i];
447                    let (input_2_val, input_2_var) = variables[i + 1];
448                    let result_val = input_1_val
449                        .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
450                    let result_var = cs.alloc(
451                        || format!("Result {}", i),
452                        || result_val.ok_or(SynthesisError::AssignmentMissing),
453                    )?;
454                    cs.enforce(
455                        || format!("Enforce constraint {}", i),
456                        |lc| lc + input_1_var,
457                        |lc| lc + input_2_var,
458                        |lc| lc + result_var,
459                    );
460                    (result_val, result_var)
461                };
462                variables.push(new_entry);
463            }
464            Ok(())
465        }
466    }
467
468    #[test]
469    fn gm17_verifier_test() {
470        let num_inputs = 100;
471        let num_constraints = num_inputs;
472        let rng = &mut thread_rng();
473        let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
474        for _ in 0..num_inputs {
475            inputs.push(Some(rng.gen()));
476        }
477        let params = {
478            let c = Bench::<Fr> {
479                inputs: vec![None; num_inputs],
480                num_constraints,
481            };
482
483            generate_random_parameters(c, rng).unwrap()
484        };
485
486        {
487            let proof = {
488                // Create an instance of our circuit (with the
489                // witness)
490                let c = Bench {
491                    inputs: inputs.clone(),
492                    num_constraints,
493                };
494                // Create a gm17 proof with our parameters.
495                create_random_proof(c, &params, rng).unwrap()
496            };
497
498            // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
499            let mut cs = TestConstraintSystem::<Fq>::new();
500
501            let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
502            let mut input_gadgets = Vec::new();
503
504            {
505                let mut cs = cs.ns(|| "Allocate Input");
506                for (i, input) in inputs.into_iter().enumerate() {
507                    let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>();
508                    // Input must be in little-endian, but BitIterator outputs in big-endian.
509                    input_bits.reverse();
510
511                    let input_bits =
512                        Vec::<Boolean>::alloc_input(cs.ns(|| format!("Input {}", i)), || {
513                            Ok(input_bits)
514                        })
515                        .unwrap();
516                    input_gadgets.push(input_bits);
517                }
518            }
519
520            let vk_gadget = TestVkGadget::alloc_input(cs.ns(|| "Vk"), || Ok(&params.vk)).unwrap();
521            let proof_gadget =
522                TestProofGadget::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap();
523            println!("Time to verify!\n\n\n\n");
524            <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::check_verify(
525                cs.ns(|| "Verify"),
526                &vk_gadget,
527                input_gadgets.iter(),
528                &proof_gadget,
529            )
530            .unwrap();
531            if !cs.is_satisfied() {
532                println!("=========================================================");
533                println!("Unsatisfied constraints:");
534                println!("{:?}", cs.which_is_unsatisfied().unwrap());
535                println!("=========================================================");
536            }
537
538            // cs.print_named_objects();
539            assert!(cs.is_satisfied());
540        }
541    }
542}