1use core::{
2 borrow::Borrow,
3 iter::Sum,
4 ops::{Add, Mul, Neg, Sub},
5};
6use std::ops::MulAssign;
7
8use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
9use rand_core::RngCore;
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
11
12use crate::{
13 bn256::{curve::*, fq::*, fq12::*, fq2::*, fq6::FROBENIUS_COEFF_FQ6_C1, fr::*},
14 ff::PrimeField,
15 ff_ext::{quadratic::QuadSparseMul, ExtField},
16 group::{cofactor::CofactorCurveAffine, Group},
17};
18
19crate::impl_gt!(Gt, Fq12, Fr);
20crate::impl_miller_loop_components!(Bn256, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr);
21
22impl MillerLoopResult for Fq12 {
23 type Gt = Gt;
24
25 fn final_exponentiation(&self) -> Self::Gt {
26 fn exp_by_x(f: &mut Fq12) {
27 let x = super::BN_X;
28 let mut res = Fq12::one();
29 for i in (0..64).rev() {
30 res.cyclotomic_square();
31 if ((x >> i) & 1) == 1 {
32 res.mul_assign(f);
33 }
34 }
35 *f = res;
36 }
37
38 let r = *self;
39 let mut f1 = *self;
40 f1.conjugate();
41
42 use ff::Field;
43 Gt(r.invert()
44 .map(|mut f2| {
45 let mut r = f1;
46 r.mul_assign(&f2);
47 f2 = r;
48 r.frobenius_map(2);
49 r.mul_assign(&f2);
50
51 let mut fp = r;
52 fp.frobenius_map(1);
53
54 let mut fp2 = r;
55 fp2.frobenius_map(2);
56 let mut fp3 = fp2;
57 fp3.frobenius_map(1);
58
59 let mut fu = r;
60 exp_by_x(&mut fu);
61
62 let mut fu2 = fu;
63 exp_by_x(&mut fu2);
64
65 let mut fu3 = fu2;
66 exp_by_x(&mut fu3);
67
68 let mut y3 = fu;
69 y3.frobenius_map(1);
70
71 let mut fu2p = fu2;
72 fu2p.frobenius_map(1);
73
74 let mut fu3p = fu3;
75 fu3p.frobenius_map(1);
76
77 let mut y2 = fu2;
78 y2.frobenius_map(2);
79
80 let mut y0 = fp;
81 y0.mul_assign(&fp2);
82 y0.mul_assign(&fp3);
83
84 let mut y1 = r;
85 y1.conjugate();
86
87 let mut y5 = fu2;
88 y5.conjugate();
89
90 y3.conjugate();
91
92 let mut y4 = fu;
93 y4.mul_assign(&fu2p);
94 y4.conjugate();
95
96 let mut y6 = fu3;
97 y6.mul_assign(&fu3p);
98 y6.conjugate();
99
100 y6.cyclotomic_square();
101 y6.mul_assign(&y4);
102 y6.mul_assign(&y5);
103
104 let mut t1 = y3;
105 t1.mul_assign(&y5);
106 t1.mul_assign(&y6);
107
108 y6.mul_assign(&y2);
109
110 t1.cyclotomic_square();
111 t1.mul_assign(&y6);
112 t1.cyclotomic_square();
113
114 let mut t0 = t1;
115 t0.mul_assign(&y1);
116
117 t1.mul_assign(&y0);
118
119 t0.cyclotomic_square();
120 t0.mul_assign(&t1);
121
122 t0
123 })
124 .unwrap())
125 }
126}
127
128pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Affine)]) -> Fq12 {
129 let terms = terms
130 .iter()
131 .filter_map(|&(p, q)| {
132 if bool::from(p.is_identity()) || bool::from(q.is_identity()) {
133 None
134 } else {
135 Some((*p, *q))
136 }
137 })
138 .collect::<Vec<_>>();
139
140 let mut f = Fq12::one();
141 let mut r = terms.iter().map(|(_, q)| q.to_curve()).collect::<Vec<_>>();
142
143 for (i, x) in super::SIX_U_PLUS_2_NAF.iter().rev().skip(1).enumerate() {
144 (i != 0).then(|| f.square_assign());
145
146 for ((p, _), r) in terms.iter().zip(r.iter_mut()) {
147 double(&mut f, r, p);
148 }
149
150 match x {
151 &val @ (1 | -1) => {
152 for ((p, q), r) in terms.iter().zip(r.iter_mut()) {
153 if val == 1 {
154 add(&mut f, r, q, p);
155 } else {
156 add(&mut f, r, &q.neg(), p);
157 }
158 }
159 }
160 _ => continue,
161 }
162 }
163
164 const XI_TO_Q_MINUS_1_OVER_2: Fq2 = Fq2 {
165 c0: Fq([
166 0xe4bbdd0c2936b629,
167 0xbb30f162e133bacb,
168 0x31a9d1b6f9645366,
169 0x253570bea500f8dd,
170 ]),
171 c1: Fq([
172 0xa1d77ce45ffe77c7,
173 0x07affd117826d1db,
174 0x6d16bd27bb7edc6b,
175 0x2c87200285defecc,
176 ]),
177 };
178
179 for ((p, q), r) in terms.iter().zip(r.iter_mut()) {
180 let mut q1: G2Affine = *q;
181 q1.x.conjugate();
182 q1.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[1]);
183 q1.y.conjugate();
184 q1.y.mul_assign(&XI_TO_Q_MINUS_1_OVER_2);
185 add(&mut f, r, &q1, p);
186 }
187
188 for ((p, q), r) in terms.iter().zip(r.iter_mut()) {
189 let mut minusq2: G2Affine = *q;
190 minusq2.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[2]);
191 add(&mut f, r, &minusq2, p);
192 }
193
194 f
195}
196
197fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
199 let mut c0 = coeffs.0;
200 let mut c1 = coeffs.1;
201 c0.c0.mul_assign(&p.y);
202 c0.c1.mul_assign(&p.y);
203 c1.c0.mul_assign(&p.x);
204 c1.c1.mul_assign(&p.x);
205 Fq12::mul_by_034(f, &c0, &c1, &coeffs.2);
206}
207
208#[cfg(test)]
209mod test {
210 use ff::Field;
211 use group::{prime::PrimeCurveAffine, Curve, Group};
212 use pairing::{Engine, MillerLoopResult, PairingCurveAffine};
213 use rand_core::OsRng;
214
215 use super::{
216 super::{Bn256, Fr, G1, G2},
217 multi_miller_loop, Fq12, G1Affine, G2Affine, Gt,
218 };
219 crate::test_pairing!(Bn256, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr);
220}