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