1use core::{
4 borrow::Borrow,
5 fmt,
6 iter::Sum,
7 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use blst::*;
11use group::{
12 Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup,
13 prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
14};
15use rand_core::RngCore;
16use subtle::{Choice, ConditionallySelectable, CtOption};
17use zeroize::Zeroize;
18
19use crate::{Bls12, Engine, G1Affine, Gt, PairingCurveAffine, Scalar, fp2::Fp2};
20
21#[derive(Copy, Clone, Zeroize)]
25#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
26#[repr(transparent)]
27pub struct G2Affine(pub(crate) blst_p2_affine);
28
29const COMPRESSED_SIZE: usize = 96;
30const UNCOMPRESSED_SIZE: usize = 192;
31
32impl fmt::Debug for G2Affine {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 let is_ident: bool = self.is_identity().into();
35 f.debug_struct("G2Affine")
36 .field("x", &self.x())
37 .field("y", &self.y())
38 .field("infinity", &is_ident)
39 .finish()
40 }
41}
42
43impl fmt::Display for G2Affine {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 if self.is_identity().into() {
46 write!(f, "G2Affine(Infinity)")
47 } else {
48 write!(f, "G2Affine(x={}, y={})", self.x(), self.y())
49 }
50 }
51}
52
53impl AsRef<blst_p2_affine> for G2Affine {
54 fn as_ref(&self) -> &blst_p2_affine {
55 &self.0
56 }
57}
58
59impl AsMut<blst_p2_affine> for G2Affine {
60 fn as_mut(&mut self) -> &mut blst_p2_affine {
61 &mut self.0
62 }
63}
64
65impl Default for G2Affine {
66 fn default() -> G2Affine {
67 G2Affine::identity()
68 }
69}
70
71impl From<&G2Projective> for G2Affine {
72 fn from(p: &G2Projective) -> G2Affine {
73 let mut out = blst_p2_affine::default();
74
75 unsafe { blst_p2_to_affine(&mut out, &p.0) };
76
77 G2Affine(out)
78 }
79}
80
81impl From<G2Projective> for G2Affine {
82 fn from(p: G2Projective) -> G2Affine {
83 G2Affine::from(&p)
84 }
85}
86
87impl Eq for G2Affine {}
88impl PartialEq for G2Affine {
89 #[inline]
90 fn eq(&self, other: &Self) -> bool {
91 unsafe { blst_p2_affine_is_equal(&self.0, &other.0) }
92 }
93}
94
95impl Neg for &G2Projective {
96 type Output = G2Projective;
97
98 #[inline]
99 fn neg(self) -> G2Projective {
100 -*self
101 }
102}
103
104impl Neg for G2Projective {
105 type Output = G2Projective;
106
107 #[inline]
108 fn neg(mut self) -> G2Projective {
109 unsafe { blst_p2_cneg(&mut self.0, true) }
110 self
111 }
112}
113
114impl Neg for &G2Affine {
115 type Output = G2Affine;
116
117 #[inline]
118 fn neg(self) -> G2Affine {
119 -*self
120 }
121}
122
123impl Neg for G2Affine {
124 type Output = G2Affine;
125
126 #[inline]
127 fn neg(mut self) -> G2Affine {
128 if (!self.is_identity()).into() {
130 unsafe {
131 blst_fp2_cneg(&mut self.0.y, &self.0.y, true);
132 }
133 }
134 self
135 }
136}
137
138impl Add<&G2Projective> for &G2Projective {
139 type Output = G2Projective;
140
141 #[inline]
142 fn add(self, rhs: &G2Projective) -> G2Projective {
143 let mut out = blst_p2::default();
144 unsafe { blst_p2_add_or_double(&mut out, &self.0, &rhs.0) };
145 G2Projective(out)
146 }
147}
148
149impl Add<&G2Affine> for &G2Projective {
150 type Output = G2Projective;
151
152 #[inline]
153 fn add(self, rhs: &G2Affine) -> G2Projective {
154 self.add_mixed(rhs)
155 }
156}
157
158impl Add<&G2Projective> for &G2Affine {
159 type Output = G2Projective;
160
161 #[inline]
162 fn add(self, rhs: &G2Projective) -> G2Projective {
163 rhs.add_mixed(self)
164 }
165}
166
167impl Sub<&G2Projective> for &G2Projective {
168 type Output = G2Projective;
169
170 #[inline]
171 fn sub(self, rhs: &G2Projective) -> G2Projective {
172 self + -rhs
173 }
174}
175
176impl Sub<&G2Projective> for &G2Affine {
177 type Output = G2Projective;
178
179 #[inline]
180 fn sub(self, rhs: &G2Projective) -> G2Projective {
181 self + -rhs
182 }
183}
184
185impl Sub<&G2Affine> for &G2Projective {
186 type Output = G2Projective;
187
188 #[inline]
189 fn sub(self, rhs: &G2Affine) -> G2Projective {
190 self + -rhs
191 }
192}
193
194impl AddAssign<&G2Projective> for G2Projective {
195 #[inline]
196 fn add_assign(&mut self, rhs: &G2Projective) {
197 unsafe { blst_p2_add_or_double(&mut self.0, &self.0, &rhs.0) };
198 }
199}
200
201impl SubAssign<&G2Projective> for G2Projective {
202 #[inline]
203 fn sub_assign(&mut self, rhs: &G2Projective) {
204 *self += &-rhs
205 }
206}
207
208impl AddAssign<&G2Affine> for G2Projective {
209 #[inline]
210 fn add_assign(&mut self, rhs: &G2Affine) {
211 unsafe { blst_p2_add_or_double_affine(&mut self.0, &self.0, &rhs.0) };
212 }
213}
214
215impl SubAssign<&G2Affine> for G2Projective {
216 #[inline]
217 fn sub_assign(&mut self, rhs: &G2Affine) {
218 *self += &-rhs;
219 }
220}
221
222impl Mul<&Scalar> for &G2Projective {
223 type Output = G2Projective;
224
225 fn mul(self, scalar: &Scalar) -> Self::Output {
226 self.multiply(scalar)
227 }
228}
229
230impl Mul<&Scalar> for &G2Affine {
231 type Output = G2Projective;
232
233 fn mul(self, scalar: &Scalar) -> Self::Output {
234 G2Projective::from(self).multiply(scalar)
235 }
236}
237
238impl MulAssign<&Scalar> for G2Projective {
239 #[inline]
240 fn mul_assign(&mut self, rhs: &Scalar) {
241 *self = *self * rhs;
242 }
243}
244
245impl MulAssign<&Scalar> for G2Affine {
246 #[inline]
247 fn mul_assign(&mut self, rhs: &Scalar) {
248 *self = (*self * rhs).into();
249 }
250}
251
252impl_add_sub!(G2Projective);
253impl_add_sub!(G2Projective, G2Affine);
254impl_add_sub!(G2Affine, G2Projective, G2Projective);
255
256impl_add_sub_assign!(G2Projective);
257impl_add_sub_assign!(G2Projective, G2Affine);
258
259impl_mul!(G2Projective, Scalar);
260impl_mul!(G2Affine, Scalar, G2Projective);
261
262impl_mul_assign!(G2Projective, Scalar);
263impl_mul_assign!(G2Affine, Scalar);
264
265impl<T> Sum<T> for G2Projective
266where
267 T: Borrow<G2Projective>,
268{
269 fn sum<I>(iter: I) -> Self
270 where
271 I: Iterator<Item = T>,
272 {
273 iter.fold(Self::identity(), |acc, item| acc + item.borrow())
274 }
275}
276
277impl PrimeCurveAffine for G2Affine {
278 type Scalar = Scalar;
279 type Curve = G2Projective;
280
281 fn identity() -> Self {
282 G2Affine(blst_p2_affine::default())
283 }
284
285 fn generator() -> Self {
286 G2Affine(unsafe { *blst_p2_affine_generator() })
287 }
288
289 fn is_identity(&self) -> Choice {
290 unsafe { Choice::from(blst_p2_affine_is_inf(&self.0) as u8) }
291 }
292
293 fn to_curve(&self) -> Self::Curve {
294 self.into()
295 }
296}
297
298impl ConditionallySelectable for G2Affine {
299 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
300 G2Affine(blst_p2_affine {
301 x: Fp2::conditional_select(&a.x(), &b.x(), choice).0,
302 y: Fp2::conditional_select(&a.y(), &b.y(), choice).0,
303 })
304 }
305}
306
307impl ConditionallySelectable for G2Projective {
308 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
309 G2Projective(blst_p2 {
310 x: Fp2::conditional_select(&a.x(), &b.x(), choice).0,
311 y: Fp2::conditional_select(&a.y(), &b.y(), choice).0,
312 z: Fp2::conditional_select(&a.z(), &b.z(), choice).0,
313 })
314 }
315}
316
317impl G2Affine {
318 pub fn to_compressed(&self) -> [u8; COMPRESSED_SIZE] {
320 let mut out = [0u8; COMPRESSED_SIZE];
321
322 unsafe {
323 blst_p2_affine_compress(out.as_mut_ptr(), &self.0);
324 }
325
326 out
327 }
328
329 pub fn to_uncompressed(&self) -> [u8; UNCOMPRESSED_SIZE] {
331 let mut out = [0u8; UNCOMPRESSED_SIZE];
332
333 unsafe {
334 blst_p2_affine_serialize(out.as_mut_ptr(), &self.0);
335 }
336
337 out
338 }
339
340 pub fn from_uncompressed(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
342 G2Affine::from_uncompressed_unchecked(bytes)
343 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
344 }
345
346 pub fn from_uncompressed_unchecked(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
352 let mut raw = blst_p2_affine::default();
353 let success =
354 unsafe { blst_p2_deserialize(&mut raw, bytes.as_ptr()) == BLST_ERROR::BLST_SUCCESS };
355 CtOption::new(G2Affine(raw), Choice::from(success as u8))
356 }
357
358 pub fn from_compressed(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
360 G2Affine::from_compressed_unchecked(bytes)
361 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
362 }
363
364 pub fn from_compressed_unchecked(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
370 let mut raw = blst_p2_affine::default();
371 let success =
372 unsafe { blst_p2_uncompress(&mut raw, bytes.as_ptr()) == BLST_ERROR::BLST_SUCCESS };
373 CtOption::new(G2Affine(raw), Choice::from(success as u8))
374 }
375
376 pub fn is_torsion_free(&self) -> Choice {
380 unsafe { Choice::from(blst_p2_affine_in_g2(&self.0) as u8) }
381 }
382
383 pub fn is_on_curve(&self) -> Choice {
386 unsafe { Choice::from(blst_p2_affine_on_curve(&self.0) as u8) }
388 }
389
390 pub fn from_raw_unchecked(x: Fp2, y: Fp2, _infinity: bool) -> Self {
391 let raw = blst_p2_affine { x: x.0, y: y.0 };
393
394 G2Affine(raw)
395 }
396
397 pub fn x(&self) -> Fp2 {
399 Fp2(self.0.x)
400 }
401
402 pub fn y(&self) -> Fp2 {
404 Fp2(self.0.y)
405 }
406
407 pub const fn uncompressed_size() -> usize {
408 UNCOMPRESSED_SIZE
409 }
410
411 pub const fn compressed_size() -> usize {
412 COMPRESSED_SIZE
413 }
414}
415
416#[derive(Copy, Clone, Zeroize)]
418#[repr(transparent)]
419pub struct G2Projective(pub(crate) blst_p2);
420
421impl fmt::Debug for G2Projective {
422 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
423 f.debug_struct("G2Projective")
424 .field("x", &self.x())
425 .field("y", &self.y())
426 .field("z", &self.z())
427 .finish()
428 }
429}
430
431impl fmt::Display for G2Projective {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 write!(f, "{}", G2Affine::from(self))
434 }
435}
436
437impl AsRef<blst_p2> for G2Projective {
438 fn as_ref(&self) -> &blst_p2 {
439 &self.0
440 }
441}
442
443impl AsMut<blst_p2> for G2Projective {
444 fn as_mut(&mut self) -> &mut blst_p2 {
445 &mut self.0
446 }
447}
448
449impl From<&G2Affine> for G2Projective {
450 fn from(p: &G2Affine) -> G2Projective {
451 let mut out = blst_p2::default();
452
453 unsafe { blst_p2_from_affine(&mut out, &p.0) };
454
455 G2Projective(out)
456 }
457}
458
459impl From<G2Affine> for G2Projective {
460 fn from(p: G2Affine) -> G2Projective {
461 G2Projective::from(&p)
462 }
463}
464
465impl Eq for G2Projective {}
466impl PartialEq for G2Projective {
467 #[inline]
468 fn eq(&self, other: &Self) -> bool {
469 let self_is_zero: bool = self.is_identity().into();
470 let other_is_zero: bool = other.is_identity().into();
471 (self_is_zero && other_is_zero)
472 || (!self_is_zero && !other_is_zero && unsafe { blst_p2_is_equal(&self.0, &other.0) })
473 }
474}
475
476impl G2Projective {
477 pub fn to_compressed(&self) -> [u8; COMPRESSED_SIZE] {
479 let mut out = [0u8; COMPRESSED_SIZE];
480
481 unsafe {
482 blst_p2_compress(out.as_mut_ptr(), &self.0);
483 }
484
485 out
486 }
487
488 pub fn to_uncompressed(&self) -> [u8; UNCOMPRESSED_SIZE] {
490 let mut out = [0u8; UNCOMPRESSED_SIZE];
491
492 unsafe {
493 blst_p2_serialize(out.as_mut_ptr(), &self.0);
494 }
495
496 out
497 }
498
499 pub fn from_uncompressed(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
501 G2Affine::from_uncompressed(bytes).map(Into::into)
502 }
503
504 pub fn from_uncompressed_unchecked(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
510 G2Affine::from_uncompressed_unchecked(bytes).map(Into::into)
511 }
512
513 pub fn from_compressed(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
515 G2Affine::from_compressed(bytes).map(Into::into)
516 }
517
518 pub fn from_compressed_unchecked(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
524 G2Affine::from_compressed_unchecked(bytes).map(Into::into)
525 }
526
527 pub fn add_mixed(&self, rhs: &G2Affine) -> G2Projective {
529 let mut out = blst_p2::default();
530
531 unsafe { blst_p2_add_or_double_affine(&mut out, &self.0, &rhs.0) };
532
533 G2Projective(out)
534 }
535
536 pub fn is_on_curve(&self) -> Choice {
539 let is_on_curve = unsafe { Choice::from(blst_p2_on_curve(&self.0) as u8) };
540 is_on_curve | self.is_identity()
541 }
542
543 fn multiply(&self, scalar: &Scalar) -> G2Projective {
544 let mut out = blst_p2::default();
545
546 const NBITS: usize = 255;
548
549 unsafe { blst_p2_mult(&mut out, &self.0, scalar.to_bytes_le().as_ptr(), NBITS) };
550
551 G2Projective(out)
552 }
553
554 pub fn from_raw_unchecked(x: Fp2, y: Fp2, z: Fp2) -> Self {
555 let raw = blst_p2 {
556 x: x.0,
557 y: y.0,
558 z: z.0,
559 };
560
561 G2Projective(raw)
562 }
563
564 pub fn x(&self) -> Fp2 {
566 Fp2(self.0.x)
567 }
568
569 pub fn y(&self) -> Fp2 {
571 Fp2(self.0.y)
572 }
573
574 pub fn z(&self) -> Fp2 {
576 Fp2(self.0.z)
577 }
578
579 pub fn hash_to_curve(msg: &[u8], dst: &[u8], aug: &[u8]) -> Self {
581 let mut res = Self::identity();
582 unsafe {
583 blst_hash_to_g2(
584 &mut res.0,
585 msg.as_ptr(),
586 msg.len(),
587 dst.as_ptr(),
588 dst.len(),
589 aug.as_ptr(),
590 aug.len(),
591 );
592 }
593 res
594 }
595
596 pub fn multi_exp(points: &[Self], scalars: &[Scalar]) -> Self {
599 let n = if points.len() < scalars.len() {
600 points.len()
601 } else {
602 scalars.len()
603 };
604
605 let points =
606 unsafe { std::slice::from_raw_parts(points.as_ptr() as *const blst_p2, points.len()) };
607 let points = p2_affines::from(points);
608
609 let mut scalar_bytes: Vec<u8> = Vec::with_capacity(n * 32);
610 for a in scalars.iter().map(|s| s.to_bytes_le()) {
611 scalar_bytes.extend_from_slice(&a);
612 }
613
614 let res = points.mult(scalar_bytes.as_slice(), 255);
615
616 G2Projective(res)
617 }
618}
619
620impl Group for G2Projective {
621 type Scalar = Scalar;
622
623 fn random(mut rng: impl RngCore) -> Self {
624 let mut out = blst_p2::default();
625 let mut msg = [0u8; 64];
626 rng.fill_bytes(&mut msg);
627 const DST: [u8; 16] = [0; 16];
628 const AUG: [u8; 16] = [0; 16];
629
630 unsafe {
631 blst_encode_to_g2(
632 &mut out,
633 msg.as_ptr(),
634 msg.len(),
635 DST.as_ptr(),
636 DST.len(),
637 AUG.as_ptr(),
638 AUG.len(),
639 )
640 };
641
642 G2Projective(out)
643 }
644
645 fn identity() -> Self {
646 G2Projective(blst_p2::default())
647 }
648
649 fn generator() -> Self {
650 G2Projective(unsafe { *blst_p2_generator() })
651 }
652
653 fn is_identity(&self) -> Choice {
654 unsafe { Choice::from(blst_p2_is_inf(&self.0) as u8) }
655 }
656
657 fn double(&self) -> Self {
658 let mut double = blst_p2::default();
659 unsafe { blst_p2_double(&mut double, &self.0) };
660 G2Projective(double)
661 }
662}
663
664impl WnafGroup for G2Projective {
665 fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
666 const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071];
667
668 let mut ret = 4;
669 for r in &RECOMMENDATIONS {
670 if num_scalars > *r {
671 ret += 1;
672 } else {
673 break;
674 }
675 }
676
677 ret
678 }
679}
680
681impl PrimeGroup for G2Projective {}
682
683impl Curve for G2Projective {
684 type AffineRepr = G2Affine;
685
686 fn to_affine(&self) -> Self::AffineRepr {
687 self.into()
688 }
689}
690
691impl PrimeCurve for G2Projective {
692 type Affine = G2Affine;
693}
694
695impl GroupEncoding for G2Projective {
696 type Repr = G2Compressed;
697
698 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
699 Self::from_compressed(&bytes.0)
700 }
701
702 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
703 Self::from_compressed_unchecked(&bytes.0)
704 }
705
706 fn to_bytes(&self) -> Self::Repr {
707 G2Compressed(self.to_compressed())
708 }
709}
710
711impl GroupEncoding for G2Affine {
712 type Repr = G2Compressed;
713
714 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
715 Self::from_compressed(&bytes.0)
716 }
717
718 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
719 Self::from_compressed_unchecked(&bytes.0)
720 }
721
722 fn to_bytes(&self) -> Self::Repr {
723 G2Compressed(self.to_compressed())
724 }
725}
726
727impl UncompressedEncoding for G2Affine {
728 type Uncompressed = G2Uncompressed;
729
730 fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
731 Self::from_uncompressed(&bytes.0)
732 }
733
734 fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
735 Self::from_uncompressed_unchecked(&bytes.0)
736 }
737
738 fn to_uncompressed(&self) -> Self::Uncompressed {
739 G2Uncompressed(self.to_uncompressed())
740 }
741}
742
743#[derive(Clone, Debug, Zeroize)]
744pub struct G2Prepared {
745 pub(crate) lines: Vec<blst_fp6>,
746 infinity: bool,
747}
748
749impl From<G2Affine> for G2Prepared {
750 fn from(affine: G2Affine) -> Self {
751 if affine.is_identity().into() {
752 G2Prepared {
753 lines: Vec::new(),
754 infinity: true,
755 }
756 } else {
757 let mut lines = vec![blst_fp6::default(); 68];
758 unsafe { blst_precompute_lines(lines.as_mut_ptr(), &affine.0) }
759 G2Prepared {
760 lines,
761 infinity: false,
762 }
763 }
764 }
765}
766
767impl G2Prepared {
768 pub fn is_identity(&self) -> Choice {
769 Choice::from(self.infinity as u8)
770 }
771}
772
773impl PairingCurveAffine for G2Affine {
774 type Pair = G1Affine;
775 type PairingResult = Gt;
776
777 fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
778 <Bls12 as Engine>::pairing(other, self)
779 }
780}
781
782#[cfg(feature = "gpu")]
783impl ec_gpu::GpuName for G2Affine {
784 fn name() -> String {
785 ec_gpu::name!()
786 }
787}
788
789#[derive(Copy, Clone, Zeroize)]
790#[repr(transparent)]
791pub struct G2Uncompressed([u8; UNCOMPRESSED_SIZE]);
792
793encoded_point_delegations!(G2Uncompressed);
794
795impl Default for G2Uncompressed {
796 fn default() -> Self {
797 G2Uncompressed([0u8; UNCOMPRESSED_SIZE])
798 }
799}
800
801impl fmt::Debug for G2Uncompressed {
802 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
803 self.0[..].fmt(formatter)
804 }
805}
806
807#[derive(Copy, Clone, Zeroize)]
808#[repr(transparent)]
809pub struct G2Compressed([u8; COMPRESSED_SIZE]);
810
811encoded_point_delegations!(G2Compressed);
812
813impl Default for G2Compressed {
814 fn default() -> Self {
815 G2Compressed([0u8; COMPRESSED_SIZE])
816 }
817}
818
819impl fmt::Debug for G2Compressed {
820 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
821 self.0[..].fmt(formatter)
822 }
823}
824
825#[cfg(test)]
826mod tests {
827 #![allow(clippy::eq_op)]
828
829 use super::*;
830
831 use crate::fp::Fp;
832 use ff::Field;
833 use rand_core::SeedableRng;
834 use rand_xorshift::XorShiftRng;
835
836 #[test]
837 fn curve_tests() {
838 let mut rng = XorShiftRng::from_seed([
839 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
840 0xbc, 0xe5,
841 ]);
842
843 {
845 let mut z = G2Projective::identity();
846 z = z.neg();
847 assert_eq!(z.is_identity().unwrap_u8(), 1);
848 }
849
850 {
852 let mut z = G2Projective::identity();
853 z = z.double();
854 assert_eq!(z.is_identity().unwrap_u8(), 1);
855 }
856
857 {
859 let mut r = G2Projective::random(&mut rng);
860 let rcopy = r;
861 r += &G2Projective::identity();
862 assert_eq!(r, rcopy);
863 r += &G2Affine::identity();
864 assert_eq!(r, rcopy);
865
866 let mut z = G2Projective::identity();
867 z += &G2Projective::identity();
868 assert_eq!(z.is_identity().unwrap_u8(), 1);
869 z += &G2Affine::identity();
870 assert_eq!(z.is_identity().unwrap_u8(), 1);
871
872 let mut z2 = z;
873 z2 += &r;
874
875 z += &G2Affine::from(r);
876
877 assert_eq!(z, z2);
878 assert_eq!(z, r);
879 }
880
881 {
883 let a = G2Projective::random(&mut rng);
884 let b: G2Projective = G2Affine::from(a).into();
885 let c = G2Projective::from(G2Affine::from(G2Projective::from(G2Affine::from(a))));
886
887 assert_eq!(a, b);
888 assert_eq!(b, c);
889 }
890 }
891
892 #[test]
893 fn g2_test_is_valid() {
894 {
896 let p = G2Affine::from_raw_unchecked(
897 Fp2::new(
898 Fp::from_u64s_le(&[
899 0xa757072d9fa35ba9,
900 0xae3fb2fb418f6e8a,
901 0xc1598ec46faa0c7c,
902 0x7a17a004747e3dbe,
903 0xcc65406a7c2e5a73,
904 0x10b8c03d64db4d0c,
905 ])
906 .unwrap(),
907 Fp::from_u64s_le(&[
908 0xd30e70fe2f029778,
909 0xda30772df0f5212e,
910 0x5b47a9ff9a233a50,
911 0xfb777e5b9b568608,
912 0x789bac1fec71a2b9,
913 0x1342f02e2da54405,
914 ])
915 .unwrap(),
916 ),
917 Fp2::new(
918 Fp::from_u64s_le(&[
919 0xfe0812043de54dca,
920 0xe455171a3d47a646,
921 0xa493f36bc20be98a,
922 0x663015d9410eb608,
923 0x78e82a79d829a544,
924 0x40a00545bb3c1e,
925 ])
926 .unwrap(),
927 Fp::from_u64s_le(&[
928 0x4709802348e79377,
929 0xb5ac4dc9204bcfbd,
930 0xda361c97d02f42b2,
931 0x15008b1dc399e8df,
932 0x68128fd0548a3829,
933 0x16a613db5c873aaa,
934 ])
935 .unwrap(),
936 ),
937 false,
938 );
939 assert_eq!(p.is_on_curve().unwrap_u8(), 0);
940 }
941
942 {
944 let p = G2Affine::from_raw_unchecked(
945 Fp2::new(
946 Fp::from_u64s_le(&[
947 0xf4fdfe95a705f917,
948 0xc2914df688233238,
949 0x37c6b12cca35a34b,
950 0x41abba710d6c692c,
951 0xffcc4b2b62ce8484,
952 0x6993ec01b8934ed,
953 ])
954 .unwrap(),
955 Fp::from_u64s_le(&[
956 0xb94e92d5f874e26,
957 0x44516408bc115d95,
958 0xe93946b290caa591,
959 0xa5a0c2b7131f3555,
960 0x83800965822367e7,
961 0x10cf1d3ad8d90bfa,
962 ])
963 .unwrap(),
964 ),
965 Fp2::new(
966 Fp::from_u64s_le(&[
967 0xbf00334c79701d97,
968 0x4fe714f9ff204f9a,
969 0xab70b28002f3d825,
970 0x5a9171720e73eb51,
971 0x38eb4fd8d658adb7,
972 0xb649051bbc1164d,
973 ])
974 .unwrap(),
975 Fp::from_u64s_le(&[
976 0x9225814253d7df75,
977 0xc196c2513477f887,
978 0xe05e2fbd15a804e0,
979 0x55f2b8efad953e04,
980 0x7379345eda55265e,
981 0x377f2e6208fd4cb,
982 ])
983 .unwrap(),
984 ),
985 false,
986 );
987 assert_eq!(p.is_on_curve().unwrap_u8(), 0);
988 assert_eq!(p.is_torsion_free().unwrap_u8(), 0);
989 }
990
991 {
994 let p = G2Affine::from_raw_unchecked(
995 Fp2::new(
996 Fp::from_u64s_le(&[
997 0x262cea73ea1906c,
998 0x2f08540770fabd6,
999 0x4ceb92d0a76057be,
1000 0x2199bc19c48c393d,
1001 0x4a151b732a6075bf,
1002 0x17762a3b9108c4a7,
1003 ])
1004 .unwrap(),
1005 Fp::from_u64s_le(&[
1006 0x26f461e944bbd3d1,
1007 0x298f3189a9cf6ed6,
1008 0x74328ad8bc2aa150,
1009 0x7e147f3f9e6e241,
1010 0x72a9b63583963fff,
1011 0x158b0083c000462,
1012 ])
1013 .unwrap(),
1014 ),
1015 Fp2::new(
1016 Fp::from_u64s_le(&[
1017 0x91fb0b225ecf103b,
1018 0x55d42edc1dc46ba0,
1019 0x43939b11997b1943,
1020 0x68cad19430706b4d,
1021 0x3ccfb97b924dcea8,
1022 0x1660f93434588f8d,
1023 ])
1024 .unwrap(),
1025 Fp::from_u64s_le(&[
1026 0xaaed3985b6dcb9c7,
1027 0xc1e985d6d898d9f4,
1028 0x618bd2ac3271ac42,
1029 0x3940a2dbb914b529,
1030 0xbeb88137cf34f3e7,
1031 0x1699ee577c61b694,
1032 ])
1033 .unwrap(),
1034 ),
1035 false,
1036 );
1037 assert_eq!(p.is_on_curve().unwrap_u8(), 1);
1038 assert_eq!(p.is_torsion_free().unwrap_u8(), 0);
1039 }
1040 }
1041
1042 #[test]
1043 fn test_g2_addition_correctness() {
1044 let mut p = G2Projective::from_raw_unchecked(
1045 Fp2::new(
1046 Fp::from_u64s_le(&[
1047 0x6c994cc1e303094e,
1048 0xf034642d2c9e85bd,
1049 0x275094f1352123a9,
1050 0x72556c999f3707ac,
1051 0x4617f2e6774e9711,
1052 0x100b2fe5bffe030b,
1053 ])
1054 .unwrap(),
1055 Fp::from_u64s_le(&[
1056 0x7a33555977ec608,
1057 0xe23039d1fe9c0881,
1058 0x19ce4678aed4fcb5,
1059 0x4637c4f417667e2e,
1060 0x93ebe7c3e41f6acc,
1061 0xde884f89a9a371b,
1062 ])
1063 .unwrap(),
1064 ),
1065 Fp2::new(
1066 Fp::from_u64s_le(&[
1067 0xe073119472e1eb62,
1068 0x44fb3391fe3c9c30,
1069 0xaa9b066d74694006,
1070 0x25fd427b4122f231,
1071 0xd83112aace35cae,
1072 0x191b2432407cbb7f,
1073 ])
1074 .unwrap(),
1075 Fp::from_u64s_le(&[
1076 0xf68ae82fe97662f5,
1077 0xe986057068b50b7d,
1078 0x96c30f0411590b48,
1079 0x9eaa6d19de569196,
1080 0xf6a03d31e2ec2183,
1081 0x3bdafaf7ca9b39b,
1082 ])
1083 .unwrap(),
1084 ),
1085 Fp2::ONE,
1086 );
1087
1088 p.add_assign(&G2Projective::from_raw_unchecked(
1089 Fp2::new(
1090 Fp::from_u64s_le(&[
1091 0xa8c763d25910bdd3,
1092 0x408777b30ca3add4,
1093 0x6115fcc12e2769e,
1094 0x8e73a96b329ad190,
1095 0x27c546f75ee1f3ab,
1096 0xa33d27add5e7e82,
1097 ])
1098 .unwrap(),
1099 Fp::from_u64s_le(&[
1100 0x93b1ebcd54870dfe,
1101 0xf1578300e1342e11,
1102 0x8270dca3a912407b,
1103 0x2089faf462438296,
1104 0x828e5848cd48ea66,
1105 0x141ecbac1deb038b,
1106 ])
1107 .unwrap(),
1108 ),
1109 Fp2::new(
1110 Fp::from_u64s_le(&[
1111 0xf5d2c28857229c3f,
1112 0x8c1574228757ca23,
1113 0xe8d8102175f5dc19,
1114 0x2767032fc37cc31d,
1115 0xd5ee2aba84fd10fe,
1116 0x16576ccd3dd0a4e8,
1117 ])
1118 .unwrap(),
1119 Fp::from_u64s_le(&[
1120 0x4da9b6f6a96d1dd2,
1121 0x9657f7da77f1650e,
1122 0xbc150712f9ffe6da,
1123 0x31898db63f87363a,
1124 0xabab040ddbd097cc,
1125 0x11ad236b9ba02990,
1126 ])
1127 .unwrap(),
1128 ),
1129 Fp2::ONE,
1130 ));
1131
1132 let p = G2Affine::from(p);
1133
1134 assert_eq!(
1135 p,
1136 G2Affine::from_raw_unchecked(
1137 Fp2::new(
1138 Fp::from_u64s_le(&[
1139 0xcde7ee8a3f2ac8af,
1140 0xfc642eb35975b069,
1141 0xa7de72b7dd0e64b7,
1142 0xf1273e6406eef9cc,
1143 0xababd760ff05cb92,
1144 0xd7c20456617e89
1145 ])
1146 .unwrap(),
1147 Fp::from_u64s_le(&[
1148 0xd1a50b8572cbd2b8,
1149 0x238f0ac6119d07df,
1150 0x4dbe924fe5fd6ac2,
1151 0x8b203284c51edf6b,
1152 0xc8a0b730bbb21f5e,
1153 0x1a3b59d29a31274
1154 ])
1155 .unwrap(),
1156 ),
1157 Fp2::new(
1158 Fp::from_u64s_le(&[
1159 0x9e709e78a8eaa4c9,
1160 0xd30921c93ec342f4,
1161 0x6d1ef332486f5e34,
1162 0x64528ab3863633dc,
1163 0x159384333d7cba97,
1164 0x4cb84741f3cafe8
1165 ])
1166 .unwrap(),
1167 Fp::from_u64s_le(&[
1168 0x242af0dc3640e1a4,
1169 0xe90a73ad65c66919,
1170 0x2bd7ca7f4346f9ec,
1171 0x38528f92b689644d,
1172 0xb6884deec59fb21f,
1173 0x3c075d3ec52ba90
1174 ])
1175 .unwrap(),
1176 ),
1177 false,
1178 )
1179 );
1180 }
1181
1182 #[test]
1183 fn test_g2_doubling_correctness() {
1184 let mut p = G2Projective::from_raw_unchecked(
1185 Fp2::new(
1186 Fp::from_u64s_le(&[
1187 0x6c994cc1e303094e,
1188 0xf034642d2c9e85bd,
1189 0x275094f1352123a9,
1190 0x72556c999f3707ac,
1191 0x4617f2e6774e9711,
1192 0x100b2fe5bffe030b,
1193 ])
1194 .unwrap(),
1195 Fp::from_u64s_le(&[
1196 0x7a33555977ec608,
1197 0xe23039d1fe9c0881,
1198 0x19ce4678aed4fcb5,
1199 0x4637c4f417667e2e,
1200 0x93ebe7c3e41f6acc,
1201 0xde884f89a9a371b,
1202 ])
1203 .unwrap(),
1204 ),
1205 Fp2::new(
1206 Fp::from_u64s_le(&[
1207 0xe073119472e1eb62,
1208 0x44fb3391fe3c9c30,
1209 0xaa9b066d74694006,
1210 0x25fd427b4122f231,
1211 0xd83112aace35cae,
1212 0x191b2432407cbb7f,
1213 ])
1214 .unwrap(),
1215 Fp::from_u64s_le(&[
1216 0xf68ae82fe97662f5,
1217 0xe986057068b50b7d,
1218 0x96c30f0411590b48,
1219 0x9eaa6d19de569196,
1220 0xf6a03d31e2ec2183,
1221 0x3bdafaf7ca9b39b,
1222 ])
1223 .unwrap(),
1224 ),
1225 Fp2::ONE,
1226 );
1227
1228 p = p.double();
1229
1230 let p = G2Affine::from(p);
1231
1232 assert_eq!(
1233 p,
1234 G2Affine::from_raw_unchecked(
1235 Fp2::new(
1236 Fp::from_u64s_le(&[
1237 0x91ccb1292727c404,
1238 0x91a6cb182438fad7,
1239 0x116aee59434de902,
1240 0xbcedcfce1e52d986,
1241 0x9755d4a3926e9862,
1242 0x18bab73760fd8024
1243 ])
1244 .unwrap(),
1245 Fp::from_u64s_le(&[
1246 0x4e7c5e0a2ae5b99e,
1247 0x96e582a27f028961,
1248 0xc74d1cf4ef2d5926,
1249 0xeb0cf5e610ef4fe7,
1250 0x7b4c2bae8db6e70b,
1251 0xf136e43909fca0
1252 ])
1253 .unwrap(),
1254 ),
1255 Fp2::new(
1256 Fp::from_u64s_le(&[
1257 0x954d4466ab13e58,
1258 0x3ee42eec614cf890,
1259 0x853bb1d28877577e,
1260 0xa5a2a51f7fde787b,
1261 0x8b92866bc6384188,
1262 0x81a53fe531d64ef
1263 ])
1264 .unwrap(),
1265 Fp::from_u64s_le(&[
1266 0x4c5d607666239b34,
1267 0xeddb5f48304d14b3,
1268 0x337167ee6e8e3cb6,
1269 0xb271f52f12ead742,
1270 0x244e6c2015c83348,
1271 0x19e2deae6eb9b441
1272 ])
1273 .unwrap(),
1274 ),
1275 false,
1276 )
1277 );
1278 }
1279
1280 #[test]
1281 fn test_affine_point_equality() {
1282 let a = G2Affine::generator();
1283 let b = G2Affine::identity();
1284
1285 assert_eq!(a, a);
1286 assert_eq!(b, b);
1287 assert_ne!(a, b);
1288 assert_ne!(b, a);
1289 }
1290
1291 #[test]
1292 fn test_projective_point_equality() {
1293 let a = G2Projective::generator();
1294 let b = G2Projective::identity();
1295
1296 assert_eq!(a, a);
1297 assert_eq!(b, b);
1298 assert_ne!(a, b);
1299 assert_ne!(b, a);
1300 }
1301
1302 #[test]
1303 fn g2_curve_tests() {
1304 use group::tests::curve_tests;
1305 curve_tests::<G2Projective>();
1306 }
1307
1308 #[test]
1309 fn test_g2_is_identity() {
1310 assert_eq!(G2Projective::identity().is_identity().unwrap_u8(), 1);
1311 assert_eq!(G2Projective::generator().is_identity().unwrap_u8(), 0);
1312 assert_eq!(G2Affine::identity().is_identity().unwrap_u8(), 1);
1313 assert_eq!(G2Affine::generator().is_identity().unwrap_u8(), 0);
1314 }
1315
1316 #[test]
1317 fn test_g2_serialization_roundtrip() {
1318 let mut rng = XorShiftRng::from_seed([
1319 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1320 0xbc, 0xe5,
1321 ]);
1322
1323 for _ in 0..100 {
1324 let el: G2Affine = G2Projective::random(&mut rng).into();
1325 let c = el.to_compressed();
1326 assert_eq!(G2Affine::from_compressed(&c).unwrap(), el);
1327 assert_eq!(G2Affine::from_compressed_unchecked(&c).unwrap(), el);
1328
1329 let u = el.to_uncompressed();
1330 assert_eq!(G2Affine::from_uncompressed(&u).unwrap(), el);
1331 assert_eq!(G2Affine::from_uncompressed_unchecked(&u).unwrap(), el);
1332
1333 let c = el.to_bytes();
1334 assert_eq!(G2Affine::from_bytes(&c).unwrap(), el);
1335 assert_eq!(G2Affine::from_bytes_unchecked(&c).unwrap(), el);
1336
1337 let el = G2Projective::random(&mut rng);
1338 let c = el.to_compressed();
1339 assert_eq!(G2Projective::from_compressed(&c).unwrap(), el);
1340 assert_eq!(G2Projective::from_compressed_unchecked(&c).unwrap(), el);
1341
1342 let u = el.to_uncompressed();
1343 assert_eq!(G2Projective::from_uncompressed(&u).unwrap(), el);
1344 assert_eq!(G2Projective::from_uncompressed_unchecked(&u).unwrap(), el);
1345
1346 let c = el.to_bytes();
1347 assert_eq!(G2Projective::from_bytes(&c).unwrap(), el);
1348 assert_eq!(G2Projective::from_bytes_unchecked(&c).unwrap(), el);
1349 }
1350 }
1351
1352 #[test]
1353 fn test_multi_exp() {
1354 const SIZE: usize = 128;
1355 let mut rng = XorShiftRng::from_seed([
1356 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1357 0xbc, 0xe5,
1358 ]);
1359
1360 let points: Vec<G2Projective> = (0..SIZE).map(|_| G2Projective::random(&mut rng)).collect();
1361 let scalars: Vec<Scalar> = (0..SIZE).map(|_| Scalar::random(&mut rng)).collect();
1362
1363 let mut naive = points[0] * scalars[0];
1364 for i in 1..SIZE {
1365 naive += points[i] * scalars[i];
1366 }
1367
1368 let pippenger = G2Projective::multi_exp(points.as_slice(), scalars.as_slice());
1369
1370 assert_eq!(naive, pippenger);
1371 }
1372}