arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/pairing/bls12/mod.rs
r1cs-std/src/pairing/bls12/mod.rsRaw
  1use r1cs_core::SynthesisError;
  2
  3use super::PairingVar as PG;
  4
  5use crate::{
  6    fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, FieldVar},
  7    groups::bls12::{G1AffineVar, G1PreparedVar, G1Var, G2PreparedVar, G2Var},
  8};
  9use algebra::{
 10    curves::bls12::{Bls12, Bls12Parameters, TwistType},
 11    fields::BitIteratorBE,
 12};
 13use core::marker::PhantomData;
 14
 15/// Specifies the constraints for computing a pairing in a BLS12 bilinear group.
 16pub struct PairingVar<P: Bls12Parameters>(PhantomData<P>);
 17
 18type Fp2V<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
 19
 20impl<P: Bls12Parameters> PairingVar<P> {
 21    // Evaluate the line function at point p.
 22    #[tracing::instrument(target = "r1cs")]
 23    fn ell(
 24        f: &mut Fp12Var<P::Fp12Params>,
 25        coeffs: &(Fp2V<P>, Fp2V<P>),
 26        p: &G1AffineVar<P>,
 27    ) -> Result<(), SynthesisError> {
 28        let zero = FpVar::<P::Fp>::zero();
 29
 30        match P::TWIST_TYPE {
 31            TwistType::M => {
 32                let c0 = coeffs.0.clone();
 33                let mut c1 = coeffs.1.clone();
 34                let c2 = Fp2V::<P>::new(p.y.clone(), zero);
 35
 36                c1.c0 = c1.c0 * &p.x;
 37                c1.c1 = c1.c1 * &p.x;
 38                *f = f.mul_by_014(&c0, &c1, &c2)?;
 39                Ok(())
 40            }
 41            TwistType::D => {
 42                let c0 = Fp2V::<P>::new(p.y.clone(), zero);
 43                let mut c1 = coeffs.0.clone();
 44                let c2 = coeffs.1.clone();
 45
 46                c1.c0 = c1.c0 * &p.x;
 47                c1.c1 = c1.c1 * &p.x;
 48                *f = f.mul_by_034(&c0, &c1, &c2)?;
 49                Ok(())
 50            }
 51        }
 52    }
 53
 54    #[tracing::instrument(target = "r1cs")]
 55    fn exp_by_x(f: &Fp12Var<P::Fp12Params>) -> Result<Fp12Var<P::Fp12Params>, SynthesisError> {
 56        let mut result = f.optimized_cyclotomic_exp(P::X)?;
 57        if P::X_IS_NEGATIVE {
 58            result = result.unitary_inverse()?;
 59        }
 60        Ok(result)
 61    }
 62}
 63
 64impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingVar<P> {
 65    type G1Var = G1Var<P>;
 66    type G2Var = G2Var<P>;
 67    type G1PreparedVar = G1PreparedVar<P>;
 68    type G2PreparedVar = G2PreparedVar<P>;
 69    type GTVar = Fp12Var<P::Fp12Params>;
 70
 71    #[tracing::instrument(target = "r1cs")]
 72    fn miller_loop(
 73        ps: &[Self::G1PreparedVar],
 74        qs: &[Self::G2PreparedVar],
 75    ) -> Result<Self::GTVar, SynthesisError> {
 76        let mut pairs = vec![];
 77        for (p, q) in ps.iter().zip(qs.iter()) {
 78            pairs.push((p, q.ell_coeffs.iter()));
 79        }
 80        let mut f = Self::GTVar::one();
 81
 82        for i in BitIteratorBE::new(P::X).skip(1) {
 83            f.square_in_place()?;
 84
 85            for &mut (p, ref mut coeffs) in pairs.iter_mut() {
 86                Self::ell(&mut f, coeffs.next().unwrap(), &p.0)?;
 87            }
 88
 89            if i {
 90                for &mut (p, ref mut coeffs) in pairs.iter_mut() {
 91                    Self::ell(&mut f, &coeffs.next().unwrap(), &p.0)?;
 92                }
 93            }
 94        }
 95
 96        if P::X_IS_NEGATIVE {
 97            f = f.unitary_inverse()?;
 98        }
 99
100        Ok(f)
101    }
102
103    #[tracing::instrument(target = "r1cs")]
104    fn final_exponentiation(f: &Self::GTVar) -> Result<Self::GTVar, SynthesisError> {
105        // Computing the final exponentation following
106        // https://eprint.iacr.org/2016/130.pdf.
107        // We don't use their "faster" formula because it is difficult to make
108        // it work for curves with odd `P::X`.
109        // Hence we implement the slower algorithm from Table 1 below.
110
111        let f1 = f.frobenius_map(6)?;
112
113        f.inverse().and_then(|mut f2| {
114            // f2 = f^(-1);
115            // r = f^(p^6 - 1)
116            let mut r = f1;
117            r *= &f2;
118
119            // f2 = f^(p^6 - 1)
120            f2 = r.clone();
121            // r = f^((p^6 - 1)(p^2))
122            r.frobenius_map_in_place(2)?;
123
124            // r = f^((p^6 - 1)(p^2) + (p^6 - 1))
125            // r = f^((p^6 - 1)(p^2 + 1))
126            r *= &f2;
127
128            // Hard part of the final exponentation is below:
129            // From https://eprint.iacr.org/2016/130.pdf, Table 1
130            let mut y0 = r.cyclotomic_square()?;
131            y0 = y0.unitary_inverse()?;
132
133            let mut y5 = Self::exp_by_x(&r)?;
134
135            let mut y1 = y5.cyclotomic_square()?;
136            let mut y3 = y0 * &y5;
137            y0 = Self::exp_by_x(&y3)?;
138            let y2 = Self::exp_by_x(&y0)?;
139            let mut y4 = Self::exp_by_x(&y2)?;
140            y4 *= &y1;
141            y1 = Self::exp_by_x(&y4)?;
142            y3 = y3.unitary_inverse()?;
143            y1 *= &y3;
144            y1 *= &r;
145            y3 = r.clone();
146            y3 = y3.unitary_inverse()?;
147            y0 *= &r;
148            y0.frobenius_map_in_place(3)?;
149            y4 *= &y3;
150            y4.frobenius_map_in_place(1)?;
151            y5 *= &y2;
152            y5.frobenius_map_in_place(2)?;
153            y5 *= &y0;
154            y5 *= &y4;
155            y5 *= &y1;
156            Ok(y5)
157        })
158    }
159
160    #[tracing::instrument(target = "r1cs")]
161    fn prepare_g1(p: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError> {
162        Self::G1PreparedVar::from_group_var(p)
163    }
164
165    #[tracing::instrument(target = "r1cs")]
166    fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError> {
167        Self::G2PreparedVar::from_group_var(q)
168    }
169}