halo2curves_axiom/bls12_381/
g2.rs

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