dcrypt_algorithms/ec/bls12_381/
pairings.rs

1use super::field::fp::Fp;
2use super::field::fp12::Fp12;
3use super::field::fp2::Fp2;
4use super::field::fp6::Fp6;
5use super::{G1Affine, G2Affine, G2Projective, Scalar, BLS_X, BLS_X_IS_NEGATIVE};
6
7use core::borrow::Borrow;
8use core::fmt;
9use core::iter::Sum;
10use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
11use rand_core::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
13
14#[cfg(feature = "alloc")]
15use alloc::vec::Vec;
16
17/// Miller loop result - must be finalized via `.final_exponentiation()` for comparison.
18#[derive(Copy, Clone, Debug)]
19pub struct MillerLoopResult(pub(crate) Fp12);
20
21impl Default for MillerLoopResult {
22    fn default() -> Self {
23        MillerLoopResult(Fp12::one())
24    }
25}
26
27#[cfg(feature = "zeroize")]
28impl zeroize::DefaultIsZeroes for MillerLoopResult {}
29
30impl ConditionallySelectable for MillerLoopResult {
31    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
32        MillerLoopResult(Fp12::conditional_select(&a.0, &b.0, choice))
33    }
34}
35
36impl MillerLoopResult {
37    /// Converts Miller loop result to target group element.
38    pub fn final_exponentiation(&self) -> Gt {
39        #[must_use]
40        fn fp4_square(a: Fp2, b: Fp2) -> (Fp2, Fp2) {
41            let t0 = a.square();
42            let t1 = b.square();
43            let mut t2 = t1.mul_by_nonresidue();
44            let c0 = t2 + t0;
45            t2 = a + b;
46            t2 = t2.square();
47            t2 -= t0;
48            let c1 = t2 - t1;
49
50            (c0, c1)
51        }
52        #[must_use]
53        fn cyclotomic_square(f: Fp12) -> Fp12 {
54            let mut z0 = f.c0.c0;
55            let mut z4 = f.c0.c1;
56            let mut z3 = f.c0.c2;
57            let mut z2 = f.c1.c0;
58            let mut z1 = f.c1.c1;
59            let mut z5 = f.c1.c2;
60
61            let (t0, t1) = fp4_square(z0, z1);
62            z0 = t0 - z0;
63            z0 = z0 + z0 + t0;
64            z1 = t1 + z1;
65            z1 = z1 + z1 + t1;
66
67            let (mut t0, t1) = fp4_square(z2, z3);
68            let (t2, t3) = fp4_square(z4, z5);
69            z4 = t0 - z4;
70            z4 = z4 + z4 + t0;
71            z5 = t1 + z5;
72            z5 = z5 + z5 + t1;
73
74            t0 = t3.mul_by_nonresidue();
75            z2 = t0 + z2;
76            z2 = z2 + z2 + t0;
77            z3 = t2 - z3;
78            z3 = z3 + z3 + t2;
79
80            Fp12 {
81                c0: Fp6 { c0: z0, c1: z4, c2: z3 },
82                c1: Fp6 { c0: z2, c1: z1, c2: z5 },
83            }
84        }
85        #[must_use]
86        fn cycolotomic_exp(f: Fp12) -> Fp12 {
87            let x = BLS_X;
88            let mut tmp = Fp12::one();
89            let mut found_one = false;
90            for i in (0..64).rev().map(|b| ((x >> b) & 1) == 1) {
91                if found_one {
92                    tmp = cyclotomic_square(tmp)
93                } else {
94                    found_one = i;
95                }
96                if i {
97                    tmp *= f;
98                }
99            }
100            tmp.conjugate()
101        }
102
103        let f = self.0;
104        let t0 = f.frobenius_map().frobenius_map().frobenius_map().frobenius_map().frobenius_map().frobenius_map();
105        Gt(f.invert()
106            .map(|t1| {
107                let mut t2 = t0 * t1;
108                let t1 = t2;
109                t2 = t2.frobenius_map().frobenius_map();
110                t2 *= t1;
111                let t1 = cyclotomic_square(t2).conjugate();
112                let t3 = cycolotomic_exp(t2);
113                let t4 = cyclotomic_square(t3);
114                let t5 = t1 * t3;
115                let t1 = cycolotomic_exp(t5);
116                let t0 = cycolotomic_exp(t1);
117                let mut t6 = cycolotomic_exp(t0);
118                t6 *= t4;
119                let t4 = cycolotomic_exp(t6);
120                let t5 = t5.conjugate();
121                let t4 = t4 * t5 * t2;
122                let t5 = t2.conjugate();
123                let t1 = t1 * t2;
124                let t1 = t1.frobenius_map().frobenius_map().frobenius_map();
125                let t6 = t6 * t5;
126                let t6 = t6.frobenius_map();
127                let t3 = t3 * t0;
128                let t3 = t3.frobenius_map().frobenius_map();
129                let t3 = t3 * t1;
130                let t3 = t3 * t6;
131                t3 * t4
132            })
133            .unwrap())
134    }
135}
136
137// Expanded: impl_add_binop_specify_output!(MillerLoopResult, MillerLoopResult, MillerLoopResult);
138impl<'a, 'b> Add<&'b MillerLoopResult> for &'a MillerLoopResult {
139    type Output = MillerLoopResult;
140
141    #[inline]
142    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
143        MillerLoopResult(self.0 * rhs.0)
144    }
145}
146
147impl<'b> Add<&'b MillerLoopResult> for MillerLoopResult {
148    type Output = MillerLoopResult;
149    #[inline]
150    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
151        &self + rhs
152    }
153}
154impl<'a> Add<MillerLoopResult> for &'a MillerLoopResult {
155    type Output = MillerLoopResult;
156    #[inline]
157    fn add(self, rhs: MillerLoopResult) -> MillerLoopResult {
158        self + &rhs
159    }
160}
161impl Add<MillerLoopResult> for MillerLoopResult {
162    type Output = MillerLoopResult;
163    #[inline]
164    fn add(self, rhs: MillerLoopResult) -> MillerLoopResult {
165        &self + &rhs
166    }
167}
168
169impl AddAssign<MillerLoopResult> for MillerLoopResult {
170    #[inline]
171    fn add_assign(&mut self, rhs: MillerLoopResult) {
172        *self = *self + rhs;
173    }
174}
175
176impl<'b> AddAssign<&'b MillerLoopResult> for MillerLoopResult {
177    #[inline]
178    fn add_assign(&mut self, rhs: &'b MillerLoopResult) {
179        *self = *self + rhs;
180    }
181}
182
183/// Target group G_T element.
184#[derive(Copy, Clone, Debug)]
185pub struct Gt(pub(crate) Fp12);
186
187impl Default for Gt {
188    fn default() -> Self {
189        Self::identity()
190    }
191}
192
193#[cfg(feature = "zeroize")]
194impl zeroize::DefaultIsZeroes for Gt {}
195
196impl fmt::Display for Gt {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        write!(f, "{:?}", self)
199    }
200}
201
202impl ConstantTimeEq for Gt {
203    fn ct_eq(&self, other: &Self) -> Choice {
204        self.0.ct_eq(&other.0)
205    }
206}
207
208impl ConditionallySelectable for Gt {
209    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
210        Gt(Fp12::conditional_select(&a.0, &b.0, choice))
211    }
212}
213
214impl Eq for Gt {}
215impl PartialEq for Gt {
216    #[inline]
217    fn eq(&self, other: &Self) -> bool {
218        bool::from(self.ct_eq(other))
219    }
220}
221
222impl Gt {
223    /// Returns the identity element (1).
224    pub fn identity() -> Gt {
225        Gt(Fp12::one())
226    }
227    
228    /// Returns a fixed generator.
229    pub fn generator() -> Self {
230        Gt(Fp12 {
231            c0: Fp6 {
232                c0: Fp2 {
233                    c0: Fp::from_raw_unchecked([0x1972_e433_a01f_85c5, 0x97d3_2b76_fd77_2538, 0xc8ce_546f_c96b_cdf9, 0xcef6_3e73_66d4_0614, 0xa611_3427_8184_3780, 0x13f3_448a_3fc6_d825]),
234                    c1: Fp::from_raw_unchecked([0xd263_31b0_2e9d_6995, 0x9d68_a482_f779_7e7d, 0x9c9b_2924_8d39_ea92, 0xf480_1ca2_e131_07aa, 0xa16c_0732_bdbc_b066, 0x083c_a4af_ba36_0478]),
235                },
236                c1: Fp2 {
237                    c0: Fp::from_raw_unchecked([0x59e2_61db_0916_b641, 0x2716_b6f4_b23e_960d, 0xc8e5_5b10_a0bd_9c45, 0x0bdb_0bd9_9c4d_eda8, 0x8cf8_9ebf_57fd_aac5, 0x12d6_b792_9e77_7a5e]),
238                    c1: Fp::from_raw_unchecked([0x5fc8_5188_b0e1_5f35, 0x34a0_6e3a_8f09_6365, 0xdb31_26a6_e02a_d62c, 0xfc6f_5aa9_7d9a_990b, 0xa12f_55f5_eb89_c210, 0x1723_703a_926f_8889]),
239                },
240                c2: Fp2 {
241                    c0: Fp::from_raw_unchecked([0x9358_8f29_7182_8778, 0x43f6_5b86_11ab_7585, 0x3183_aaf5_ec27_9fdf, 0xfa73_d7e1_8ac9_9df6, 0x64e1_76a6_a64c_99b0, 0x179f_a78c_5838_8f1f]),
242                    c1: Fp::from_raw_unchecked([0x672a_0a11_ca2a_ef12, 0x0d11_b9b5_2aa3_f16b, 0xa444_12d0_699d_056e, 0xc01d_0177_221a_5ba5, 0x66e0_cede_6c73_5529, 0x05f5_a71e_9fdd_c339]),
243                },
244            },
245            c1: Fp6 {
246                c0: Fp2 {
247                    c0: Fp::from_raw_unchecked([0xd30a_88a1_b062_c679, 0x5ac5_6a5d_35fc_8304, 0xd0c8_34a6_a81f_290d, 0xcd54_30c2_da37_07c7, 0xf0c2_7ff7_8050_0af0, 0x0924_5da6_e2d7_2eae]),
248                    c1: Fp::from_raw_unchecked([0x9f2e_0676_791b_5156, 0xe2d1_c823_4918_fe13, 0x4c9e_459f_3c56_1bf4, 0xa3e8_5e53_b9d3_e3c1, 0x820a_121e_21a7_0020, 0x15af_6183_41c5_9acc]),
249                },
250                c1: Fp2 {
251                    c0: Fp::from_raw_unchecked([0x7c95_658c_2499_3ab1, 0x73eb_3872_1ca8_86b9, 0x5256_d749_4774_34bc, 0x8ba4_1902_ea50_4a8b, 0x04a3_d3f8_0c86_ce6d, 0x18a6_4a87_fb68_6eaa]),
252                    c1: Fp::from_raw_unchecked([0xbb83_e71b_b920_cf26, 0x2a52_77ac_92a7_3945, 0xfc0e_e59f_94f0_46a0, 0x7158_cdf3_7860_58f7, 0x7cc1_061b_82f9_45f6, 0x03f8_47aa_9fdb_e567]),
253                },
254                c2: Fp2 {
255                    c0: Fp::from_raw_unchecked([0x8078_dba5_6134_e657, 0x1cd7_ec9a_4399_8a6e, 0xb1aa_599a_1a99_3766, 0xc9a0_f62f_0842_ee44, 0x8e15_9be3_b605_dffa, 0x0c86_ba0d_4af1_3fc2]),
256                    c1: Fp::from_raw_unchecked([0xe80f_f2a0_6a52_ffb1, 0x7694_ca48_721a_906c, 0x7583_183e_03b0_8514, 0xf567_afdd_40ce_e4e2, 0x9a6d_96d2_e526_a5fc, 0x197e_9f49_861f_2242]),
257                },
258            },
259        })
260    }
261
262    /// Checks if this is the identity.
263    pub fn is_identity(&self) -> Choice {
264        self.ct_eq(&Self::identity())
265    }
266
267    /// Doubles this element.
268    pub fn double(&self) -> Gt {
269        Gt(self.0.square())
270    }
271
272    /// Creates a random GT element.
273    pub fn random(mut rng: impl RngCore) -> Self {
274        loop {
275            let inner = Fp12::random(&mut rng);
276            if !bool::from(inner.is_zero()) {
277                return MillerLoopResult(inner).final_exponentiation();
278            }
279        }
280    }
281}
282
283impl<'a> Neg for &'a Gt {
284    type Output = Gt;
285    #[inline]
286    fn neg(self) -> Gt { Gt(self.0.conjugate()) }
287}
288
289impl Neg for Gt {
290    type Output = Gt;
291    #[inline]
292    fn neg(self) -> Gt { -&self }
293}
294
295impl<'a, 'b> Add<&'b Gt> for &'a Gt {
296    type Output = Gt;
297    #[inline]
298    fn add(self, rhs: &'b Gt) -> Gt { Gt(self.0 * rhs.0) }
299}
300
301impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
302    type Output = Gt;
303    #[inline]
304    fn sub(self, rhs: &'b Gt) -> Gt { self + &(-rhs) }
305}
306
307impl<'a, 'b> Mul<&'b Scalar> for &'a Gt {
308    type Output = Gt;
309    fn mul(self, other: &'b Scalar) -> Self::Output {
310        let mut acc = Gt::identity();
311        for bit in other.to_bytes().iter().rev().flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))).skip(1) {
312            acc = acc.double();
313            acc = Gt::conditional_select(&acc, &(acc + self), bit);
314        }
315        acc
316    }
317}
318
319// Expanded: impl_binops_additive!(Gt, Gt);
320impl<'b> Add<&'b Gt> for Gt {
321    type Output = Gt;
322    #[inline]
323    fn add(self, rhs: &'b Gt) -> Gt { &self + rhs }
324}
325impl<'a> Add<Gt> for &'a Gt {
326    type Output = Gt;
327    #[inline]
328    fn add(self, rhs: Gt) -> Gt { self + &rhs }
329}
330impl Add<Gt> for Gt {
331    type Output = Gt;
332    #[inline]
333    fn add(self, rhs: Gt) -> Gt { &self + &rhs }
334}
335impl<'b> Sub<&'b Gt> for Gt {
336    type Output = Gt;
337    #[inline]
338    fn sub(self, rhs: &'b Gt) -> Gt { &self - rhs }
339}
340impl<'a> Sub<Gt> for &'a Gt {
341    type Output = Gt;
342    #[inline]
343    fn sub(self, rhs: Gt) -> Gt { self - &rhs }
344}
345impl Sub<Gt> for Gt {
346    type Output = Gt;
347    #[inline]
348    fn sub(self, rhs: Gt) -> Gt { &self - &rhs }
349}
350impl SubAssign<Gt> for Gt {
351    #[inline]
352    fn sub_assign(&mut self, rhs: Gt) { *self = &*self - &rhs; }
353}
354impl AddAssign<Gt> for Gt {
355    #[inline]
356    fn add_assign(&mut self, rhs: Gt) { *self = &*self + &rhs; }
357}
358impl<'b> SubAssign<&'b Gt> for Gt {
359    #[inline]
360    fn sub_assign(&mut self, rhs: &'b Gt) { *self = &*self - rhs; }
361}
362impl<'b> AddAssign<&'b Gt> for Gt {
363    #[inline]
364    fn add_assign(&mut self, rhs: &'b Gt) { *self = &*self + rhs; }
365}
366
367// Expanded: impl_binops_multiplicative!(Gt, Scalar);
368impl<'b> Mul<&'b Scalar> for Gt {
369    type Output = Gt;
370    #[inline]
371    fn mul(self, rhs: &'b Scalar) -> Gt { &self * rhs }
372}
373impl<'a> Mul<Scalar> for &'a Gt {
374    type Output = Gt;
375    #[inline]
376    fn mul(self, rhs: Scalar) -> Gt { self * &rhs }
377}
378impl Mul<Scalar> for Gt {
379    type Output = Gt;
380    #[inline]
381    fn mul(self, rhs: Scalar) -> Gt { &self * &rhs }
382}
383impl MulAssign<Scalar> for Gt {
384    #[inline]
385    fn mul_assign(&mut self, rhs: Scalar) { *self = &*self * &rhs; }
386}
387impl<'b> MulAssign<&'b Scalar> for Gt {
388    #[inline]
389    fn mul_assign(&mut self, rhs: &'b Scalar) { *self = &*self * rhs; }
390}
391
392
393impl<T> Sum<T> for Gt
394where
395    T: Borrow<Gt>,
396{
397    fn sum<I>(iter: I) -> Self
398    where
399        I: Iterator<Item = T>,
400    {
401        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
402    }
403}
404
405#[cfg(feature = "alloc")]
406#[derive(Clone, Debug)]
407/// Pre-computed G2 for efficient multi-pairing.
408pub struct G2Prepared {
409    infinity: Choice,
410    coeffs: Vec<(Fp2, Fp2, Fp2)>,
411}
412
413#[cfg(feature = "alloc")]
414impl From<G2Affine> for G2Prepared {
415    fn from(q: G2Affine) -> G2Prepared {
416        struct Adder {
417            cur: G2Projective,
418            base: G2Affine,
419            coeffs: Vec<(Fp2, Fp2, Fp2)>,
420        }
421
422        impl MillerLoopDriver for Adder {
423            type Output = ();
424            fn doubling_step(&mut self, _: Self::Output) -> Self::Output {
425                self.coeffs.push(doubling_step(&mut self.cur));
426            }
427            fn addition_step(&mut self, _: Self::Output) -> Self::Output {
428                self.coeffs.push(addition_step(&mut self.cur, &self.base));
429            }
430            fn square_output(_: Self::Output) -> Self::Output {}
431            fn conjugate(_: Self::Output) -> Self::Output {}
432            fn one() -> Self::Output {}
433        }
434
435        let is_identity = q.is_identity();
436        let q = G2Affine::conditional_select(&q, &G2Affine::generator(), is_identity);
437        let mut adder = Adder {
438            cur: G2Projective::from(q),
439            base: q,
440            coeffs: Vec::with_capacity(68),
441        };
442        miller_loop(&mut adder);
443        G2Prepared {
444            infinity: is_identity,
445            coeffs: adder.coeffs,
446        }
447    }
448}
449
450#[cfg(feature = "alloc")]
451/// Multi-pairing computation in single Miller loop.
452pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult {
453    struct Adder<'a, 'b, 'c> {
454        terms: &'c [(&'a G1Affine, &'b G2Prepared)],
455        index: usize,
456    }
457
458    impl<'a, 'b, 'c> MillerLoopDriver for Adder<'a, 'b, 'c> {
459        type Output = Fp12;
460        fn doubling_step(&mut self, mut f: Self::Output) -> Self::Output {
461            for term in self.terms {
462                let either_identity = term.0.is_identity() | term.1.infinity;
463                let new_f = ell(f, &term.1.coeffs[self.index], term.0);
464                f = Fp12::conditional_select(&new_f, &f, either_identity);
465            }
466            self.index += 1;
467            f
468        }
469        fn addition_step(&mut self, mut f: Self::Output) -> Self::Output {
470            for term in self.terms {
471                let either_identity = term.0.is_identity() | term.1.infinity;
472                let new_f = ell(f, &term.1.coeffs[self.index], term.0);
473                f = Fp12::conditional_select(&new_f, &f, either_identity);
474            }
475            self.index += 1;
476            f
477        }
478        fn square_output(f: Self::Output) -> Self::Output { f.square() }
479        fn conjugate(f: Self::Output) -> Self::Output { f.conjugate() }
480        fn one() -> Self::Output { Fp12::one() }
481    }
482
483    let mut adder = Adder { terms, index: 0 };
484    MillerLoopResult(miller_loop(&mut adder))
485}
486
487/// Computes the BLS12-381 pairing.
488pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt {
489    struct Adder<'a> {
490        cur: G2Projective,
491        base: G2Affine,
492        p: &'a G1Affine,
493    }
494
495    impl<'a> MillerLoopDriver for Adder<'a> {
496        type Output = Fp12;
497        fn doubling_step(&mut self, f: Self::Output) -> Self::Output {
498            ell(f, &doubling_step(&mut self.cur), self.p)
499        }
500        fn addition_step(&mut self, f: Self::Output) -> Self::Output {
501            ell(f, &addition_step(&mut self.cur, &self.base), self.p)
502        }
503        fn square_output(f: Self::Output) -> Self::Output { f.square() }
504        fn conjugate(f: Self::Output) -> Self::Output { f.conjugate() }
505        fn one() -> Self::Output { Fp12::one() }
506    }
507
508    let either_identity = p.is_identity() | q.is_identity();
509    let p_selected = G1Affine::conditional_select(p, &G1Affine::generator(), either_identity);
510    let q_selected = G2Affine::conditional_select(q, &G2Affine::generator(), either_identity);
511
512    let mut adder = Adder {
513        cur: G2Projective::from(q_selected),
514        base: q_selected,
515        p: &p_selected,
516    };
517    
518    let tmp = miller_loop(&mut adder);
519    MillerLoopResult(Fp12::conditional_select(&tmp, &Fp12::one(), either_identity)).final_exponentiation()
520}
521
522trait MillerLoopDriver {
523    type Output;
524    fn doubling_step(&mut self, f: Self::Output) -> Self::Output;
525    fn addition_step(&mut self, f: Self::Output) -> Self::Output;
526    fn square_output(f: Self::Output) -> Self::Output;
527    fn conjugate(f: Self::Output) -> Self::Output;
528    fn one() -> Self::Output;
529}
530
531fn miller_loop<D: MillerLoopDriver>(driver: &mut D) -> D::Output {
532    let mut f = D::one();
533    let mut found_one = false;
534    for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
535        if !found_one {
536            found_one = i;
537            continue;
538        }
539        f = driver.doubling_step(f);
540        if i {
541            f = driver.addition_step(f);
542        }
543        f = D::square_output(f);
544    }
545    f = driver.doubling_step(f);
546    if BLS_X_IS_NEGATIVE {
547        f = D::conjugate(f);
548    }
549    f
550}
551
552fn ell(f: Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 {
553    let mut c0 = coeffs.0;
554    let mut c1 = coeffs.1;
555    c0.c0 *= p.y;
556    c0.c1 *= p.y;
557    c1.c0 *= p.x;
558    c1.c1 *= p.x;
559    f.mul_by_014(&coeffs.2, &c1, &c0)
560}
561
562fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) {
563    let tmp0 = r.x.square();
564    let tmp1 = r.y.square();
565    let tmp2 = tmp1.square();
566    let tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2;
567    let tmp3 = tmp3 + tmp3;
568    let tmp4 = tmp0 + tmp0 + tmp0;
569    let tmp6 = r.x + tmp4;
570    let tmp5 = tmp4.square();
571    let zsquared = r.z.square();
572    r.x = tmp5 - tmp3 - tmp3;
573    r.z = (r.z + r.y).square() - tmp1 - zsquared;
574    r.y = (tmp3 - r.x) * tmp4;
575    let tmp2 = tmp2 + tmp2;
576    let tmp2 = tmp2 + tmp2;
577    let tmp2 = tmp2 + tmp2;
578    r.y -= tmp2;
579    let tmp3 = tmp4 * zsquared;
580    let tmp3 = tmp3 + tmp3;
581    let tmp3 = -tmp3;
582    let tmp6 = tmp6.square() - tmp0 - tmp5;
583    let tmp1 = tmp1 + tmp1;
584    let tmp1 = tmp1 + tmp1;
585    let tmp6 = tmp6 - tmp1;
586    let tmp0 = r.z * zsquared;
587    let tmp0 = tmp0 + tmp0;
588    (tmp0, tmp3, tmp6)
589}
590
591fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
592    let zsquared = r.z.square();
593    let ysquared = q.y.square();
594    let t0 = zsquared * q.x;
595    let t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared;
596    let t2 = t0 - r.x;
597    let t3 = t2.square();
598    let t4 = t3 + t3;
599    let t4 = t4 + t4;
600    let t5 = t4 * t2;
601    let t6 = t1 - r.y - r.y;
602    let t9 = t6 * q.x;
603    let t7 = t4 * r.x;
604    r.x = t6.square() - t5 - t7 - t7;
605    r.z = (r.z + t2).square() - zsquared - t3;
606    let t10 = q.y + r.z;
607    let t8 = (t7 - r.x) * t6;
608    let t0 = r.y * t5;
609    let t0 = t0 + t0;
610    r.y = t8 - t0;
611    let t10 = t10.square() - ysquared;
612    let ztsquared = r.z.square();
613    let t10 = t10 - ztsquared;
614    let t9 = t9 + t9 - t10;
615    let t10 = r.z + r.z;
616    let t6 = -t6;
617    let t1 = t6 + t6;
618    (t10, t1, t9)
619}
620
621/// BLS12-381 pairing engine marker.
622#[derive(Clone, Debug)]
623pub struct Bls12;