1use core::borrow::Borrow;
5use core::fmt;
6use core::iter::Sum;
7use core::ops::{Add, Mul, Neg, Sub};
8use ff::Field;
9use group::{
10 prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
11 Curve, Group, GroupEncoding, UncompressedEncoding,
12};
13use pasta_curves::arithmetic::{Coordinates, CurveAffine, CurveExt};
14use rand_core::RngCore;
15use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
16
17use crate::CurveAffineExt;
18use crate::{
19 impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
20 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
21};
22
23use super::fp::Fp;
24use super::fp2::Fp2;
25use super::hash_to_curve::{ExpandMsgXmd, HashToCurve};
26use super::Scalar;
27
28#[cfg(feature = "alloc")]
29use group::WnafGroup;
30
31#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
38#[derive(Copy, Clone, Debug)]
39pub struct G2Affine {
40 pub x: Fp2,
41 pub y: Fp2,
42 infinity: Choice,
43}
44
45impl Default for G2Affine {
46 fn default() -> G2Affine {
47 G2Affine::identity()
48 }
49}
50
51#[cfg(feature = "zeroize")]
52impl zeroize::DefaultIsZeroes for G2Affine {}
53
54impl fmt::Display for G2Affine {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 write!(f, "{self:?}")
57 }
58}
59
60impl<'a> From<&'a G2Projective> for G2Affine {
61 fn from(p: &'a G2Projective) -> G2Affine {
62 let zinv = p.z.invert().unwrap_or(Fp2::zero());
63 let x = p.x * zinv;
64 let y = p.y * zinv;
65
66 let tmp = G2Affine {
67 x,
68 y,
69 infinity: Choice::from(0u8),
70 };
71
72 G2Affine::conditional_select(&tmp, &G2Affine::identity(), zinv.is_zero())
73 }
74}
75
76impl From<G2Projective> for G2Affine {
77 fn from(p: G2Projective) -> G2Affine {
78 G2Affine::from(&p)
79 }
80}
81
82impl ConstantTimeEq for G2Affine {
83 fn ct_eq(&self, other: &Self) -> Choice {
84 (self.infinity & other.infinity)
89 | ((!self.infinity)
90 & (!other.infinity)
91 & self.x.ct_eq(&other.x)
92 & self.y.ct_eq(&other.y))
93 }
94}
95
96impl ConditionallySelectable for G2Affine {
97 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
98 G2Affine {
99 x: Fp2::conditional_select(&a.x, &b.x, choice),
100 y: Fp2::conditional_select(&a.y, &b.y, choice),
101 infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
102 }
103 }
104}
105
106impl Eq for G2Affine {}
107impl PartialEq for G2Affine {
108 #[inline]
109 fn eq(&self, other: &Self) -> bool {
110 bool::from(self.ct_eq(other))
111 }
112}
113
114impl<'a> Neg for &'a G2Affine {
115 type Output = G2Affine;
116
117 #[inline]
118 fn neg(self) -> G2Affine {
119 G2Affine {
120 x: self.x,
121 y: Fp2::conditional_select(&-self.y, &Fp2::one(), self.infinity),
122 infinity: self.infinity,
123 }
124 }
125}
126
127impl Neg for G2Affine {
128 type Output = G2Affine;
129
130 #[inline]
131 fn neg(self) -> G2Affine {
132 -&self
133 }
134}
135
136impl<'a, 'b> Add<&'b G2Projective> for &'a G2Affine {
137 type Output = G2Projective;
138
139 #[inline]
140 fn add(self, rhs: &'b G2Projective) -> G2Projective {
141 rhs.add_mixed(self)
142 }
143}
144
145impl<'a, 'b> Add<&'b G2Affine> for &'a G2Projective {
146 type Output = G2Projective;
147
148 #[inline]
149 fn add(self, rhs: &'b G2Affine) -> G2Projective {
150 self.add_mixed(rhs)
151 }
152}
153
154impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Affine {
155 type Output = G2Projective;
156
157 #[inline]
158 fn sub(self, rhs: &'b G2Projective) -> G2Projective {
159 self + (-rhs)
160 }
161}
162
163impl<'a, 'b> Sub<&'b G2Affine> for &'a G2Projective {
164 type Output = G2Projective;
165
166 #[inline]
167 fn sub(self, rhs: &'b G2Affine) -> G2Projective {
168 self + (-rhs)
169 }
170}
171
172impl Add<G2Affine> for G2Affine {
173 type Output = G2Projective;
174 fn add(self, rhs: G2Affine) -> Self::Output {
175 self.to_curve() + rhs.to_curve()
176 }
177}
178
179impl Sub<G2Affine> for G2Affine {
180 type Output = G2Projective;
181 fn sub(self, rhs: G2Affine) -> Self::Output {
182 self + -rhs
183 }
184}
185
186impl<T> Sum<T> for G2Projective
187where
188 T: Borrow<G2Projective>,
189{
190 fn sum<I>(iter: I) -> Self
191 where
192 I: Iterator<Item = T>,
193 {
194 iter.fold(Self::identity(), |acc, item| acc + item.borrow())
195 }
196}
197
198impl_binops_additive!(G2Projective, G2Affine);
199impl_binops_additive_specify_output!(G2Affine, G2Projective, G2Projective);
200
201const B: Fp2 = Fp2 {
202 c0: Fp::from_raw_unchecked([
203 0xaa27_0000_000c_fff3,
204 0x53cc_0032_fc34_000a,
205 0x478f_e97a_6b0a_807f,
206 0xb1d3_7ebe_e6ba_24d7,
207 0x8ec9_733b_bf78_ab2f,
208 0x09d6_4551_3d83_de7e,
209 ]),
210 c1: Fp::from_raw_unchecked([
211 0xaa27_0000_000c_fff3,
212 0x53cc_0032_fc34_000a,
213 0x478f_e97a_6b0a_807f,
214 0xb1d3_7ebe_e6ba_24d7,
215 0x8ec9_733b_bf78_ab2f,
216 0x09d6_4551_3d83_de7e,
217 ]),
218};
219
220const B3: Fp2 = Fp2::add(&Fp2::add(&B, &B), &B);
221
222impl G2Affine {
223 pub fn identity() -> G2Affine {
225 G2Affine {
226 x: Fp2::zero(),
227 y: Fp2::one(),
228 infinity: Choice::from(1u8),
229 }
230 }
231
232 pub fn random(mut rng: impl RngCore) -> Self {
233 loop {
234 let x = Fp2::random(&mut rng);
235 let ysign = (rng.next_u32() % 2) as u8;
236
237 let x3 = x.square() * x;
238 let y = (x3 + B).sqrt();
239 if let Some(y) = Option::<Fp2>::from(y) {
240 let sign = y.to_bytes()[0] & 1;
241 let y = if ysign ^ sign == 0 { y } else { -y };
242
243 let p = G2Affine {
244 x,
245 y,
246 infinity: 0.into(),
247 };
248
249 let p = p.to_curve();
250 return p.clear_cofactor().to_affine();
251 }
252 }
253 }
254
255 pub fn generator() -> G2Affine {
258 G2Affine {
259 x: Fp2 {
260 c0: Fp::from_raw_unchecked([
261 0xf5f2_8fa2_0294_0a10,
262 0xb3f5_fb26_87b4_961a,
263 0xa1a8_93b5_3e2a_e580,
264 0x9894_999d_1a3c_aee9,
265 0x6f67_b763_1863_366b,
266 0x0581_9192_4350_bcd7,
267 ]),
268 c1: Fp::from_raw_unchecked([
269 0xa5a9_c075_9e23_f606,
270 0xaaa0_c59d_bccd_60c3,
271 0x3bb1_7e18_e286_7806,
272 0x1b1a_b6cc_8541_b367,
273 0xc2b6_ed0e_f215_8547,
274 0x1192_2a09_7360_edf3,
275 ]),
276 },
277 y: Fp2 {
278 c0: Fp::from_raw_unchecked([
279 0x4c73_0af8_6049_4c4a,
280 0x597c_fa1f_5e36_9c5a,
281 0xe7e6_856c_aa0a_635a,
282 0xbbef_b5e9_6e0d_495f,
283 0x07d3_a975_f0ef_25a2,
284 0x0083_fd8e_7e80_dae5,
285 ]),
286 c1: Fp::from_raw_unchecked([
287 0xadc0_fc92_df64_b05d,
288 0x18aa_270a_2b14_61dc,
289 0x86ad_ac6a_3be4_eba0,
290 0x7949_5c4e_c93d_a33a,
291 0xe717_5850_a43c_caed,
292 0x0b2b_c2a1_63de_1bf2,
293 ]),
294 },
295 infinity: Choice::from(0u8),
296 }
297 }
298
299 pub fn to_compressed_be(&self) -> [u8; 96] {
302 let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
305
306 let mut res = [0; 96];
307
308 res[0..48].copy_from_slice(&x.c1.to_bytes_be()[..]);
309 res[48..96].copy_from_slice(&x.c0.to_bytes_be()[..]);
310
311 res[0] |= 1u8 << 7;
313
314 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
316
317 res[0] |= u8::conditional_select(
321 &0u8,
322 &(1u8 << 5),
323 (!self.infinity) & self.y.lexicographically_largest(),
324 );
325
326 res
327 }
328
329 pub fn to_compressed_le(&self) -> [u8; 96] {
331 let mut bytes = self.to_compressed_be();
332 bytes.reverse();
333 bytes
334 }
335
336 pub fn to_uncompressed_be(&self) -> [u8; 192] {
339 let mut res = [0; 192];
340
341 let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
342 let y = Fp2::conditional_select(&self.y, &Fp2::zero(), self.infinity);
343
344 res[0..48].copy_from_slice(&x.c1.to_bytes_be()[..]);
345 res[48..96].copy_from_slice(&x.c0.to_bytes_be()[..]);
346 res[96..144].copy_from_slice(&y.c1.to_bytes_be()[..]);
347 res[144..192].copy_from_slice(&y.c0.to_bytes_be()[..]);
348
349 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
351
352 res
353 }
354
355 pub fn to_uncompressed_le(&self) -> [u8; 192] {
357 let mut res = [0; 192];
358
359 let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
360 let y = Fp2::conditional_select(&self.y, &Fp2::zero(), self.infinity);
361
362 res[0..48].copy_from_slice(&x.c1.to_bytes()[..]);
363 res[48..96].copy_from_slice(&x.c0.to_bytes()[..]);
364 res[96..144].copy_from_slice(&y.c1.to_bytes()[..]);
365 res[144..192].copy_from_slice(&y.c0.to_bytes()[..]);
366
367 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
369
370 res
371 }
372
373 pub fn from_uncompressed_be(bytes: &[u8; 192]) -> CtOption<Self> {
376 Self::from_uncompressed_unchecked_be(bytes)
377 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
378 }
379
380 pub fn from_uncompressed_unchecked_be(bytes: &[u8; 192]) -> CtOption<Self> {
385 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
387 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
388 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
389
390 let xc1 = {
392 let mut tmp = [0; 48];
393 tmp.copy_from_slice(&bytes[0..48]);
394
395 tmp[0] &= 0b0001_1111;
397
398 Fp::from_bytes_be(&tmp)
399 };
400 let xc0 = {
401 let mut tmp = [0; 48];
402 tmp.copy_from_slice(&bytes[48..96]);
403
404 Fp::from_bytes_be(&tmp)
405 };
406
407 let yc1 = {
409 let mut tmp = [0; 48];
410 tmp.copy_from_slice(&bytes[96..144]);
411
412 Fp::from_bytes_be(&tmp)
413 };
414 let yc0 = {
415 let mut tmp = [0; 48];
416 tmp.copy_from_slice(&bytes[144..192]);
417
418 Fp::from_bytes_be(&tmp)
419 };
420
421 xc1.and_then(|xc1| {
422 xc0.and_then(|xc0| {
423 yc1.and_then(|yc1| {
424 yc0.and_then(|yc0| {
425 let x = Fp2 {
426 c0: xc0,
427 c1: xc1
428 };
429 let y = Fp2 {
430 c0: yc0,
431 c1: yc1
432 };
433
434 let p = G2Affine::conditional_select(
436 &G2Affine {
437 x,
438 y,
439 infinity: infinity_flag_set,
440 },
441 &G2Affine::identity(),
442 infinity_flag_set,
443 );
444
445 CtOption::new(
446 p,
447 ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero())) &
449 (!compression_flag_set) &
451 (!sort_flag_set),
453 )
454 })
455 })
456 })
457 })
458 }
459
460 pub fn from_compressed_be(bytes: &[u8; 96]) -> CtOption<Self> {
463 Self::from_compressed_unchecked_be(bytes)
467 .and_then(|p| CtOption::new(p, p.is_torsion_free()))
468 }
469
470 pub fn from_compressed_unchecked_be(bytes: &[u8; 96]) -> CtOption<Self> {
475 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
477 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
478 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
479
480 let xc1 = {
482 let mut tmp = [0; 48];
483 tmp.copy_from_slice(&bytes[0..48]);
484
485 tmp[0] &= 0b0001_1111;
487
488 Fp::from_bytes_be(&tmp)
489 };
490 let xc0 = {
491 let mut tmp = [0; 48];
492 tmp.copy_from_slice(&bytes[48..96]);
493
494 Fp::from_bytes_be(&tmp)
495 };
496
497 xc1.and_then(|xc1| {
498 xc0.and_then(|xc0| {
499 let x = Fp2 { c0: xc0, c1: xc1 };
500
501 CtOption::new(
508 G2Affine::identity(),
509 infinity_flag_set & compression_flag_set & (!sort_flag_set) & x.is_zero(), )
514 .or_else(|| {
515 ((x.square() * x) + B).sqrt().and_then(|y| {
517 let y = Fp2::conditional_select(
519 &y,
520 &-y,
521 y.lexicographically_largest() ^ sort_flag_set,
522 );
523
524 CtOption::new(
525 G2Affine {
526 x,
527 y,
528 infinity: infinity_flag_set,
529 },
530 (!infinity_flag_set) & compression_flag_set, )
533 })
534 })
535 })
536 })
537 }
538
539 pub fn from_uncompressed_le(bytes: &[u8; 192]) -> CtOption<Self> {
542 Self::from_uncompressed_unchecked_le(bytes)
543 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
544 }
545
546 pub fn from_uncompressed_unchecked_le(bytes: &[u8; 192]) -> CtOption<Self> {
551 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
553
554 let xc1 = {
556 let mut tmp = [0; 48];
557 tmp.copy_from_slice(&bytes[0..48]);
558
559 Fp::from_bytes(&tmp)
560 };
561 let xc0 = {
562 let mut tmp = [0; 48];
563 tmp.copy_from_slice(&bytes[48..96]);
564
565 Fp::from_bytes(&tmp)
566 };
567
568 let yc1 = {
570 let mut tmp = [0; 48];
571 tmp.copy_from_slice(&bytes[96..144]);
572
573 Fp::from_bytes(&tmp)
574 };
575 let yc0 = {
576 let mut tmp = [0; 48];
577 tmp.copy_from_slice(&bytes[144..192]);
578
579 Fp::from_bytes(&tmp)
580 };
581
582 xc1.and_then(|xc1| {
583 xc0.and_then(|xc0| {
584 yc1.and_then(|yc1| {
585 yc0.and_then(|yc0| {
586 let x = Fp2 { c0: xc0, c1: xc1 };
587 let y = Fp2 { c0: yc0, c1: yc1 };
588
589 let p = G2Affine::conditional_select(
591 &G2Affine {
592 x,
593 y,
594 infinity: infinity_flag_set,
595 },
596 &G2Affine::identity(),
597 infinity_flag_set,
598 );
599
600 CtOption::new(
601 p,
602 (!infinity_flag_set) | (x.is_zero() & y.is_zero()),
604 )
605 })
606 })
607 })
608 })
609 }
610
611 pub fn from_compressed_unchecked_le(bytes: &[u8; 96]) -> CtOption<Self> {
614 let mut bytes = *bytes;
615 bytes.reverse();
616 Self::from_compressed_unchecked_be(&bytes)
617 }
618
619 pub fn from_compressed_le(bytes: &[u8; 96]) -> CtOption<Self> {
621 Self::from_compressed_unchecked_le(bytes)
625 .and_then(|p| CtOption::new(p, p.is_torsion_free()))
626 }
627
628 #[inline]
630 pub fn is_identity(&self) -> Choice {
631 self.infinity
632 }
633
634 pub fn is_torsion_free(&self) -> Choice {
638 let p = G2Projective::from(self);
643 p.psi().ct_eq(&p.mul_by_x())
644 }
645
646 pub fn is_on_curve(&self) -> Choice {
649 (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
651 }
652}
653
654#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
656#[derive(Copy, Clone, Debug)]
657pub struct G2Projective {
658 pub(crate) x: Fp2,
659 pub(crate) y: Fp2,
660 pub(crate) z: Fp2,
661}
662
663impl Default for G2Projective {
664 fn default() -> G2Projective {
665 G2Projective::identity()
666 }
667}
668
669#[cfg(feature = "zeroize")]
670impl zeroize::DefaultIsZeroes for G2Projective {}
671
672impl fmt::Display for G2Projective {
673 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
674 write!(f, "{self:?}")
675 }
676}
677
678impl<'a> From<&'a G2Affine> for G2Projective {
679 fn from(p: &'a G2Affine) -> G2Projective {
680 G2Projective {
681 x: p.x,
682 y: p.y,
683 z: Fp2::conditional_select(&Fp2::one(), &Fp2::zero(), p.infinity),
684 }
685 }
686}
687
688impl From<G2Affine> for G2Projective {
689 fn from(p: G2Affine) -> G2Projective {
690 G2Projective::from(&p)
691 }
692}
693
694impl ConstantTimeEq for G2Projective {
695 fn ct_eq(&self, other: &Self) -> Choice {
696 let x1 = self.x * other.z;
699 let x2 = other.x * self.z;
700
701 let y1 = self.y * other.z;
702 let y2 = other.y * self.z;
703
704 let self_is_zero = self.z.is_zero();
705 let other_is_zero = other.z.is_zero();
706
707 (self_is_zero & other_is_zero) | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
709 }
711}
712
713impl ConditionallySelectable for G2Projective {
714 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
715 G2Projective {
716 x: Fp2::conditional_select(&a.x, &b.x, choice),
717 y: Fp2::conditional_select(&a.y, &b.y, choice),
718 z: Fp2::conditional_select(&a.z, &b.z, choice),
719 }
720 }
721}
722
723impl Eq for G2Projective {}
724impl PartialEq for G2Projective {
725 #[inline]
726 fn eq(&self, other: &Self) -> bool {
727 bool::from(self.ct_eq(other))
728 }
729}
730
731impl<'a> Neg for &'a G2Projective {
732 type Output = G2Projective;
733
734 #[inline]
735 fn neg(self) -> G2Projective {
736 G2Projective {
737 x: self.x,
738 y: -self.y,
739 z: self.z,
740 }
741 }
742}
743
744impl Neg for G2Projective {
745 type Output = G2Projective;
746
747 #[inline]
748 fn neg(self) -> G2Projective {
749 -&self
750 }
751}
752
753impl<'a, 'b> Add<&'b G2Projective> for &'a G2Projective {
754 type Output = G2Projective;
755
756 #[inline]
757 fn add(self, rhs: &'b G2Projective) -> G2Projective {
758 self.add(rhs)
759 }
760}
761
762impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Projective {
763 type Output = G2Projective;
764
765 #[inline]
766 fn sub(self, rhs: &'b G2Projective) -> G2Projective {
767 self + (-rhs)
768 }
769}
770
771impl<'a, 'b> Mul<&'b Scalar> for &'a G2Projective {
772 type Output = G2Projective;
773
774 fn mul(self, other: &'b Scalar) -> Self::Output {
775 self.multiply(&other.to_bytes())
776 }
777}
778
779impl<'a, 'b> Mul<&'b G2Projective> for &'a Scalar {
780 type Output = G2Projective;
781
782 #[inline]
783 fn mul(self, rhs: &'b G2Projective) -> Self::Output {
784 rhs * self
785 }
786}
787
788impl<'a, 'b> Mul<&'b Scalar> for &'a G2Affine {
789 type Output = G2Projective;
790
791 fn mul(self, other: &'b Scalar) -> Self::Output {
792 G2Projective::from(self).multiply(&other.to_bytes())
793 }
794}
795
796impl<'a, 'b> Mul<&'b G2Affine> for &'a Scalar {
797 type Output = G2Projective;
798
799 #[inline]
800 fn mul(self, rhs: &'b G2Affine) -> Self::Output {
801 rhs * self
802 }
803}
804
805impl_binops_additive!(G2Projective, G2Projective);
806impl_binops_multiplicative!(G2Projective, Scalar);
807impl_binops_multiplicative_mixed!(G2Affine, Scalar, G2Projective);
808impl_binops_multiplicative_mixed!(Scalar, G2Affine, G2Projective);
809impl_binops_multiplicative_mixed!(Scalar, G2Projective, G2Projective);
810
811#[inline(always)]
812fn mul_by_3b(x: Fp2) -> Fp2 {
813 x * B3
814}
815
816impl G2Projective {
817 pub fn identity() -> G2Projective {
819 G2Projective {
820 x: Fp2::zero(),
821 y: Fp2::one(),
822 z: Fp2::zero(),
823 }
824 }
825
826 pub fn generator() -> G2Projective {
829 G2Projective {
830 x: Fp2 {
831 c0: Fp::from_raw_unchecked([
832 0xf5f2_8fa2_0294_0a10,
833 0xb3f5_fb26_87b4_961a,
834 0xa1a8_93b5_3e2a_e580,
835 0x9894_999d_1a3c_aee9,
836 0x6f67_b763_1863_366b,
837 0x0581_9192_4350_bcd7,
838 ]),
839 c1: Fp::from_raw_unchecked([
840 0xa5a9_c075_9e23_f606,
841 0xaaa0_c59d_bccd_60c3,
842 0x3bb1_7e18_e286_7806,
843 0x1b1a_b6cc_8541_b367,
844 0xc2b6_ed0e_f215_8547,
845 0x1192_2a09_7360_edf3,
846 ]),
847 },
848 y: Fp2 {
849 c0: Fp::from_raw_unchecked([
850 0x4c73_0af8_6049_4c4a,
851 0x597c_fa1f_5e36_9c5a,
852 0xe7e6_856c_aa0a_635a,
853 0xbbef_b5e9_6e0d_495f,
854 0x07d3_a975_f0ef_25a2,
855 0x0083_fd8e_7e80_dae5,
856 ]),
857 c1: Fp::from_raw_unchecked([
858 0xadc0_fc92_df64_b05d,
859 0x18aa_270a_2b14_61dc,
860 0x86ad_ac6a_3be4_eba0,
861 0x7949_5c4e_c93d_a33a,
862 0xe717_5850_a43c_caed,
863 0x0b2b_c2a1_63de_1bf2,
864 ]),
865 },
866 z: Fp2::one(),
867 }
868 }
869
870 pub fn double(&self) -> G2Projective {
872 let t0 = self.y.square();
875 let z3 = t0 + t0;
876 let z3 = z3 + z3;
877 let z3 = z3 + z3;
878 let t1 = self.y * self.z;
879 let t2 = self.z.square();
880 let t2 = mul_by_3b(t2);
881 let x3 = t2 * z3;
882 let y3 = t0 + t2;
883 let z3 = t1 * z3;
884 let t1 = t2 + t2;
885 let t2 = t1 + t2;
886 let t0 = t0 - t2;
887 let y3 = t0 * y3;
888 let y3 = x3 + y3;
889 let t1 = self.x * self.y;
890 let x3 = t0 * t1;
891 let x3 = x3 + x3;
892
893 let tmp = G2Projective {
894 x: x3,
895 y: y3,
896 z: z3,
897 };
898
899 G2Projective::conditional_select(&tmp, &G2Projective::identity(), self.is_identity())
900 }
901
902 pub fn add(&self, rhs: &G2Projective) -> G2Projective {
904 let t0 = self.x * rhs.x;
907 let t1 = self.y * rhs.y;
908 let t2 = self.z * rhs.z;
909 let t3 = self.x + self.y;
910 let t4 = rhs.x + rhs.y;
911 let t3 = t3 * t4;
912 let t4 = t0 + t1;
913 let t3 = t3 - t4;
914 let t4 = self.y + self.z;
915 let x3 = rhs.y + rhs.z;
916 let t4 = t4 * x3;
917 let x3 = t1 + t2;
918 let t4 = t4 - x3;
919 let x3 = self.x + self.z;
920 let y3 = rhs.x + rhs.z;
921 let x3 = x3 * y3;
922 let y3 = t0 + t2;
923 let y3 = x3 - y3;
924 let x3 = t0 + t0;
925 let t0 = x3 + t0;
926 let t2 = mul_by_3b(t2);
927 let z3 = t1 + t2;
928 let t1 = t1 - t2;
929 let y3 = mul_by_3b(y3);
930 let x3 = t4 * y3;
931 let t2 = t3 * t1;
932 let x3 = t2 - x3;
933 let y3 = y3 * t0;
934 let t1 = t1 * z3;
935 let y3 = t1 + y3;
936 let t0 = t0 * t3;
937 let z3 = z3 * t4;
938 let z3 = z3 + t0;
939
940 G2Projective {
941 x: x3,
942 y: y3,
943 z: z3,
944 }
945 }
946
947 pub fn add_mixed(&self, rhs: &G2Affine) -> G2Projective {
949 let t0 = self.x * rhs.x;
952 let t1 = self.y * rhs.y;
953 let t3 = rhs.x + rhs.y;
954 let t4 = self.x + self.y;
955 let t3 = t3 * t4;
956 let t4 = t0 + t1;
957 let t3 = t3 - t4;
958 let t4 = rhs.y * self.z;
959 let t4 = t4 + self.y;
960 let y3 = rhs.x * self.z;
961 let y3 = y3 + self.x;
962 let x3 = t0 + t0;
963 let t0 = x3 + t0;
964 let t2 = mul_by_3b(self.z);
965 let z3 = t1 + t2;
966 let t1 = t1 - t2;
967 let y3 = mul_by_3b(y3);
968 let x3 = t4 * y3;
969 let t2 = t3 * t1;
970 let x3 = t2 - x3;
971 let y3 = y3 * t0;
972 let t1 = t1 * z3;
973 let y3 = t1 + y3;
974 let t0 = t0 * t3;
975 let z3 = z3 * t4;
976 let z3 = z3 + t0;
977
978 let tmp = G2Projective {
979 x: x3,
980 y: y3,
981 z: z3,
982 };
983
984 G2Projective::conditional_select(&tmp, self, rhs.is_identity())
985 }
986
987 fn multiply(&self, by: &[u8]) -> G2Projective {
988 let mut acc = G2Projective::identity();
989
990 for bit in by
997 .iter()
998 .rev()
999 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
1000 .skip(1)
1001 {
1002 acc = acc.double();
1003 acc = G2Projective::conditional_select(&acc, &(acc + self), bit);
1004 }
1005
1006 acc
1007 }
1008
1009 fn psi(&self) -> G2Projective {
1010 let psi_coeff_x = Fp2 {
1012 c0: Fp::zero(),
1013 c1: Fp::from_raw_unchecked([
1014 0x890dc9e4867545c3,
1015 0x2af322533285a5d5,
1016 0x50880866309b7e2c,
1017 0xa20d1b8c7e881024,
1018 0x14e4f04fe2db9068,
1019 0x14e56d3f1564853a,
1020 ]),
1021 };
1022 let psi_coeff_y = Fp2 {
1024 c0: Fp::from_raw_unchecked([
1025 0x3e2f585da55c9ad1,
1026 0x4294213d86c18183,
1027 0x382844c88b623732,
1028 0x92ad2afd19103e18,
1029 0x1d794e4fac7cf0b9,
1030 0x0bd592fc7d825ec8,
1031 ]),
1032 c1: Fp::from_raw_unchecked([
1033 0x7bcfa7a25aa30fda,
1034 0xdc17dec12a927e7c,
1035 0x2f088dd86b4ebef1,
1036 0xd1ca2087da74d4a7,
1037 0x2da2596696cebc1d,
1038 0x0e2b7eedbbfd87d2,
1039 ]),
1040 };
1041
1042 G2Projective {
1043 x: self.x.frobenius_map() * psi_coeff_x,
1045 y: self.y.frobenius_map() * psi_coeff_y,
1047 z: self.z.frobenius_map(),
1049 }
1050 }
1051
1052 fn psi2(&self) -> G2Projective {
1053 let psi2_coeff_x = Fp2 {
1055 c0: Fp::from_raw_unchecked([
1056 0xcd03c9e48671f071,
1057 0x5dab22461fcda5d2,
1058 0x587042afd3851b95,
1059 0x8eb60ebe01bacb9e,
1060 0x03f97d6e83d050d2,
1061 0x18f0206554638741,
1062 ]),
1063 c1: Fp::zero(),
1064 };
1065
1066 G2Projective {
1067 x: self.x * psi2_coeff_x,
1069 y: self.y.neg(),
1071 z: self.z,
1073 }
1074 }
1075
1076 fn mul_by_x(&self) -> G2Projective {
1078 let mut xself = G2Projective::identity();
1079 let mut x = super::BLS_X >> 1;
1081 let mut acc = *self;
1082 while x != 0 {
1083 acc = acc.double();
1084 if x % 2 == 1 {
1085 xself += acc;
1086 }
1087 x >>= 1;
1088 }
1089 if super::BLS_X_IS_NEGATIVE {
1091 xself = -xself;
1092 }
1093 xself
1094 }
1095
1096 pub fn clear_cofactor(&self) -> G2Projective {
1101 let t1 = self.mul_by_x(); let t2 = self.psi(); self.double().psi2() + (t1 + t2).mul_by_x() - t1 - t2 - self }
1110
1111 pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) {
1114 assert_eq!(p.len(), q.len());
1115
1116 let mut acc = Fp2::one();
1117 for (p, q) in p.iter().zip(q.iter_mut()) {
1118 q.x = acc;
1121
1122 acc = Fp2::conditional_select(&(acc * p.z), &acc, p.is_identity());
1124 }
1125
1126 acc = acc.invert().unwrap();
1129
1130 for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
1131 let skip = p.is_identity();
1132
1133 let tmp = q.x * acc;
1135
1136 acc = Fp2::conditional_select(&(acc * p.z), &acc, skip);
1138
1139 q.x = p.x * tmp;
1141 q.y = p.y * tmp;
1142 q.infinity = Choice::from(0u8);
1143
1144 *q = G2Affine::conditional_select(q, &G2Affine::identity(), skip);
1145 }
1146 }
1147
1148 #[inline]
1150 pub fn is_identity(&self) -> Choice {
1151 self.z.is_zero()
1152 }
1153
1154 pub fn is_on_curve(&self) -> Choice {
1157 (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
1160 | self.z.is_zero()
1161 }
1162}
1163
1164#[derive(Clone, Copy)]
1165pub struct G2Compressed([u8; 96]);
1166
1167impl fmt::Debug for G2Compressed {
1168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1169 self.0[..].fmt(f)
1170 }
1171}
1172
1173impl Default for G2Compressed {
1174 fn default() -> Self {
1175 G2Compressed([0; 96])
1176 }
1177}
1178
1179#[cfg(feature = "zeroize")]
1180impl zeroize::DefaultIsZeroes for G2Compressed {}
1181
1182impl AsRef<[u8]> for G2Compressed {
1183 fn as_ref(&self) -> &[u8] {
1184 &self.0
1185 }
1186}
1187
1188impl AsMut<[u8]> for G2Compressed {
1189 fn as_mut(&mut self) -> &mut [u8] {
1190 &mut self.0
1191 }
1192}
1193
1194impl ConstantTimeEq for G2Compressed {
1195 fn ct_eq(&self, other: &Self) -> Choice {
1196 self.0.ct_eq(&other.0)
1197 }
1198}
1199
1200impl Eq for G2Compressed {}
1201impl PartialEq for G2Compressed {
1202 #[inline]
1203 fn eq(&self, other: &Self) -> bool {
1204 bool::from(self.ct_eq(other))
1205 }
1206}
1207
1208impl TryFrom<&[u8]> for G2Compressed {
1209 type Error = std::array::TryFromSliceError;
1210
1211 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
1212 Ok(G2Compressed(value.try_into()?))
1213 }
1214}
1215
1216#[derive(Clone, Copy)]
1217pub struct G2Uncompressed([u8; 192]);
1218
1219impl fmt::Debug for G2Uncompressed {
1220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1221 self.0[..].fmt(f)
1222 }
1223}
1224
1225impl Default for G2Uncompressed {
1226 fn default() -> Self {
1227 G2Uncompressed([0; 192])
1228 }
1229}
1230
1231#[cfg(feature = "zeroize")]
1232impl zeroize::DefaultIsZeroes for G2Uncompressed {}
1233
1234impl AsRef<[u8]> for G2Uncompressed {
1235 fn as_ref(&self) -> &[u8] {
1236 &self.0
1237 }
1238}
1239
1240impl AsMut<[u8]> for G2Uncompressed {
1241 fn as_mut(&mut self) -> &mut [u8] {
1242 &mut self.0
1243 }
1244}
1245
1246impl ConstantTimeEq for G2Uncompressed {
1247 fn ct_eq(&self, other: &Self) -> Choice {
1248 self.0.ct_eq(&other.0)
1249 }
1250}
1251
1252impl Eq for G2Uncompressed {}
1253impl PartialEq for G2Uncompressed {
1254 #[inline]
1255 fn eq(&self, other: &Self) -> bool {
1256 bool::from(self.ct_eq(other))
1257 }
1258}
1259
1260impl TryFrom<&[u8]> for G2Uncompressed {
1261 type Error = std::array::TryFromSliceError;
1262
1263 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
1264 Ok(G2Uncompressed(value.try_into()?))
1265 }
1266}
1267
1268impl Group for G2Projective {
1269 type Scalar = Scalar;
1270
1271 fn random(mut rng: impl RngCore) -> Self {
1272 loop {
1273 let x = Fp2::random(&mut rng);
1274 let flip_sign = rng.next_u32() % 2 != 0;
1275
1276 let p = ((x.square() * x) + B).sqrt().map(|y| G2Affine {
1278 x,
1279 y: if flip_sign { -y } else { y },
1280 infinity: 0.into(),
1281 });
1282
1283 if p.is_some().into() {
1284 let p = p.unwrap().to_curve().clear_cofactor();
1285
1286 if bool::from(!p.is_identity()) {
1287 return p;
1288 }
1289 }
1290 }
1291 }
1292
1293 fn identity() -> Self {
1294 Self::identity()
1295 }
1296
1297 fn generator() -> Self {
1298 Self::generator()
1299 }
1300
1301 fn is_identity(&self) -> Choice {
1302 self.is_identity()
1303 }
1304
1305 #[must_use]
1306 fn double(&self) -> Self {
1307 self.double()
1308 }
1309}
1310
1311#[cfg(feature = "alloc")]
1312impl WnafGroup for G2Projective {
1313 fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
1314 const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071];
1315
1316 let mut ret = 4;
1317 for r in &RECOMMENDATIONS {
1318 if num_scalars > *r {
1319 ret += 1;
1320 } else {
1321 break;
1322 }
1323 }
1324
1325 ret
1326 }
1327}
1328
1329impl PrimeGroup for G2Projective {}
1330
1331impl Curve for G2Projective {
1332 type AffineRepr = G2Affine;
1333
1334 fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
1335 Self::batch_normalize(p, q);
1336 }
1337
1338 fn to_affine(&self) -> Self::AffineRepr {
1339 self.into()
1340 }
1341}
1342
1343impl PrimeCurve for G2Projective {
1344 type Affine = G2Affine;
1345}
1346
1347impl PrimeCurveAffine for G2Affine {
1348 type Scalar = Scalar;
1349 type Curve = G2Projective;
1350
1351 fn identity() -> Self {
1352 Self::identity()
1353 }
1354
1355 fn generator() -> Self {
1356 Self::generator()
1357 }
1358
1359 fn is_identity(&self) -> Choice {
1360 self.is_identity()
1361 }
1362
1363 fn to_curve(&self) -> Self::Curve {
1364 self.into()
1365 }
1366}
1367
1368impl GroupEncoding for G2Projective {
1369 type Repr = G2Compressed;
1370
1371 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1372 G2Affine::from_bytes(bytes).map(Self::from)
1373 }
1374
1375 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1376 G2Affine::from_bytes_unchecked(bytes).map(Self::from)
1377 }
1378
1379 fn to_bytes(&self) -> Self::Repr {
1380 G2Affine::from(self).to_bytes()
1381 }
1382}
1383
1384impl GroupEncoding for G2Affine {
1385 type Repr = G2Compressed;
1386
1387 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1388 Self::from_compressed_le(&bytes.0)
1389 }
1390
1391 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1392 Self::from_compressed_unchecked_le(&bytes.0)
1393 }
1394
1395 fn to_bytes(&self) -> Self::Repr {
1396 G2Compressed(self.to_compressed_le())
1397 }
1398}
1399
1400impl UncompressedEncoding for G2Affine {
1401 type Uncompressed = G2Uncompressed;
1402
1403 fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
1404 Self::from_uncompressed_le(&bytes.0)
1405 }
1406
1407 fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
1408 Self::from_uncompressed_unchecked_le(&bytes.0)
1409 }
1410
1411 fn to_uncompressed(&self) -> Self::Uncompressed {
1412 G2Uncompressed(self.to_uncompressed_le())
1413 }
1414}
1415
1416impl CurveExt for G2Projective {
1417 type ScalarExt = Scalar;
1418 type Base = Fp2;
1419 type AffineExt = G2Affine;
1420
1421 const CURVE_ID: &'static str = "Bls12-381";
1422
1423 fn endo(&self) -> Self {
1424 unimplemented!()
1425 }
1426
1427 fn jacobian_coordinates(&self) -> (Fp2, Fp2, Fp2) {
1428 let x = self.x * self.z;
1430 let y = self.y * self.z.square();
1431 (x, y, self.z)
1432 }
1433
1434 fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
1435 Box::new(|msg| {
1436 <G2Projective as HashToCurve<ExpandMsgXmd<sha2::Sha256>>>::hash_to_curve(
1437 msg,
1438 domain_prefix.as_bytes(),
1439 )
1440 })
1441 }
1442
1443 fn is_on_curve(&self) -> Choice {
1444 unimplemented!()
1451 }
1452
1453 fn b() -> Self::Base {
1454 B
1455 }
1456
1457 fn a() -> Self::Base {
1458 Self::Base::ZERO
1459 }
1460
1461 fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self> {
1462 let z_inv = z.invert().unwrap_or(Fp2::zero());
1464 let p_x = x * z_inv;
1465 let p_y = y * z_inv.square();
1466 let p = Self {
1467 x: p_x,
1468 y: Fp2::conditional_select(&p_y, &Fp2::ONE, z.is_zero()),
1469 z,
1470 };
1471 CtOption::new(p, p.is_on_curve())
1472 }
1473}
1474
1475impl CurveAffine for G2Affine {
1476 type ScalarExt = super::Scalar;
1478 type Base = super::fp2::Fp2;
1480 type CurveExt = G2Projective;
1482
1483 fn coordinates(&self) -> CtOption<Coordinates<Self>> {
1487 Coordinates::from_xy(self.x, self.y)
1488 }
1489
1490 fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
1493 let p: G2Affine = Self {
1494 x,
1495 y,
1496 infinity: x.ct_eq(&Self::Base::ZERO) & y.ct_eq(&Self::Base::ZERO),
1497 };
1498 CtOption::new(p, p.is_on_curve())
1499 }
1500
1501 fn is_on_curve(&self) -> Choice {
1504 self.is_on_curve()
1505 }
1506
1507 fn a() -> Self::Base {
1509 Self::Base::ZERO
1510 }
1511
1512 fn b() -> Self::Base {
1514 B
1515 }
1516}
1517
1518impl CurveAffineExt for G2Affine {
1519 fn into_coordinates(self) -> (Self::Base, Self::Base) {
1520 (self.x, self.y)
1521 }
1522}
1523
1524#[test]
1525fn test_is_on_curve() {
1526 assert!(bool::from(G2Affine::identity().is_on_curve()));
1527 assert!(bool::from(G2Affine::generator().is_on_curve()));
1528 assert!(bool::from(G2Projective::identity().is_on_curve()));
1529 assert!(bool::from(G2Projective::generator().is_on_curve()));
1530
1531 let z = Fp2 {
1532 c0: Fp::from_raw_unchecked([
1533 0xba7a_fa1f_9a6f_e250,
1534 0xfa0f_5b59_5eaf_e731,
1535 0x3bdc_4776_94c3_06e7,
1536 0x2149_be4b_3949_fa24,
1537 0x64aa_6e06_49b2_078c,
1538 0x12b1_08ac_3364_3c3e,
1539 ]),
1540 c1: Fp::from_raw_unchecked([
1541 0x1253_25df_3d35_b5a8,
1542 0xdc46_9ef5_555d_7fe3,
1543 0x02d7_16d2_4431_06a9,
1544 0x05a1_db59_a6ff_37d0,
1545 0x7cf7_784e_5300_bb8f,
1546 0x16a8_8922_c7a5_e844,
1547 ]),
1548 };
1549
1550 let gen = G2Affine::generator();
1551 let mut test = G2Projective {
1552 x: gen.x * z,
1553 y: gen.y * z,
1554 z,
1555 };
1556
1557 assert!(bool::from(test.is_on_curve()));
1558
1559 test.x = z;
1560 assert!(!bool::from(test.is_on_curve()));
1561}
1562
1563#[test]
1564#[allow(clippy::eq_op)]
1565fn test_affine_point_equality() {
1566 let a = G2Affine::generator();
1567 let b = G2Affine::identity();
1568
1569 assert!(a == a);
1570 assert!(b == b);
1571 assert!(a != b);
1572 assert!(b != a);
1573}
1574
1575#[test]
1576#[allow(clippy::eq_op)]
1577fn test_projective_point_equality() {
1578 let a = G2Projective::generator();
1579 let b = G2Projective::identity();
1580
1581 assert!(a == a);
1582 assert!(b == b);
1583 assert!(a != b);
1584 assert!(b != a);
1585
1586 let z = Fp2 {
1587 c0: Fp::from_raw_unchecked([
1588 0xba7a_fa1f_9a6f_e250,
1589 0xfa0f_5b59_5eaf_e731,
1590 0x3bdc_4776_94c3_06e7,
1591 0x2149_be4b_3949_fa24,
1592 0x64aa_6e06_49b2_078c,
1593 0x12b1_08ac_3364_3c3e,
1594 ]),
1595 c1: Fp::from_raw_unchecked([
1596 0x1253_25df_3d35_b5a8,
1597 0xdc46_9ef5_555d_7fe3,
1598 0x02d7_16d2_4431_06a9,
1599 0x05a1_db59_a6ff_37d0,
1600 0x7cf7_784e_5300_bb8f,
1601 0x16a8_8922_c7a5_e844,
1602 ]),
1603 };
1604
1605 let mut c = G2Projective {
1606 x: a.x * z,
1607 y: a.y * z,
1608 z,
1609 };
1610 assert!(bool::from(c.is_on_curve()));
1611
1612 assert!(a == c);
1613 assert!(b != c);
1614 assert!(c == a);
1615 assert!(c != b);
1616
1617 c.y = -c.y;
1618 assert!(bool::from(c.is_on_curve()));
1619
1620 assert!(a != c);
1621 assert!(b != c);
1622 assert!(c != a);
1623 assert!(c != b);
1624
1625 c.y = -c.y;
1626 c.x = z;
1627 assert!(!bool::from(c.is_on_curve()));
1628 assert!(a != b);
1629 assert!(a != c);
1630 assert!(b != c);
1631}
1632
1633#[test]
1634fn test_conditionally_select_affine() {
1635 let a = G2Affine::generator();
1636 let b = G2Affine::identity();
1637
1638 assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(0u8)), a);
1639 assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(1u8)), b);
1640}
1641
1642#[test]
1643fn test_conditionally_select_projective() {
1644 let a = G2Projective::generator();
1645 let b = G2Projective::identity();
1646
1647 assert_eq!(
1648 G2Projective::conditional_select(&a, &b, Choice::from(0u8)),
1649 a
1650 );
1651 assert_eq!(
1652 G2Projective::conditional_select(&a, &b, Choice::from(1u8)),
1653 b
1654 );
1655}
1656
1657#[test]
1658fn test_projective_to_affine() {
1659 let a = G2Projective::generator();
1660 let b = G2Projective::identity();
1661
1662 assert!(bool::from(G2Affine::from(a).is_on_curve()));
1663 assert!(!bool::from(G2Affine::from(a).is_identity()));
1664 assert!(bool::from(G2Affine::from(b).is_on_curve()));
1665 assert!(bool::from(G2Affine::from(b).is_identity()));
1666
1667 let z = Fp2 {
1668 c0: Fp::from_raw_unchecked([
1669 0xba7a_fa1f_9a6f_e250,
1670 0xfa0f_5b59_5eaf_e731,
1671 0x3bdc_4776_94c3_06e7,
1672 0x2149_be4b_3949_fa24,
1673 0x64aa_6e06_49b2_078c,
1674 0x12b1_08ac_3364_3c3e,
1675 ]),
1676 c1: Fp::from_raw_unchecked([
1677 0x1253_25df_3d35_b5a8,
1678 0xdc46_9ef5_555d_7fe3,
1679 0x02d7_16d2_4431_06a9,
1680 0x05a1_db59_a6ff_37d0,
1681 0x7cf7_784e_5300_bb8f,
1682 0x16a8_8922_c7a5_e844,
1683 ]),
1684 };
1685
1686 let c = G2Projective {
1687 x: a.x * z,
1688 y: a.y * z,
1689 z,
1690 };
1691
1692 assert_eq!(G2Affine::from(c), G2Affine::generator());
1693}
1694
1695#[test]
1696fn test_affine_to_projective() {
1697 let a = G2Affine::generator();
1698 let b = G2Affine::identity();
1699
1700 assert!(bool::from(G2Projective::from(a).is_on_curve()));
1701 assert!(!bool::from(G2Projective::from(a).is_identity()));
1702 assert!(bool::from(G2Projective::from(b).is_on_curve()));
1703 assert!(bool::from(G2Projective::from(b).is_identity()));
1704}
1705
1706#[test]
1707fn test_doubling() {
1708 {
1709 let tmp = G2Projective::identity().double();
1710 assert!(bool::from(tmp.is_identity()));
1711 assert!(bool::from(tmp.is_on_curve()));
1712 }
1713 {
1714 let tmp = G2Projective::generator().double();
1715 assert!(!bool::from(tmp.is_identity()));
1716 assert!(bool::from(tmp.is_on_curve()));
1717
1718 assert_eq!(
1719 G2Affine::from(tmp),
1720 G2Affine {
1721 x: Fp2 {
1722 c0: Fp::from_raw_unchecked([
1723 0xe9d9_e2da_9620_f98b,
1724 0x54f1_1993_46b9_7f36,
1725 0x3db3_b820_376b_ed27,
1726 0xcfdb_31c9_b0b6_4f4c,
1727 0x41d7_c127_8635_4493,
1728 0x0571_0794_c255_c064,
1729 ]),
1730 c1: Fp::from_raw_unchecked([
1731 0xd6c1_d3ca_6ea0_d06e,
1732 0xda0c_bd90_5595_489f,
1733 0x4f53_52d4_3479_221d,
1734 0x8ade_5d73_6f8c_97e0,
1735 0x48cc_8433_925e_f70e,
1736 0x08d7_ea71_ea91_ef81,
1737 ]),
1738 },
1739 y: Fp2 {
1740 c0: Fp::from_raw_unchecked([
1741 0x15ba_26eb_4b0d_186f,
1742 0x0d08_6d64_b7e9_e01e,
1743 0xc8b8_48dd_652f_4c78,
1744 0xeecf_46a6_123b_ae4f,
1745 0x255e_8dd8_b6dc_812a,
1746 0x1641_42af_21dc_f93f,
1747 ]),
1748 c1: Fp::from_raw_unchecked([
1749 0xf9b4_a1a8_9598_4db4,
1750 0xd417_b114_cccf_f748,
1751 0x6856_301f_c89f_086e,
1752 0x41c7_7787_8931_e3da,
1753 0x3556_b155_066a_2105,
1754 0x00ac_f7d3_25cb_89cf,
1755 ]),
1756 },
1757 infinity: Choice::from(0u8)
1758 }
1759 );
1760 }
1761}
1762
1763#[test]
1764fn test_projective_addition() {
1765 {
1766 let a = G2Projective::identity();
1767 let b = G2Projective::identity();
1768 let c = a + b;
1769 assert!(bool::from(c.is_identity()));
1770 assert!(bool::from(c.is_on_curve()));
1771 }
1772 {
1773 let a = G2Projective::identity();
1774 let mut b = G2Projective::generator();
1775 {
1776 let z = Fp2 {
1777 c0: Fp::from_raw_unchecked([
1778 0xba7a_fa1f_9a6f_e250,
1779 0xfa0f_5b59_5eaf_e731,
1780 0x3bdc_4776_94c3_06e7,
1781 0x2149_be4b_3949_fa24,
1782 0x64aa_6e06_49b2_078c,
1783 0x12b1_08ac_3364_3c3e,
1784 ]),
1785 c1: Fp::from_raw_unchecked([
1786 0x1253_25df_3d35_b5a8,
1787 0xdc46_9ef5_555d_7fe3,
1788 0x02d7_16d2_4431_06a9,
1789 0x05a1_db59_a6ff_37d0,
1790 0x7cf7_784e_5300_bb8f,
1791 0x16a8_8922_c7a5_e844,
1792 ]),
1793 };
1794
1795 b = G2Projective {
1796 x: b.x * z,
1797 y: b.y * z,
1798 z,
1799 };
1800 }
1801 let c = a + b;
1802 assert!(!bool::from(c.is_identity()));
1803 assert!(bool::from(c.is_on_curve()));
1804 assert!(c == G2Projective::generator());
1805 }
1806 {
1807 let a = G2Projective::identity();
1808 let mut b = G2Projective::generator();
1809 {
1810 let z = Fp2 {
1811 c0: Fp::from_raw_unchecked([
1812 0xba7a_fa1f_9a6f_e250,
1813 0xfa0f_5b59_5eaf_e731,
1814 0x3bdc_4776_94c3_06e7,
1815 0x2149_be4b_3949_fa24,
1816 0x64aa_6e06_49b2_078c,
1817 0x12b1_08ac_3364_3c3e,
1818 ]),
1819 c1: Fp::from_raw_unchecked([
1820 0x1253_25df_3d35_b5a8,
1821 0xdc46_9ef5_555d_7fe3,
1822 0x02d7_16d2_4431_06a9,
1823 0x05a1_db59_a6ff_37d0,
1824 0x7cf7_784e_5300_bb8f,
1825 0x16a8_8922_c7a5_e844,
1826 ]),
1827 };
1828
1829 b = G2Projective {
1830 x: b.x * z,
1831 y: b.y * z,
1832 z,
1833 };
1834 }
1835 let c = b + a;
1836 assert!(!bool::from(c.is_identity()));
1837 assert!(bool::from(c.is_on_curve()));
1838 assert!(c == G2Projective::generator());
1839 }
1840 {
1841 let a = G2Projective::generator().double().double(); let b = G2Projective::generator().double(); let c = a + b;
1844
1845 let mut d = G2Projective::generator();
1846 for _ in 0..5 {
1847 d += G2Projective::generator();
1848 }
1849 assert!(!bool::from(c.is_identity()));
1850 assert!(bool::from(c.is_on_curve()));
1851 assert!(!bool::from(d.is_identity()));
1852 assert!(bool::from(d.is_on_curve()));
1853 assert_eq!(c, d);
1854 }
1855
1856 {
1858 let beta = Fp2 {
1859 c0: Fp::from_raw_unchecked([
1860 0xcd03_c9e4_8671_f071,
1861 0x5dab_2246_1fcd_a5d2,
1862 0x5870_42af_d385_1b95,
1863 0x8eb6_0ebe_01ba_cb9e,
1864 0x03f9_7d6e_83d0_50d2,
1865 0x18f0_2065_5463_8741,
1866 ]),
1867 c1: Fp::zero(),
1868 };
1869 let beta = beta.square();
1870 let a = G2Projective::generator().double().double();
1871 let b = G2Projective {
1872 x: a.x * beta,
1873 y: -a.y,
1874 z: a.z,
1875 };
1876 assert!(bool::from(a.is_on_curve()));
1877 assert!(bool::from(b.is_on_curve()));
1878
1879 let c = a + b;
1880 assert_eq!(
1881 G2Affine::from(c),
1882 G2Affine::from(G2Projective {
1883 x: Fp2 {
1884 c0: Fp::from_raw_unchecked([
1885 0x705a_bc79_9ca7_73d3,
1886 0xfe13_2292_c1d4_bf08,
1887 0xf37e_ce3e_07b2_b466,
1888 0x887e_1c43_f447_e301,
1889 0x1e09_70d0_33bc_77e8,
1890 0x1985_c81e_20a6_93f2,
1891 ]),
1892 c1: Fp::from_raw_unchecked([
1893 0x1d79_b25d_b36a_b924,
1894 0x2394_8e4d_5296_39d3,
1895 0x471b_a7fb_0d00_6297,
1896 0x2c36_d4b4_465d_c4c0,
1897 0x82bb_c3cf_ec67_f538,
1898 0x051d_2728_b67b_f952,
1899 ])
1900 },
1901 y: Fp2 {
1902 c0: Fp::from_raw_unchecked([
1903 0x41b1_bbf6_576c_0abf,
1904 0xb6cc_9371_3f7a_0f9a,
1905 0x6b65_b43e_48f3_f01f,
1906 0xfb7a_4cfc_af81_be4f,
1907 0x3e32_dadc_6ec2_2cb6,
1908 0x0bb0_fc49_d798_07e3,
1909 ]),
1910 c1: Fp::from_raw_unchecked([
1911 0x7d13_9778_8f5f_2ddf,
1912 0xab29_0714_4ff0_d8e8,
1913 0x5b75_73e0_cdb9_1f92,
1914 0x4cb8_932d_d31d_af28,
1915 0x62bb_fac6_db05_2a54,
1916 0x11f9_5c16_d14c_3bbe,
1917 ])
1918 },
1919 z: Fp2::one()
1920 })
1921 );
1922 assert!(!bool::from(c.is_identity()));
1923 assert!(bool::from(c.is_on_curve()));
1924 }
1925}
1926
1927#[test]
1928fn test_mixed_addition() {
1929 {
1930 let a = G2Affine::identity();
1931 let b = G2Projective::identity();
1932 let c = a + b;
1933 assert!(bool::from(c.is_identity()));
1934 assert!(bool::from(c.is_on_curve()));
1935 }
1936 {
1937 let a = G2Affine::identity();
1938 let mut b = G2Projective::generator();
1939 {
1940 let z = Fp2 {
1941 c0: Fp::from_raw_unchecked([
1942 0xba7a_fa1f_9a6f_e250,
1943 0xfa0f_5b59_5eaf_e731,
1944 0x3bdc_4776_94c3_06e7,
1945 0x2149_be4b_3949_fa24,
1946 0x64aa_6e06_49b2_078c,
1947 0x12b1_08ac_3364_3c3e,
1948 ]),
1949 c1: Fp::from_raw_unchecked([
1950 0x1253_25df_3d35_b5a8,
1951 0xdc46_9ef5_555d_7fe3,
1952 0x02d7_16d2_4431_06a9,
1953 0x05a1_db59_a6ff_37d0,
1954 0x7cf7_784e_5300_bb8f,
1955 0x16a8_8922_c7a5_e844,
1956 ]),
1957 };
1958
1959 b = G2Projective {
1960 x: b.x * z,
1961 y: b.y * z,
1962 z,
1963 };
1964 }
1965 let c = a + b;
1966 assert!(!bool::from(c.is_identity()));
1967 assert!(bool::from(c.is_on_curve()));
1968 assert!(c == G2Projective::generator());
1969 }
1970 {
1971 let a = G2Affine::identity();
1972 let mut b = G2Projective::generator();
1973 {
1974 let z = Fp2 {
1975 c0: Fp::from_raw_unchecked([
1976 0xba7a_fa1f_9a6f_e250,
1977 0xfa0f_5b59_5eaf_e731,
1978 0x3bdc_4776_94c3_06e7,
1979 0x2149_be4b_3949_fa24,
1980 0x64aa_6e06_49b2_078c,
1981 0x12b1_08ac_3364_3c3e,
1982 ]),
1983 c1: Fp::from_raw_unchecked([
1984 0x1253_25df_3d35_b5a8,
1985 0xdc46_9ef5_555d_7fe3,
1986 0x02d7_16d2_4431_06a9,
1987 0x05a1_db59_a6ff_37d0,
1988 0x7cf7_784e_5300_bb8f,
1989 0x16a8_8922_c7a5_e844,
1990 ]),
1991 };
1992
1993 b = G2Projective {
1994 x: b.x * z,
1995 y: b.y * z,
1996 z,
1997 };
1998 }
1999 let c = b + a;
2000 assert!(!bool::from(c.is_identity()));
2001 assert!(bool::from(c.is_on_curve()));
2002 assert!(c == G2Projective::generator());
2003 }
2004 {
2005 let a = G2Projective::generator().double().double(); let b = G2Projective::generator().double(); let c = a + b;
2008
2009 let mut d = G2Projective::generator();
2010 for _ in 0..5 {
2011 d += G2Affine::generator();
2012 }
2013 assert!(!bool::from(c.is_identity()));
2014 assert!(bool::from(c.is_on_curve()));
2015 assert!(!bool::from(d.is_identity()));
2016 assert!(bool::from(d.is_on_curve()));
2017 assert_eq!(c, d);
2018 }
2019
2020 {
2022 let beta = Fp2 {
2023 c0: Fp::from_raw_unchecked([
2024 0xcd03_c9e4_8671_f071,
2025 0x5dab_2246_1fcd_a5d2,
2026 0x5870_42af_d385_1b95,
2027 0x8eb6_0ebe_01ba_cb9e,
2028 0x03f9_7d6e_83d0_50d2,
2029 0x18f0_2065_5463_8741,
2030 ]),
2031 c1: Fp::zero(),
2032 };
2033 let beta = beta.square();
2034 let a = G2Projective::generator().double().double();
2035 let b = G2Projective {
2036 x: a.x * beta,
2037 y: -a.y,
2038 z: a.z,
2039 };
2040 let a = G2Affine::from(a);
2041 assert!(bool::from(a.is_on_curve()));
2042 assert!(bool::from(b.is_on_curve()));
2043
2044 let c = a + b;
2045 assert_eq!(
2046 G2Affine::from(c),
2047 G2Affine::from(G2Projective {
2048 x: Fp2 {
2049 c0: Fp::from_raw_unchecked([
2050 0x705a_bc79_9ca7_73d3,
2051 0xfe13_2292_c1d4_bf08,
2052 0xf37e_ce3e_07b2_b466,
2053 0x887e_1c43_f447_e301,
2054 0x1e09_70d0_33bc_77e8,
2055 0x1985_c81e_20a6_93f2,
2056 ]),
2057 c1: Fp::from_raw_unchecked([
2058 0x1d79_b25d_b36a_b924,
2059 0x2394_8e4d_5296_39d3,
2060 0x471b_a7fb_0d00_6297,
2061 0x2c36_d4b4_465d_c4c0,
2062 0x82bb_c3cf_ec67_f538,
2063 0x051d_2728_b67b_f952,
2064 ])
2065 },
2066 y: Fp2 {
2067 c0: Fp::from_raw_unchecked([
2068 0x41b1_bbf6_576c_0abf,
2069 0xb6cc_9371_3f7a_0f9a,
2070 0x6b65_b43e_48f3_f01f,
2071 0xfb7a_4cfc_af81_be4f,
2072 0x3e32_dadc_6ec2_2cb6,
2073 0x0bb0_fc49_d798_07e3,
2074 ]),
2075 c1: Fp::from_raw_unchecked([
2076 0x7d13_9778_8f5f_2ddf,
2077 0xab29_0714_4ff0_d8e8,
2078 0x5b75_73e0_cdb9_1f92,
2079 0x4cb8_932d_d31d_af28,
2080 0x62bb_fac6_db05_2a54,
2081 0x11f9_5c16_d14c_3bbe,
2082 ])
2083 },
2084 z: Fp2::one()
2085 })
2086 );
2087 assert!(!bool::from(c.is_identity()));
2088 assert!(bool::from(c.is_on_curve()));
2089 }
2090}
2091
2092#[test]
2093#[allow(clippy::eq_op)]
2094fn test_projective_negation_and_subtraction() {
2095 let a = G2Projective::generator().double();
2096 assert_eq!(a + (-a), G2Projective::identity());
2097 assert_eq!(a + (-a), a - a);
2098}
2099
2100#[test]
2101fn test_affine_negation_and_subtraction() {
2102 let a = G2Affine::generator();
2103 assert_eq!(G2Projective::from(a) + (-a), G2Projective::identity());
2104 assert_eq!(G2Projective::from(a) + (-a), G2Projective::from(a) - a);
2105}
2106
2107#[test]
2108fn test_projective_scalar_multiplication() {
2109 let g = G2Projective::generator();
2110 let a = Scalar::from_raw([
2111 0x2b56_8297_a56d_a71c,
2112 0xd8c3_9ecb_0ef3_75d1,
2113 0x435c_38da_67bf_bf96,
2114 0x8088_a050_26b6_59b2,
2115 ]);
2116 let b = Scalar::from_raw([
2117 0x785f_dd9b_26ef_8b85,
2118 0xc997_f258_3769_5c18,
2119 0x4c8d_bc39_e7b7_56c1,
2120 0x70d9_b6cc_6d87_df20,
2121 ]);
2122 let c = a * b;
2123
2124 assert_eq!((g * a) * b, g * c);
2125}
2126
2127#[test]
2128fn test_affine_scalar_multiplication() {
2129 let g = G2Affine::generator();
2130 let a = Scalar::from_raw([
2131 0x2b56_8297_a56d_a71c,
2132 0xd8c3_9ecb_0ef3_75d1,
2133 0x435c_38da_67bf_bf96,
2134 0x8088_a050_26b6_59b2,
2135 ]);
2136 let b = Scalar::from_raw([
2137 0x785f_dd9b_26ef_8b85,
2138 0xc997_f258_3769_5c18,
2139 0x4c8d_bc39_e7b7_56c1,
2140 0x70d9_b6cc_6d87_df20,
2141 ]);
2142 let c = a * b;
2143
2144 assert_eq!(G2Affine::from(g * a) * b, g * c);
2145}
2146
2147#[test]
2148fn test_is_torsion_free() {
2149 let a = G2Affine {
2150 x: Fp2 {
2151 c0: Fp::from_raw_unchecked([
2152 0x89f5_50c8_13db_6431,
2153 0xa50b_e8c4_56cd_8a1a,
2154 0xa45b_3741_14ca_e851,
2155 0xbb61_90f5_bf7f_ff63,
2156 0x970c_a02c_3ba8_0bc7,
2157 0x02b8_5d24_e840_fbac,
2158 ]),
2159 c1: Fp::from_raw_unchecked([
2160 0x6888_bc53_d707_16dc,
2161 0x3dea_6b41_1768_2d70,
2162 0xd8f5_f930_500c_a354,
2163 0x6b5e_cb65_56f5_c155,
2164 0xc96b_ef04_3477_8ab0,
2165 0x0508_1505_5150_06ad,
2166 ]),
2167 },
2168 y: Fp2 {
2169 c0: Fp::from_raw_unchecked([
2170 0x3cf1_ea0d_434b_0f40,
2171 0x1a0d_c610_e603_e333,
2172 0x7f89_9561_60c7_2fa0,
2173 0x25ee_03de_cf64_31c5,
2174 0xeee8_e206_ec0f_e137,
2175 0x0975_92b2_26df_ef28,
2176 ]),
2177 c1: Fp::from_raw_unchecked([
2178 0x71e8_bb5f_2924_7367,
2179 0xa5fe_049e_2118_31ce,
2180 0x0ce6_b354_502a_3896,
2181 0x93b0_1200_0997_314e,
2182 0x6759_f3b6_aa5b_42ac,
2183 0x1569_44c4_dfe9_2bbb,
2184 ]),
2185 },
2186 infinity: Choice::from(0u8),
2187 };
2188 assert!(!bool::from(a.is_torsion_free()));
2189
2190 assert!(bool::from(G2Affine::identity().is_torsion_free()));
2191 assert!(bool::from(G2Affine::generator().is_torsion_free()));
2192}
2193
2194#[test]
2195fn test_mul_by_x() {
2196 let generator = G2Projective::generator();
2199 let x = if super::BLS_X_IS_NEGATIVE {
2200 -Scalar::from(super::BLS_X)
2201 } else {
2202 Scalar::from(super::BLS_X)
2203 };
2204 assert_eq!(generator.mul_by_x(), generator * x);
2205
2206 let point = G2Projective::generator() * Scalar::from(42);
2207 assert_eq!(point.mul_by_x(), point * x);
2208}
2209
2210#[test]
2211fn test_psi() {
2212 let generator = G2Projective::generator();
2213
2214 let z = Fp2 {
2215 c0: Fp::from_raw_unchecked([
2216 0x0ef2ddffab187c0a,
2217 0x2424522b7d5ecbfc,
2218 0xc6f341a3398054f4,
2219 0x5523ddf409502df0,
2220 0xd55c0b5a88e0dd97,
2221 0x066428d704923e52,
2222 ]),
2223 c1: Fp::from_raw_unchecked([
2224 0x538bbe0c95b4878d,
2225 0xad04a50379522881,
2226 0x6d5c05bf5c12fb64,
2227 0x4ce4a069a2d34787,
2228 0x59ea6c8d0dffaeaf,
2229 0x0d42a083a75bd6f3,
2230 ]),
2231 };
2232
2233 let point = G2Projective {
2235 x: Fp2 {
2236 c0: Fp::from_raw_unchecked([
2237 0xee4c8cb7c047eaf2,
2238 0x44ca22eee036b604,
2239 0x33b3affb2aefe101,
2240 0x15d3e45bbafaeb02,
2241 0x7bfc2154cd7419a4,
2242 0x0a2d0c2b756e5edc,
2243 ]),
2244 c1: Fp::from_raw_unchecked([
2245 0xfc224361029a8777,
2246 0x4cbf2baab8740924,
2247 0xc5008c6ec6592c89,
2248 0xecc2c57b472a9c2d,
2249 0x8613eafd9d81ffb1,
2250 0x10fe54daa2d3d495,
2251 ]),
2252 } * z,
2253 y: Fp2 {
2254 c0: Fp::from_raw_unchecked([
2255 0x7de7edc43953b75c,
2256 0x58be1d2de35e87dc,
2257 0x5731d30b0e337b40,
2258 0xbe93b60cfeaae4c9,
2259 0x8b22c203764bedca,
2260 0x01616c8d1033b771,
2261 ]),
2262 c1: Fp::from_raw_unchecked([
2263 0xea126fe476b5733b,
2264 0x85cee68b5dae1652,
2265 0x98247779f7272b04,
2266 0xa649c8b468c6e808,
2267 0xb5b9a62dff0c4e45,
2268 0x1555b67fc7bbe73d,
2269 ]),
2270 },
2271 z: z.square() * z,
2272 };
2273 assert!(bool::from(point.is_on_curve()));
2274
2275 assert_eq!(generator.psi2(), generator.psi().psi());
2277 assert_eq!(point.psi2(), point.psi().psi());
2278 assert_eq!(generator.double().psi(), generator.psi().double());
2280 assert_eq!(point.psi() + generator.psi(), (point + generator).psi());
2281 let mut normalized_point = [G2Affine::identity()];
2283 G2Projective::batch_normalize(&[point], &mut normalized_point);
2284 let normalized_point = G2Projective::from(normalized_point[0]);
2285 assert_eq!(point.psi(), normalized_point.psi());
2286 assert_eq!(point.psi2(), normalized_point.psi2());
2287}
2288
2289#[test]
2290fn test_clear_cofactor() {
2291 let z = Fp2 {
2292 c0: Fp::from_raw_unchecked([
2293 0x0ef2ddffab187c0a,
2294 0x2424522b7d5ecbfc,
2295 0xc6f341a3398054f4,
2296 0x5523ddf409502df0,
2297 0xd55c0b5a88e0dd97,
2298 0x066428d704923e52,
2299 ]),
2300 c1: Fp::from_raw_unchecked([
2301 0x538bbe0c95b4878d,
2302 0xad04a50379522881,
2303 0x6d5c05bf5c12fb64,
2304 0x4ce4a069a2d34787,
2305 0x59ea6c8d0dffaeaf,
2306 0x0d42a083a75bd6f3,
2307 ]),
2308 };
2309
2310 let point = G2Projective {
2312 x: Fp2 {
2313 c0: Fp::from_raw_unchecked([
2314 0xee4c8cb7c047eaf2,
2315 0x44ca22eee036b604,
2316 0x33b3affb2aefe101,
2317 0x15d3e45bbafaeb02,
2318 0x7bfc2154cd7419a4,
2319 0x0a2d0c2b756e5edc,
2320 ]),
2321 c1: Fp::from_raw_unchecked([
2322 0xfc224361029a8777,
2323 0x4cbf2baab8740924,
2324 0xc5008c6ec6592c89,
2325 0xecc2c57b472a9c2d,
2326 0x8613eafd9d81ffb1,
2327 0x10fe54daa2d3d495,
2328 ]),
2329 } * z,
2330 y: Fp2 {
2331 c0: Fp::from_raw_unchecked([
2332 0x7de7edc43953b75c,
2333 0x58be1d2de35e87dc,
2334 0x5731d30b0e337b40,
2335 0xbe93b60cfeaae4c9,
2336 0x8b22c203764bedca,
2337 0x01616c8d1033b771,
2338 ]),
2339 c1: Fp::from_raw_unchecked([
2340 0xea126fe476b5733b,
2341 0x85cee68b5dae1652,
2342 0x98247779f7272b04,
2343 0xa649c8b468c6e808,
2344 0xb5b9a62dff0c4e45,
2345 0x1555b67fc7bbe73d,
2346 ]),
2347 },
2348 z: z.square() * z,
2349 };
2350
2351 assert!(bool::from(point.is_on_curve()));
2352 assert!(!bool::from(G2Affine::from(point).is_torsion_free()));
2353 let cleared_point = point.clear_cofactor();
2354
2355 assert!(bool::from(cleared_point.is_on_curve()));
2356 assert!(bool::from(G2Affine::from(cleared_point).is_torsion_free()));
2357
2358 let generator = G2Projective::generator();
2361 assert!(bool::from(generator.clear_cofactor().is_on_curve()));
2362 let id = G2Projective::identity();
2363 assert!(bool::from(id.clear_cofactor().is_on_curve()));
2364
2365 let h_eff_modq: [u8; 32] = [
2368 0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16,
2369 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2370 0x00, 0x00,
2371 ];
2372 assert_eq!(generator.clear_cofactor(), generator.multiply(&h_eff_modq));
2373 assert_eq!(
2374 cleared_point.clear_cofactor(),
2375 cleared_point.multiply(&h_eff_modq)
2376 );
2377}
2378
2379#[test]
2380fn test_batch_normalize() {
2381 let a = G2Projective::generator().double();
2382 let b = a.double();
2383 let c = b.double();
2384
2385 for a_identity in (0..=1).map(|n| n == 1) {
2386 for b_identity in (0..=1).map(|n| n == 1) {
2387 for c_identity in (0..=1).map(|n| n == 1) {
2388 let mut v = [a, b, c];
2389 if a_identity {
2390 v[0] = G2Projective::identity()
2391 }
2392 if b_identity {
2393 v[1] = G2Projective::identity()
2394 }
2395 if c_identity {
2396 v[2] = G2Projective::identity()
2397 }
2398
2399 let mut t = [
2400 G2Affine::identity(),
2401 G2Affine::identity(),
2402 G2Affine::identity(),
2403 ];
2404 let expected = [
2405 G2Affine::from(v[0]),
2406 G2Affine::from(v[1]),
2407 G2Affine::from(v[2]),
2408 ];
2409
2410 G2Projective::batch_normalize(&v[..], &mut t[..]);
2411
2412 assert_eq!(&t[..], &expected[..]);
2413 }
2414 }
2415 }
2416}
2417
2418#[cfg(feature = "zeroize")]
2419#[test]
2420fn test_zeroize() {
2421 use zeroize::Zeroize;
2422
2423 let mut a = G2Affine::generator();
2424 a.zeroize();
2425 assert!(bool::from(a.is_identity()));
2426
2427 let mut a = G2Projective::generator();
2428 a.zeroize();
2429 assert!(bool::from(a.is_identity()));
2430
2431 let mut a = GroupEncoding::to_bytes(&G2Affine::generator());
2432 a.zeroize();
2433 assert_eq!(&a, &G2Compressed::default());
2434
2435 let mut a = UncompressedEncoding::to_uncompressed(&G2Affine::generator());
2436 a.zeroize();
2437 assert_eq!(&a, &G2Uncompressed::default());
2438}
2439
2440#[allow(clippy::op_ref)]
2441#[test]
2442fn test_commutative_scalar_subgroup_multiplication() {
2443 let a = Scalar::from_raw([
2444 0x1fff_3231_233f_fffd,
2445 0x4884_b7fa_0003_4802,
2446 0x998c_4fef_ecbc_4ff3,
2447 0x1824_b159_acc5_0562,
2448 ]);
2449
2450 let g2_a = G2Affine::generator();
2451 let g2_p = G2Projective::generator();
2452
2453 assert_eq!(&g2_a * &a, &a * &g2_a);
2455 assert_eq!(&g2_p * &a, &a * &g2_p);
2456
2457 assert_eq!(&g2_a * a, a * &g2_a);
2459 assert_eq!(&g2_p * a, a * &g2_p);
2460 assert_eq!(g2_a * &a, &a * g2_a);
2461 assert_eq!(g2_p * &a, &a * g2_p);
2462
2463 assert_eq!(g2_p * a, a * g2_p);
2465 assert_eq!(g2_a * a, a * g2_a);
2466}