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#[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 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 #[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 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 z4 = t0 - z4;
88 z4 = z4 + z4 + t0;
89
90 z5 = t1 + z5;
91 z5 = z5 + z5 + t1;
92
93 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 .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#[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 pub fn identity() -> Gt {
251 Gt(Fp12::one())
252 }
253
254 pub fn double(&self) -> Gt {
256 Gt(self.0.square())
257 }
258
259 pub fn to_uncompressed(&self) -> [u8; 576] {
262 self.0.to_bytes()
263 }
264
265 pub fn from_uncompressed(bytes: &[u8; 576]) -> CtOption<Self> {
268 Fp12::from_bytes(bytes).map(Gt)
269 }
270
271 pub fn to_compressed(&self) -> [u8; 288] {
274 let mut res = self.0.c1.to_bytes();
275
276 res[0] |= 1u8 << 7;
278
279 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.0.c0.lexicographically_largest());
283
284 res
285 }
286
287 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 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 tmp[0] &= 0b0011_1111;
307
308 Fp6::from_bytes_unchecked(&tmp)
309 };
310
311 xc1.and_then(|c1| {
312 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 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 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 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 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)]
561pub 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"))))]
621pub 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#[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
736fn 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 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 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#[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}