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}