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