halo2curves/bls12381/
engine.rs

1use core::{
2    borrow::Borrow,
3    iter::Sum,
4    ops::{Add, Mul, Neg, Sub},
5};
6use std::ops::MulAssign;
7
8use ff::{Field, PrimeField};
9use group::{prime::PrimeCurveAffine, Group};
10use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
11use rand::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
13
14use super::{fq12::Fq12, fq2::Fq2, Fr, G1Affine, G2Affine, BLS_X, G1, G2};
15use crate::ff_ext::{quadratic::QuadSparseMul, ExtField};
16
17crate::impl_gt!(Gt, Fq12, Fr);
18crate::impl_miller_loop_components!(Bls12381, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr);
19
20impl MillerLoopResult for Fq12 {
21    type Gt = Gt;
22
23    fn final_exponentiation(&self) -> Gt {
24        #[must_use]
25        fn exp_by_x(f: Fq12) -> Fq12 {
26            let mut acc = Fq12::one();
27            for (i, b) in BLS_X.into_iter().enumerate() {
28                (i != 0).then(|| acc.cyclotomic_square());
29                (b == 1).then(|| acc *= f);
30            }
31            acc.conjugate();
32            acc
33        }
34
35        let mut t0 = *self;
36        t0.frobenius_map(6);
37
38        Gt(self
39            .invert()
40            .map(|mut t1| {
41                let mut t2 = t0 * t1;
42                t1 = t2;
43                t2.frobenius_map(2);
44                t2 *= t1;
45                t1 = t2;
46                t1.cyclotomic_square();
47                t1.conjugate();
48                let mut t3 = exp_by_x(t2);
49                let mut t4 = t3;
50                t4.cyclotomic_square();
51                let mut t5 = t1 * t3;
52                t1 = exp_by_x(t5);
53                t0 = exp_by_x(t1);
54                let mut t6 = exp_by_x(t0) * t4;
55                t4 = exp_by_x(t6);
56                t5.conjugate();
57                t4 *= t5 * t2;
58                t1 *= t2;
59                t1.frobenius_map(3);
60                t2.conjugate();
61                t6 *= t2;
62                t6.frobenius_map(1);
63                t3 *= t0;
64                t3.frobenius_map(2);
65                t3 * t4 * t1 * t6
66            })
67            .unwrap())
68    }
69}
70
71pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Affine)]) -> Fq12 {
72    let terms = terms
73        .iter()
74        .filter_map(|&(p, q)| {
75            if bool::from(p.is_identity()) || bool::from(q.is_identity()) {
76                None
77            } else {
78                Some((p, q))
79            }
80        })
81        .collect::<Vec<_>>();
82
83    let mut f = Fq12::one();
84    let mut r = terms.iter().map(|(_, q)| q.to_curve()).collect::<Vec<_>>();
85
86    for (i, x) in BLS_X.iter().map(|&b| b == 1).skip(1).enumerate() {
87        if i != 0 {
88            f.square_assign();
89        }
90
91        terms.iter().zip(r.iter_mut()).for_each(|((p, _), r)| {
92            double(&mut f, r, p);
93        });
94
95        if x {
96            for ((p, q), r) in terms.iter().zip(r.iter_mut()) {
97                add(&mut f, r, q, p);
98            }
99        }
100    }
101
102    f.conjugate();
103    f
104}
105
106fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
107    let mut c0 = coeffs.0;
108    let mut c1 = coeffs.1;
109    c0.c0.mul_assign(&p.y);
110    c0.c1.mul_assign(&p.y);
111    c1.c0.mul_assign(&p.x);
112    c1.c1.mul_assign(&p.x);
113    Fq12::mul_by_014(f, &coeffs.2, &c1, &c0);
114}
115
116#[cfg(test)]
117mod test {
118    use ff::Field;
119    use group::{prime::PrimeCurveAffine, Curve, Group};
120    use pairing::{Engine as _, MillerLoopResult, PairingCurveAffine};
121    use rand_core::OsRng;
122
123    use super::{
124        super::{Bls12381, Fr, G1, G2},
125        multi_miller_loop, Fq12, G1Affine, G2Affine, Gt,
126    };
127    crate::test_pairing!(Bls12381, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr);
128}