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::{ConstraintSystem, SynthesisError};
  2
  3use super::PairingGadget as PG;
  4
  5use crate::{
  6    fields::{fp::FpGadget, fp12::Fp12Gadget, fp2::Fp2Gadget, FieldGadget},
  7    groups::bls12::{G1Gadget, G1PreparedGadget, G2Gadget, G2PreparedGadget},
  8};
  9use algebra::{
 10    curves::{
 11        bls12::{
 12            Bls12, Bls12Parameters, G1Affine, G1Prepared, G1Projective, G2Affine, G2Prepared,
 13            G2Projective, TwistType,
 14        },
 15        models::ModelParameters,
 16        PairingCurve,
 17    },
 18    fields::{fp12_2over3over2::Fp12, BitIterator},
 19};
 20use std::marker::PhantomData;
 21
 22pub mod bls12_377;
 23
 24pub struct PairingGadget<P: Bls12Parameters>(PhantomData<P>);
 25
 26type Fp2G<P> = Fp2Gadget<<P as Bls12Parameters>::Fp2Params, <P as Bls12Parameters>::Fp>;
 27
 28impl<P: Bls12Parameters> PairingGadget<P> {
 29    // Evaluate the line function at point p.
 30    fn ell<CS: ConstraintSystem<P::Fp>>(
 31        mut cs: CS,
 32        f: &mut Fp12Gadget<P::Fp12Params, P::Fp>,
 33        coeffs: &(Fp2G<P>, Fp2G<P>),
 34        p: &G1Gadget<P>,
 35    ) -> Result<(), SynthesisError> {
 36        let zero = FpGadget::<P::Fp>::zero(cs.ns(|| "fpg zero"))?;
 37
 38        match P::TWIST_TYPE {
 39            TwistType::M => {
 40                let c0 = coeffs.0.clone();
 41                let mut c1 = coeffs.1.clone();
 42                let c2 = Fp2G::<P>::new(p.y.clone(), zero.clone());
 43
 44                c1.c0 = c1.c0.mul(cs.ns(|| "mul c1.c0"), &p.x)?;
 45                c1.c1 = c1.c1.mul(cs.ns(|| "mul c1.c1"), &p.x)?;
 46                *f = f.mul_by_014(cs.ns(|| "sparse mul f"), &c0, &c1, &c2)?;
 47                Ok(())
 48            },
 49            TwistType::D => {
 50                let c0 = Fp2G::<P>::new(p.y.clone(), zero.clone());
 51                let mut c1 = coeffs.0.clone();
 52                let c2 = coeffs.1.clone();
 53
 54                c1.c0 = c1.c0.mul(cs.ns(|| "mul c1.c0"), &p.x)?;
 55                c1.c1 = c1.c1.mul(cs.ns(|| "mul c1.c1"), &p.x)?;
 56                *f = f.mul_by_034(cs.ns(|| "sparse mul f"), &c0, &c1, &c2)?;
 57                Ok(())
 58            },
 59        }
 60    }
 61
 62    fn exp_by_x<CS: ConstraintSystem<P::Fp>>(
 63        mut cs: CS,
 64        f: &Fp12Gadget<P::Fp12Params, P::Fp>,
 65    ) -> Result<Fp12Gadget<P::Fp12Params, P::Fp>, SynthesisError> {
 66        let mut result = f.cyclotomic_exp(cs.ns(|| "exp_by_x"), P::X)?;
 67        if P::X_IS_NEGATIVE {
 68            result.conjugate_in_place(cs.ns(|| "conjugate"))?;
 69        }
 70        Ok(result)
 71    }
 72}
 73
 74impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingGadget<P>
 75where
 76    G1Affine<P>: PairingCurve<
 77        BaseField = <P::G1Parameters as ModelParameters>::BaseField,
 78        ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
 79        Projective = G1Projective<P>,
 80        PairWith = G2Affine<P>,
 81        Prepared = G1Prepared<P>,
 82        PairingResult = Fp12<P::Fp12Params>,
 83    >,
 84    G2Affine<P>: PairingCurve<
 85        BaseField = <P::G2Parameters as ModelParameters>::BaseField,
 86        ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
 87        Projective = G2Projective<P>,
 88        PairWith = G1Affine<P>,
 89        Prepared = G2Prepared<P>,
 90        PairingResult = Fp12<P::Fp12Params>,
 91    >,
 92{
 93    type G1Gadget = G1Gadget<P>;
 94    type G2Gadget = G2Gadget<P>;
 95    type G1PreparedGadget = G1PreparedGadget<P>;
 96    type G2PreparedGadget = G2PreparedGadget<P>;
 97    type GTGadget = Fp12Gadget<P::Fp12Params, P::Fp>;
 98
 99    fn miller_loop<CS: ConstraintSystem<P::Fp>>(
100        mut cs: CS,
101        ps: &[Self::G1PreparedGadget],
102        qs: &[Self::G2PreparedGadget],
103    ) -> Result<Self::GTGadget, SynthesisError> {
104        let mut pairs = vec![];
105        for (p, q) in ps.iter().zip(qs.iter()) {
106            pairs.push((p, q.ell_coeffs.iter()));
107        }
108        let mut f = Self::GTGadget::one(cs.ns(|| "one"))?;
109
110        for (j, i) in BitIterator::new(P::X).skip(1).enumerate() {
111            let mut cs = cs.ns(|| format!("Iteration {}", j));
112            f.square_in_place(cs.ns(|| "square"))?;
113
114            for (k, &mut (p, ref mut coeffs)) in pairs.iter_mut().enumerate() {
115                let cs = cs.ns(|| format!("Double input {}", k));
116                Self::ell(cs, &mut f, coeffs.next().unwrap(), &p.0)?;
117            }
118
119            if i {
120                for (k, &mut (p, ref mut coeffs)) in pairs.iter_mut().enumerate() {
121                    let cs = cs.ns(|| format!("Addition input {}", k));
122                    Self::ell(cs, &mut f, &coeffs.next().unwrap(), &p.0)?;
123                }
124            }
125        }
126
127        if P::X_IS_NEGATIVE {
128            f.conjugate_in_place(cs.ns(|| "f conjugate"))?;
129        }
130
131        Ok(f)
132    }
133
134    fn final_exponentiation<CS: ConstraintSystem<P::Fp>>(
135        mut cs: CS,
136        f: &Self::GTGadget,
137    ) -> Result<Self::GTGadget, SynthesisError> {
138        // Computing the final exponentation following
139        // https://eprint.iacr.org/2016/130.pdf.
140        // We don't use their "faster" formula because it is difficult to make
141        // it work for curves with odd `P::X`.
142        // Hence we implement the slower algorithm from Table 1 below.
143
144        let f1 = f.frobenius_map(cs.ns(|| "frobmap 1"), 6)?;
145
146        f.inverse(cs.ns(|| "inverse 1")).and_then(|mut f2| {
147            // f2 = f^(-1);
148            // r = f^(p^6 - 1)
149            let mut r = f1;
150            r.mul_in_place(cs.ns(|| "r = f1 * f2"), &f2)?;
151
152            // f2 = f^(p^6 - 1)
153            f2 = r.clone();
154            // r = f^((p^6 - 1)(p^2))
155            r.frobenius_map_in_place(cs.ns(|| "frobenius map 2"), 2)?;
156
157            // r = f^((p^6 - 1)(p^2) + (p^6 - 1))
158            // r = f^((p^6 - 1)(p^2 + 1))
159            r.mul_in_place(cs.ns(|| "mul 0"), &f2)?;
160
161            // Hard part of the final exponentation is below:
162            // From https://eprint.iacr.org/2016/130.pdf, Table 1
163            let mut y0 = r.cyclotomic_square(cs.ns(|| "cyclotomic_sq 1"))?;
164            y0.conjugate_in_place(&mut cs.ns(|| "conjugate 2"))?;
165
166            let mut y5 = Self::exp_by_x(&mut cs.ns(|| "exp_by_x 1"), &r)?;
167
168            let mut y1 = y5.cyclotomic_square(&mut cs.ns(|| "square 1"))?;
169            let mut y3 = y0.mul(&mut cs.ns(|| "mul 1"), &y5)?;
170            y0 = Self::exp_by_x(cs.ns(|| "exp_by_x 2"), &y3)?;
171            let y2 = Self::exp_by_x(cs.ns(|| "exp_by_x 3"), &y0)?;
172            let mut y4 = Self::exp_by_x(cs.ns(|| "exp_by_x 4"), &y2)?;
173            y4.mul_in_place(cs.ns(|| "mul 2"), &y1)?;
174            y1 = Self::exp_by_x(cs.ns(|| "exp_by_x 5"), &y4)?;
175            y3.conjugate_in_place(cs.ns(|| "conjugate 3"))?;
176            y1.mul_in_place(cs.ns(|| "mul 3"), &y3)?;
177            y1.mul_in_place(cs.ns(|| "mul 4"), &r)?;
178            y3 = r.clone();
179            y3.conjugate_in_place(cs.ns(|| "conjugate 4"))?;
180            y0.mul_in_place(cs.ns(|| "mul 5"), &r)?;
181            y0.frobenius_map_in_place(cs.ns(|| "frobmap 3"), 3)?;
182            y4.mul_in_place(cs.ns(|| "mul 6"), &y3)?;
183            y4.frobenius_map_in_place(cs.ns(|| "frobmap 4"), 1)?;
184            y5.mul_in_place(cs.ns(|| "mul 7"), &y2)?;
185            y5.frobenius_map_in_place(cs.ns(|| "frobmap 5"), 2)?;
186            y5.mul_in_place(cs.ns(|| "mul 8"), &y0)?;
187            y5.mul_in_place(cs.ns(|| "mul 9"), &y4)?;
188            y5.mul_in_place(cs.ns(|| "mul 10"), &y1)?;
189            Ok(y5)
190        })
191    }
192
193    fn prepare_g1<CS: ConstraintSystem<P::Fp>>(
194        cs: CS,
195        p: &Self::G1Gadget,
196    ) -> Result<Self::G1PreparedGadget, SynthesisError> {
197        Self::G1PreparedGadget::from_affine(cs, p)
198    }
199
200    fn prepare_g2<CS: ConstraintSystem<P::Fp>>(
201        cs: CS,
202        q: &Self::G2Gadget,
203    ) -> Result<Self::G2PreparedGadget, SynthesisError> {
204        Self::G2PreparedGadget::from_affine(cs, q)
205    }
206}