bls12_381/
pairings.rs

1use crate::fp::Fp;
2use crate::fp12::Fp12;
3use crate::fp2::Fp2;
4use crate::fp6::Fp6;
5use crate::{G1Affine, G1Projective, 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 group::Group;
12use pairing::{Engine, PairingCurveAffine};
13use rand_core::RngCore;
14use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
15
16#[cfg(feature = "alloc")]
17use alloc::vec::Vec;
18#[cfg(feature = "alloc")]
19use pairing::MultiMillerLoop;
20
21/// Represents results of a Miller loop, one of the most expensive portions
22/// of the pairing function. `MillerLoopResult`s cannot be compared with each
23/// other until `.final_exponentiation()` is called, which is also expensive.
24#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
25#[derive(Copy, Clone, Debug)]
26pub struct MillerLoopResult(pub(crate) Fp12);
27
28impl Default for MillerLoopResult {
29    fn default() -> Self {
30        MillerLoopResult(Fp12::one())
31    }
32}
33
34#[cfg(feature = "zeroize")]
35impl zeroize::DefaultIsZeroes for MillerLoopResult {}
36
37impl ConditionallySelectable for MillerLoopResult {
38    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
39        MillerLoopResult(Fp12::conditional_select(&a.0, &b.0, choice))
40    }
41}
42
43impl MillerLoopResult {
44    /// This performs a "final exponentiation" routine to convert the result
45    /// of a Miller loop into an element of `Gt` with help of efficient squaring
46    /// operation in the so-called `cyclotomic subgroup` of `Fq6` so that
47    /// it can be compared with other elements of `Gt`.
48    pub fn final_exponentiation(&self) -> Gt {
49        #[must_use]
50        fn fp4_square(a: Fp2, b: Fp2) -> (Fp2, Fp2) {
51            let t0 = a.square();
52            let t1 = b.square();
53            let mut t2 = t1.mul_by_nonresidue();
54            let c0 = t2 + t0;
55            t2 = a + b;
56            t2 = t2.square();
57            t2 -= t0;
58            let c1 = t2 - t1;
59
60            (c0, c1)
61        }
62        // Adaptation of Algorithm 5.5.4, Guide to Pairing-Based Cryptography
63        // Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions
64        // https://eprint.iacr.org/2009/565.pdf
65        #[must_use]
66        fn cyclotomic_square(f: Fp12) -> Fp12 {
67            let mut z0 = f.c0.c0;
68            let mut z4 = f.c0.c1;
69            let mut z3 = f.c0.c2;
70            let mut z2 = f.c1.c0;
71            let mut z1 = f.c1.c1;
72            let mut z5 = f.c1.c2;
73
74            let (t0, t1) = fp4_square(z0, z1);
75
76            // For A
77            z0 = t0 - z0;
78            z0 = z0 + z0 + t0;
79
80            z1 = t1 + z1;
81            z1 = z1 + z1 + t1;
82
83            let (mut t0, t1) = fp4_square(z2, z3);
84            let (t2, t3) = fp4_square(z4, z5);
85
86            // For C
87            z4 = t0 - z4;
88            z4 = z4 + z4 + t0;
89
90            z5 = t1 + z5;
91            z5 = z5 + z5 + t1;
92
93            // For B
94            t0 = t3.mul_by_nonresidue();
95            z2 = t0 + z2;
96            z2 = z2 + z2 + t0;
97
98            z3 = t2 - z3;
99            z3 = z3 + z3 + t2;
100
101            Fp12 {
102                c0: Fp6 {
103                    c0: z0,
104                    c1: z4,
105                    c2: z3,
106                },
107                c1: Fp6 {
108                    c0: z2,
109                    c1: z1,
110                    c2: z5,
111                },
112            }
113        }
114        #[must_use]
115        fn cycolotomic_exp(f: Fp12) -> Fp12 {
116            let x = BLS_X;
117            let mut tmp = Fp12::one();
118            let mut found_one = false;
119            for i in (0..64).rev().map(|b| ((x >> b) & 1) == 1) {
120                if found_one {
121                    tmp = cyclotomic_square(tmp)
122                } else {
123                    found_one = i;
124                }
125
126                if i {
127                    tmp *= f;
128                }
129            }
130
131            tmp.conjugate()
132        }
133
134        let mut f = self.0;
135        let mut t0 = f
136            .frobenius_map()
137            .frobenius_map()
138            .frobenius_map()
139            .frobenius_map()
140            .frobenius_map()
141            .frobenius_map();
142        Gt(f.invert()
143            .map(|mut t1| {
144                let mut t2 = t0 * t1;
145                t1 = t2;
146                t2 = t2.frobenius_map().frobenius_map();
147                t2 *= t1;
148                t1 = cyclotomic_square(t2).conjugate();
149                let mut t3 = cycolotomic_exp(t2);
150                let mut t4 = cyclotomic_square(t3);
151                let mut t5 = t1 * t3;
152                t1 = cycolotomic_exp(t5);
153                t0 = cycolotomic_exp(t1);
154                let mut t6 = cycolotomic_exp(t0);
155                t6 *= t4;
156                t4 = cycolotomic_exp(t6);
157                t5 = t5.conjugate();
158                t4 *= t5 * t2;
159                t5 = t2.conjugate();
160                t1 *= t2;
161                t1 = t1.frobenius_map().frobenius_map().frobenius_map();
162                t6 *= t5;
163                t6 = t6.frobenius_map();
164                t3 *= t0;
165                t3 = t3.frobenius_map().frobenius_map();
166                t3 *= t1;
167                t3 *= t6;
168                f = t3 * t4;
169
170                f
171            })
172            // We unwrap() because `MillerLoopResult` can only be constructed
173            // by a function within this crate, and we uphold the invariant
174            // that the enclosed value is nonzero.
175            .unwrap())
176    }
177}
178
179impl<'a, 'b> Add<&'b MillerLoopResult> for &'a MillerLoopResult {
180    type Output = MillerLoopResult;
181
182    #[inline]
183    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
184        MillerLoopResult(self.0 * rhs.0)
185    }
186}
187
188impl_add_binop_specify_output!(MillerLoopResult, MillerLoopResult, MillerLoopResult);
189
190impl AddAssign<MillerLoopResult> for MillerLoopResult {
191    #[inline]
192    fn add_assign(&mut self, rhs: MillerLoopResult) {
193        *self = *self + rhs;
194    }
195}
196
197impl<'b> AddAssign<&'b MillerLoopResult> for MillerLoopResult {
198    #[inline]
199    fn add_assign(&mut self, rhs: &'b MillerLoopResult) {
200        *self = *self + rhs;
201    }
202}
203
204/// This is an element of $\mathbb{G}_T$, the target group of the pairing function. As with
205/// $\mathbb{G}_1$ and $\mathbb{G}_2$ this group has order $q$.
206///
207/// Typically, $\mathbb{G}_T$ is written multiplicatively but we will write it additively to
208/// keep code and abstractions consistent.
209#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
210#[derive(Copy, Clone, Debug)]
211pub struct Gt(pub(crate) Fp12);
212
213impl Default for Gt {
214    fn default() -> Self {
215        Self::identity()
216    }
217}
218
219#[cfg(feature = "zeroize")]
220impl zeroize::DefaultIsZeroes for Gt {}
221
222impl fmt::Display for Gt {
223    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224        write!(f, "{:?}", self)
225    }
226}
227
228impl ConstantTimeEq for Gt {
229    fn ct_eq(&self, other: &Self) -> Choice {
230        self.0.ct_eq(&other.0)
231    }
232}
233
234impl ConditionallySelectable for Gt {
235    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
236        Gt(Fp12::conditional_select(&a.0, &b.0, choice))
237    }
238}
239
240impl Eq for Gt {}
241impl PartialEq for Gt {
242    #[inline]
243    fn eq(&self, other: &Self) -> bool {
244        bool::from(self.ct_eq(other))
245    }
246}
247
248impl Gt {
249    /// Returns the group identity, which is $1$.
250    pub fn identity() -> Gt {
251        Gt(Fp12::one())
252    }
253
254    /// Doubles this group element.
255    pub fn double(&self) -> Gt {
256        Gt(self.0.square())
257    }
258}
259
260impl<'a> Neg for &'a Gt {
261    type Output = Gt;
262
263    #[inline]
264    fn neg(self) -> Gt {
265        // The element is unitary, so we just conjugate.
266        Gt(self.0.conjugate())
267    }
268}
269
270impl Neg for Gt {
271    type Output = Gt;
272
273    #[inline]
274    fn neg(self) -> Gt {
275        -&self
276    }
277}
278
279impl<'a, 'b> Add<&'b Gt> for &'a Gt {
280    type Output = Gt;
281
282    #[inline]
283    fn add(self, rhs: &'b Gt) -> Gt {
284        Gt(self.0 * rhs.0)
285    }
286}
287
288impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
289    type Output = Gt;
290
291    #[inline]
292    fn sub(self, rhs: &'b Gt) -> Gt {
293        self + (-rhs)
294    }
295}
296
297impl<'a, 'b> Mul<&'b Scalar> for &'a Gt {
298    type Output = Gt;
299
300    fn mul(self, other: &'b Scalar) -> Self::Output {
301        let mut acc = Gt::identity();
302
303        // This is a simple double-and-add implementation of group element
304        // multiplication, moving from most significant to least
305        // significant bit of the scalar.
306        //
307        // We skip the leading bit because it's always unset for Fq
308        // elements.
309        for bit in other
310            .to_bytes()
311            .iter()
312            .rev()
313            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
314            .skip(1)
315        {
316            acc = acc.double();
317            acc = Gt::conditional_select(&acc, &(acc + self), bit);
318        }
319
320        acc
321    }
322}
323
324impl_binops_additive!(Gt, Gt);
325impl_binops_multiplicative!(Gt, Scalar);
326
327impl<T> Sum<T> for Gt
328where
329    T: Borrow<Gt>,
330{
331    fn sum<I>(iter: I) -> Self
332    where
333        I: Iterator<Item = T>,
334    {
335        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
336    }
337}
338
339impl Group for Gt {
340    type Scalar = Scalar;
341
342    fn random(mut rng: impl RngCore) -> Self {
343        loop {
344            let inner = Fp12::random(&mut rng);
345
346            // Not all elements of Fp12 are elements of the prime-order multiplicative
347            // subgroup. We run the random element through final_exponentiation to obtain
348            // a valid element, which requires that it is non-zero.
349            if !bool::from(inner.is_zero()) {
350                return MillerLoopResult(inner).final_exponentiation();
351            }
352        }
353    }
354
355    fn identity() -> Self {
356        Self::identity()
357    }
358
359    fn generator() -> Self {
360        // pairing(&G1Affine::generator(), &G2Affine::generator())
361        Gt(Fp12 {
362            c0: Fp6 {
363                c0: Fp2 {
364                    c0: Fp::from_raw_unchecked([
365                        0x1972_e433_a01f_85c5,
366                        0x97d3_2b76_fd77_2538,
367                        0xc8ce_546f_c96b_cdf9,
368                        0xcef6_3e73_66d4_0614,
369                        0xa611_3427_8184_3780,
370                        0x13f3_448a_3fc6_d825,
371                    ]),
372                    c1: Fp::from_raw_unchecked([
373                        0xd263_31b0_2e9d_6995,
374                        0x9d68_a482_f779_7e7d,
375                        0x9c9b_2924_8d39_ea92,
376                        0xf480_1ca2_e131_07aa,
377                        0xa16c_0732_bdbc_b066,
378                        0x083c_a4af_ba36_0478,
379                    ]),
380                },
381                c1: Fp2 {
382                    c0: Fp::from_raw_unchecked([
383                        0x59e2_61db_0916_b641,
384                        0x2716_b6f4_b23e_960d,
385                        0xc8e5_5b10_a0bd_9c45,
386                        0x0bdb_0bd9_9c4d_eda8,
387                        0x8cf8_9ebf_57fd_aac5,
388                        0x12d6_b792_9e77_7a5e,
389                    ]),
390                    c1: Fp::from_raw_unchecked([
391                        0x5fc8_5188_b0e1_5f35,
392                        0x34a0_6e3a_8f09_6365,
393                        0xdb31_26a6_e02a_d62c,
394                        0xfc6f_5aa9_7d9a_990b,
395                        0xa12f_55f5_eb89_c210,
396                        0x1723_703a_926f_8889,
397                    ]),
398                },
399                c2: Fp2 {
400                    c0: Fp::from_raw_unchecked([
401                        0x9358_8f29_7182_8778,
402                        0x43f6_5b86_11ab_7585,
403                        0x3183_aaf5_ec27_9fdf,
404                        0xfa73_d7e1_8ac9_9df6,
405                        0x64e1_76a6_a64c_99b0,
406                        0x179f_a78c_5838_8f1f,
407                    ]),
408                    c1: Fp::from_raw_unchecked([
409                        0x672a_0a11_ca2a_ef12,
410                        0x0d11_b9b5_2aa3_f16b,
411                        0xa444_12d0_699d_056e,
412                        0xc01d_0177_221a_5ba5,
413                        0x66e0_cede_6c73_5529,
414                        0x05f5_a71e_9fdd_c339,
415                    ]),
416                },
417            },
418            c1: Fp6 {
419                c0: Fp2 {
420                    c0: Fp::from_raw_unchecked([
421                        0xd30a_88a1_b062_c679,
422                        0x5ac5_6a5d_35fc_8304,
423                        0xd0c8_34a6_a81f_290d,
424                        0xcd54_30c2_da37_07c7,
425                        0xf0c2_7ff7_8050_0af0,
426                        0x0924_5da6_e2d7_2eae,
427                    ]),
428                    c1: Fp::from_raw_unchecked([
429                        0x9f2e_0676_791b_5156,
430                        0xe2d1_c823_4918_fe13,
431                        0x4c9e_459f_3c56_1bf4,
432                        0xa3e8_5e53_b9d3_e3c1,
433                        0x820a_121e_21a7_0020,
434                        0x15af_6183_41c5_9acc,
435                    ]),
436                },
437                c1: Fp2 {
438                    c0: Fp::from_raw_unchecked([
439                        0x7c95_658c_2499_3ab1,
440                        0x73eb_3872_1ca8_86b9,
441                        0x5256_d749_4774_34bc,
442                        0x8ba4_1902_ea50_4a8b,
443                        0x04a3_d3f8_0c86_ce6d,
444                        0x18a6_4a87_fb68_6eaa,
445                    ]),
446                    c1: Fp::from_raw_unchecked([
447                        0xbb83_e71b_b920_cf26,
448                        0x2a52_77ac_92a7_3945,
449                        0xfc0e_e59f_94f0_46a0,
450                        0x7158_cdf3_7860_58f7,
451                        0x7cc1_061b_82f9_45f6,
452                        0x03f8_47aa_9fdb_e567,
453                    ]),
454                },
455                c2: Fp2 {
456                    c0: Fp::from_raw_unchecked([
457                        0x8078_dba5_6134_e657,
458                        0x1cd7_ec9a_4399_8a6e,
459                        0xb1aa_599a_1a99_3766,
460                        0xc9a0_f62f_0842_ee44,
461                        0x8e15_9be3_b605_dffa,
462                        0x0c86_ba0d_4af1_3fc2,
463                    ]),
464                    c1: Fp::from_raw_unchecked([
465                        0xe80f_f2a0_6a52_ffb1,
466                        0x7694_ca48_721a_906c,
467                        0x7583_183e_03b0_8514,
468                        0xf567_afdd_40ce_e4e2,
469                        0x9a6d_96d2_e526_a5fc,
470                        0x197e_9f49_861f_2242,
471                    ]),
472                },
473            },
474        })
475    }
476
477    fn is_identity(&self) -> Choice {
478        self.ct_eq(&Self::identity())
479    }
480
481    #[must_use]
482    fn double(&self) -> Self {
483        self.double()
484    }
485}
486
487#[cfg(feature = "alloc")]
488#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))]
489#[derive(Clone, Debug)]
490/// This structure contains cached computations pertaining to a $\mathbb{G}_2$
491/// element as part of the pairing function (specifically, the Miller loop) and
492/// so should be computed whenever a $\mathbb{G}_2$ element is being used in
493/// multiple pairings or is otherwise known in advance. This should be used in
494/// conjunction with the [`multi_miller_loop`](crate::multi_miller_loop)
495/// function provided by this crate.
496///
497/// Requires the `alloc` and `pairing` crate features to be enabled.
498pub struct G2Prepared {
499    infinity: Choice,
500    coeffs: Vec<(Fp2, Fp2, Fp2)>,
501}
502
503#[cfg(feature = "alloc")]
504impl From<G2Affine> for G2Prepared {
505    fn from(q: G2Affine) -> G2Prepared {
506        struct Adder {
507            cur: G2Projective,
508            base: G2Affine,
509            coeffs: Vec<(Fp2, Fp2, Fp2)>,
510        }
511
512        impl MillerLoopDriver for Adder {
513            type Output = ();
514
515            fn doubling_step(&mut self, _: Self::Output) -> Self::Output {
516                let coeffs = doubling_step(&mut self.cur);
517                self.coeffs.push(coeffs);
518            }
519            fn addition_step(&mut self, _: Self::Output) -> Self::Output {
520                let coeffs = addition_step(&mut self.cur, &self.base);
521                self.coeffs.push(coeffs);
522            }
523            fn square_output(_: Self::Output) -> Self::Output {}
524            fn conjugate(_: Self::Output) -> Self::Output {}
525            fn one() -> Self::Output {}
526        }
527
528        let is_identity = q.is_identity();
529        let q = G2Affine::conditional_select(&q, &G2Affine::generator(), is_identity);
530
531        let mut adder = Adder {
532            cur: G2Projective::from(q),
533            base: q,
534            coeffs: Vec::with_capacity(68),
535        };
536
537        miller_loop(&mut adder);
538
539        assert_eq!(adder.coeffs.len(), 68);
540
541        G2Prepared {
542            infinity: is_identity,
543            coeffs: adder.coeffs,
544        }
545    }
546}
547
548#[cfg(feature = "alloc")]
549#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))]
550/// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms
551/// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$
552///
553/// Requires the `alloc` and `pairing` crate features to be enabled.
554pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult {
555    struct Adder<'a, 'b, 'c> {
556        terms: &'c [(&'a G1Affine, &'b G2Prepared)],
557        index: usize,
558    }
559
560    impl<'a, 'b, 'c> MillerLoopDriver for Adder<'a, 'b, 'c> {
561        type Output = Fp12;
562
563        fn doubling_step(&mut self, mut f: Self::Output) -> Self::Output {
564            let index = self.index;
565            for term in self.terms {
566                let either_identity = term.0.is_identity() | term.1.infinity;
567
568                let new_f = ell(f, &term.1.coeffs[index], term.0);
569                f = Fp12::conditional_select(&new_f, &f, either_identity);
570            }
571            self.index += 1;
572
573            f
574        }
575        fn addition_step(&mut self, mut f: Self::Output) -> Self::Output {
576            let index = self.index;
577            for term in self.terms {
578                let either_identity = term.0.is_identity() | term.1.infinity;
579
580                let new_f = ell(f, &term.1.coeffs[index], term.0);
581                f = Fp12::conditional_select(&new_f, &f, either_identity);
582            }
583            self.index += 1;
584
585            f
586        }
587        fn square_output(f: Self::Output) -> Self::Output {
588            f.square()
589        }
590        fn conjugate(f: Self::Output) -> Self::Output {
591            f.conjugate()
592        }
593        fn one() -> Self::Output {
594            Fp12::one()
595        }
596    }
597
598    let mut adder = Adder { terms, index: 0 };
599
600    let tmp = miller_loop(&mut adder);
601
602    MillerLoopResult(tmp)
603}
604
605/// Invoke the pairing function without the use of precomputation and other optimizations.
606#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
607pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt {
608    struct Adder {
609        cur: G2Projective,
610        base: G2Affine,
611        p: G1Affine,
612    }
613
614    impl MillerLoopDriver for Adder {
615        type Output = Fp12;
616
617        fn doubling_step(&mut self, f: Self::Output) -> Self::Output {
618            let coeffs = doubling_step(&mut self.cur);
619            ell(f, &coeffs, &self.p)
620        }
621        fn addition_step(&mut self, f: Self::Output) -> Self::Output {
622            let coeffs = addition_step(&mut self.cur, &self.base);
623            ell(f, &coeffs, &self.p)
624        }
625        fn square_output(f: Self::Output) -> Self::Output {
626            f.square()
627        }
628        fn conjugate(f: Self::Output) -> Self::Output {
629            f.conjugate()
630        }
631        fn one() -> Self::Output {
632            Fp12::one()
633        }
634    }
635
636    let either_identity = p.is_identity() | q.is_identity();
637    let p = G1Affine::conditional_select(p, &G1Affine::generator(), either_identity);
638    let q = G2Affine::conditional_select(q, &G2Affine::generator(), either_identity);
639
640    let mut adder = Adder {
641        cur: G2Projective::from(q),
642        base: q,
643        p,
644    };
645
646    let tmp = miller_loop(&mut adder);
647    let tmp = MillerLoopResult(Fp12::conditional_select(
648        &tmp,
649        &Fp12::one(),
650        either_identity,
651    ));
652    tmp.final_exponentiation()
653}
654
655trait MillerLoopDriver {
656    type Output;
657
658    fn doubling_step(&mut self, f: Self::Output) -> Self::Output;
659    fn addition_step(&mut self, f: Self::Output) -> Self::Output;
660    fn square_output(f: Self::Output) -> Self::Output;
661    fn conjugate(f: Self::Output) -> Self::Output;
662    fn one() -> Self::Output;
663}
664
665/// This is a "generic" implementation of the Miller loop to avoid duplicating code
666/// structure elsewhere; instead, we'll write concrete instantiations of
667/// `MillerLoopDriver` for whatever purposes we need (such as caching modes).
668fn miller_loop<D: MillerLoopDriver>(driver: &mut D) -> D::Output {
669    let mut f = D::one();
670
671    let mut found_one = false;
672    for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
673        if !found_one {
674            found_one = i;
675            continue;
676        }
677
678        f = driver.doubling_step(f);
679
680        if i {
681            f = driver.addition_step(f);
682        }
683
684        f = D::square_output(f);
685    }
686
687    f = driver.doubling_step(f);
688
689    if BLS_X_IS_NEGATIVE {
690        f = D::conjugate(f);
691    }
692
693    f
694}
695
696fn ell(f: Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 {
697    let mut c0 = coeffs.0;
698    let mut c1 = coeffs.1;
699
700    c0.c0 *= p.y;
701    c0.c1 *= p.y;
702
703    c1.c0 *= p.x;
704    c1.c1 *= p.x;
705
706    f.mul_by_014(&coeffs.2, &c1, &c0)
707}
708
709fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) {
710    // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
711    let tmp0 = r.x.square();
712    let tmp1 = r.y.square();
713    let tmp2 = tmp1.square();
714    let tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2;
715    let tmp3 = tmp3 + tmp3;
716    let tmp4 = tmp0 + tmp0 + tmp0;
717    let tmp6 = r.x + tmp4;
718    let tmp5 = tmp4.square();
719    let zsquared = r.z.square();
720    r.x = tmp5 - tmp3 - tmp3;
721    r.z = (r.z + r.y).square() - tmp1 - zsquared;
722    r.y = (tmp3 - r.x) * tmp4;
723    let tmp2 = tmp2 + tmp2;
724    let tmp2 = tmp2 + tmp2;
725    let tmp2 = tmp2 + tmp2;
726    r.y -= tmp2;
727    let tmp3 = tmp4 * zsquared;
728    let tmp3 = tmp3 + tmp3;
729    let tmp3 = -tmp3;
730    let tmp6 = tmp6.square() - tmp0 - tmp5;
731    let tmp1 = tmp1 + tmp1;
732    let tmp1 = tmp1 + tmp1;
733    let tmp6 = tmp6 - tmp1;
734    let tmp0 = r.z * zsquared;
735    let tmp0 = tmp0 + tmp0;
736
737    (tmp0, tmp3, tmp6)
738}
739
740fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
741    // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
742    let zsquared = r.z.square();
743    let ysquared = q.y.square();
744    let t0 = zsquared * q.x;
745    let t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared;
746    let t2 = t0 - r.x;
747    let t3 = t2.square();
748    let t4 = t3 + t3;
749    let t4 = t4 + t4;
750    let t5 = t4 * t2;
751    let t6 = t1 - r.y - r.y;
752    let t9 = t6 * q.x;
753    let t7 = t4 * r.x;
754    r.x = t6.square() - t5 - t7 - t7;
755    r.z = (r.z + t2).square() - zsquared - t3;
756    let t10 = q.y + r.z;
757    let t8 = (t7 - r.x) * t6;
758    let t0 = r.y * t5;
759    let t0 = t0 + t0;
760    r.y = t8 - t0;
761    let t10 = t10.square() - ysquared;
762    let ztsquared = r.z.square();
763    let t10 = t10 - ztsquared;
764    let t9 = t9 + t9 - t10;
765    let t10 = r.z + r.z;
766    let t6 = -t6;
767    let t1 = t6 + t6;
768
769    (t10, t1, t9)
770}
771
772impl PairingCurveAffine for G1Affine {
773    type Pair = G2Affine;
774    type PairingResult = Gt;
775
776    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
777        pairing(self, other)
778    }
779}
780
781impl PairingCurveAffine for G2Affine {
782    type Pair = G1Affine;
783    type PairingResult = Gt;
784
785    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
786        pairing(other, self)
787    }
788}
789
790/// A [`pairing::Engine`] for BLS12-381 pairing operations.
791#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
792#[derive(Clone, Debug)]
793pub struct Bls12;
794
795impl Engine for Bls12 {
796    type Fr = Scalar;
797    type G1 = G1Projective;
798    type G1Affine = G1Affine;
799    type G2 = G2Projective;
800    type G2Affine = G2Affine;
801    type Gt = Gt;
802
803    fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
804        pairing(p, q)
805    }
806}
807
808impl pairing::MillerLoopResult for MillerLoopResult {
809    type Gt = Gt;
810
811    fn final_exponentiation(&self) -> Self::Gt {
812        self.final_exponentiation()
813    }
814}
815
816#[cfg(feature = "alloc")]
817impl MultiMillerLoop for Bls12 {
818    type G2Prepared = G2Prepared;
819    type Result = MillerLoopResult;
820
821    fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
822        multi_miller_loop(terms)
823    }
824}
825
826#[test]
827fn test_gt_generator() {
828    assert_eq!(
829        Gt::generator(),
830        pairing(&G1Affine::generator(), &G2Affine::generator())
831    );
832}
833
834#[test]
835fn test_bilinearity() {
836    use crate::Scalar;
837
838    let a = Scalar::from_raw([1, 2, 3, 4]).invert().unwrap().square();
839    let b = Scalar::from_raw([5, 6, 7, 8]).invert().unwrap().square();
840    let c = a * b;
841
842    let g = G1Affine::from(G1Affine::generator() * a);
843    let h = G2Affine::from(G2Affine::generator() * b);
844    let p = pairing(&g, &h);
845
846    assert!(p != Gt::identity());
847
848    let expected = G1Affine::from(G1Affine::generator() * c);
849
850    assert_eq!(p, pairing(&expected, &G2Affine::generator()));
851    assert_eq!(
852        p,
853        pairing(&G1Affine::generator(), &G2Affine::generator()) * c
854    );
855}
856
857#[test]
858fn test_unitary() {
859    let g = G1Affine::generator();
860    let h = G2Affine::generator();
861    let p = -pairing(&g, &h);
862    let q = pairing(&g, &-h);
863    let r = pairing(&-g, &h);
864
865    assert_eq!(p, q);
866    assert_eq!(q, r);
867}
868
869#[cfg(feature = "alloc")]
870#[test]
871fn test_multi_miller_loop() {
872    let a1 = G1Affine::generator();
873    let b1 = G2Affine::generator();
874
875    let a2 = G1Affine::from(
876        G1Affine::generator() * Scalar::from_raw([1, 2, 3, 4]).invert().unwrap().square(),
877    );
878    let b2 = G2Affine::from(
879        G2Affine::generator() * Scalar::from_raw([4, 2, 2, 4]).invert().unwrap().square(),
880    );
881
882    let a3 = G1Affine::identity();
883    let b3 = G2Affine::from(
884        G2Affine::generator() * Scalar::from_raw([9, 2, 2, 4]).invert().unwrap().square(),
885    );
886
887    let a4 = G1Affine::from(
888        G1Affine::generator() * Scalar::from_raw([5, 5, 5, 5]).invert().unwrap().square(),
889    );
890    let b4 = G2Affine::identity();
891
892    let a5 = G1Affine::from(
893        G1Affine::generator() * Scalar::from_raw([323, 32, 3, 1]).invert().unwrap().square(),
894    );
895    let b5 = G2Affine::from(
896        G2Affine::generator() * Scalar::from_raw([4, 2, 2, 9099]).invert().unwrap().square(),
897    );
898
899    let b1_prepared = G2Prepared::from(b1);
900    let b2_prepared = G2Prepared::from(b2);
901    let b3_prepared = G2Prepared::from(b3);
902    let b4_prepared = G2Prepared::from(b4);
903    let b5_prepared = G2Prepared::from(b5);
904
905    let expected = pairing(&a1, &b1)
906        + pairing(&a2, &b2)
907        + pairing(&a3, &b3)
908        + pairing(&a4, &b4)
909        + pairing(&a5, &b5);
910
911    let test = multi_miller_loop(&[
912        (&a1, &b1_prepared),
913        (&a2, &b2_prepared),
914        (&a3, &b3_prepared),
915        (&a4, &b4_prepared),
916        (&a5, &b5_prepared),
917    ])
918    .final_exponentiation();
919
920    assert_eq!(expected, test);
921}
922
923#[test]
924fn test_miller_loop_result_default() {
925    assert_eq!(
926        MillerLoopResult::default().final_exponentiation(),
927        Gt::identity(),
928    );
929}
930
931#[cfg(feature = "zeroize")]
932#[test]
933fn test_miller_loop_result_zeroize() {
934    use zeroize::Zeroize;
935
936    let mut m = multi_miller_loop(&[
937        (&G1Affine::generator(), &G2Affine::generator().into()),
938        (&-G1Affine::generator(), &G2Affine::generator().into()),
939    ]);
940    m.zeroize();
941    assert_eq!(m.0, MillerLoopResult::default().0);
942}
943
944#[test]
945fn tricking_miller_loop_result() {
946    assert_eq!(
947        multi_miller_loop(&[(&G1Affine::identity(), &G2Affine::generator().into())]).0,
948        Fp12::one()
949    );
950    assert_eq!(
951        multi_miller_loop(&[(&G1Affine::generator(), &G2Affine::identity().into())]).0,
952        Fp12::one()
953    );
954    assert_ne!(
955        multi_miller_loop(&[
956            (&G1Affine::generator(), &G2Affine::generator().into()),
957            (&-G1Affine::generator(), &G2Affine::generator().into())
958        ])
959        .0,
960        Fp12::one()
961    );
962    assert_eq!(
963        multi_miller_loop(&[
964            (&G1Affine::generator(), &G2Affine::generator().into()),
965            (&-G1Affine::generator(), &G2Affine::generator().into())
966        ])
967        .final_exponentiation(),
968        Gt::identity()
969    );
970}