pg_curve/
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, CtOption};
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    /// Serializes this element into uncompressed form. See [`notes::serialization`](crate::notes::serialization)
260    /// for details about how group elements are serialized.
261    pub fn to_uncompressed(&self) -> [u8; 576] {
262        self.0.to_bytes()
263    }
264
265    /// Attempts to deserialize an uncompressed element. See [`notes::serialization`](crate::notes::serialization)
266    /// for details about how group elements are serialized.
267    pub fn from_uncompressed(bytes: &[u8; 576]) -> CtOption<Self> {
268        Fp12::from_bytes(bytes).map(Gt)
269    }
270
271    /// Serializes this element into compressed form. See [`notes::serialization`](crate::notes::serialization)
272    /// for details about how group elements are serialized.
273    pub fn to_compressed(&self) -> [u8; 288] {
274        let mut res = self.0.c1.to_bytes();
275
276        // This point is in compressed form, so we set the most significant bit.
277        res[0] |= 1u8 << 7;
278
279        // Is the y-coordinate the lexicographically largest of the two associated with the
280        // x-coordinate? If so, set the second-most significant bit so long as this is not
281        // the point at infinity.
282        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.0.c0.lexicographically_largest());
283
284        res
285    }
286
287    /// Attempts to deserialize a compressed element. See [`notes::serialization`](crate::notes::serialization)
288    /// for details about how group elements are serialized.
289    pub fn from_compressed(bytes: &[u8; 288]) -> CtOption<Self> {
290        Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.0.is_element()))
291    }
292
293    /// Attempts to deserialize a compressed element, not checking if the
294    /// element is in the correct pairing group.
295    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
296    /// API invariants may be broken.** Please consider using `from_uncompressed()` instead.
297    pub fn from_compressed_unchecked(bytes: &[u8; 288]) -> CtOption<Self> {
298        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
299        let sort_flag_set = Choice::from((bytes[0] >> 6) & 1);
300
301        let xc1 = {
302            let mut tmp = [0; 288];
303            tmp.copy_from_slice(&bytes[0..288]);
304
305            // Mask away the flag bits
306            tmp[0] &= 0b0011_1111;
307
308            Fp6::from_bytes_unchecked(&tmp)
309        };
310
311        xc1.and_then(|c1| {
312            // c_0^2 = 1 + v * c_1^2
313            let xc0 = (Fp6::one() + c1.square().mul_by_nonresidue()).sqrt();
314
315            xc0.and_then(|c0| {
316                let p = Fp12 {
317                    c0: Fp6::conditional_select(
318                        &c0,
319                        &-c0,
320                        c0.lexicographically_largest() ^ sort_flag_set,
321                    ),
322                    c1,
323                };
324
325                CtOption::new(Gt(p), compression_flag_set)
326            })
327        })
328    }
329}
330
331impl<'a> Neg for &'a Gt {
332    type Output = Gt;
333
334    #[inline]
335    fn neg(self) -> Gt {
336        // The element is unitary, so we just conjugate.
337        Gt(self.0.conjugate())
338    }
339}
340
341impl Neg for Gt {
342    type Output = Gt;
343
344    #[inline]
345    fn neg(self) -> Gt {
346        -&self
347    }
348}
349
350impl<'a, 'b> Add<&'b Gt> for &'a Gt {
351    type Output = Gt;
352
353    #[inline]
354    fn add(self, rhs: &'b Gt) -> Gt {
355        Gt(self.0 * rhs.0)
356    }
357}
358
359impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
360    type Output = Gt;
361
362    #[inline]
363    fn sub(self, rhs: &'b Gt) -> Gt {
364        self + (-rhs)
365    }
366}
367
368impl<'a, 'b> Mul<&'b Scalar> for &'a Gt {
369    type Output = Gt;
370
371    fn mul(self, other: &'b Scalar) -> Self::Output {
372        let mut acc = Gt::identity();
373
374        // This is a simple double-and-add implementation of group element
375        // multiplication, moving from most significant to least
376        // significant bit of the scalar.
377        //
378        // We skip the leading bit because it's always unset for Fq
379        // elements.
380        for bit in other
381            .to_bytes()
382            .iter()
383            .rev()
384            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
385            .skip(1)
386        {
387            acc = acc.double();
388            acc = Gt::conditional_select(&acc, &(acc + self), bit);
389        }
390
391        acc
392    }
393}
394
395impl_binops_additive!(Gt, Gt);
396impl_binops_multiplicative!(Gt, Scalar);
397
398impl<T> Sum<T> for Gt
399where
400    T: Borrow<Gt>,
401{
402    fn sum<I>(iter: I) -> Self
403    where
404        I: Iterator<Item = T>,
405    {
406        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
407    }
408}
409
410impl Group for Gt {
411    type Scalar = Scalar;
412
413    fn random(mut rng: impl RngCore) -> Self {
414        loop {
415            let inner = Fp12::random(&mut rng);
416
417            // Not all elements of Fp12 are elements of the prime-order multiplicative
418            // subgroup. We run the random element through final_exponentiation to obtain
419            // a valid element, which requires that it is non-zero.
420            if !bool::from(inner.is_zero()) {
421                return MillerLoopResult(inner).final_exponentiation();
422            }
423        }
424    }
425
426    fn identity() -> Self {
427        Self::identity()
428    }
429
430    fn generator() -> Self {
431        // pairing(&G1Affine::generator(), &G2Affine::generator())
432        Gt(Fp12 {
433            c0: Fp6 {
434                c0: Fp2 {
435                    c0: Fp::from_raw_unchecked([
436                        0x1972_e433_a01f_85c5,
437                        0x97d3_2b76_fd77_2538,
438                        0xc8ce_546f_c96b_cdf9,
439                        0xcef6_3e73_66d4_0614,
440                        0xa611_3427_8184_3780,
441                        0x13f3_448a_3fc6_d825,
442                    ]),
443                    c1: Fp::from_raw_unchecked([
444                        0xd263_31b0_2e9d_6995,
445                        0x9d68_a482_f779_7e7d,
446                        0x9c9b_2924_8d39_ea92,
447                        0xf480_1ca2_e131_07aa,
448                        0xa16c_0732_bdbc_b066,
449                        0x083c_a4af_ba36_0478,
450                    ]),
451                },
452                c1: Fp2 {
453                    c0: Fp::from_raw_unchecked([
454                        0x59e2_61db_0916_b641,
455                        0x2716_b6f4_b23e_960d,
456                        0xc8e5_5b10_a0bd_9c45,
457                        0x0bdb_0bd9_9c4d_eda8,
458                        0x8cf8_9ebf_57fd_aac5,
459                        0x12d6_b792_9e77_7a5e,
460                    ]),
461                    c1: Fp::from_raw_unchecked([
462                        0x5fc8_5188_b0e1_5f35,
463                        0x34a0_6e3a_8f09_6365,
464                        0xdb31_26a6_e02a_d62c,
465                        0xfc6f_5aa9_7d9a_990b,
466                        0xa12f_55f5_eb89_c210,
467                        0x1723_703a_926f_8889,
468                    ]),
469                },
470                c2: Fp2 {
471                    c0: Fp::from_raw_unchecked([
472                        0x9358_8f29_7182_8778,
473                        0x43f6_5b86_11ab_7585,
474                        0x3183_aaf5_ec27_9fdf,
475                        0xfa73_d7e1_8ac9_9df6,
476                        0x64e1_76a6_a64c_99b0,
477                        0x179f_a78c_5838_8f1f,
478                    ]),
479                    c1: Fp::from_raw_unchecked([
480                        0x672a_0a11_ca2a_ef12,
481                        0x0d11_b9b5_2aa3_f16b,
482                        0xa444_12d0_699d_056e,
483                        0xc01d_0177_221a_5ba5,
484                        0x66e0_cede_6c73_5529,
485                        0x05f5_a71e_9fdd_c339,
486                    ]),
487                },
488            },
489            c1: Fp6 {
490                c0: Fp2 {
491                    c0: Fp::from_raw_unchecked([
492                        0xd30a_88a1_b062_c679,
493                        0x5ac5_6a5d_35fc_8304,
494                        0xd0c8_34a6_a81f_290d,
495                        0xcd54_30c2_da37_07c7,
496                        0xf0c2_7ff7_8050_0af0,
497                        0x0924_5da6_e2d7_2eae,
498                    ]),
499                    c1: Fp::from_raw_unchecked([
500                        0x9f2e_0676_791b_5156,
501                        0xe2d1_c823_4918_fe13,
502                        0x4c9e_459f_3c56_1bf4,
503                        0xa3e8_5e53_b9d3_e3c1,
504                        0x820a_121e_21a7_0020,
505                        0x15af_6183_41c5_9acc,
506                    ]),
507                },
508                c1: Fp2 {
509                    c0: Fp::from_raw_unchecked([
510                        0x7c95_658c_2499_3ab1,
511                        0x73eb_3872_1ca8_86b9,
512                        0x5256_d749_4774_34bc,
513                        0x8ba4_1902_ea50_4a8b,
514                        0x04a3_d3f8_0c86_ce6d,
515                        0x18a6_4a87_fb68_6eaa,
516                    ]),
517                    c1: Fp::from_raw_unchecked([
518                        0xbb83_e71b_b920_cf26,
519                        0x2a52_77ac_92a7_3945,
520                        0xfc0e_e59f_94f0_46a0,
521                        0x7158_cdf3_7860_58f7,
522                        0x7cc1_061b_82f9_45f6,
523                        0x03f8_47aa_9fdb_e567,
524                    ]),
525                },
526                c2: Fp2 {
527                    c0: Fp::from_raw_unchecked([
528                        0x8078_dba5_6134_e657,
529                        0x1cd7_ec9a_4399_8a6e,
530                        0xb1aa_599a_1a99_3766,
531                        0xc9a0_f62f_0842_ee44,
532                        0x8e15_9be3_b605_dffa,
533                        0x0c86_ba0d_4af1_3fc2,
534                    ]),
535                    c1: Fp::from_raw_unchecked([
536                        0xe80f_f2a0_6a52_ffb1,
537                        0x7694_ca48_721a_906c,
538                        0x7583_183e_03b0_8514,
539                        0xf567_afdd_40ce_e4e2,
540                        0x9a6d_96d2_e526_a5fc,
541                        0x197e_9f49_861f_2242,
542                    ]),
543                },
544            },
545        })
546    }
547
548    fn is_identity(&self) -> Choice {
549        self.ct_eq(&Self::identity())
550    }
551
552    #[must_use]
553    fn double(&self) -> Self {
554        self.double()
555    }
556}
557
558#[cfg(feature = "alloc")]
559#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))]
560#[derive(Clone, Debug)]
561/// This structure contains cached computations pertaining to a $\mathbb{G}_2$
562/// element as part of the pairing function (specifically, the Miller loop) and
563/// so should be computed whenever a $\mathbb{G}_2$ element is being used in
564/// multiple pairings or is otherwise known in advance. This should be used in
565/// conjunction with the [`multi_miller_loop`](crate::multi_miller_loop)
566/// function provided by this crate.
567///
568/// Requires the `alloc` and `pairing` crate features to be enabled.
569pub struct G2Prepared {
570    infinity: Choice,
571    coeffs: Vec<(Fp2, Fp2, Fp2)>,
572}
573
574#[cfg(feature = "alloc")]
575impl From<G2Affine> for G2Prepared {
576    fn from(q: G2Affine) -> G2Prepared {
577        struct Adder {
578            cur: G2Projective,
579            base: G2Affine,
580            coeffs: Vec<(Fp2, Fp2, Fp2)>,
581        }
582
583        impl MillerLoopDriver for Adder {
584            type Output = ();
585
586            fn doubling_step(&mut self, _: Self::Output) -> Self::Output {
587                let coeffs = doubling_step(&mut self.cur);
588                self.coeffs.push(coeffs);
589            }
590            fn addition_step(&mut self, _: Self::Output) -> Self::Output {
591                let coeffs = addition_step(&mut self.cur, &self.base);
592                self.coeffs.push(coeffs);
593            }
594            fn square_output(_: Self::Output) -> Self::Output {}
595            fn conjugate(_: Self::Output) -> Self::Output {}
596            fn one() -> Self::Output {}
597        }
598
599        let is_identity = q.is_identity();
600        let q = G2Affine::conditional_select(&q, &G2Affine::generator(), is_identity);
601
602        let mut adder = Adder {
603            cur: G2Projective::from(q),
604            base: q,
605            coeffs: Vec::with_capacity(68),
606        };
607
608        miller_loop(&mut adder);
609
610        assert_eq!(adder.coeffs.len(), 68);
611
612        G2Prepared {
613            infinity: is_identity,
614            coeffs: adder.coeffs,
615        }
616    }
617}
618
619#[cfg(feature = "alloc")]
620#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))]
621/// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms
622/// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$
623///
624/// Requires the `alloc` and `pairing` crate features to be enabled.
625pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult {
626    struct Adder<'a, 'b, 'c> {
627        terms: &'c [(&'a G1Affine, &'b G2Prepared)],
628        index: usize,
629    }
630
631    impl<'a, 'b, 'c> MillerLoopDriver for Adder<'a, 'b, 'c> {
632        type Output = Fp12;
633
634        fn doubling_step(&mut self, mut f: Self::Output) -> Self::Output {
635            let index = self.index;
636            for term in self.terms {
637                let either_identity = term.0.is_identity() | term.1.infinity;
638
639                let new_f = ell(f, &term.1.coeffs[index], term.0);
640                f = Fp12::conditional_select(&new_f, &f, either_identity);
641            }
642            self.index += 1;
643
644            f
645        }
646        fn addition_step(&mut self, mut f: Self::Output) -> Self::Output {
647            let index = self.index;
648            for term in self.terms {
649                let either_identity = term.0.is_identity() | term.1.infinity;
650
651                let new_f = ell(f, &term.1.coeffs[index], term.0);
652                f = Fp12::conditional_select(&new_f, &f, either_identity);
653            }
654            self.index += 1;
655
656            f
657        }
658        fn square_output(f: Self::Output) -> Self::Output {
659            f.square()
660        }
661        fn conjugate(f: Self::Output) -> Self::Output {
662            f.conjugate()
663        }
664        fn one() -> Self::Output {
665            Fp12::one()
666        }
667    }
668
669    let mut adder = Adder { terms, index: 0 };
670
671    let tmp = miller_loop(&mut adder);
672
673    MillerLoopResult(tmp)
674}
675
676/// Invoke the pairing function without the use of precomputation and other optimizations.
677#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
678pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt {
679    struct Adder {
680        cur: G2Projective,
681        base: G2Affine,
682        p: G1Affine,
683    }
684
685    impl MillerLoopDriver for Adder {
686        type Output = Fp12;
687
688        fn doubling_step(&mut self, f: Self::Output) -> Self::Output {
689            let coeffs = doubling_step(&mut self.cur);
690            ell(f, &coeffs, &self.p)
691        }
692        fn addition_step(&mut self, f: Self::Output) -> Self::Output {
693            let coeffs = addition_step(&mut self.cur, &self.base);
694            ell(f, &coeffs, &self.p)
695        }
696        fn square_output(f: Self::Output) -> Self::Output {
697            f.square()
698        }
699        fn conjugate(f: Self::Output) -> Self::Output {
700            f.conjugate()
701        }
702        fn one() -> Self::Output {
703            Fp12::one()
704        }
705    }
706
707    let either_identity = p.is_identity() | q.is_identity();
708    let p = G1Affine::conditional_select(p, &G1Affine::generator(), either_identity);
709    let q = G2Affine::conditional_select(q, &G2Affine::generator(), either_identity);
710
711    let mut adder = Adder {
712        cur: G2Projective::from(q),
713        base: q,
714        p,
715    };
716
717    let tmp = miller_loop(&mut adder);
718    let tmp = MillerLoopResult(Fp12::conditional_select(
719        &tmp,
720        &Fp12::one(),
721        either_identity,
722    ));
723    tmp.final_exponentiation()
724}
725
726trait MillerLoopDriver {
727    type Output;
728
729    fn doubling_step(&mut self, f: Self::Output) -> Self::Output;
730    fn addition_step(&mut self, f: Self::Output) -> Self::Output;
731    fn square_output(f: Self::Output) -> Self::Output;
732    fn conjugate(f: Self::Output) -> Self::Output;
733    fn one() -> Self::Output;
734}
735
736/// This is a "generic" implementation of the Miller loop to avoid duplicating code
737/// structure elsewhere; instead, we'll write concrete instantiations of
738/// `MillerLoopDriver` for whatever purposes we need (such as caching modes).
739fn miller_loop<D: MillerLoopDriver>(driver: &mut D) -> D::Output {
740    let mut f = D::one();
741
742    let mut found_one = false;
743    for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
744        if !found_one {
745            found_one = i;
746            continue;
747        }
748
749        f = driver.doubling_step(f);
750
751        if i {
752            f = driver.addition_step(f);
753        }
754
755        f = D::square_output(f);
756    }
757
758    f = driver.doubling_step(f);
759
760    if BLS_X_IS_NEGATIVE {
761        f = D::conjugate(f);
762    }
763
764    f
765}
766
767fn ell(f: Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 {
768    let mut c0 = coeffs.0;
769    let mut c1 = coeffs.1;
770
771    c0.c0 *= p.y;
772    c0.c1 *= p.y;
773
774    c1.c0 *= p.x;
775    c1.c1 *= p.x;
776
777    f.mul_by_014(&coeffs.2, &c1, &c0)
778}
779
780fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) {
781    // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
782    let tmp0 = r.x.square();
783    let tmp1 = r.y.square();
784    let tmp2 = tmp1.square();
785    let tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2;
786    let tmp3 = tmp3 + tmp3;
787    let tmp4 = tmp0 + tmp0 + tmp0;
788    let tmp6 = r.x + tmp4;
789    let tmp5 = tmp4.square();
790    let zsquared = r.z.square();
791    r.x = tmp5 - tmp3 - tmp3;
792    r.z = (r.z + r.y).square() - tmp1 - zsquared;
793    r.y = (tmp3 - r.x) * tmp4;
794    let tmp2 = tmp2 + tmp2;
795    let tmp2 = tmp2 + tmp2;
796    let tmp2 = tmp2 + tmp2;
797    r.y -= tmp2;
798    let tmp3 = tmp4 * zsquared;
799    let tmp3 = tmp3 + tmp3;
800    let tmp3 = -tmp3;
801    let tmp6 = tmp6.square() - tmp0 - tmp5;
802    let tmp1 = tmp1 + tmp1;
803    let tmp1 = tmp1 + tmp1;
804    let tmp6 = tmp6 - tmp1;
805    let tmp0 = r.z * zsquared;
806    let tmp0 = tmp0 + tmp0;
807
808    (tmp0, tmp3, tmp6)
809}
810
811fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
812    // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
813    let zsquared = r.z.square();
814    let ysquared = q.y.square();
815    let t0 = zsquared * q.x;
816    let t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared;
817    let t2 = t0 - r.x;
818    let t3 = t2.square();
819    let t4 = t3 + t3;
820    let t4 = t4 + t4;
821    let t5 = t4 * t2;
822    let t6 = t1 - r.y - r.y;
823    let t9 = t6 * q.x;
824    let t7 = t4 * r.x;
825    r.x = t6.square() - t5 - t7 - t7;
826    r.z = (r.z + t2).square() - zsquared - t3;
827    let t10 = q.y + r.z;
828    let t8 = (t7 - r.x) * t6;
829    let t0 = r.y * t5;
830    let t0 = t0 + t0;
831    r.y = t8 - t0;
832    let t10 = t10.square() - ysquared;
833    let ztsquared = r.z.square();
834    let t10 = t10 - ztsquared;
835    let t9 = t9 + t9 - t10;
836    let t10 = r.z + r.z;
837    let t6 = -t6;
838    let t1 = t6 + t6;
839
840    (t10, t1, t9)
841}
842
843impl PairingCurveAffine for G1Affine {
844    type Pair = G2Affine;
845    type PairingResult = Gt;
846
847    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
848        pairing(self, other)
849    }
850}
851
852impl PairingCurveAffine for G2Affine {
853    type Pair = G1Affine;
854    type PairingResult = Gt;
855
856    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
857        pairing(other, self)
858    }
859}
860
861/// A [`pairing::Engine`] for BLS12-381 pairing operations.
862#[cfg_attr(docsrs, doc(cfg(feature = "pairings")))]
863#[derive(Clone, Debug)]
864pub struct Bls12;
865
866impl Engine for Bls12 {
867    type Fr = Scalar;
868    type G1 = G1Projective;
869    type G1Affine = G1Affine;
870    type G2 = G2Projective;
871    type G2Affine = G2Affine;
872    type Gt = Gt;
873
874    fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
875        pairing(p, q)
876    }
877}
878
879impl pairing::MillerLoopResult for MillerLoopResult {
880    type Gt = Gt;
881
882    fn final_exponentiation(&self) -> Self::Gt {
883        self.final_exponentiation()
884    }
885}
886
887#[cfg(feature = "alloc")]
888impl MultiMillerLoop for Bls12 {
889    type G2Prepared = G2Prepared;
890    type Result = MillerLoopResult;
891
892    fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
893        multi_miller_loop(terms)
894    }
895}
896
897#[test]
898fn test_gt_generator() {
899    assert_eq!(
900        Gt::generator(),
901        pairing(&G1Affine::generator(), &G2Affine::generator())
902    );
903}
904
905#[test]
906fn test_bilinearity() {
907    use crate::Scalar;
908
909    let a = Scalar::from_raw([1, 2, 3, 4]).invert().unwrap().square();
910    let b = Scalar::from_raw([5, 6, 7, 8]).invert().unwrap().square();
911    let c = a * b;
912
913    let g = G1Affine::from(G1Affine::generator() * a);
914    let h = G2Affine::from(G2Affine::generator() * b);
915    let p = pairing(&g, &h);
916
917    assert!(p != Gt::identity());
918
919    let expected = G1Affine::from(G1Affine::generator() * c);
920
921    assert_eq!(p, pairing(&expected, &G2Affine::generator()));
922    assert_eq!(
923        p,
924        pairing(&G1Affine::generator(), &G2Affine::generator()) * c
925    );
926}
927
928#[test]
929fn test_unitary() {
930    let g = G1Affine::generator();
931    let h = G2Affine::generator();
932    let p = -pairing(&g, &h);
933    let q = pairing(&g, &-h);
934    let r = pairing(&-g, &h);
935
936    assert_eq!(p, q);
937    assert_eq!(q, r);
938}
939
940#[cfg(feature = "alloc")]
941#[test]
942fn test_multi_miller_loop() {
943    let a1 = G1Affine::generator();
944    let b1 = G2Affine::generator();
945
946    let a2 = G1Affine::from(
947        G1Affine::generator() * Scalar::from_raw([1, 2, 3, 4]).invert().unwrap().square(),
948    );
949    let b2 = G2Affine::from(
950        G2Affine::generator() * Scalar::from_raw([4, 2, 2, 4]).invert().unwrap().square(),
951    );
952
953    let a3 = G1Affine::identity();
954    let b3 = G2Affine::from(
955        G2Affine::generator() * Scalar::from_raw([9, 2, 2, 4]).invert().unwrap().square(),
956    );
957
958    let a4 = G1Affine::from(
959        G1Affine::generator() * Scalar::from_raw([5, 5, 5, 5]).invert().unwrap().square(),
960    );
961    let b4 = G2Affine::identity();
962
963    let a5 = G1Affine::from(
964        G1Affine::generator() * Scalar::from_raw([323, 32, 3, 1]).invert().unwrap().square(),
965    );
966    let b5 = G2Affine::from(
967        G2Affine::generator() * Scalar::from_raw([4, 2, 2, 9099]).invert().unwrap().square(),
968    );
969
970    let b1_prepared = G2Prepared::from(b1);
971    let b2_prepared = G2Prepared::from(b2);
972    let b3_prepared = G2Prepared::from(b3);
973    let b4_prepared = G2Prepared::from(b4);
974    let b5_prepared = G2Prepared::from(b5);
975
976    let expected = pairing(&a1, &b1)
977        + pairing(&a2, &b2)
978        + pairing(&a3, &b3)
979        + pairing(&a4, &b4)
980        + pairing(&a5, &b5);
981
982    let test = multi_miller_loop(&[
983        (&a1, &b1_prepared),
984        (&a2, &b2_prepared),
985        (&a3, &b3_prepared),
986        (&a4, &b4_prepared),
987        (&a5, &b5_prepared),
988    ])
989    .final_exponentiation();
990
991    assert_eq!(expected, test);
992}
993
994#[test]
995fn test_miller_loop_result_default() {
996    assert_eq!(
997        MillerLoopResult::default().final_exponentiation(),
998        Gt::identity(),
999    );
1000}
1001
1002#[cfg(feature = "zeroize")]
1003#[test]
1004fn test_miller_loop_result_zeroize() {
1005    use zeroize::Zeroize;
1006
1007    let mut m = multi_miller_loop(&[
1008        (&G1Affine::generator(), &G2Affine::generator().into()),
1009        (&-G1Affine::generator(), &G2Affine::generator().into()),
1010    ]);
1011    m.zeroize();
1012    assert_eq!(m.0, MillerLoopResult::default().0);
1013}
1014
1015#[test]
1016fn tricking_miller_loop_result() {
1017    assert_eq!(
1018        multi_miller_loop(&[(&G1Affine::identity(), &G2Affine::generator().into())]).0,
1019        Fp12::one()
1020    );
1021    assert_eq!(
1022        multi_miller_loop(&[(&G1Affine::generator(), &G2Affine::identity().into())]).0,
1023        Fp12::one()
1024    );
1025    assert_ne!(
1026        multi_miller_loop(&[
1027            (&G1Affine::generator(), &G2Affine::generator().into()),
1028            (&-G1Affine::generator(), &G2Affine::generator().into())
1029        ])
1030        .0,
1031        Fp12::one()
1032    );
1033    assert_eq!(
1034        multi_miller_loop(&[
1035            (&G1Affine::generator(), &G2Affine::generator().into()),
1036            (&-G1Affine::generator(), &G2Affine::generator().into())
1037        ])
1038        .final_exponentiation(),
1039        Gt::identity()
1040    );
1041}
1042
1043#[test]
1044fn test_uncompressed() {
1045    let gt =
1046        pairing(&G1Affine::generator(), &G2Affine::generator()) * Scalar::from_raw([1, 2, 3, 4]);
1047    let buf = gt.to_uncompressed();
1048    let gt2 = Gt::from_uncompressed(&buf).unwrap();
1049
1050    assert_eq!(gt, gt2);
1051
1052    let gt =
1053        pairing(&G1Affine::generator(), &G2Affine::generator()) * Scalar::from_raw([1, 2, 3, 5]);
1054    let buf = gt.to_uncompressed();
1055    let gt2 = Gt::from_uncompressed(&buf).unwrap();
1056
1057    assert_eq!(gt, gt2);
1058}
1059
1060#[test]
1061fn test_compressed() {
1062    let gt =
1063        pairing(&G1Affine::generator(), &G2Affine::generator()) * Scalar::from_raw([1, 2, 3, 4]);
1064
1065    let buf = gt.to_compressed();
1066
1067    assert_eq!(buf[0] >> 7 & 1, 1);
1068    assert_eq!(buf[0] >> 6 & 1, 1);
1069
1070    let gt2 = Gt::from_compressed(&buf).unwrap();
1071
1072    assert_eq!(gt, gt2);
1073
1074    let gt = pairing(&G1Affine::generator(), &G2Affine::generator())
1075        * Scalar::from_raw([500001, 2, 3, 4]);
1076
1077    let buf = gt.to_compressed();
1078
1079    assert_eq!(buf[0] >> 7 & 1, 1);
1080    assert_eq!(buf[0] >> 6 & 1, 0);
1081
1082    let gt2 = Gt::from_compressed(&buf).unwrap();
1083
1084    assert_eq!(gt, gt2);
1085}