1#![allow(clippy::suspicious_arithmetic_impl)]
2use crate::ff::{Field, PrimeField};
3use crate::group::cofactor::CofactorCurveAffine;
4use crate::group::Group;
5use crate::pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
6use crate::pluto_eris::curve::*;
7use crate::pluto_eris::fields::fp::*;
8use crate::pluto_eris::fields::fp12::*;
9use crate::pluto_eris::fields::fp2::*;
10use crate::pluto_eris::fields::fp6::FROBENIUS_COEFF_FP6_C1;
11use crate::pluto_eris::fields::fq::*;
12use core::borrow::Borrow;
13use core::iter::Sum;
14use core::ops::{Add, Mul, MulAssign, Neg, Sub};
15use rand_core::RngCore;
16use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
17
18const NEG_PLUTO_U: u128 = 0x4000000000001000008780000000;
21
22const NEG_SIX_U_PLUS_2_NAF: [i8; 114] = [
23 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24 0, 1, 0, -1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25 -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1,
27];
28
29const XI_TO_P_MINUS_1_OVER_2: Fp2 = Fp2 {
31 c0: Fp::from_raw([
32 0x54cf5ad1c0926216,
33 0x186c1f3ce4a46d4e,
34 0x9c23800ce9c9452f,
35 0x50e0d09ff6d6c08b,
36 0x7cf421e4d46f6666,
37 0x678664ba4b6d8343,
38 0x21cc26d5de0f80f4,
39 ]),
40
41 c1: Fp::from_raw([
42 0xc0505f4c260e91f4,
43 0xe7bbd15f10723657,
44 0xb4b3e0c35358097e,
45 0x87c56f42a558750d,
46 0x4b7211d23f34f0ae,
47 0xf6839d29e2f0d250,
48 0x16ebe8b2e12a1106,
49 ]),
50};
51
52impl PairingCurveAffine for G1Affine {
53 type Pair = G2Affine;
54 type PairingResult = Gt;
55
56 fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
57 Pluto::pairing(self, other)
58 }
59}
60
61impl PairingCurveAffine for G2Affine {
62 type Pair = G1Affine;
63 type PairingResult = Gt;
64
65 fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
66 Pluto::pairing(other, self)
67 }
68}
69
70#[derive(Copy, Clone, Debug, Default)]
71pub struct Gt(pub(crate) Fp12);
72
73impl std::fmt::Display for Gt {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "{:?}", self)
76 }
77}
78
79impl ConstantTimeEq for Gt {
80 fn ct_eq(&self, other: &Self) -> Choice {
81 self.0.ct_eq(&other.0)
82 }
83}
84
85impl ConditionallySelectable for Gt {
86 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
87 Gt(Fp12::conditional_select(&a.0, &b.0, choice))
88 }
89}
90
91impl Eq for Gt {}
92impl PartialEq for Gt {
93 #[inline]
94 fn eq(&self, other: &Self) -> bool {
95 bool::from(self.ct_eq(other))
96 }
97}
98
99impl Gt {
100 pub const fn identity() -> Gt {
102 Gt(Fp12::ONE)
103 }
104
105 pub fn double(&self) -> Gt {
107 Gt(self.0.square())
108 }
109}
110
111impl<'a> Neg for &'a Gt {
112 type Output = Gt;
113
114 #[inline]
115 fn neg(self) -> Gt {
116 let mut u = self.0;
118 u.conjugate();
119 Gt(u)
120 }
121}
122
123impl Neg for Gt {
124 type Output = Gt;
125
126 #[inline]
127 fn neg(self) -> Gt {
128 -&self
129 }
130}
131
132impl<'a, 'b> Add<&'b Gt> for &'a Gt {
133 type Output = Gt;
134
135 #[inline]
136 fn add(self, rhs: &'b Gt) -> Gt {
137 Gt(self.0 * rhs.0)
138 }
139}
140
141impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
142 type Output = Gt;
143
144 #[inline]
145 fn sub(self, rhs: &'b Gt) -> Gt {
146 self + (-rhs)
147 }
148}
149
150impl<'a, 'b> Mul<&'b Fq> for &'a Gt {
151 type Output = Gt;
152
153 fn mul(self, other: &'b Fq) -> Self::Output {
154 let mut acc = Gt::identity();
155
156 for bit in other
157 .to_repr()
158 .iter()
159 .rev()
160 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
161 .skip(1)
162 {
163 acc = acc.double();
164 acc = Gt::conditional_select(&acc, &(acc + self), bit);
165 }
166
167 acc
168 }
169}
170
171use crate::{
172 impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
173 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
174};
175impl_binops_additive!(Gt, Gt);
176impl_binops_multiplicative!(Gt, Fq);
177
178impl<T> Sum<T> for Gt
179where
180 T: Borrow<Gt>,
181{
182 fn sum<I>(iter: I) -> Self
183 where
184 I: Iterator<Item = T>,
185 {
186 iter.fold(Self::identity(), |acc, item| acc + item.borrow())
187 }
188}
189
190impl Group for Gt {
191 type Scalar = Fq;
192
193 fn random(_: impl RngCore) -> Self {
194 unimplemented!();
195 }
196
197 fn identity() -> Self {
198 Self::identity()
199 }
200
201 fn generator() -> Self {
202 unimplemented!();
203 }
204
205 fn is_identity(&self) -> Choice {
206 self.ct_eq(&Self::identity())
207 }
208
209 #[must_use]
210 fn double(&self) -> Self {
211 self.double()
212 }
213}
214
215#[derive(Clone, Debug)]
218pub struct G2Prepared {
219 pub(crate) coeffs: Vec<(Fp2, Fp2, Fp2)>,
220 pub(crate) infinity: bool,
221}
222
223impl G2Prepared {
224 pub fn is_zero(&self) -> bool {
226 self.infinity
227 }
228
229 pub fn from_affine(q: G2Affine) -> Self {
231 if bool::from(q.is_identity()) {
232 return G2Prepared {
233 coeffs: vec![],
234 infinity: true,
235 };
236 }
237
238 fn doubling_step(r: &mut G2) -> (Fp2, Fp2, Fp2) {
240 let mut tmp0 = r.x;
241 tmp0.square_assign();
242
243 let mut tmp1 = r.y;
244 tmp1.square_assign();
245
246 let mut tmp2 = tmp1;
247 tmp2.square_assign();
248
249 let mut tmp3 = tmp1;
250 tmp3 += &r.x;
251 tmp3.square_assign();
252 tmp3 -= &tmp0;
253 tmp3 -= &tmp2;
254 tmp3.double_assign();
255
256 let mut tmp4 = tmp0;
257 tmp4.double_assign();
258 tmp4 += &tmp0;
259
260 let mut tmp6 = r.x;
261 tmp6 += &tmp4;
262
263 let mut tmp5 = tmp4;
264 tmp5.square_assign();
265
266 let mut zsquared = r.z;
267 zsquared.square_assign();
268
269 r.x = tmp5;
270 r.x -= &tmp3;
271 r.x -= &tmp3;
272
273 r.z += &r.y;
274 r.z.square_assign();
275 r.z -= &tmp1;
276 r.z -= &zsquared;
277
278 r.y = tmp3;
279 r.y -= &r.x;
280 r.y.mul_assign(&tmp4);
281
282 tmp2.double_assign();
283 tmp2.double_assign();
284 tmp2.double_assign();
285
286 r.y -= &tmp2;
287
288 tmp3 = tmp4;
293 tmp3.mul_assign(&zsquared);
294 tmp3.double_assign();
295 tmp3 = tmp3.neg();
296
297 tmp6.square_assign();
299 tmp6 -= &tmp0;
300 tmp6 -= &tmp5;
301
302 tmp1.double_assign();
303 tmp1.double_assign();
304
305 tmp6 -= &tmp1;
306
307 tmp0 = r.z;
309 tmp0.mul_assign(&zsquared);
310 tmp0.double_assign();
311
312 (tmp0, tmp3, tmp6)
313 }
314
315 fn addition_step(r: &mut G2, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
317 let mut zsquared = r.z;
318 zsquared.square_assign();
319
320 let mut ysquared = q.y;
321 ysquared.square_assign();
322
323 let mut t0 = zsquared;
325 t0.mul_assign(&q.x);
326
327 let mut t1 = q.y;
329 t1 += &r.z;
330 t1.square_assign();
331 t1 -= &ysquared;
332 t1 -= &zsquared;
333 t1.mul_assign(&zsquared);
334
335 let mut t2 = t0;
337 t2 -= &r.x;
338
339 let mut t3 = t2;
341 t3.square_assign();
342
343 let mut t4 = t3;
345 t4.double_assign();
346 t4.double_assign();
347
348 let mut t5 = t4;
350 t5.mul_assign(&t2);
351
352 let mut t6 = t1;
354 t6 -= &r.y;
355 t6 -= &r.y;
356
357 let mut t9 = t6;
359 t9.mul_assign(&q.x);
360
361 let mut t7 = t4;
363 t7.mul_assign(&r.x);
364
365 r.x = t6;
367 r.x.square_assign();
368 r.x -= &t5;
369 r.x -= &t7;
370 r.x -= &t7;
371
372 r.z += &t2;
374 r.z.square_assign();
375 r.z -= &zsquared;
376 r.z -= &t3;
377
378 let mut t10 = q.y;
380 t10 += &r.z;
381
382 let mut t8 = t7;
384 t8 -= &r.x;
385 t8.mul_assign(&t6);
386
387 t0 = r.y;
389 t0.mul_assign(&t5);
390 t0.double_assign();
391
392 r.y = t8;
394 r.y -= &t0;
395
396 t10.square_assign();
398 t10 -= &ysquared;
399
400 let mut ztsquared = r.z;
401 ztsquared.square_assign();
402
403 t10 -= &ztsquared;
404
405 t9.double_assign();
407 t9 -= &t10;
408
409 t10 = r.z;
411 t10.double_assign();
412
413 t6 = t6.neg();
415
416 t1 = t6;
417 t1.double_assign();
418
419 (t10, t1, t9)
421 }
422
423 let mut coeffs = vec![];
424 let mut r: G2 = q.into();
425
426 let mut negq = q;
427 negq = -negq;
428
429 coeffs.push(doubling_step(&mut r));
430
431 let last_position = NEG_SIX_U_PLUS_2_NAF.len() - 2;
432 match NEG_SIX_U_PLUS_2_NAF[last_position] {
433 1 => {
434 coeffs.push(addition_step(&mut r, &q));
435 }
436 -1 => {
437 coeffs.push(addition_step(&mut r, &negq));
438 }
439 _ => (),
440 }
441
442 for i in (0..last_position).rev() {
443 coeffs.push(doubling_step(&mut r));
444
445 match NEG_SIX_U_PLUS_2_NAF[i] {
446 1 => {
447 coeffs.push(addition_step(&mut r, &q));
448 }
449 -1 => {
450 coeffs.push(addition_step(&mut r, &negq));
451 }
452 _ => continue,
453 }
454 }
455
456 let mut neg_r = r;
457 neg_r = -neg_r;
458
459 let mut q1 = q;
460
461 q1.x.c1 = q1.x.c1.neg();
462 q1.x.mul_assign(&FROBENIUS_COEFF_FP6_C1[1]);
463
464 q1.y.c1 = q1.y.c1.neg();
465 q1.y.mul_assign(&XI_TO_P_MINUS_1_OVER_2);
466
467 coeffs.push(addition_step(&mut neg_r, &q1));
468
469 let mut minusq2 = q;
470 minusq2.x.mul_assign(&FROBENIUS_COEFF_FP6_C1[2]);
471
472 coeffs.push(addition_step(&mut neg_r, &minusq2));
473
474 G2Prepared {
475 coeffs,
476 infinity: false,
477 }
478 }
479}
480
481impl From<G2Affine> for G2Prepared {
482 fn from(q: G2Affine) -> G2Prepared {
483 G2Prepared::from_affine(q)
484 }
485}
486
487impl MillerLoopResult for Gt {
488 type Gt = Self;
489 fn final_exponentiation(&self) -> Gt {
490 fn exp_by_x(f: &mut Fp12) {
491 let x = NEG_PLUTO_U;
492 let mut res = Fp12::ONE;
493 for i in (0..111).rev() {
494 res.cyclotomic_square();
495 if ((x >> i) & 1) == 1 {
496 res.mul_assign(f);
497 }
498 }
499 res.conjugate();
500 *f = res;
501 }
502
503 let r = self.0;
504 let mut f1 = self.0;
505 f1.conjugate();
506
507 Gt(r.invert()
508 .map(|mut f2| {
509 let mut r = f1;
510 r.mul_assign(&f2);
511 f2 = r;
512 r.frobenius_map(2);
513 r.mul_assign(&f2);
514
515 let mut fp = r;
516 fp.frobenius_map(1);
517
518 let mut fp2 = r;
519 fp2.frobenius_map(2);
520 let mut fp3 = fp2;
521 fp3.frobenius_map(1);
522
523 let mut fu = r;
524 exp_by_x(&mut fu);
525
526 let mut fu2 = fu;
527 exp_by_x(&mut fu2);
528
529 let mut fu3 = fu2;
530 exp_by_x(&mut fu3);
531
532 let mut y3 = fu;
533 y3.frobenius_map(1);
534
535 let mut fu2p = fu2;
536 fu2p.frobenius_map(1);
537
538 let mut fu3p = fu3;
539 fu3p.frobenius_map(1);
540
541 let mut y2 = fu2;
542 y2.frobenius_map(2);
543
544 let mut y0 = fp;
545 y0.mul_assign(&fp2);
546 y0.mul_assign(&fp3);
547
548 let mut y1 = r;
549 y1.conjugate();
550
551 let mut y5 = fu2;
552 y5.conjugate();
553
554 y3.conjugate();
555
556 let mut y4 = fu;
557 y4.mul_assign(&fu2p);
558 y4.conjugate();
559
560 let mut y6 = fu3;
561 y6.mul_assign(&fu3p);
562 y6.conjugate();
563
564 y6.cyclotomic_square();
565 y6.mul_assign(&y4);
566 y6.mul_assign(&y5);
567
568 let mut t1 = y3;
569 t1.mul_assign(&y5);
570 t1.mul_assign(&y6);
571
572 y6.mul_assign(&y2);
573
574 t1.cyclotomic_square();
575 t1.mul_assign(&y6);
576 t1.cyclotomic_square();
577
578 let mut t0 = t1;
579 t0.mul_assign(&y1);
580
581 t1.mul_assign(&y0);
582
583 t0.cyclotomic_square();
584 t0.mul_assign(&t1);
585
586 t0
587 })
588 .unwrap())
589 }
590}
591impl MultiMillerLoop for Pluto {
592 type G2Prepared = G2Prepared;
594
595 type Result = Gt;
597 fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> Self::Result {
598 let mut pairs = vec![];
599 for &(p, q) in terms {
600 if !bool::from(p.is_identity()) && !q.is_zero() {
601 pairs.push((p, q.coeffs.iter()));
602 }
603 }
604
605 fn ell(f: &mut Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) {
607 let mut c0 = coeffs.0;
608 let mut c1 = coeffs.1;
609
610 c0.c0.mul_assign(&p.y);
611 c0.c1.mul_assign(&p.y);
612
613 c1.c0.mul_assign(&p.x);
614 c1.c1.mul_assign(&p.x);
615
616 f.mul_by_034(&c0, &c1, &coeffs.2);
618 }
619
620 let mut f = Fp12::ONE;
621
622 for &mut (p, ref mut coeffs) in &mut pairs {
623 ell(&mut f, coeffs.next().unwrap(), p);
624 }
625
626 let len_min2 = NEG_SIX_U_PLUS_2_NAF.len() - 2;
628
629 if NEG_SIX_U_PLUS_2_NAF[len_min2] != 0 {
630 for &mut (p, ref mut coeffs) in &mut pairs {
631 ell(&mut f, coeffs.next().unwrap(), p);
632 }
633 }
634
635 for x in NEG_SIX_U_PLUS_2_NAF[..len_min2].iter().rev() {
636 f.square_assign();
637
638 for &mut (p, ref mut coeffs) in &mut pairs {
639 ell(&mut f, coeffs.next().unwrap(), p);
640 }
641 if *x != 0 {
642 for &mut (p, ref mut coeffs) in &mut pairs {
643 ell(&mut f, coeffs.next().unwrap(), p);
644 }
645 }
646 }
647
648 f.conjugate();
649
650 for &mut (p, ref mut coeffs) in &mut pairs {
651 ell(&mut f, coeffs.next().unwrap(), p);
652 }
653
654 for &mut (p, ref mut coeffs) in &mut pairs {
655 ell(&mut f, coeffs.next().unwrap(), p);
656 }
657
658 for &mut (_p, ref mut coeffs) in &mut pairs {
659 assert_eq!(coeffs.next(), None);
660 }
661
662 Gt(f)
663 }
664}
665
666#[derive(Clone, Debug)]
668pub struct Pluto;
669
670impl Engine for Pluto {
671 type Fr = Fq;
672 type G1 = G1;
673 type G1Affine = G1Affine;
674 type G2 = G2;
675 type G2Affine = G2Affine;
676 type Gt = Gt;
677
678 fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
679 let q = G2Prepared::from_affine(*q);
680 let terms: &[(&G1Affine, &G2Prepared)] = &[(p, &q)];
681 let u = Self::multi_miller_loop(terms);
682 u.final_exponentiation()
683 }
684}
685
686#[cfg(test)]
687use rand::SeedableRng;
688#[cfg(test)]
689use rand_xorshift::XorShiftRng;
690
691#[test]
692fn test_pairing() {
693 let g1 = G1::generator();
694 let mut g2 = G2::generator();
695 g2 = g2.double();
696 let pair12 = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
697
698 let mut g1 = G1::generator();
699 let g2 = G2::generator();
700 g1 = g1.double();
701 let pair21 = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
702
703 assert_eq!(pair12, pair21);
704
705 let g1 = G1::generator();
706 let mut g2 = G2::generator();
707 g2 = g2.double().double();
708 let pair12 = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
709
710 let mut g1 = G1::generator();
711 let mut g2 = G2::generator();
712 g1 = g1.double();
713 g2 = g2.double();
714 let pair21 = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
715
716 assert_eq!(pair12, pair21);
717
718 let mut rng = XorShiftRng::from_seed([
719 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
720 0xe5,
721 ]);
722 for _ in 0..100 {
723 let a = Fq::random(&mut rng);
724 let b = Fq::random(&mut rng);
725
726 let mut g1 = G1::generator();
727 g1.mul_assign(a);
728
729 let mut g2 = G2::generator();
730 g1.mul_assign(b);
731
732 let pair_ab = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
733
734 g1 = G1::generator();
735 g1.mul_assign(b);
736
737 g2 = G2::generator();
738 g1.mul_assign(a);
739
740 let pair_ba = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
741
742 assert_eq!(pair_ab, pair_ba);
743 }
744}
745
746#[test]
747fn tricking_miller_loop_result() {
748 assert_eq!(
749 Pluto::multi_miller_loop(&[(&G1Affine::identity(), &G2Affine::generator().into())]).0,
750 Fp12::one()
751 );
752 assert_eq!(
753 Pluto::multi_miller_loop(&[(&G1Affine::generator(), &G2Affine::identity().into())]).0,
754 Fp12::one()
755 );
756 assert_ne!(
757 Pluto::multi_miller_loop(&[
758 (&G1Affine::generator(), &G2Affine::generator().into()),
759 (&-G1Affine::generator(), &G2Affine::generator().into())
760 ])
761 .0,
762 Fp12::one()
763 );
764 assert_eq!(
765 Pluto::multi_miller_loop(&[
766 (&G1Affine::generator(), &G2Affine::generator().into()),
767 (&-G1Affine::generator(), &G2Affine::generator().into())
768 ])
769 .final_exponentiation(),
770 Gt::identity()
771 );
772}
773
774#[test]
775fn random_bilinearity_tests() {
776 let mut rng = XorShiftRng::from_seed([
777 0x55, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
778 0xe5,
779 ]);
780
781 for _ in 0..10 {
782 let mut a = G1::generator();
783 let ka = Fq::random(&mut rng);
784 a.mul_assign(ka);
785
786 let mut b = G2::generator();
787 let kb = Fq::random(&mut rng);
788 b.mul_assign(kb);
789
790 let c = Fq::random(&mut rng);
791 let d = Fq::random(&mut rng);
792
793 let mut ac = a;
794 ac.mul_assign(c);
795
796 let mut ad = a;
797 ad.mul_assign(d);
798
799 let mut bc = b;
800 bc.mul_assign(c);
801
802 let mut bd = b;
803 bd.mul_assign(d);
804
805 let acbd = Pluto::pairing(&G1Affine::from(ac), &G2Affine::from(bd));
806 let adbc = Pluto::pairing(&G1Affine::from(ad), &G2Affine::from(bc));
807
808 let mut cd = c;
809 cd.mul_assign(&d);
810
811 cd *= Fq([1, 0, 0, 0, 0, 0, 0]);
812
813 let abcd = Gt(Pluto::pairing(&G1Affine::from(a), &G2Affine::from(b))
814 .0
815 .pow_vartime(cd.0));
816
817 assert_eq!(acbd, adbc);
818 assert_eq!(acbd, abcd);
819 }
820}
821
822#[test]
823pub fn engine_tests() {
824 let mut rng = XorShiftRng::from_seed([
825 0x56, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
826 0xe5,
827 ]);
828
829 for _ in 0..10 {
830 let a = G1Affine::from(G1::random(&mut rng));
831 let b = G2Affine::from(G2::random(&mut rng));
832
833 assert!(a.pairing_with(&b) == b.pairing_with(&a));
834 assert!(a.pairing_with(&b) == Pluto::pairing(&a, &b));
835 }
836
837 for _ in 0..10 {
838 let z1 = G1Affine::identity();
839 let z2 = G2Prepared::from(G2Affine::identity());
840
841 let a = G1Affine::from(G1::random(&mut rng));
842 let b = G2Prepared::from(G2Affine::from(G2::random(&mut rng)));
843 let c = G1Affine::from(G1::random(&mut rng));
844 let d = G2Prepared::from(G2Affine::from(G2::random(&mut rng)));
845
846 assert_eq!(
847 Fp12::ONE,
848 Pluto::multi_miller_loop(&[(&z1, &b)])
849 .final_exponentiation()
850 .0,
851 );
852
853 assert_eq!(
854 Fp12::ONE,
855 Pluto::multi_miller_loop(&[(&a, &z2)])
856 .final_exponentiation()
857 .0,
858 );
859
860 assert_eq!(
861 Pluto::multi_miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(),
862 Pluto::multi_miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation(),
863 );
864
865 assert_eq!(
866 Pluto::multi_miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(),
867 Pluto::multi_miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation(),
868 );
869 }
870}
871
872#[test]
873fn random_miller_loop_tests() {
874 let mut rng = XorShiftRng::from_seed([
875 0x58, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
876 0xe5,
877 ]);
878
879 for _ in 0..10 {
881 let a = G1Affine::from(G1::random(&mut rng));
882 let b = G2Affine::from(G2::random(&mut rng));
883 let c = G1Affine::from(G1::random(&mut rng));
884 let d = G2Affine::from(G2::random(&mut rng));
885
886 let ab = Pluto::pairing(&a, &b);
887 let cd = Pluto::pairing(&c, &d);
888
889 let mut abcd = ab;
890 abcd = Gt(abcd.0 * cd.0);
891
892 let b = G2Prepared::from(b);
893 let d = G2Prepared::from(d);
894
895 let abcd_with_double_loop =
896 Pluto::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();
897
898 assert_eq!(abcd, abcd_with_double_loop);
899 }
900}
901
902#[test]
903pub fn multi_miller_final_exp_tests() {
904 let g1 = G1::generator();
905 let g2 = G2::generator();
906
907 let mut rng = XorShiftRng::from_seed([
908 0x56, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
909 0xe5,
910 ]);
911
912 for _ in 0..10 {
913 let s = Fq::random(&mut rng);
914
915 let mut s_g1 = g1;
916 s_g1.mul_assign(s);
917
918 let mut s_g2 = g2;
919 s_g2.mul_assign(s);
920
921 let s_g2_prepared = G2Prepared::from(G2Affine::from(s_g2));
922 let g2_prepared = G2Prepared::from(G2Affine::from(g2));
923
924 let (term_1, term_2) = (
925 (&G1Affine::from(g1), &s_g2_prepared),
926 (&-G1Affine::from(s_g1), &g2_prepared),
927 );
928
929 let terms = &[term_1, term_2];
930
931 assert!(
932 bool::from(
933 Pluto::multi_miller_loop(&terms[..])
934 .final_exponentiation()
935 .is_identity(),
936 ),
937 "trivial pairing check failed"
938 );
939
940 let lhs = Pluto::pairing(&G1Affine::from(g1), &G2Affine::from(s_g2));
941 let rhs = Pluto::pairing(&G1Affine::from(s_g1), &G2Affine::from(g2));
942
943 assert_eq!(lhs, rhs, "failed trivial check");
944 }
945}