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