halo2curves_axiom/bls12_381/
pairings.rs

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