bls12_381/
g2.rs

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