Skip to main content

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 {
82                    c0: z0,
83                    c1: z4,
84                    c2: z3,
85                },
86                c1: Fp6 {
87                    c0: z2,
88                    c1: z1,
89                    c2: z5,
90                },
91            }
92        }
93        #[must_use]
94        fn cycolotomic_exp(f: Fp12) -> Fp12 {
95            let x = BLS_X;
96            let mut tmp = Fp12::one();
97            let mut found_one = false;
98            for i in (0..64).rev().map(|b| ((x >> b) & 1) == 1) {
99                if found_one {
100                    tmp = cyclotomic_square(tmp)
101                } else {
102                    found_one = i;
103                }
104                if i {
105                    tmp *= f;
106                }
107            }
108            tmp.conjugate()
109        }
110
111        let f = self.0;
112        let t0 = f
113            .frobenius_map()
114            .frobenius_map()
115            .frobenius_map()
116            .frobenius_map()
117            .frobenius_map()
118            .frobenius_map();
119        Gt(f.invert()
120            .map(|t1| {
121                let mut t2 = t0 * t1;
122                let t1 = t2;
123                t2 = t2.frobenius_map().frobenius_map();
124                t2 *= t1;
125                let t1 = cyclotomic_square(t2).conjugate();
126                let t3 = cycolotomic_exp(t2);
127                let t4 = cyclotomic_square(t3);
128                let t5 = t1 * t3;
129                let t1 = cycolotomic_exp(t5);
130                let t0 = cycolotomic_exp(t1);
131                let mut t6 = cycolotomic_exp(t0);
132                t6 *= t4;
133                let t4 = cycolotomic_exp(t6);
134                let t5 = t5.conjugate();
135                let t4 = t4 * t5 * t2;
136                let t5 = t2.conjugate();
137                let t1 = t1 * t2;
138                let t1 = t1.frobenius_map().frobenius_map().frobenius_map();
139                let t6 = t6 * t5;
140                let t6 = t6.frobenius_map();
141                let t3 = t3 * t0;
142                let t3 = t3.frobenius_map().frobenius_map();
143                let t3 = t3 * t1;
144                let t3 = t3 * t6;
145                t3 * t4
146            })
147            .unwrap())
148    }
149}
150
151// Expanded: impl_add_binop_specify_output!(MillerLoopResult, MillerLoopResult, MillerLoopResult);
152impl<'a, 'b> Add<&'b MillerLoopResult> for &'a MillerLoopResult {
153    type Output = MillerLoopResult;
154
155    #[inline]
156    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
157        MillerLoopResult(self.0 * rhs.0)
158    }
159}
160
161impl<'b> Add<&'b MillerLoopResult> for MillerLoopResult {
162    type Output = MillerLoopResult;
163    #[inline]
164    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
165        &self + rhs
166    }
167}
168impl<'a> Add<MillerLoopResult> for &'a MillerLoopResult {
169    type Output = MillerLoopResult;
170    #[inline]
171    fn add(self, rhs: MillerLoopResult) -> MillerLoopResult {
172        self + &rhs
173    }
174}
175impl Add<MillerLoopResult> for MillerLoopResult {
176    type Output = MillerLoopResult;
177    #[inline]
178    fn add(self, rhs: MillerLoopResult) -> MillerLoopResult {
179        &self + &rhs
180    }
181}
182
183impl AddAssign<MillerLoopResult> for MillerLoopResult {
184    #[inline]
185    fn add_assign(&mut self, rhs: MillerLoopResult) {
186        *self = *self + rhs;
187    }
188}
189
190impl<'b> AddAssign<&'b MillerLoopResult> for MillerLoopResult {
191    #[inline]
192    fn add_assign(&mut self, rhs: &'b MillerLoopResult) {
193        *self = *self + rhs;
194    }
195}
196
197/// Target group G_T element.
198#[derive(Copy, Clone, Debug)]
199pub struct Gt(pub(crate) Fp12);
200
201impl Default for Gt {
202    fn default() -> Self {
203        Self::identity()
204    }
205}
206
207#[cfg(feature = "zeroize")]
208impl zeroize::DefaultIsZeroes for Gt {}
209
210impl fmt::Display for Gt {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        write!(f, "{:?}", self)
213    }
214}
215
216impl ConstantTimeEq for Gt {
217    fn ct_eq(&self, other: &Self) -> Choice {
218        self.0.ct_eq(&other.0)
219    }
220}
221
222impl ConditionallySelectable for Gt {
223    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
224        Gt(Fp12::conditional_select(&a.0, &b.0, choice))
225    }
226}
227
228impl Eq for Gt {}
229impl PartialEq for Gt {
230    #[inline]
231    fn eq(&self, other: &Self) -> bool {
232        bool::from(self.ct_eq(other))
233    }
234}
235
236impl Gt {
237    /// Returns the identity element (1).
238    pub fn identity() -> Gt {
239        Gt(Fp12::one())
240    }
241
242    /// Returns a fixed generator.
243    pub fn generator() -> Self {
244        Gt(Fp12 {
245            c0: Fp6 {
246                c0: Fp2 {
247                    c0: Fp::from_raw_unchecked([
248                        0x1972_e433_a01f_85c5,
249                        0x97d3_2b76_fd77_2538,
250                        0xc8ce_546f_c96b_cdf9,
251                        0xcef6_3e73_66d4_0614,
252                        0xa611_3427_8184_3780,
253                        0x13f3_448a_3fc6_d825,
254                    ]),
255                    c1: Fp::from_raw_unchecked([
256                        0xd263_31b0_2e9d_6995,
257                        0x9d68_a482_f779_7e7d,
258                        0x9c9b_2924_8d39_ea92,
259                        0xf480_1ca2_e131_07aa,
260                        0xa16c_0732_bdbc_b066,
261                        0x083c_a4af_ba36_0478,
262                    ]),
263                },
264                c1: Fp2 {
265                    c0: Fp::from_raw_unchecked([
266                        0x59e2_61db_0916_b641,
267                        0x2716_b6f4_b23e_960d,
268                        0xc8e5_5b10_a0bd_9c45,
269                        0x0bdb_0bd9_9c4d_eda8,
270                        0x8cf8_9ebf_57fd_aac5,
271                        0x12d6_b792_9e77_7a5e,
272                    ]),
273                    c1: Fp::from_raw_unchecked([
274                        0x5fc8_5188_b0e1_5f35,
275                        0x34a0_6e3a_8f09_6365,
276                        0xdb31_26a6_e02a_d62c,
277                        0xfc6f_5aa9_7d9a_990b,
278                        0xa12f_55f5_eb89_c210,
279                        0x1723_703a_926f_8889,
280                    ]),
281                },
282                c2: Fp2 {
283                    c0: Fp::from_raw_unchecked([
284                        0x9358_8f29_7182_8778,
285                        0x43f6_5b86_11ab_7585,
286                        0x3183_aaf5_ec27_9fdf,
287                        0xfa73_d7e1_8ac9_9df6,
288                        0x64e1_76a6_a64c_99b0,
289                        0x179f_a78c_5838_8f1f,
290                    ]),
291                    c1: Fp::from_raw_unchecked([
292                        0x672a_0a11_ca2a_ef12,
293                        0x0d11_b9b5_2aa3_f16b,
294                        0xa444_12d0_699d_056e,
295                        0xc01d_0177_221a_5ba5,
296                        0x66e0_cede_6c73_5529,
297                        0x05f5_a71e_9fdd_c339,
298                    ]),
299                },
300            },
301            c1: Fp6 {
302                c0: Fp2 {
303                    c0: Fp::from_raw_unchecked([
304                        0xd30a_88a1_b062_c679,
305                        0x5ac5_6a5d_35fc_8304,
306                        0xd0c8_34a6_a81f_290d,
307                        0xcd54_30c2_da37_07c7,
308                        0xf0c2_7ff7_8050_0af0,
309                        0x0924_5da6_e2d7_2eae,
310                    ]),
311                    c1: Fp::from_raw_unchecked([
312                        0x9f2e_0676_791b_5156,
313                        0xe2d1_c823_4918_fe13,
314                        0x4c9e_459f_3c56_1bf4,
315                        0xa3e8_5e53_b9d3_e3c1,
316                        0x820a_121e_21a7_0020,
317                        0x15af_6183_41c5_9acc,
318                    ]),
319                },
320                c1: Fp2 {
321                    c0: Fp::from_raw_unchecked([
322                        0x7c95_658c_2499_3ab1,
323                        0x73eb_3872_1ca8_86b9,
324                        0x5256_d749_4774_34bc,
325                        0x8ba4_1902_ea50_4a8b,
326                        0x04a3_d3f8_0c86_ce6d,
327                        0x18a6_4a87_fb68_6eaa,
328                    ]),
329                    c1: Fp::from_raw_unchecked([
330                        0xbb83_e71b_b920_cf26,
331                        0x2a52_77ac_92a7_3945,
332                        0xfc0e_e59f_94f0_46a0,
333                        0x7158_cdf3_7860_58f7,
334                        0x7cc1_061b_82f9_45f6,
335                        0x03f8_47aa_9fdb_e567,
336                    ]),
337                },
338                c2: Fp2 {
339                    c0: Fp::from_raw_unchecked([
340                        0x8078_dba5_6134_e657,
341                        0x1cd7_ec9a_4399_8a6e,
342                        0xb1aa_599a_1a99_3766,
343                        0xc9a0_f62f_0842_ee44,
344                        0x8e15_9be3_b605_dffa,
345                        0x0c86_ba0d_4af1_3fc2,
346                    ]),
347                    c1: Fp::from_raw_unchecked([
348                        0xe80f_f2a0_6a52_ffb1,
349                        0x7694_ca48_721a_906c,
350                        0x7583_183e_03b0_8514,
351                        0xf567_afdd_40ce_e4e2,
352                        0x9a6d_96d2_e526_a5fc,
353                        0x197e_9f49_861f_2242,
354                    ]),
355                },
356            },
357        })
358    }
359
360    /// Checks if this is the identity.
361    pub fn is_identity(&self) -> Choice {
362        self.ct_eq(&Self::identity())
363    }
364
365    /// Doubles this element.
366    pub fn double(&self) -> Gt {
367        Gt(self.0.square())
368    }
369
370    /// Creates a random GT element.
371    pub fn random(mut rng: impl RngCore) -> Self {
372        loop {
373            let inner = Fp12::random(&mut rng);
374            if !bool::from(inner.is_zero()) {
375                return MillerLoopResult(inner).final_exponentiation();
376            }
377        }
378    }
379}
380
381impl<'a> Neg for &'a Gt {
382    type Output = Gt;
383    #[inline]
384    fn neg(self) -> Gt {
385        Gt(self.0.conjugate())
386    }
387}
388
389impl Neg for Gt {
390    type Output = Gt;
391    #[inline]
392    fn neg(self) -> Gt {
393        -&self
394    }
395}
396
397impl<'a, 'b> Add<&'b Gt> for &'a Gt {
398    type Output = Gt;
399    #[inline]
400    fn add(self, rhs: &'b Gt) -> Gt {
401        Gt(self.0 * rhs.0)
402    }
403}
404
405impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
406    type Output = Gt;
407    #[inline]
408    fn sub(self, rhs: &'b Gt) -> Gt {
409        self + &(-rhs)
410    }
411}
412
413impl<'a, 'b> Mul<&'b Scalar> for &'a Gt {
414    type Output = Gt;
415    fn mul(self, other: &'b Scalar) -> Self::Output {
416        let mut acc = Gt::identity();
417        for bit in other
418            .to_bytes()
419            .iter()
420            .rev()
421            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
422            .skip(1)
423        {
424            acc = acc.double();
425            acc = Gt::conditional_select(&acc, &(acc + self), bit);
426        }
427        acc
428    }
429}
430
431// Expanded: impl_binops_additive!(Gt, Gt);
432impl<'b> Add<&'b Gt> for Gt {
433    type Output = Gt;
434    #[inline]
435    fn add(self, rhs: &'b Gt) -> Gt {
436        &self + rhs
437    }
438}
439impl<'a> Add<Gt> for &'a Gt {
440    type Output = Gt;
441    #[inline]
442    fn add(self, rhs: Gt) -> Gt {
443        self + &rhs
444    }
445}
446impl Add<Gt> for Gt {
447    type Output = Gt;
448    #[inline]
449    fn add(self, rhs: Gt) -> Gt {
450        &self + &rhs
451    }
452}
453impl<'b> Sub<&'b Gt> for Gt {
454    type Output = Gt;
455    #[inline]
456    fn sub(self, rhs: &'b Gt) -> Gt {
457        &self - rhs
458    }
459}
460impl<'a> Sub<Gt> for &'a Gt {
461    type Output = Gt;
462    #[inline]
463    fn sub(self, rhs: Gt) -> Gt {
464        self - &rhs
465    }
466}
467impl Sub<Gt> for Gt {
468    type Output = Gt;
469    #[inline]
470    fn sub(self, rhs: Gt) -> Gt {
471        &self - &rhs
472    }
473}
474impl SubAssign<Gt> for Gt {
475    #[inline]
476    fn sub_assign(&mut self, rhs: Gt) {
477        *self = &*self - &rhs;
478    }
479}
480impl AddAssign<Gt> for Gt {
481    #[inline]
482    fn add_assign(&mut self, rhs: Gt) {
483        *self = &*self + &rhs;
484    }
485}
486impl<'b> SubAssign<&'b Gt> for Gt {
487    #[inline]
488    fn sub_assign(&mut self, rhs: &'b Gt) {
489        *self = &*self - rhs;
490    }
491}
492impl<'b> AddAssign<&'b Gt> for Gt {
493    #[inline]
494    fn add_assign(&mut self, rhs: &'b Gt) {
495        *self = &*self + rhs;
496    }
497}
498
499// Expanded: impl_binops_multiplicative!(Gt, Scalar);
500impl<'b> Mul<&'b Scalar> for Gt {
501    type Output = Gt;
502    #[inline]
503    fn mul(self, rhs: &'b Scalar) -> Gt {
504        &self * rhs
505    }
506}
507impl<'a> Mul<Scalar> for &'a Gt {
508    type Output = Gt;
509    #[inline]
510    fn mul(self, rhs: Scalar) -> Gt {
511        self * &rhs
512    }
513}
514impl Mul<Scalar> for Gt {
515    type Output = Gt;
516    #[inline]
517    fn mul(self, rhs: Scalar) -> Gt {
518        &self * &rhs
519    }
520}
521impl MulAssign<Scalar> for Gt {
522    #[inline]
523    fn mul_assign(&mut self, rhs: Scalar) {
524        *self = &*self * &rhs;
525    }
526}
527impl<'b> MulAssign<&'b Scalar> for Gt {
528    #[inline]
529    fn mul_assign(&mut self, rhs: &'b Scalar) {
530        *self = &*self * rhs;
531    }
532}
533
534impl<T> Sum<T> for Gt
535where
536    T: Borrow<Gt>,
537{
538    fn sum<I>(iter: I) -> Self
539    where
540        I: Iterator<Item = T>,
541    {
542        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
543    }
544}
545
546#[cfg(feature = "alloc")]
547#[derive(Clone, Debug)]
548/// Pre-computed G2 for efficient multi-pairing.
549pub struct G2Prepared {
550    infinity: Choice,
551    coeffs: Vec<(Fp2, Fp2, Fp2)>,
552}
553
554#[cfg(feature = "alloc")]
555impl From<G2Affine> for G2Prepared {
556    fn from(q: G2Affine) -> G2Prepared {
557        struct Adder {
558            cur: G2Projective,
559            base: G2Affine,
560            coeffs: Vec<(Fp2, Fp2, Fp2)>,
561        }
562
563        impl MillerLoopDriver for Adder {
564            type Output = ();
565            fn doubling_step(&mut self, _: Self::Output) -> Self::Output {
566                self.coeffs.push(doubling_step(&mut self.cur));
567            }
568            fn addition_step(&mut self, _: Self::Output) -> Self::Output {
569                self.coeffs.push(addition_step(&mut self.cur, &self.base));
570            }
571            fn square_output(_: Self::Output) -> Self::Output {}
572            fn conjugate(_: Self::Output) -> Self::Output {}
573            fn one() -> Self::Output {}
574        }
575
576        let is_identity = q.is_identity();
577        let q = G2Affine::conditional_select(&q, &G2Affine::generator(), is_identity);
578        let mut adder = Adder {
579            cur: G2Projective::from(q),
580            base: q,
581            coeffs: Vec::with_capacity(68),
582        };
583        miller_loop(&mut adder);
584        G2Prepared {
585            infinity: is_identity,
586            coeffs: adder.coeffs,
587        }
588    }
589}
590
591#[cfg(feature = "alloc")]
592/// Multi-pairing computation in single Miller loop.
593pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult {
594    struct Adder<'a, 'b, 'c> {
595        terms: &'c [(&'a G1Affine, &'b G2Prepared)],
596        index: usize,
597    }
598
599    impl<'a, 'b, 'c> MillerLoopDriver for Adder<'a, 'b, 'c> {
600        type Output = Fp12;
601        fn doubling_step(&mut self, mut f: Self::Output) -> Self::Output {
602            for term in self.terms {
603                let either_identity = term.0.is_identity() | term.1.infinity;
604                let new_f = ell(f, &term.1.coeffs[self.index], term.0);
605                f = Fp12::conditional_select(&new_f, &f, either_identity);
606            }
607            self.index += 1;
608            f
609        }
610        fn addition_step(&mut self, mut f: Self::Output) -> Self::Output {
611            for term in self.terms {
612                let either_identity = term.0.is_identity() | term.1.infinity;
613                let new_f = ell(f, &term.1.coeffs[self.index], term.0);
614                f = Fp12::conditional_select(&new_f, &f, either_identity);
615            }
616            self.index += 1;
617            f
618        }
619        fn square_output(f: Self::Output) -> Self::Output {
620            f.square()
621        }
622        fn conjugate(f: Self::Output) -> Self::Output {
623            f.conjugate()
624        }
625        fn one() -> Self::Output {
626            Fp12::one()
627        }
628    }
629
630    let mut adder = Adder { terms, index: 0 };
631    MillerLoopResult(miller_loop(&mut adder))
632}
633
634/// Computes the BLS12-381 pairing.
635pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt {
636    struct Adder<'a> {
637        cur: G2Projective,
638        base: G2Affine,
639        p: &'a G1Affine,
640    }
641
642    impl<'a> MillerLoopDriver for Adder<'a> {
643        type Output = Fp12;
644        fn doubling_step(&mut self, f: Self::Output) -> Self::Output {
645            ell(f, &doubling_step(&mut self.cur), self.p)
646        }
647        fn addition_step(&mut self, f: Self::Output) -> Self::Output {
648            ell(f, &addition_step(&mut self.cur, &self.base), self.p)
649        }
650        fn square_output(f: Self::Output) -> Self::Output {
651            f.square()
652        }
653        fn conjugate(f: Self::Output) -> Self::Output {
654            f.conjugate()
655        }
656        fn one() -> Self::Output {
657            Fp12::one()
658        }
659    }
660
661    let either_identity = p.is_identity() | q.is_identity();
662    let p_selected = G1Affine::conditional_select(p, &G1Affine::generator(), either_identity);
663    let q_selected = G2Affine::conditional_select(q, &G2Affine::generator(), either_identity);
664
665    let mut adder = Adder {
666        cur: G2Projective::from(q_selected),
667        base: q_selected,
668        p: &p_selected,
669    };
670
671    let tmp = miller_loop(&mut adder);
672    MillerLoopResult(Fp12::conditional_select(
673        &tmp,
674        &Fp12::one(),
675        either_identity,
676    ))
677    .final_exponentiation()
678}
679
680trait MillerLoopDriver {
681    type Output;
682    fn doubling_step(&mut self, f: Self::Output) -> Self::Output;
683    fn addition_step(&mut self, f: Self::Output) -> Self::Output;
684    fn square_output(f: Self::Output) -> Self::Output;
685    fn conjugate(f: Self::Output) -> Self::Output;
686    fn one() -> Self::Output;
687}
688
689fn miller_loop<D: MillerLoopDriver>(driver: &mut D) -> D::Output {
690    let mut f = D::one();
691    let mut found_one = false;
692    for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
693        if !found_one {
694            found_one = i;
695            continue;
696        }
697        f = driver.doubling_step(f);
698        if i {
699            f = driver.addition_step(f);
700        }
701        f = D::square_output(f);
702    }
703    f = driver.doubling_step(f);
704    if BLS_X_IS_NEGATIVE {
705        f = D::conjugate(f);
706    }
707    f
708}
709
710fn ell(f: Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 {
711    let mut c0 = coeffs.0;
712    let mut c1 = coeffs.1;
713    c0.c0 *= p.y;
714    c0.c1 *= p.y;
715    c1.c0 *= p.x;
716    c1.c1 *= p.x;
717    f.mul_by_014(&coeffs.2, &c1, &c0)
718}
719
720fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) {
721    let tmp0 = r.x.square();
722    let tmp1 = r.y.square();
723    let tmp2 = tmp1.square();
724    let tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2;
725    let tmp3 = tmp3 + tmp3;
726    let tmp4 = tmp0 + tmp0 + tmp0;
727    let tmp6 = r.x + tmp4;
728    let tmp5 = tmp4.square();
729    let zsquared = r.z.square();
730    r.x = tmp5 - tmp3 - tmp3;
731    r.z = (r.z + r.y).square() - tmp1 - zsquared;
732    r.y = (tmp3 - r.x) * tmp4;
733    let tmp2 = tmp2 + tmp2;
734    let tmp2 = tmp2 + tmp2;
735    let tmp2 = tmp2 + tmp2;
736    r.y -= tmp2;
737    let tmp3 = tmp4 * zsquared;
738    let tmp3 = tmp3 + tmp3;
739    let tmp3 = -tmp3;
740    let tmp6 = tmp6.square() - tmp0 - tmp5;
741    let tmp1 = tmp1 + tmp1;
742    let tmp1 = tmp1 + tmp1;
743    let tmp6 = tmp6 - tmp1;
744    let tmp0 = r.z * zsquared;
745    let tmp0 = tmp0 + tmp0;
746    (tmp0, tmp3, tmp6)
747}
748
749fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
750    let zsquared = r.z.square();
751    let ysquared = q.y.square();
752    let t0 = zsquared * q.x;
753    let t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared;
754    let t2 = t0 - r.x;
755    let t3 = t2.square();
756    let t4 = t3 + t3;
757    let t4 = t4 + t4;
758    let t5 = t4 * t2;
759    let t6 = t1 - r.y - r.y;
760    let t9 = t6 * q.x;
761    let t7 = t4 * r.x;
762    r.x = t6.square() - t5 - t7 - t7;
763    r.z = (r.z + t2).square() - zsquared - t3;
764    let t10 = q.y + r.z;
765    let t8 = (t7 - r.x) * t6;
766    let t0 = r.y * t5;
767    let t0 = t0 + t0;
768    r.y = t8 - t0;
769    let t10 = t10.square() - ysquared;
770    let ztsquared = r.z.square();
771    let t10 = t10 - ztsquared;
772    let t9 = t9 + t9 - t10;
773    let t10 = r.z + r.z;
774    let t6 = -t6;
775    let t1 = t6 + t6;
776    (t10, t1, t9)
777}
778
779/// BLS12-381 pairing engine marker.
780#[derive(Clone, Debug)]
781pub struct Bls12;