1use core::borrow::Borrow;
4use core::fmt;
5use core::iter::Sum;
6use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use group::{
8 prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
9 Curve, Group, GroupEncoding, UncompressedEncoding,
10};
11use rand_core::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
13
14#[cfg(feature = "alloc")]
15use group::WnafGroup;
16
17use crate::fp::Fp;
18use crate::fp2::Fp2;
19use crate::Scalar;
20
21#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
28#[derive(Copy, Clone, Debug)]
29pub struct G2Affine {
30 pub(crate) x: Fp2,
31 pub(crate) y: Fp2,
32 infinity: Choice,
33}
34
35impl Default for G2Affine {
36 fn default() -> G2Affine {
37 G2Affine::identity()
38 }
39}
40
41#[cfg(feature = "zeroize")]
42impl zeroize::DefaultIsZeroes for G2Affine {}
43
44impl fmt::Display for G2Affine {
45 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46 write!(f, "{:?}", self)
47 }
48}
49
50impl<'a> From<&'a G2Projective> for G2Affine {
51 fn from(p: &'a G2Projective) -> G2Affine {
52 let zinv = p.z.invert().unwrap_or(Fp2::zero());
53 let x = p.x * zinv;
54 let y = p.y * zinv;
55
56 let tmp = G2Affine {
57 x,
58 y,
59 infinity: Choice::from(0u8),
60 };
61
62 G2Affine::conditional_select(&tmp, &G2Affine::identity(), zinv.is_zero())
63 }
64}
65
66impl From<G2Projective> for G2Affine {
67 fn from(p: G2Projective) -> G2Affine {
68 G2Affine::from(&p)
69 }
70}
71
72impl ConstantTimeEq for G2Affine {
73 fn ct_eq(&self, other: &Self) -> Choice {
74 (self.infinity & other.infinity)
79 | ((!self.infinity)
80 & (!other.infinity)
81 & self.x.ct_eq(&other.x)
82 & self.y.ct_eq(&other.y))
83 }
84}
85
86impl ConditionallySelectable for G2Affine {
87 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
88 G2Affine {
89 x: Fp2::conditional_select(&a.x, &b.x, choice),
90 y: Fp2::conditional_select(&a.y, &b.y, choice),
91 infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
92 }
93 }
94}
95
96impl Eq for G2Affine {}
97impl PartialEq for G2Affine {
98 #[inline]
99 fn eq(&self, other: &Self) -> bool {
100 bool::from(self.ct_eq(other))
101 }
102}
103
104impl<'a> Neg for &'a G2Affine {
105 type Output = G2Affine;
106
107 #[inline]
108 fn neg(self) -> G2Affine {
109 G2Affine {
110 x: self.x,
111 y: Fp2::conditional_select(&-self.y, &Fp2::one(), self.infinity),
112 infinity: self.infinity,
113 }
114 }
115}
116
117impl Neg for G2Affine {
118 type Output = G2Affine;
119
120 #[inline]
121 fn neg(self) -> G2Affine {
122 -&self
123 }
124}
125
126impl<'a, 'b> Add<&'b G2Projective> for &'a G2Affine {
127 type Output = G2Projective;
128
129 #[inline]
130 fn add(self, rhs: &'b G2Projective) -> G2Projective {
131 rhs.add_mixed(self)
132 }
133}
134
135impl<'a, 'b> Add<&'b G2Affine> for &'a G2Projective {
136 type Output = G2Projective;
137
138 #[inline]
139 fn add(self, rhs: &'b G2Affine) -> G2Projective {
140 self.add_mixed(rhs)
141 }
142}
143
144impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Affine {
145 type Output = G2Projective;
146
147 #[inline]
148 fn sub(self, rhs: &'b G2Projective) -> G2Projective {
149 self + (-rhs)
150 }
151}
152
153impl<'a, 'b> Sub<&'b G2Affine> for &'a G2Projective {
154 type Output = G2Projective;
155
156 #[inline]
157 fn sub(self, rhs: &'b G2Affine) -> G2Projective {
158 self + (-rhs)
159 }
160}
161
162impl<T> Sum<T> for G2Projective
163where
164 T: Borrow<G2Projective>,
165{
166 fn sum<I>(iter: I) -> Self
167 where
168 I: Iterator<Item = T>,
169 {
170 iter.fold(Self::identity(), |acc, item| acc + item.borrow())
171 }
172}
173
174impl_binops_additive!(G2Projective, G2Affine);
175impl_binops_additive_specify_output!(G2Affine, G2Projective, G2Projective);
176
177const B: Fp2 = Fp2 {
178 c0: Fp::from_raw_unchecked([
179 0xaa27_0000_000c_fff3,
180 0x53cc_0032_fc34_000a,
181 0x478f_e97a_6b0a_807f,
182 0xb1d3_7ebe_e6ba_24d7,
183 0x8ec9_733b_bf78_ab2f,
184 0x09d6_4551_3d83_de7e,
185 ]),
186 c1: Fp::from_raw_unchecked([
187 0xaa27_0000_000c_fff3,
188 0x53cc_0032_fc34_000a,
189 0x478f_e97a_6b0a_807f,
190 0xb1d3_7ebe_e6ba_24d7,
191 0x8ec9_733b_bf78_ab2f,
192 0x09d6_4551_3d83_de7e,
193 ]),
194};
195
196const B3: Fp2 = Fp2::add(&Fp2::add(&B, &B), &B);
197
198impl G2Affine {
199 pub fn identity() -> G2Affine {
201 G2Affine {
202 x: Fp2::zero(),
203 y: Fp2::one(),
204 infinity: Choice::from(1u8),
205 }
206 }
207
208 pub fn generator() -> G2Affine {
211 G2Affine {
212 x: Fp2 {
213 c0: Fp::from_raw_unchecked([
214 0xf5f2_8fa2_0294_0a10,
215 0xb3f5_fb26_87b4_961a,
216 0xa1a8_93b5_3e2a_e580,
217 0x9894_999d_1a3c_aee9,
218 0x6f67_b763_1863_366b,
219 0x0581_9192_4350_bcd7,
220 ]),
221 c1: Fp::from_raw_unchecked([
222 0xa5a9_c075_9e23_f606,
223 0xaaa0_c59d_bccd_60c3,
224 0x3bb1_7e18_e286_7806,
225 0x1b1a_b6cc_8541_b367,
226 0xc2b6_ed0e_f215_8547,
227 0x1192_2a09_7360_edf3,
228 ]),
229 },
230 y: Fp2 {
231 c0: Fp::from_raw_unchecked([
232 0x4c73_0af8_6049_4c4a,
233 0x597c_fa1f_5e36_9c5a,
234 0xe7e6_856c_aa0a_635a,
235 0xbbef_b5e9_6e0d_495f,
236 0x07d3_a975_f0ef_25a2,
237 0x0083_fd8e_7e80_dae5,
238 ]),
239 c1: Fp::from_raw_unchecked([
240 0xadc0_fc92_df64_b05d,
241 0x18aa_270a_2b14_61dc,
242 0x86ad_ac6a_3be4_eba0,
243 0x7949_5c4e_c93d_a33a,
244 0xe717_5850_a43c_caed,
245 0x0b2b_c2a1_63de_1bf2,
246 ]),
247 },
248 infinity: Choice::from(0u8),
249 }
250 }
251
252 pub fn to_compressed(&self) -> [u8; 96] {
255 let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
258
259 let mut res = [0; 96];
260
261 (&mut res[0..48]).copy_from_slice(&x.c1.to_bytes()[..]);
262 (&mut res[48..96]).copy_from_slice(&x.c0.to_bytes()[..]);
263
264 res[0] |= 1u8 << 7;
266
267 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
269
270 res[0] |= u8::conditional_select(
274 &0u8,
275 &(1u8 << 5),
276 (!self.infinity) & self.y.lexicographically_largest(),
277 );
278
279 res
280 }
281
282 pub fn to_uncompressed(&self) -> [u8; 192] {
285 let mut res = [0; 192];
286
287 let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
288 let y = Fp2::conditional_select(&self.y, &Fp2::zero(), self.infinity);
289
290 res[0..48].copy_from_slice(&x.c1.to_bytes()[..]);
291 res[48..96].copy_from_slice(&x.c0.to_bytes()[..]);
292 res[96..144].copy_from_slice(&y.c1.to_bytes()[..]);
293 res[144..192].copy_from_slice(&y.c0.to_bytes()[..]);
294
295 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
297
298 res
299 }
300
301 pub fn from_uncompressed(bytes: &[u8; 192]) -> CtOption<Self> {
304 Self::from_uncompressed_unchecked(bytes)
305 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
306 }
307
308 pub fn from_uncompressed_unchecked(bytes: &[u8; 192]) -> CtOption<Self> {
313 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
315 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
316 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
317
318 let xc1 = {
320 let mut tmp = [0; 48];
321 tmp.copy_from_slice(&bytes[0..48]);
322
323 tmp[0] &= 0b0001_1111;
325
326 Fp::from_bytes(&tmp)
327 };
328 let xc0 = {
329 let mut tmp = [0; 48];
330 tmp.copy_from_slice(&bytes[48..96]);
331
332 Fp::from_bytes(&tmp)
333 };
334
335 let yc1 = {
337 let mut tmp = [0; 48];
338 tmp.copy_from_slice(&bytes[96..144]);
339
340 Fp::from_bytes(&tmp)
341 };
342 let yc0 = {
343 let mut tmp = [0; 48];
344 tmp.copy_from_slice(&bytes[144..192]);
345
346 Fp::from_bytes(&tmp)
347 };
348
349 xc1.and_then(|xc1| {
350 xc0.and_then(|xc0| {
351 yc1.and_then(|yc1| {
352 yc0.and_then(|yc0| {
353 let x = Fp2 {
354 c0: xc0,
355 c1: xc1
356 };
357 let y = Fp2 {
358 c0: yc0,
359 c1: yc1
360 };
361
362 let p = G2Affine::conditional_select(
364 &G2Affine {
365 x,
366 y,
367 infinity: infinity_flag_set,
368 },
369 &G2Affine::identity(),
370 infinity_flag_set,
371 );
372
373 CtOption::new(
374 p,
375 ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero())) &
377 (!compression_flag_set) &
379 (!sort_flag_set),
381 )
382 })
383 })
384 })
385 })
386 }
387
388 pub fn from_compressed(bytes: &[u8; 96]) -> CtOption<Self> {
391 Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_torsion_free()))
395 }
396
397 pub fn from_compressed_unchecked(bytes: &[u8; 96]) -> CtOption<Self> {
402 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
404 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
405 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
406
407 let xc1 = {
409 let mut tmp = [0; 48];
410 tmp.copy_from_slice(&bytes[0..48]);
411
412 tmp[0] &= 0b0001_1111;
414
415 Fp::from_bytes(&tmp)
416 };
417 let xc0 = {
418 let mut tmp = [0; 48];
419 tmp.copy_from_slice(&bytes[48..96]);
420
421 Fp::from_bytes(&tmp)
422 };
423
424 xc1.and_then(|xc1| {
425 xc0.and_then(|xc0| {
426 let x = Fp2 { c0: xc0, c1: xc1 };
427
428 CtOption::new(
435 G2Affine::identity(),
436 infinity_flag_set & compression_flag_set & (!sort_flag_set) & x.is_zero(), )
441 .or_else(|| {
442 ((x.square() * x) + B).sqrt().and_then(|y| {
444 let y = Fp2::conditional_select(
446 &y,
447 &-y,
448 y.lexicographically_largest() ^ sort_flag_set,
449 );
450
451 CtOption::new(
452 G2Affine {
453 x,
454 y,
455 infinity: infinity_flag_set,
456 },
457 (!infinity_flag_set) & compression_flag_set, )
460 })
461 })
462 })
463 })
464 }
465
466 #[inline]
468 pub fn is_identity(&self) -> Choice {
469 self.infinity
470 }
471
472 pub fn is_torsion_free(&self) -> Choice {
476 let p = G2Projective::from(self);
481 p.psi().ct_eq(&p.mul_by_x())
482 }
483
484 pub fn is_on_curve(&self) -> Choice {
487 (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
489 }
490}
491
492#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
494#[derive(Copy, Clone, Debug)]
495pub struct G2Projective {
496 pub(crate) x: Fp2,
497 pub(crate) y: Fp2,
498 pub(crate) z: Fp2,
499}
500
501impl Default for G2Projective {
502 fn default() -> G2Projective {
503 G2Projective::identity()
504 }
505}
506
507#[cfg(feature = "zeroize")]
508impl zeroize::DefaultIsZeroes for G2Projective {}
509
510impl fmt::Display for G2Projective {
511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512 write!(f, "{:?}", self)
513 }
514}
515
516impl<'a> From<&'a G2Affine> for G2Projective {
517 fn from(p: &'a G2Affine) -> G2Projective {
518 G2Projective {
519 x: p.x,
520 y: p.y,
521 z: Fp2::conditional_select(&Fp2::one(), &Fp2::zero(), p.infinity),
522 }
523 }
524}
525
526impl From<G2Affine> for G2Projective {
527 fn from(p: G2Affine) -> G2Projective {
528 G2Projective::from(&p)
529 }
530}
531
532impl ConstantTimeEq for G2Projective {
533 fn ct_eq(&self, other: &Self) -> Choice {
534 let x1 = self.x * other.z;
537 let x2 = other.x * self.z;
538
539 let y1 = self.y * other.z;
540 let y2 = other.y * self.z;
541
542 let self_is_zero = self.z.is_zero();
543 let other_is_zero = other.z.is_zero();
544
545 (self_is_zero & other_is_zero) | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
547 }
549}
550
551impl ConditionallySelectable for G2Projective {
552 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
553 G2Projective {
554 x: Fp2::conditional_select(&a.x, &b.x, choice),
555 y: Fp2::conditional_select(&a.y, &b.y, choice),
556 z: Fp2::conditional_select(&a.z, &b.z, choice),
557 }
558 }
559}
560
561impl Eq for G2Projective {}
562impl PartialEq for G2Projective {
563 #[inline]
564 fn eq(&self, other: &Self) -> bool {
565 bool::from(self.ct_eq(other))
566 }
567}
568
569impl<'a> Neg for &'a G2Projective {
570 type Output = G2Projective;
571
572 #[inline]
573 fn neg(self) -> G2Projective {
574 G2Projective {
575 x: self.x,
576 y: -self.y,
577 z: self.z,
578 }
579 }
580}
581
582impl Neg for G2Projective {
583 type Output = G2Projective;
584
585 #[inline]
586 fn neg(self) -> G2Projective {
587 -&self
588 }
589}
590
591impl<'a, 'b> Add<&'b G2Projective> for &'a G2Projective {
592 type Output = G2Projective;
593
594 #[inline]
595 fn add(self, rhs: &'b G2Projective) -> G2Projective {
596 self.add(rhs)
597 }
598}
599
600impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Projective {
601 type Output = G2Projective;
602
603 #[inline]
604 fn sub(self, rhs: &'b G2Projective) -> G2Projective {
605 self + (-rhs)
606 }
607}
608
609impl<'a, 'b> Mul<&'b Scalar> for &'a G2Projective {
610 type Output = G2Projective;
611
612 fn mul(self, other: &'b Scalar) -> Self::Output {
613 self.multiply(&other.to_bytes())
614 }
615}
616
617impl<'a, 'b> Mul<&'b G2Projective> for &'a Scalar {
618 type Output = G2Projective;
619
620 #[inline]
621 fn mul(self, rhs: &'b G2Projective) -> Self::Output {
622 rhs * self
623 }
624}
625
626impl<'a, 'b> Mul<&'b Scalar> for &'a G2Affine {
627 type Output = G2Projective;
628
629 fn mul(self, other: &'b Scalar) -> Self::Output {
630 G2Projective::from(self).multiply(&other.to_bytes())
631 }
632}
633
634impl<'a, 'b> Mul<&'b G2Affine> for &'a Scalar {
635 type Output = G2Projective;
636
637 #[inline]
638 fn mul(self, rhs: &'b G2Affine) -> Self::Output {
639 rhs * self
640 }
641}
642
643impl_binops_additive!(G2Projective, G2Projective);
644impl_binops_multiplicative!(G2Projective, Scalar);
645impl_binops_multiplicative_mixed!(G2Affine, Scalar, G2Projective);
646impl_binops_multiplicative_mixed!(Scalar, G2Affine, G2Projective);
647impl_binops_multiplicative_mixed!(Scalar, G2Projective, G2Projective);
648
649#[inline(always)]
650fn mul_by_3b(x: Fp2) -> Fp2 {
651 x * B3
652}
653
654impl G2Projective {
655 pub fn identity() -> G2Projective {
657 G2Projective {
658 x: Fp2::zero(),
659 y: Fp2::one(),
660 z: Fp2::zero(),
661 }
662 }
663
664 pub fn generator() -> G2Projective {
667 G2Projective {
668 x: Fp2 {
669 c0: Fp::from_raw_unchecked([
670 0xf5f2_8fa2_0294_0a10,
671 0xb3f5_fb26_87b4_961a,
672 0xa1a8_93b5_3e2a_e580,
673 0x9894_999d_1a3c_aee9,
674 0x6f67_b763_1863_366b,
675 0x0581_9192_4350_bcd7,
676 ]),
677 c1: Fp::from_raw_unchecked([
678 0xa5a9_c075_9e23_f606,
679 0xaaa0_c59d_bccd_60c3,
680 0x3bb1_7e18_e286_7806,
681 0x1b1a_b6cc_8541_b367,
682 0xc2b6_ed0e_f215_8547,
683 0x1192_2a09_7360_edf3,
684 ]),
685 },
686 y: Fp2 {
687 c0: Fp::from_raw_unchecked([
688 0x4c73_0af8_6049_4c4a,
689 0x597c_fa1f_5e36_9c5a,
690 0xe7e6_856c_aa0a_635a,
691 0xbbef_b5e9_6e0d_495f,
692 0x07d3_a975_f0ef_25a2,
693 0x0083_fd8e_7e80_dae5,
694 ]),
695 c1: Fp::from_raw_unchecked([
696 0xadc0_fc92_df64_b05d,
697 0x18aa_270a_2b14_61dc,
698 0x86ad_ac6a_3be4_eba0,
699 0x7949_5c4e_c93d_a33a,
700 0xe717_5850_a43c_caed,
701 0x0b2b_c2a1_63de_1bf2,
702 ]),
703 },
704 z: Fp2::one(),
705 }
706 }
707
708 pub fn double(&self) -> G2Projective {
710 let t0 = self.y.square();
713 let z3 = t0 + t0;
714 let z3 = z3 + z3;
715 let z3 = z3 + z3;
716 let t1 = self.y * self.z;
717 let t2 = self.z.square();
718 let t2 = mul_by_3b(t2);
719 let x3 = t2 * z3;
720 let y3 = t0 + t2;
721 let z3 = t1 * z3;
722 let t1 = t2 + t2;
723 let t2 = t1 + t2;
724 let t0 = t0 - t2;
725 let y3 = t0 * y3;
726 let y3 = x3 + y3;
727 let t1 = self.x * self.y;
728 let x3 = t0 * t1;
729 let x3 = x3 + x3;
730
731 let tmp = G2Projective {
732 x: x3,
733 y: y3,
734 z: z3,
735 };
736
737 G2Projective::conditional_select(&tmp, &G2Projective::identity(), self.is_identity())
738 }
739
740 pub fn add(&self, rhs: &G2Projective) -> G2Projective {
742 let t0 = self.x * rhs.x;
745 let t1 = self.y * rhs.y;
746 let t2 = self.z * rhs.z;
747 let t3 = self.x + self.y;
748 let t4 = rhs.x + rhs.y;
749 let t3 = t3 * t4;
750 let t4 = t0 + t1;
751 let t3 = t3 - t4;
752 let t4 = self.y + self.z;
753 let x3 = rhs.y + rhs.z;
754 let t4 = t4 * x3;
755 let x3 = t1 + t2;
756 let t4 = t4 - x3;
757 let x3 = self.x + self.z;
758 let y3 = rhs.x + rhs.z;
759 let x3 = x3 * y3;
760 let y3 = t0 + t2;
761 let y3 = x3 - y3;
762 let x3 = t0 + t0;
763 let t0 = x3 + t0;
764 let t2 = mul_by_3b(t2);
765 let z3 = t1 + t2;
766 let t1 = t1 - t2;
767 let y3 = mul_by_3b(y3);
768 let x3 = t4 * y3;
769 let t2 = t3 * t1;
770 let x3 = t2 - x3;
771 let y3 = y3 * t0;
772 let t1 = t1 * z3;
773 let y3 = t1 + y3;
774 let t0 = t0 * t3;
775 let z3 = z3 * t4;
776 let z3 = z3 + t0;
777
778 G2Projective {
779 x: x3,
780 y: y3,
781 z: z3,
782 }
783 }
784
785 pub fn add_mixed(&self, rhs: &G2Affine) -> G2Projective {
787 let t0 = self.x * rhs.x;
790 let t1 = self.y * rhs.y;
791 let t3 = rhs.x + rhs.y;
792 let t4 = self.x + self.y;
793 let t3 = t3 * t4;
794 let t4 = t0 + t1;
795 let t3 = t3 - t4;
796 let t4 = rhs.y * self.z;
797 let t4 = t4 + self.y;
798 let y3 = rhs.x * self.z;
799 let y3 = y3 + self.x;
800 let x3 = t0 + t0;
801 let t0 = x3 + t0;
802 let t2 = mul_by_3b(self.z);
803 let z3 = t1 + t2;
804 let t1 = t1 - t2;
805 let y3 = mul_by_3b(y3);
806 let x3 = t4 * y3;
807 let t2 = t3 * t1;
808 let x3 = t2 - x3;
809 let y3 = y3 * t0;
810 let t1 = t1 * z3;
811 let y3 = t1 + y3;
812 let t0 = t0 * t3;
813 let z3 = z3 * t4;
814 let z3 = z3 + t0;
815
816 let tmp = G2Projective {
817 x: x3,
818 y: y3,
819 z: z3,
820 };
821
822 G2Projective::conditional_select(&tmp, self, rhs.is_identity())
823 }
824
825 fn multiply(&self, by: &[u8]) -> G2Projective {
826 let mut acc = G2Projective::identity();
827
828 for bit in by
835 .iter()
836 .rev()
837 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
838 .skip(1)
839 {
840 acc = acc.double();
841 acc = G2Projective::conditional_select(&acc, &(acc + self), bit);
842 }
843
844 acc
845 }
846
847 fn psi(&self) -> G2Projective {
848 let psi_coeff_x = Fp2 {
850 c0: Fp::zero(),
851 c1: Fp::from_raw_unchecked([
852 0x890dc9e4867545c3,
853 0x2af322533285a5d5,
854 0x50880866309b7e2c,
855 0xa20d1b8c7e881024,
856 0x14e4f04fe2db9068,
857 0x14e56d3f1564853a,
858 ]),
859 };
860 let psi_coeff_y = Fp2 {
862 c0: Fp::from_raw_unchecked([
863 0x3e2f585da55c9ad1,
864 0x4294213d86c18183,
865 0x382844c88b623732,
866 0x92ad2afd19103e18,
867 0x1d794e4fac7cf0b9,
868 0x0bd592fc7d825ec8,
869 ]),
870 c1: Fp::from_raw_unchecked([
871 0x7bcfa7a25aa30fda,
872 0xdc17dec12a927e7c,
873 0x2f088dd86b4ebef1,
874 0xd1ca2087da74d4a7,
875 0x2da2596696cebc1d,
876 0x0e2b7eedbbfd87d2,
877 ]),
878 };
879
880 G2Projective {
881 x: self.x.frobenius_map() * psi_coeff_x,
883 y: self.y.frobenius_map() * psi_coeff_y,
885 z: self.z.frobenius_map(),
887 }
888 }
889
890 fn psi2(&self) -> G2Projective {
891 let psi2_coeff_x = Fp2 {
893 c0: Fp::from_raw_unchecked([
894 0xcd03c9e48671f071,
895 0x5dab22461fcda5d2,
896 0x587042afd3851b95,
897 0x8eb60ebe01bacb9e,
898 0x03f97d6e83d050d2,
899 0x18f0206554638741,
900 ]),
901 c1: Fp::zero(),
902 };
903
904 G2Projective {
905 x: self.x * psi2_coeff_x,
907 y: self.y.neg(),
909 z: self.z,
911 }
912 }
913
914 fn mul_by_x(&self) -> G2Projective {
916 let mut xself = G2Projective::identity();
917 let mut x = crate::BLS_X >> 1;
919 let mut acc = *self;
920 while x != 0 {
921 acc = acc.double();
922 if x % 2 == 1 {
923 xself += acc;
924 }
925 x >>= 1;
926 }
927 if crate::BLS_X_IS_NEGATIVE {
929 xself = -xself;
930 }
931 xself
932 }
933
934 pub fn clear_cofactor(&self) -> G2Projective {
939 let t1 = self.mul_by_x(); let t2 = self.psi(); self.double().psi2() + (t1 + t2).mul_by_x() - t1 - t2 - self }
948
949 pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) {
952 assert_eq!(p.len(), q.len());
953
954 let mut acc = Fp2::one();
955 for (p, q) in p.iter().zip(q.iter_mut()) {
956 q.x = acc;
959
960 acc = Fp2::conditional_select(&(acc * p.z), &acc, p.is_identity());
962 }
963
964 acc = acc.invert().unwrap();
967
968 for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
969 let skip = p.is_identity();
970
971 let tmp = q.x * acc;
973
974 acc = Fp2::conditional_select(&(acc * p.z), &acc, skip);
976
977 q.x = p.x * tmp;
979 q.y = p.y * tmp;
980 q.infinity = Choice::from(0u8);
981
982 *q = G2Affine::conditional_select(q, &G2Affine::identity(), skip);
983 }
984 }
985
986 #[inline]
988 pub fn is_identity(&self) -> Choice {
989 self.z.is_zero()
990 }
991
992 pub fn is_on_curve(&self) -> Choice {
995 (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
998 | self.z.is_zero()
999 }
1000}
1001
1002#[derive(Clone, Copy)]
1003pub struct G2Compressed([u8; 96]);
1004
1005impl fmt::Debug for G2Compressed {
1006 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1007 self.0[..].fmt(f)
1008 }
1009}
1010
1011impl Default for G2Compressed {
1012 fn default() -> Self {
1013 G2Compressed([0; 96])
1014 }
1015}
1016
1017#[cfg(feature = "zeroize")]
1018impl zeroize::DefaultIsZeroes for G2Compressed {}
1019
1020impl AsRef<[u8]> for G2Compressed {
1021 fn as_ref(&self) -> &[u8] {
1022 &self.0
1023 }
1024}
1025
1026impl AsMut<[u8]> for G2Compressed {
1027 fn as_mut(&mut self) -> &mut [u8] {
1028 &mut self.0
1029 }
1030}
1031
1032impl ConstantTimeEq for G2Compressed {
1033 fn ct_eq(&self, other: &Self) -> Choice {
1034 self.0.ct_eq(&other.0)
1035 }
1036}
1037
1038impl Eq for G2Compressed {}
1039impl PartialEq for G2Compressed {
1040 #[inline]
1041 fn eq(&self, other: &Self) -> bool {
1042 bool::from(self.ct_eq(other))
1043 }
1044}
1045
1046#[derive(Clone, Copy)]
1047pub struct G2Uncompressed([u8; 192]);
1048
1049impl fmt::Debug for G2Uncompressed {
1050 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1051 self.0[..].fmt(f)
1052 }
1053}
1054
1055impl Default for G2Uncompressed {
1056 fn default() -> Self {
1057 G2Uncompressed([0; 192])
1058 }
1059}
1060
1061#[cfg(feature = "zeroize")]
1062impl zeroize::DefaultIsZeroes for G2Uncompressed {}
1063
1064impl AsRef<[u8]> for G2Uncompressed {
1065 fn as_ref(&self) -> &[u8] {
1066 &self.0
1067 }
1068}
1069
1070impl AsMut<[u8]> for G2Uncompressed {
1071 fn as_mut(&mut self) -> &mut [u8] {
1072 &mut self.0
1073 }
1074}
1075
1076impl ConstantTimeEq for G2Uncompressed {
1077 fn ct_eq(&self, other: &Self) -> Choice {
1078 self.0.ct_eq(&other.0)
1079 }
1080}
1081
1082impl Eq for G2Uncompressed {}
1083impl PartialEq for G2Uncompressed {
1084 #[inline]
1085 fn eq(&self, other: &Self) -> bool {
1086 bool::from(self.ct_eq(other))
1087 }
1088}
1089
1090impl Group for G2Projective {
1091 type Scalar = Scalar;
1092
1093 fn random(mut rng: impl RngCore) -> Self {
1094 loop {
1095 let x = Fp2::random(&mut rng);
1096 let flip_sign = rng.next_u32() % 2 != 0;
1097
1098 let p = ((x.square() * x) + B).sqrt().map(|y| G2Affine {
1100 x,
1101 y: if flip_sign { -y } else { y },
1102 infinity: 0.into(),
1103 });
1104
1105 if p.is_some().into() {
1106 let p = p.unwrap().to_curve().clear_cofactor();
1107
1108 if bool::from(!p.is_identity()) {
1109 return p;
1110 }
1111 }
1112 }
1113 }
1114
1115 fn identity() -> Self {
1116 Self::identity()
1117 }
1118
1119 fn generator() -> Self {
1120 Self::generator()
1121 }
1122
1123 fn is_identity(&self) -> Choice {
1124 self.is_identity()
1125 }
1126
1127 #[must_use]
1128 fn double(&self) -> Self {
1129 self.double()
1130 }
1131}
1132
1133#[cfg(feature = "alloc")]
1134impl WnafGroup for G2Projective {
1135 fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
1136 const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071];
1137
1138 let mut ret = 4;
1139 for r in &RECOMMENDATIONS {
1140 if num_scalars > *r {
1141 ret += 1;
1142 } else {
1143 break;
1144 }
1145 }
1146
1147 ret
1148 }
1149}
1150
1151impl PrimeGroup for G2Projective {}
1152
1153impl Curve for G2Projective {
1154 type AffineRepr = G2Affine;
1155
1156 fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
1157 Self::batch_normalize(p, q);
1158 }
1159
1160 fn to_affine(&self) -> Self::AffineRepr {
1161 self.into()
1162 }
1163}
1164
1165impl PrimeCurve for G2Projective {
1166 type Affine = G2Affine;
1167}
1168
1169impl PrimeCurveAffine for G2Affine {
1170 type Scalar = Scalar;
1171 type Curve = G2Projective;
1172
1173 fn identity() -> Self {
1174 Self::identity()
1175 }
1176
1177 fn generator() -> Self {
1178 Self::generator()
1179 }
1180
1181 fn is_identity(&self) -> Choice {
1182 self.is_identity()
1183 }
1184
1185 fn to_curve(&self) -> Self::Curve {
1186 self.into()
1187 }
1188}
1189
1190impl GroupEncoding for G2Projective {
1191 type Repr = G2Compressed;
1192
1193 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1194 G2Affine::from_bytes(bytes).map(Self::from)
1195 }
1196
1197 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1198 G2Affine::from_bytes_unchecked(bytes).map(Self::from)
1199 }
1200
1201 fn to_bytes(&self) -> Self::Repr {
1202 G2Affine::from(self).to_bytes()
1203 }
1204}
1205
1206impl GroupEncoding for G2Affine {
1207 type Repr = G2Compressed;
1208
1209 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1210 Self::from_compressed(&bytes.0)
1211 }
1212
1213 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1214 Self::from_compressed_unchecked(&bytes.0)
1215 }
1216
1217 fn to_bytes(&self) -> Self::Repr {
1218 G2Compressed(self.to_compressed())
1219 }
1220}
1221
1222impl UncompressedEncoding for G2Affine {
1223 type Uncompressed = G2Uncompressed;
1224
1225 fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
1226 Self::from_uncompressed(&bytes.0)
1227 }
1228
1229 fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
1230 Self::from_uncompressed_unchecked(&bytes.0)
1231 }
1232
1233 fn to_uncompressed(&self) -> Self::Uncompressed {
1234 G2Uncompressed(self.to_uncompressed())
1235 }
1236}
1237
1238#[test]
1239fn test_is_on_curve() {
1240 assert!(bool::from(G2Affine::identity().is_on_curve()));
1241 assert!(bool::from(G2Affine::generator().is_on_curve()));
1242 assert!(bool::from(G2Projective::identity().is_on_curve()));
1243 assert!(bool::from(G2Projective::generator().is_on_curve()));
1244
1245 let z = Fp2 {
1246 c0: Fp::from_raw_unchecked([
1247 0xba7a_fa1f_9a6f_e250,
1248 0xfa0f_5b59_5eaf_e731,
1249 0x3bdc_4776_94c3_06e7,
1250 0x2149_be4b_3949_fa24,
1251 0x64aa_6e06_49b2_078c,
1252 0x12b1_08ac_3364_3c3e,
1253 ]),
1254 c1: Fp::from_raw_unchecked([
1255 0x1253_25df_3d35_b5a8,
1256 0xdc46_9ef5_555d_7fe3,
1257 0x02d7_16d2_4431_06a9,
1258 0x05a1_db59_a6ff_37d0,
1259 0x7cf7_784e_5300_bb8f,
1260 0x16a8_8922_c7a5_e844,
1261 ]),
1262 };
1263
1264 let gen = G2Affine::generator();
1265 let mut test = G2Projective {
1266 x: gen.x * z,
1267 y: gen.y * z,
1268 z,
1269 };
1270
1271 assert!(bool::from(test.is_on_curve()));
1272
1273 test.x = z;
1274 assert!(!bool::from(test.is_on_curve()));
1275}
1276
1277#[test]
1278#[allow(clippy::eq_op)]
1279fn test_affine_point_equality() {
1280 let a = G2Affine::generator();
1281 let b = G2Affine::identity();
1282
1283 assert!(a == a);
1284 assert!(b == b);
1285 assert!(a != b);
1286 assert!(b != a);
1287}
1288
1289#[test]
1290#[allow(clippy::eq_op)]
1291fn test_projective_point_equality() {
1292 let a = G2Projective::generator();
1293 let b = G2Projective::identity();
1294
1295 assert!(a == a);
1296 assert!(b == b);
1297 assert!(a != b);
1298 assert!(b != a);
1299
1300 let z = Fp2 {
1301 c0: Fp::from_raw_unchecked([
1302 0xba7a_fa1f_9a6f_e250,
1303 0xfa0f_5b59_5eaf_e731,
1304 0x3bdc_4776_94c3_06e7,
1305 0x2149_be4b_3949_fa24,
1306 0x64aa_6e06_49b2_078c,
1307 0x12b1_08ac_3364_3c3e,
1308 ]),
1309 c1: Fp::from_raw_unchecked([
1310 0x1253_25df_3d35_b5a8,
1311 0xdc46_9ef5_555d_7fe3,
1312 0x02d7_16d2_4431_06a9,
1313 0x05a1_db59_a6ff_37d0,
1314 0x7cf7_784e_5300_bb8f,
1315 0x16a8_8922_c7a5_e844,
1316 ]),
1317 };
1318
1319 let mut c = G2Projective {
1320 x: a.x * z,
1321 y: a.y * z,
1322 z,
1323 };
1324 assert!(bool::from(c.is_on_curve()));
1325
1326 assert!(a == c);
1327 assert!(b != c);
1328 assert!(c == a);
1329 assert!(c != b);
1330
1331 c.y = -c.y;
1332 assert!(bool::from(c.is_on_curve()));
1333
1334 assert!(a != c);
1335 assert!(b != c);
1336 assert!(c != a);
1337 assert!(c != b);
1338
1339 c.y = -c.y;
1340 c.x = z;
1341 assert!(!bool::from(c.is_on_curve()));
1342 assert!(a != b);
1343 assert!(a != c);
1344 assert!(b != c);
1345}
1346
1347#[test]
1348fn test_conditionally_select_affine() {
1349 let a = G2Affine::generator();
1350 let b = G2Affine::identity();
1351
1352 assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(0u8)), a);
1353 assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(1u8)), b);
1354}
1355
1356#[test]
1357fn test_conditionally_select_projective() {
1358 let a = G2Projective::generator();
1359 let b = G2Projective::identity();
1360
1361 assert_eq!(
1362 G2Projective::conditional_select(&a, &b, Choice::from(0u8)),
1363 a
1364 );
1365 assert_eq!(
1366 G2Projective::conditional_select(&a, &b, Choice::from(1u8)),
1367 b
1368 );
1369}
1370
1371#[test]
1372fn test_projective_to_affine() {
1373 let a = G2Projective::generator();
1374 let b = G2Projective::identity();
1375
1376 assert!(bool::from(G2Affine::from(a).is_on_curve()));
1377 assert!(!bool::from(G2Affine::from(a).is_identity()));
1378 assert!(bool::from(G2Affine::from(b).is_on_curve()));
1379 assert!(bool::from(G2Affine::from(b).is_identity()));
1380
1381 let z = Fp2 {
1382 c0: Fp::from_raw_unchecked([
1383 0xba7a_fa1f_9a6f_e250,
1384 0xfa0f_5b59_5eaf_e731,
1385 0x3bdc_4776_94c3_06e7,
1386 0x2149_be4b_3949_fa24,
1387 0x64aa_6e06_49b2_078c,
1388 0x12b1_08ac_3364_3c3e,
1389 ]),
1390 c1: Fp::from_raw_unchecked([
1391 0x1253_25df_3d35_b5a8,
1392 0xdc46_9ef5_555d_7fe3,
1393 0x02d7_16d2_4431_06a9,
1394 0x05a1_db59_a6ff_37d0,
1395 0x7cf7_784e_5300_bb8f,
1396 0x16a8_8922_c7a5_e844,
1397 ]),
1398 };
1399
1400 let c = G2Projective {
1401 x: a.x * z,
1402 y: a.y * z,
1403 z,
1404 };
1405
1406 assert_eq!(G2Affine::from(c), G2Affine::generator());
1407}
1408
1409#[test]
1410fn test_affine_to_projective() {
1411 let a = G2Affine::generator();
1412 let b = G2Affine::identity();
1413
1414 assert!(bool::from(G2Projective::from(a).is_on_curve()));
1415 assert!(!bool::from(G2Projective::from(a).is_identity()));
1416 assert!(bool::from(G2Projective::from(b).is_on_curve()));
1417 assert!(bool::from(G2Projective::from(b).is_identity()));
1418}
1419
1420#[test]
1421fn test_doubling() {
1422 {
1423 let tmp = G2Projective::identity().double();
1424 assert!(bool::from(tmp.is_identity()));
1425 assert!(bool::from(tmp.is_on_curve()));
1426 }
1427 {
1428 let tmp = G2Projective::generator().double();
1429 assert!(!bool::from(tmp.is_identity()));
1430 assert!(bool::from(tmp.is_on_curve()));
1431
1432 assert_eq!(
1433 G2Affine::from(tmp),
1434 G2Affine {
1435 x: Fp2 {
1436 c0: Fp::from_raw_unchecked([
1437 0xe9d9_e2da_9620_f98b,
1438 0x54f1_1993_46b9_7f36,
1439 0x3db3_b820_376b_ed27,
1440 0xcfdb_31c9_b0b6_4f4c,
1441 0x41d7_c127_8635_4493,
1442 0x0571_0794_c255_c064,
1443 ]),
1444 c1: Fp::from_raw_unchecked([
1445 0xd6c1_d3ca_6ea0_d06e,
1446 0xda0c_bd90_5595_489f,
1447 0x4f53_52d4_3479_221d,
1448 0x8ade_5d73_6f8c_97e0,
1449 0x48cc_8433_925e_f70e,
1450 0x08d7_ea71_ea91_ef81,
1451 ]),
1452 },
1453 y: Fp2 {
1454 c0: Fp::from_raw_unchecked([
1455 0x15ba_26eb_4b0d_186f,
1456 0x0d08_6d64_b7e9_e01e,
1457 0xc8b8_48dd_652f_4c78,
1458 0xeecf_46a6_123b_ae4f,
1459 0x255e_8dd8_b6dc_812a,
1460 0x1641_42af_21dc_f93f,
1461 ]),
1462 c1: Fp::from_raw_unchecked([
1463 0xf9b4_a1a8_9598_4db4,
1464 0xd417_b114_cccf_f748,
1465 0x6856_301f_c89f_086e,
1466 0x41c7_7787_8931_e3da,
1467 0x3556_b155_066a_2105,
1468 0x00ac_f7d3_25cb_89cf,
1469 ]),
1470 },
1471 infinity: Choice::from(0u8)
1472 }
1473 );
1474 }
1475}
1476
1477#[test]
1478fn test_projective_addition() {
1479 {
1480 let a = G2Projective::identity();
1481 let b = G2Projective::identity();
1482 let c = a + b;
1483 assert!(bool::from(c.is_identity()));
1484 assert!(bool::from(c.is_on_curve()));
1485 }
1486 {
1487 let a = G2Projective::identity();
1488 let mut b = G2Projective::generator();
1489 {
1490 let z = Fp2 {
1491 c0: Fp::from_raw_unchecked([
1492 0xba7a_fa1f_9a6f_e250,
1493 0xfa0f_5b59_5eaf_e731,
1494 0x3bdc_4776_94c3_06e7,
1495 0x2149_be4b_3949_fa24,
1496 0x64aa_6e06_49b2_078c,
1497 0x12b1_08ac_3364_3c3e,
1498 ]),
1499 c1: Fp::from_raw_unchecked([
1500 0x1253_25df_3d35_b5a8,
1501 0xdc46_9ef5_555d_7fe3,
1502 0x02d7_16d2_4431_06a9,
1503 0x05a1_db59_a6ff_37d0,
1504 0x7cf7_784e_5300_bb8f,
1505 0x16a8_8922_c7a5_e844,
1506 ]),
1507 };
1508
1509 b = G2Projective {
1510 x: b.x * z,
1511 y: b.y * z,
1512 z,
1513 };
1514 }
1515 let c = a + b;
1516 assert!(!bool::from(c.is_identity()));
1517 assert!(bool::from(c.is_on_curve()));
1518 assert!(c == G2Projective::generator());
1519 }
1520 {
1521 let a = G2Projective::identity();
1522 let mut b = G2Projective::generator();
1523 {
1524 let z = Fp2 {
1525 c0: Fp::from_raw_unchecked([
1526 0xba7a_fa1f_9a6f_e250,
1527 0xfa0f_5b59_5eaf_e731,
1528 0x3bdc_4776_94c3_06e7,
1529 0x2149_be4b_3949_fa24,
1530 0x64aa_6e06_49b2_078c,
1531 0x12b1_08ac_3364_3c3e,
1532 ]),
1533 c1: Fp::from_raw_unchecked([
1534 0x1253_25df_3d35_b5a8,
1535 0xdc46_9ef5_555d_7fe3,
1536 0x02d7_16d2_4431_06a9,
1537 0x05a1_db59_a6ff_37d0,
1538 0x7cf7_784e_5300_bb8f,
1539 0x16a8_8922_c7a5_e844,
1540 ]),
1541 };
1542
1543 b = G2Projective {
1544 x: b.x * z,
1545 y: b.y * z,
1546 z,
1547 };
1548 }
1549 let c = b + a;
1550 assert!(!bool::from(c.is_identity()));
1551 assert!(bool::from(c.is_on_curve()));
1552 assert!(c == G2Projective::generator());
1553 }
1554 {
1555 let a = G2Projective::generator().double().double(); let b = G2Projective::generator().double(); let c = a + b;
1558
1559 let mut d = G2Projective::generator();
1560 for _ in 0..5 {
1561 d += G2Projective::generator();
1562 }
1563 assert!(!bool::from(c.is_identity()));
1564 assert!(bool::from(c.is_on_curve()));
1565 assert!(!bool::from(d.is_identity()));
1566 assert!(bool::from(d.is_on_curve()));
1567 assert_eq!(c, d);
1568 }
1569
1570 {
1572 let beta = Fp2 {
1573 c0: Fp::from_raw_unchecked([
1574 0xcd03_c9e4_8671_f071,
1575 0x5dab_2246_1fcd_a5d2,
1576 0x5870_42af_d385_1b95,
1577 0x8eb6_0ebe_01ba_cb9e,
1578 0x03f9_7d6e_83d0_50d2,
1579 0x18f0_2065_5463_8741,
1580 ]),
1581 c1: Fp::zero(),
1582 };
1583 let beta = beta.square();
1584 let a = G2Projective::generator().double().double();
1585 let b = G2Projective {
1586 x: a.x * beta,
1587 y: -a.y,
1588 z: a.z,
1589 };
1590 assert!(bool::from(a.is_on_curve()));
1591 assert!(bool::from(b.is_on_curve()));
1592
1593 let c = a + b;
1594 assert_eq!(
1595 G2Affine::from(c),
1596 G2Affine::from(G2Projective {
1597 x: Fp2 {
1598 c0: Fp::from_raw_unchecked([
1599 0x705a_bc79_9ca7_73d3,
1600 0xfe13_2292_c1d4_bf08,
1601 0xf37e_ce3e_07b2_b466,
1602 0x887e_1c43_f447_e301,
1603 0x1e09_70d0_33bc_77e8,
1604 0x1985_c81e_20a6_93f2,
1605 ]),
1606 c1: Fp::from_raw_unchecked([
1607 0x1d79_b25d_b36a_b924,
1608 0x2394_8e4d_5296_39d3,
1609 0x471b_a7fb_0d00_6297,
1610 0x2c36_d4b4_465d_c4c0,
1611 0x82bb_c3cf_ec67_f538,
1612 0x051d_2728_b67b_f952,
1613 ])
1614 },
1615 y: Fp2 {
1616 c0: Fp::from_raw_unchecked([
1617 0x41b1_bbf6_576c_0abf,
1618 0xb6cc_9371_3f7a_0f9a,
1619 0x6b65_b43e_48f3_f01f,
1620 0xfb7a_4cfc_af81_be4f,
1621 0x3e32_dadc_6ec2_2cb6,
1622 0x0bb0_fc49_d798_07e3,
1623 ]),
1624 c1: Fp::from_raw_unchecked([
1625 0x7d13_9778_8f5f_2ddf,
1626 0xab29_0714_4ff0_d8e8,
1627 0x5b75_73e0_cdb9_1f92,
1628 0x4cb8_932d_d31d_af28,
1629 0x62bb_fac6_db05_2a54,
1630 0x11f9_5c16_d14c_3bbe,
1631 ])
1632 },
1633 z: Fp2::one()
1634 })
1635 );
1636 assert!(!bool::from(c.is_identity()));
1637 assert!(bool::from(c.is_on_curve()));
1638 }
1639}
1640
1641#[test]
1642fn test_mixed_addition() {
1643 {
1644 let a = G2Affine::identity();
1645 let b = G2Projective::identity();
1646 let c = a + b;
1647 assert!(bool::from(c.is_identity()));
1648 assert!(bool::from(c.is_on_curve()));
1649 }
1650 {
1651 let a = G2Affine::identity();
1652 let mut b = G2Projective::generator();
1653 {
1654 let z = Fp2 {
1655 c0: Fp::from_raw_unchecked([
1656 0xba7a_fa1f_9a6f_e250,
1657 0xfa0f_5b59_5eaf_e731,
1658 0x3bdc_4776_94c3_06e7,
1659 0x2149_be4b_3949_fa24,
1660 0x64aa_6e06_49b2_078c,
1661 0x12b1_08ac_3364_3c3e,
1662 ]),
1663 c1: Fp::from_raw_unchecked([
1664 0x1253_25df_3d35_b5a8,
1665 0xdc46_9ef5_555d_7fe3,
1666 0x02d7_16d2_4431_06a9,
1667 0x05a1_db59_a6ff_37d0,
1668 0x7cf7_784e_5300_bb8f,
1669 0x16a8_8922_c7a5_e844,
1670 ]),
1671 };
1672
1673 b = G2Projective {
1674 x: b.x * z,
1675 y: b.y * z,
1676 z,
1677 };
1678 }
1679 let c = a + b;
1680 assert!(!bool::from(c.is_identity()));
1681 assert!(bool::from(c.is_on_curve()));
1682 assert!(c == G2Projective::generator());
1683 }
1684 {
1685 let a = G2Affine::identity();
1686 let mut b = G2Projective::generator();
1687 {
1688 let z = Fp2 {
1689 c0: Fp::from_raw_unchecked([
1690 0xba7a_fa1f_9a6f_e250,
1691 0xfa0f_5b59_5eaf_e731,
1692 0x3bdc_4776_94c3_06e7,
1693 0x2149_be4b_3949_fa24,
1694 0x64aa_6e06_49b2_078c,
1695 0x12b1_08ac_3364_3c3e,
1696 ]),
1697 c1: Fp::from_raw_unchecked([
1698 0x1253_25df_3d35_b5a8,
1699 0xdc46_9ef5_555d_7fe3,
1700 0x02d7_16d2_4431_06a9,
1701 0x05a1_db59_a6ff_37d0,
1702 0x7cf7_784e_5300_bb8f,
1703 0x16a8_8922_c7a5_e844,
1704 ]),
1705 };
1706
1707 b = G2Projective {
1708 x: b.x * z,
1709 y: b.y * z,
1710 z,
1711 };
1712 }
1713 let c = b + a;
1714 assert!(!bool::from(c.is_identity()));
1715 assert!(bool::from(c.is_on_curve()));
1716 assert!(c == G2Projective::generator());
1717 }
1718 {
1719 let a = G2Projective::generator().double().double(); let b = G2Projective::generator().double(); let c = a + b;
1722
1723 let mut d = G2Projective::generator();
1724 for _ in 0..5 {
1725 d += G2Affine::generator();
1726 }
1727 assert!(!bool::from(c.is_identity()));
1728 assert!(bool::from(c.is_on_curve()));
1729 assert!(!bool::from(d.is_identity()));
1730 assert!(bool::from(d.is_on_curve()));
1731 assert_eq!(c, d);
1732 }
1733
1734 {
1736 let beta = Fp2 {
1737 c0: Fp::from_raw_unchecked([
1738 0xcd03_c9e4_8671_f071,
1739 0x5dab_2246_1fcd_a5d2,
1740 0x5870_42af_d385_1b95,
1741 0x8eb6_0ebe_01ba_cb9e,
1742 0x03f9_7d6e_83d0_50d2,
1743 0x18f0_2065_5463_8741,
1744 ]),
1745 c1: Fp::zero(),
1746 };
1747 let beta = beta.square();
1748 let a = G2Projective::generator().double().double();
1749 let b = G2Projective {
1750 x: a.x * beta,
1751 y: -a.y,
1752 z: a.z,
1753 };
1754 let a = G2Affine::from(a);
1755 assert!(bool::from(a.is_on_curve()));
1756 assert!(bool::from(b.is_on_curve()));
1757
1758 let c = a + b;
1759 assert_eq!(
1760 G2Affine::from(c),
1761 G2Affine::from(G2Projective {
1762 x: Fp2 {
1763 c0: Fp::from_raw_unchecked([
1764 0x705a_bc79_9ca7_73d3,
1765 0xfe13_2292_c1d4_bf08,
1766 0xf37e_ce3e_07b2_b466,
1767 0x887e_1c43_f447_e301,
1768 0x1e09_70d0_33bc_77e8,
1769 0x1985_c81e_20a6_93f2,
1770 ]),
1771 c1: Fp::from_raw_unchecked([
1772 0x1d79_b25d_b36a_b924,
1773 0x2394_8e4d_5296_39d3,
1774 0x471b_a7fb_0d00_6297,
1775 0x2c36_d4b4_465d_c4c0,
1776 0x82bb_c3cf_ec67_f538,
1777 0x051d_2728_b67b_f952,
1778 ])
1779 },
1780 y: Fp2 {
1781 c0: Fp::from_raw_unchecked([
1782 0x41b1_bbf6_576c_0abf,
1783 0xb6cc_9371_3f7a_0f9a,
1784 0x6b65_b43e_48f3_f01f,
1785 0xfb7a_4cfc_af81_be4f,
1786 0x3e32_dadc_6ec2_2cb6,
1787 0x0bb0_fc49_d798_07e3,
1788 ]),
1789 c1: Fp::from_raw_unchecked([
1790 0x7d13_9778_8f5f_2ddf,
1791 0xab29_0714_4ff0_d8e8,
1792 0x5b75_73e0_cdb9_1f92,
1793 0x4cb8_932d_d31d_af28,
1794 0x62bb_fac6_db05_2a54,
1795 0x11f9_5c16_d14c_3bbe,
1796 ])
1797 },
1798 z: Fp2::one()
1799 })
1800 );
1801 assert!(!bool::from(c.is_identity()));
1802 assert!(bool::from(c.is_on_curve()));
1803 }
1804}
1805
1806#[test]
1807#[allow(clippy::eq_op)]
1808fn test_projective_negation_and_subtraction() {
1809 let a = G2Projective::generator().double();
1810 assert_eq!(a + (-a), G2Projective::identity());
1811 assert_eq!(a + (-a), a - a);
1812}
1813
1814#[test]
1815fn test_affine_negation_and_subtraction() {
1816 let a = G2Affine::generator();
1817 assert_eq!(G2Projective::from(a) + (-a), G2Projective::identity());
1818 assert_eq!(G2Projective::from(a) + (-a), G2Projective::from(a) - a);
1819}
1820
1821#[test]
1822fn test_projective_scalar_multiplication() {
1823 let g = G2Projective::generator();
1824 let a = Scalar::from_raw([
1825 0x2b56_8297_a56d_a71c,
1826 0xd8c3_9ecb_0ef3_75d1,
1827 0x435c_38da_67bf_bf96,
1828 0x8088_a050_26b6_59b2,
1829 ]);
1830 let b = Scalar::from_raw([
1831 0x785f_dd9b_26ef_8b85,
1832 0xc997_f258_3769_5c18,
1833 0x4c8d_bc39_e7b7_56c1,
1834 0x70d9_b6cc_6d87_df20,
1835 ]);
1836 let c = a * b;
1837
1838 assert_eq!((g * a) * b, g * c);
1839}
1840
1841#[test]
1842fn test_affine_scalar_multiplication() {
1843 let g = G2Affine::generator();
1844 let a = Scalar::from_raw([
1845 0x2b56_8297_a56d_a71c,
1846 0xd8c3_9ecb_0ef3_75d1,
1847 0x435c_38da_67bf_bf96,
1848 0x8088_a050_26b6_59b2,
1849 ]);
1850 let b = Scalar::from_raw([
1851 0x785f_dd9b_26ef_8b85,
1852 0xc997_f258_3769_5c18,
1853 0x4c8d_bc39_e7b7_56c1,
1854 0x70d9_b6cc_6d87_df20,
1855 ]);
1856 let c = a * b;
1857
1858 assert_eq!(G2Affine::from(g * a) * b, g * c);
1859}
1860
1861#[test]
1862fn test_is_torsion_free() {
1863 let a = G2Affine {
1864 x: Fp2 {
1865 c0: Fp::from_raw_unchecked([
1866 0x89f5_50c8_13db_6431,
1867 0xa50b_e8c4_56cd_8a1a,
1868 0xa45b_3741_14ca_e851,
1869 0xbb61_90f5_bf7f_ff63,
1870 0x970c_a02c_3ba8_0bc7,
1871 0x02b8_5d24_e840_fbac,
1872 ]),
1873 c1: Fp::from_raw_unchecked([
1874 0x6888_bc53_d707_16dc,
1875 0x3dea_6b41_1768_2d70,
1876 0xd8f5_f930_500c_a354,
1877 0x6b5e_cb65_56f5_c155,
1878 0xc96b_ef04_3477_8ab0,
1879 0x0508_1505_5150_06ad,
1880 ]),
1881 },
1882 y: Fp2 {
1883 c0: Fp::from_raw_unchecked([
1884 0x3cf1_ea0d_434b_0f40,
1885 0x1a0d_c610_e603_e333,
1886 0x7f89_9561_60c7_2fa0,
1887 0x25ee_03de_cf64_31c5,
1888 0xeee8_e206_ec0f_e137,
1889 0x0975_92b2_26df_ef28,
1890 ]),
1891 c1: Fp::from_raw_unchecked([
1892 0x71e8_bb5f_2924_7367,
1893 0xa5fe_049e_2118_31ce,
1894 0x0ce6_b354_502a_3896,
1895 0x93b0_1200_0997_314e,
1896 0x6759_f3b6_aa5b_42ac,
1897 0x1569_44c4_dfe9_2bbb,
1898 ]),
1899 },
1900 infinity: Choice::from(0u8),
1901 };
1902 assert!(!bool::from(a.is_torsion_free()));
1903
1904 assert!(bool::from(G2Affine::identity().is_torsion_free()));
1905 assert!(bool::from(G2Affine::generator().is_torsion_free()));
1906}
1907
1908#[test]
1909fn test_mul_by_x() {
1910 let generator = G2Projective::generator();
1913 let x = if crate::BLS_X_IS_NEGATIVE {
1914 -Scalar::from(crate::BLS_X)
1915 } else {
1916 Scalar::from(crate::BLS_X)
1917 };
1918 assert_eq!(generator.mul_by_x(), generator * x);
1919
1920 let point = G2Projective::generator() * Scalar::from(42);
1921 assert_eq!(point.mul_by_x(), point * x);
1922}
1923
1924#[test]
1925fn test_psi() {
1926 let generator = G2Projective::generator();
1927
1928 let z = Fp2 {
1929 c0: Fp::from_raw_unchecked([
1930 0x0ef2ddffab187c0a,
1931 0x2424522b7d5ecbfc,
1932 0xc6f341a3398054f4,
1933 0x5523ddf409502df0,
1934 0xd55c0b5a88e0dd97,
1935 0x066428d704923e52,
1936 ]),
1937 c1: Fp::from_raw_unchecked([
1938 0x538bbe0c95b4878d,
1939 0xad04a50379522881,
1940 0x6d5c05bf5c12fb64,
1941 0x4ce4a069a2d34787,
1942 0x59ea6c8d0dffaeaf,
1943 0x0d42a083a75bd6f3,
1944 ]),
1945 };
1946
1947 let point = G2Projective {
1949 x: Fp2 {
1950 c0: Fp::from_raw_unchecked([
1951 0xee4c8cb7c047eaf2,
1952 0x44ca22eee036b604,
1953 0x33b3affb2aefe101,
1954 0x15d3e45bbafaeb02,
1955 0x7bfc2154cd7419a4,
1956 0x0a2d0c2b756e5edc,
1957 ]),
1958 c1: Fp::from_raw_unchecked([
1959 0xfc224361029a8777,
1960 0x4cbf2baab8740924,
1961 0xc5008c6ec6592c89,
1962 0xecc2c57b472a9c2d,
1963 0x8613eafd9d81ffb1,
1964 0x10fe54daa2d3d495,
1965 ]),
1966 } * z,
1967 y: Fp2 {
1968 c0: Fp::from_raw_unchecked([
1969 0x7de7edc43953b75c,
1970 0x58be1d2de35e87dc,
1971 0x5731d30b0e337b40,
1972 0xbe93b60cfeaae4c9,
1973 0x8b22c203764bedca,
1974 0x01616c8d1033b771,
1975 ]),
1976 c1: Fp::from_raw_unchecked([
1977 0xea126fe476b5733b,
1978 0x85cee68b5dae1652,
1979 0x98247779f7272b04,
1980 0xa649c8b468c6e808,
1981 0xb5b9a62dff0c4e45,
1982 0x1555b67fc7bbe73d,
1983 ]),
1984 },
1985 z: z.square() * z,
1986 };
1987 assert!(bool::from(point.is_on_curve()));
1988
1989 assert_eq!(generator.psi2(), generator.psi().psi());
1991 assert_eq!(point.psi2(), point.psi().psi());
1992 assert_eq!(generator.double().psi(), generator.psi().double());
1994 assert_eq!(point.psi() + generator.psi(), (point + generator).psi());
1995 let mut normalized_point = [G2Affine::identity()];
1997 G2Projective::batch_normalize(&[point], &mut normalized_point);
1998 let normalized_point = G2Projective::from(normalized_point[0]);
1999 assert_eq!(point.psi(), normalized_point.psi());
2000 assert_eq!(point.psi2(), normalized_point.psi2());
2001}
2002
2003#[test]
2004fn test_clear_cofactor() {
2005 let z = Fp2 {
2006 c0: Fp::from_raw_unchecked([
2007 0x0ef2ddffab187c0a,
2008 0x2424522b7d5ecbfc,
2009 0xc6f341a3398054f4,
2010 0x5523ddf409502df0,
2011 0xd55c0b5a88e0dd97,
2012 0x066428d704923e52,
2013 ]),
2014 c1: Fp::from_raw_unchecked([
2015 0x538bbe0c95b4878d,
2016 0xad04a50379522881,
2017 0x6d5c05bf5c12fb64,
2018 0x4ce4a069a2d34787,
2019 0x59ea6c8d0dffaeaf,
2020 0x0d42a083a75bd6f3,
2021 ]),
2022 };
2023
2024 let point = G2Projective {
2026 x: Fp2 {
2027 c0: Fp::from_raw_unchecked([
2028 0xee4c8cb7c047eaf2,
2029 0x44ca22eee036b604,
2030 0x33b3affb2aefe101,
2031 0x15d3e45bbafaeb02,
2032 0x7bfc2154cd7419a4,
2033 0x0a2d0c2b756e5edc,
2034 ]),
2035 c1: Fp::from_raw_unchecked([
2036 0xfc224361029a8777,
2037 0x4cbf2baab8740924,
2038 0xc5008c6ec6592c89,
2039 0xecc2c57b472a9c2d,
2040 0x8613eafd9d81ffb1,
2041 0x10fe54daa2d3d495,
2042 ]),
2043 } * z,
2044 y: Fp2 {
2045 c0: Fp::from_raw_unchecked([
2046 0x7de7edc43953b75c,
2047 0x58be1d2de35e87dc,
2048 0x5731d30b0e337b40,
2049 0xbe93b60cfeaae4c9,
2050 0x8b22c203764bedca,
2051 0x01616c8d1033b771,
2052 ]),
2053 c1: Fp::from_raw_unchecked([
2054 0xea126fe476b5733b,
2055 0x85cee68b5dae1652,
2056 0x98247779f7272b04,
2057 0xa649c8b468c6e808,
2058 0xb5b9a62dff0c4e45,
2059 0x1555b67fc7bbe73d,
2060 ]),
2061 },
2062 z: z.square() * z,
2063 };
2064
2065 assert!(bool::from(point.is_on_curve()));
2066 assert!(!bool::from(G2Affine::from(point).is_torsion_free()));
2067 let cleared_point = point.clear_cofactor();
2068
2069 assert!(bool::from(cleared_point.is_on_curve()));
2070 assert!(bool::from(G2Affine::from(cleared_point).is_torsion_free()));
2071
2072 let generator = G2Projective::generator();
2075 assert!(bool::from(generator.clear_cofactor().is_on_curve()));
2076 let id = G2Projective::identity();
2077 assert!(bool::from(id.clear_cofactor().is_on_curve()));
2078
2079 let h_eff_modq: [u8; 32] = [
2082 0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16,
2083 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2084 0x00, 0x00,
2085 ];
2086 assert_eq!(generator.clear_cofactor(), generator.multiply(&h_eff_modq));
2087 assert_eq!(
2088 cleared_point.clear_cofactor(),
2089 cleared_point.multiply(&h_eff_modq)
2090 );
2091}
2092
2093#[test]
2094fn test_batch_normalize() {
2095 let a = G2Projective::generator().double();
2096 let b = a.double();
2097 let c = b.double();
2098
2099 for a_identity in (0..=1).map(|n| n == 1) {
2100 for b_identity in (0..=1).map(|n| n == 1) {
2101 for c_identity in (0..=1).map(|n| n == 1) {
2102 let mut v = [a, b, c];
2103 if a_identity {
2104 v[0] = G2Projective::identity()
2105 }
2106 if b_identity {
2107 v[1] = G2Projective::identity()
2108 }
2109 if c_identity {
2110 v[2] = G2Projective::identity()
2111 }
2112
2113 let mut t = [
2114 G2Affine::identity(),
2115 G2Affine::identity(),
2116 G2Affine::identity(),
2117 ];
2118 let expected = [
2119 G2Affine::from(v[0]),
2120 G2Affine::from(v[1]),
2121 G2Affine::from(v[2]),
2122 ];
2123
2124 G2Projective::batch_normalize(&v[..], &mut t[..]);
2125
2126 assert_eq!(&t[..], &expected[..]);
2127 }
2128 }
2129 }
2130}
2131
2132#[cfg(feature = "zeroize")]
2133#[test]
2134fn test_zeroize() {
2135 use zeroize::Zeroize;
2136
2137 let mut a = G2Affine::generator();
2138 a.zeroize();
2139 assert!(bool::from(a.is_identity()));
2140
2141 let mut a = G2Projective::generator();
2142 a.zeroize();
2143 assert!(bool::from(a.is_identity()));
2144
2145 let mut a = GroupEncoding::to_bytes(&G2Affine::generator());
2146 a.zeroize();
2147 assert_eq!(&a, &G2Compressed::default());
2148
2149 let mut a = UncompressedEncoding::to_uncompressed(&G2Affine::generator());
2150 a.zeroize();
2151 assert_eq!(&a, &G2Uncompressed::default());
2152}
2153
2154#[test]
2155fn test_commutative_scalar_subgroup_multiplication() {
2156 let a = Scalar::from_raw([
2157 0x1fff_3231_233f_fffd,
2158 0x4884_b7fa_0003_4802,
2159 0x998c_4fef_ecbc_4ff3,
2160 0x1824_b159_acc5_0562,
2161 ]);
2162
2163 let g2_a = G2Affine::generator();
2164 let g2_p = G2Projective::generator();
2165
2166 assert_eq!(&g2_a * &a, &a * &g2_a);
2168 assert_eq!(&g2_p * &a, &a * &g2_p);
2169
2170 assert_eq!(&g2_a * a.clone(), a.clone() * &g2_a);
2172 assert_eq!(&g2_p * a.clone(), a.clone() * &g2_p);
2173 assert_eq!(g2_a.clone() * &a, &a * g2_a.clone());
2174 assert_eq!(g2_p.clone() * &a, &a * g2_p.clone());
2175
2176 assert_eq!(g2_p * a, a * g2_p);
2178 assert_eq!(g2_a * a, a * g2_a);
2179}