ark-r1cs-std/r1cs-std/src/pairing/mod.rs
r1cs-std/src/pairing/mod.rsRaw
1use crate::prelude::*;
2use algebra::{Field, PairingEngine};
3use core::fmt::Debug;
4use r1cs_core::SynthesisError;
5
6pub mod bls12;
7pub mod mnt4;
8pub mod mnt6;
9
10pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> {
11 type G1Var: CurveVar<E::G1Projective, ConstraintF>
12 + AllocVar<E::G1Projective, ConstraintF>
13 + AllocVar<E::G1Affine, ConstraintF>;
14 type G2Var: CurveVar<E::G2Projective, ConstraintF>
15 + AllocVar<E::G2Projective, ConstraintF>
16 + AllocVar<E::G2Affine, ConstraintF>;
17
18 type GTVar: FieldVar<E::Fqk, ConstraintF>;
19
20 type G1PreparedVar: ToBytesGadget<ConstraintF>
21 + AllocVar<E::G1Prepared, ConstraintF>
22 + Clone
23 + Debug;
24 type G2PreparedVar: ToBytesGadget<ConstraintF>
25 + AllocVar<E::G2Prepared, ConstraintF>
26 + Clone
27 + Debug;
28
29 fn miller_loop(
30 p: &[Self::G1PreparedVar],
31 q: &[Self::G2PreparedVar],
32 ) -> Result<Self::GTVar, SynthesisError>;
33
34 fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
35
36 #[tracing::instrument(target = "r1cs")]
37 fn pairing(
38 p: Self::G1PreparedVar,
39 q: Self::G2PreparedVar,
40 ) -> Result<Self::GTVar, SynthesisError> {
41 let tmp = Self::miller_loop(&[p], &[q])?;
42 Self::final_exponentiation(&tmp)
43 }
44
45 /// Computes a product of pairings.
46 #[must_use]
47 #[tracing::instrument(target = "r1cs")]
48 fn product_of_pairings(
49 p: &[Self::G1PreparedVar],
50 q: &[Self::G2PreparedVar],
51 ) -> Result<Self::GTVar, SynthesisError> {
52 let miller_result = Self::miller_loop(p, q)?;
53 Self::final_exponentiation(&miller_result)
54 }
55
56 fn prepare_g1(q: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError>;
57
58 fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError>;
59}
60
61#[cfg(test)]
62pub(crate) mod tests {
63 use crate::{prelude::*, Vec};
64 use algebra::{
65 test_rng, BitIteratorLE, Field, PairingEngine, PrimeField, ProjectiveCurve, UniformRand,
66 };
67 use r1cs_core::{ConstraintSystem, SynthesisError};
68
69 #[allow(dead_code)]
70 pub(crate) fn bilinearity_test<E: PairingEngine, P: PairingVar<E>>(
71 ) -> Result<(), SynthesisError>
72 where
73 for<'a> &'a P::G1Var: GroupOpsBounds<'a, E::G1Projective, P::G1Var>,
74 for<'a> &'a P::G2Var: GroupOpsBounds<'a, E::G2Projective, P::G2Var>,
75 for<'a> &'a P::GTVar: FieldOpsBounds<'a, E::Fqk, P::GTVar>,
76 {
77 let cs = ConstraintSystem::<E::Fq>::new_ref();
78
79 let mut rng = test_rng();
80 let a = E::G1Projective::rand(&mut rng);
81 let b = E::G2Projective::rand(&mut rng);
82 let s = E::Fr::rand(&mut rng);
83
84 let mut sa = a;
85 sa *= s;
86 let mut sb = b;
87 sb *= s;
88
89 let a_g = P::G1Var::new_witness(cs.clone(), || Ok(a.into_affine()))?;
90 let b_g = P::G2Var::new_witness(cs.clone(), || Ok(b.into_affine()))?;
91 let sa_g = P::G1Var::new_witness(cs.clone(), || Ok(sa.into_affine()))?;
92 let sb_g = P::G2Var::new_witness(cs.clone(), || Ok(sb.into_affine()))?;
93
94 let mut preparation_num_constraints = cs.num_constraints();
95 let a_prep_g = P::prepare_g1(&a_g)?;
96 let b_prep_g = P::prepare_g2(&b_g)?;
97 preparation_num_constraints = cs.num_constraints() - preparation_num_constraints;
98 println!(
99 "Preparation num constraints: {}",
100 preparation_num_constraints
101 );
102
103 let sa_prep_g = P::prepare_g1(&sa_g)?;
104 let sb_prep_g = P::prepare_g2(&sb_g)?;
105
106 let (ans1_g, ans1_n) = {
107 let ml_constraints = cs.num_constraints();
108 let ml_g = P::miller_loop(&[sa_prep_g], &[b_prep_g.clone()])?;
109 println!(
110 "ML num constraints: {}",
111 cs.num_constraints() - ml_constraints
112 );
113 let fe_constraints = cs.num_constraints();
114 let ans_g = P::final_exponentiation(&ml_g)?;
115 println!(
116 "FE num constraints: {}",
117 cs.num_constraints() - fe_constraints
118 );
119 let ans_n = E::pairing(sa, b);
120 (ans_g, ans_n)
121 };
122
123 let (ans2_g, ans2_n) = {
124 let ans_g = P::pairing(a_prep_g.clone(), sb_prep_g)?;
125 let ans_n = E::pairing(a, sb);
126 (ans_g, ans_n)
127 };
128
129 let (ans3_g, ans3_n) = {
130 let s_iter = BitIteratorLE::without_trailing_zeros(s.into_repr())
131 .map(Boolean::constant)
132 .collect::<Vec<_>>();
133
134 let mut ans_g = P::pairing(a_prep_g, b_prep_g)?;
135 let mut ans_n = E::pairing(a, b);
136 ans_n = ans_n.pow(s.into_repr());
137 ans_g = ans_g.pow_le(&s_iter)?;
138
139 (ans_g, ans_n)
140 };
141
142 ans1_g.enforce_equal(&ans2_g)?;
143 ans2_g.enforce_equal(&ans3_g)?;
144
145 assert_eq!(ans1_g.value()?, ans1_n, "Failed native test 1");
146 assert_eq!(ans2_g.value()?, ans2_n, "Failed native test 2");
147 assert_eq!(ans3_g.value()?, ans3_n, "Failed native test 3");
148
149 assert_eq!(ans1_n, ans2_n, "Failed ans1_native == ans2_native");
150 assert_eq!(ans2_n, ans3_n, "Failed ans2_native == ans3_native");
151 assert_eq!(ans1_g.value()?, ans3_g.value()?, "Failed ans1 == ans3");
152 assert_eq!(ans1_g.value()?, ans2_g.value()?, "Failed ans1 == ans2");
153 assert_eq!(ans2_g.value()?, ans3_g.value()?, "Failed ans2 == ans3");
154
155 if !cs.is_satisfied().unwrap() {
156 println!("Unsatisfied: {:?}", cs.which_is_unsatisfied());
157 }
158
159 assert!(cs.is_satisfied().unwrap(), "cs is not satisfied");
160 Ok(())
161 }
162}