halo2curves/bn256/
engine.rs

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
197// Final steps of the line function on prepared coefficients
198fn 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}