fullcodec_bls12_381/
g2.rs

1//! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.
2
3use crate::fp::Fp;
4use crate::fp2::Fp2;
5use crate::BlsScalar;
6
7use core::borrow::Borrow;
8use core::iter::Sum;
9use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
10use dusk_bytes::{Error as BytesError, HexDebug, Serializable};
11use parity_scale_codec::{Decode, Encode};
12use subtle;
13use serde::{Deserialize, Serialize};
14use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
15
16#[cfg(feature = "canon")]
17use canonical::{Canon, CanonError, Sink, Source};
18#[cfg(feature = "canon")]
19use canonical_derive::Canon;
20#[cfg(feature = "serde_req")]
21use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
22
23/// This is an element of $\mathbb{G}_2$ represented in the affine coordinate space.
24/// It is ideal to keep elements in this representation to reduce memory usage and
25/// improve performance through the use of mixed curve model arithmetic.
26///
27/// Values of `G2Affine` are guaranteed to be in the $q$-order subgroup unless an
28/// "unchecked" API was misused.
29#[derive(Copy, Clone, HexDebug, Encode, Decode, Serialize, Deserialize)]
30pub struct G2Affine {
31    pub(crate) x: Fp2,
32    pub(crate) y: Fp2,
33    infinity: Choice,
34}
35
36#[cfg(feature = "canon")]
37impl Canon for G2Affine {
38    fn encode(&self, sink: &mut Sink) {
39        sink.copy_bytes(&self.to_bytes());
40    }
41
42    fn decode(source: &mut Source) -> Result<Self, CanonError> {
43        let mut bytes = [0u8; Self::SIZE];
44
45        bytes.copy_from_slice(source.read_bytes(Self::SIZE));
46
47        Self::from_bytes(&bytes).map_err(|_| CanonError::InvalidEncoding)
48    }
49
50    fn encoded_len(&self) -> usize {
51        Self::SIZE
52    }
53}
54
55impl Default for G2Affine {
56    fn default() -> G2Affine {
57        G2Affine::identity()
58    }
59}
60
61impl<'a> From<&'a G2Projective> for G2Affine {
62    fn from(p: &'a G2Projective) -> G2Affine {
63        let zinv = p.z.invert().unwrap_or(Fp2::zero());
64        let zinv2 = zinv.square();
65        let x = p.x * zinv2;
66        let zinv3 = zinv2 * zinv;
67        let y = p.y * zinv3;
68
69        let tmp = G2Affine {
70            x,
71            y,
72            infinity: Choice::from(0u8),
73        };
74
75        G2Affine::conditional_select(&tmp, &G2Affine::identity(), zinv.is_zero())
76    }
77}
78
79impl From<G2Projective> for G2Affine {
80    fn from(p: G2Projective) -> G2Affine {
81        G2Affine::from(&p)
82    }
83}
84
85impl ConstantTimeEq for G2Affine {
86    fn ct_eq(&self, other: &Self) -> Choice {
87        // The only cases in which two points are equal are
88        // 1. infinity is set on both
89        // 2. infinity is not set on both, and their coordinates are equal
90
91        (self.infinity & other.infinity)
92            | ((!self.infinity)
93                & (!other.infinity)
94                & self.x.ct_eq(&other.x)
95                & self.y.ct_eq(&other.y))
96    }
97}
98
99impl ConditionallySelectable for G2Affine {
100    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
101        G2Affine {
102            x: Fp2::conditional_select(&a.x, &b.x, choice),
103            y: Fp2::conditional_select(&a.y, &b.y, choice),
104            infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
105        }
106    }
107}
108
109impl Eq for G2Affine {}
110impl PartialEq for G2Affine {
111    #[inline]
112    fn eq(&self, other: &Self) -> bool {
113        bool::from(self.ct_eq(other))
114    }
115}
116
117impl Serializable<96> for G2Affine {
118    type Error = BytesError;
119
120    /// Serializes this element into compressed form. See [`notes::serialization`](crate::notes::serialization)
121    /// for details about how group elements are serialized.
122    fn to_bytes(&self) -> [u8; Self::SIZE] {
123        // Strictly speaking, self.x is zero already when self.infinity is true, but
124        // to guard against implementation mistakes we do not assume this.
125        let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
126
127        let mut res = [0; Self::SIZE];
128
129        (&mut res[0..48]).copy_from_slice(&x.c1.to_bytes()[..]);
130        (&mut res[48..96]).copy_from_slice(&x.c0.to_bytes()[..]);
131
132        // This point is in compressed form, so we set the most significant bit.
133        res[0] |= 1u8 << 7;
134
135        // Is this point at infinity? If so, set the second-most significant bit.
136        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
137
138        // Is the y-coordinate the lexicographically largest of the two associated with the
139        // x-coordinate? If so, set the third-most significant bit so long as this is not
140        // the point at infinity.
141        res[0] |= u8::conditional_select(
142            &0u8,
143            &(1u8 << 5),
144            (!self.infinity) & self.y.lexicographically_largest(),
145        );
146
147        res
148    }
149
150    /// Attempts to deserialize a compressed element. See [`notes::serialization`](crate::notes::serialization)
151    /// for details about how group elements are serialized.
152    fn from_bytes(buf: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
153        // We already know the point is on the curve because this is established
154        // by the y-coordinate recovery procedure in from_compressed_unchecked().
155
156        // Obtain the three flags from the start of the byte sequence
157        let compression_flag_set = Choice::from((buf[0] >> 7) & 1);
158        let infinity_flag_set = Choice::from((buf[0] >> 6) & 1);
159        let sort_flag_set = Choice::from((buf[0] >> 5) & 1);
160
161        // Attempt to obtain the x-coordinate
162        let xc1 = {
163            let mut tmp = [0; 48];
164            tmp.copy_from_slice(&buf[0..48]);
165
166            // Mask away the flag bits
167            tmp[0] &= 0b0001_1111;
168
169            Fp::from_bytes(&tmp)
170        };
171        let xc0 = {
172            let mut tmp = [0; 48];
173            tmp.copy_from_slice(&buf[48..96]);
174
175            Fp::from_bytes(&tmp)
176        };
177
178        let x: Option<Self> = xc1
179            .and_then(|xc1| {
180                xc0.and_then(|xc0| {
181                    let x = Fp2 { c0: xc0, c1: xc1 };
182
183                    // If the infinity flag is set, return the value assuming
184                    // the x-coordinate is zero and the sort bit is not set.
185                    //
186                    // Otherwise, return a recovered point (assuming the correct
187                    // y-coordinate can be found) so long as the infinity flag
188                    // was not set.
189                    CtOption::new(
190                        G2Affine::identity(),
191                        infinity_flag_set & // Infinity flag should be set
192                    compression_flag_set & // Compression flag should be set
193                    (!sort_flag_set) & // Sort flag should not be set
194                    x.is_zero(), // The x-coordinate should be zero
195                    )
196                    .or_else(|| {
197                        // Recover a y-coordinate given x by y = sqrt(x^3 + 4)
198                        ((x.square() * x) + B).sqrt().and_then(|y| {
199                            // Switch to the correct y-coordinate if necessary.
200                            let y = Fp2::conditional_select(
201                                &y,
202                                &-y,
203                                y.lexicographically_largest() ^ sort_flag_set,
204                            );
205
206                            CtOption::new(
207                                G2Affine {
208                                    x,
209                                    y,
210                                    infinity: infinity_flag_set,
211                                },
212                                (!infinity_flag_set) & // Infinity flag should not be set
213                            compression_flag_set, // Compression flag should be set
214                            )
215                        })
216                    })
217                })
218            })
219            .into();
220
221        match x {
222            Some(x) if x.is_torsion_free().unwrap_u8() == 1 => Ok(x),
223            _ => Err(BytesError::InvalidData),
224        }
225    }
226}
227
228#[cfg(feature = "serde_req")]
229impl Serialize for G2Affine {
230    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
231    where
232        S: Serializer,
233    {
234        use serde::ser::SerializeTuple;
235        let mut tup = serializer.serialize_tuple(Self::SIZE)?;
236        for byte in self.to_bytes().iter() {
237            tup.serialize_element(byte)?;
238        }
239        tup.end()
240    }
241}
242
243#[cfg(feature = "serde_req")]
244impl<'de> Deserialize<'de> for G2Affine {
245    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
246    where
247        D: Deserializer<'de>,
248    {
249        struct G2AffineVisitor;
250
251        impl<'de> Visitor<'de> for G2AffineVisitor {
252            type Value = G2Affine;
253
254            fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
255                formatter.write_str("a 48-byte cannonical compressed G2Affine point from Bls12_381")
256            }
257
258            fn visit_seq<A>(self, mut seq: A) -> Result<G2Affine, A::Error>
259            where
260                A: serde::de::SeqAccess<'de>,
261            {
262                let mut bytes = [0u8; G2Affine::SIZE];
263                for i in 0..G2Affine::SIZE {
264                    bytes[i] = seq
265                        .next_element()?
266                        .ok_or(serde::de::Error::invalid_length(i, &"expected 48 bytes"))?;
267                }
268
269                G2Affine::from_bytes(&bytes).map_err(|_| {
270                    serde::de::Error::custom(&"compressed G2Affine was not canonically encoded")
271                })
272            }
273        }
274
275        deserializer.deserialize_tuple(Self::SIZE, G2AffineVisitor)
276    }
277}
278
279impl<'a> Neg for &'a G2Affine {
280    type Output = G2Affine;
281
282    #[inline]
283    fn neg(self) -> G2Affine {
284        G2Affine {
285            x: self.x,
286            y: Fp2::conditional_select(&-self.y, &Fp2::one(), self.infinity),
287            infinity: self.infinity,
288        }
289    }
290}
291
292impl Neg for G2Affine {
293    type Output = G2Affine;
294
295    #[inline]
296    fn neg(self) -> G2Affine {
297        -&self
298    }
299}
300
301impl<'a, 'b> Add<&'b G2Projective> for &'a G2Affine {
302    type Output = G2Projective;
303
304    #[inline]
305    fn add(self, rhs: &'b G2Projective) -> G2Projective {
306        rhs.add_mixed(self)
307    }
308}
309
310impl<'a, 'b> Add<&'b G2Affine> for &'a G2Projective {
311    type Output = G2Projective;
312
313    #[inline]
314    fn add(self, rhs: &'b G2Affine) -> G2Projective {
315        self.add_mixed(rhs)
316    }
317}
318
319impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Affine {
320    type Output = G2Projective;
321
322    #[inline]
323    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
324        self + (-rhs)
325    }
326}
327
328impl<'a, 'b> Sub<&'b G2Affine> for &'a G2Projective {
329    type Output = G2Projective;
330
331    #[inline]
332    fn sub(self, rhs: &'b G2Affine) -> G2Projective {
333        self + (-rhs)
334    }
335}
336
337impl<T> Sum<T> for G2Projective
338where
339    T: Borrow<G2Projective>,
340{
341    fn sum<I>(iter: I) -> Self
342    where
343        I: Iterator<Item = T>,
344    {
345        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
346    }
347}
348
349impl_binops_additive!(G2Projective, G2Affine);
350impl_binops_additive_specify_output!(G2Affine, G2Projective, G2Projective);
351
352const B: Fp2 = Fp2 {
353    c0: Fp::from_raw_unchecked([
354        0xaa270000000cfff3,
355        0x53cc0032fc34000a,
356        0x478fe97a6b0a807f,
357        0xb1d37ebee6ba24d7,
358        0x8ec9733bbf78ab2f,
359        0x9d645513d83de7e,
360    ]),
361    c1: Fp::from_raw_unchecked([
362        0xaa270000000cfff3,
363        0x53cc0032fc34000a,
364        0x478fe97a6b0a807f,
365        0xb1d37ebee6ba24d7,
366        0x8ec9733bbf78ab2f,
367        0x9d645513d83de7e,
368    ]),
369};
370
371impl G2Affine {
372    /// Bytes size of the raw representation
373    pub const RAW_SIZE: usize = 193;
374
375    /// Returns the identity of the group: the point at infinity.
376    pub fn identity() -> G2Affine {
377        G2Affine {
378            x: Fp2::zero(),
379            y: Fp2::one(),
380            infinity: Choice::from(1u8),
381        }
382    }
383
384    /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
385    /// for how this generator is chosen.
386    pub fn generator() -> G2Affine {
387        G2Affine {
388            x: Fp2 {
389                c0: Fp::from_raw_unchecked([
390                    0xf5f28fa202940a10,
391                    0xb3f5fb2687b4961a,
392                    0xa1a893b53e2ae580,
393                    0x9894999d1a3caee9,
394                    0x6f67b7631863366b,
395                    0x58191924350bcd7,
396                ]),
397                c1: Fp::from_raw_unchecked([
398                    0xa5a9c0759e23f606,
399                    0xaaa0c59dbccd60c3,
400                    0x3bb17e18e2867806,
401                    0x1b1ab6cc8541b367,
402                    0xc2b6ed0ef2158547,
403                    0x11922a097360edf3,
404                ]),
405            },
406            y: Fp2 {
407                c0: Fp::from_raw_unchecked([
408                    0x4c730af860494c4a,
409                    0x597cfa1f5e369c5a,
410                    0xe7e6856caa0a635a,
411                    0xbbefb5e96e0d495f,
412                    0x7d3a975f0ef25a2,
413                    0x83fd8e7e80dae5,
414                ]),
415                c1: Fp::from_raw_unchecked([
416                    0xadc0fc92df64b05d,
417                    0x18aa270a2b1461dc,
418                    0x86adac6a3be4eba0,
419                    0x79495c4ec93da33a,
420                    0xe7175850a43ccaed,
421                    0xb2bc2a163de1bf2,
422                ]),
423            },
424            infinity: Choice::from(0u8),
425        }
426    }
427
428    /// Raw bytes representation
429    ///
430    /// The intended usage of this function is for trusted sets of data where performance is
431    /// critical.
432    ///
433    /// For secure serialization, check `to_bytes`
434    pub fn to_raw_bytes(&self) -> [u8; Self::RAW_SIZE] {
435        let mut bytes = [0u8; Self::RAW_SIZE];
436        let chunks = bytes.chunks_mut(8);
437
438        self.x
439            .c0
440            .internal_repr()
441            .iter()
442            .chain(self.x.c1.internal_repr().iter())
443            .chain(self.y.c0.internal_repr().iter())
444            .chain(self.y.c1.internal_repr().iter())
445            .zip(chunks)
446            .for_each(|(n, c)| c.copy_from_slice(&n.to_le_bytes()));
447
448        bytes[Self::RAW_SIZE - 1] = self.infinity.unwrap_u8();
449
450        bytes
451    }
452
453    /// Create a `G2Affine` from a set of bytes created by `G2Affine::to_raw_bytes`.
454    ///
455    /// No check is performed and no constant time is granted. The expected usage of this function
456    /// is for trusted bytes where performance is critical.
457    ///
458    /// For secure serialization, check `from_bytes`
459    ///
460    /// After generating the point, you can check `is_on_curve` and `is_torsion_free` to grant its
461    /// security
462    pub unsafe fn from_slice_unchecked(bytes: &[u8]) -> Self {
463        let mut xc0 = [0u64; 6];
464        let mut xc1 = [0u64; 6];
465        let mut yc0 = [0u64; 6];
466        let mut yc1 = [0u64; 6];
467        let mut z = [0u8; 8];
468
469        xc0.iter_mut()
470            .chain(xc1.iter_mut())
471            .chain(yc0.iter_mut())
472            .chain(yc1.iter_mut())
473            .zip(bytes.chunks_exact(8))
474            .for_each(|(n, c)| {
475                z.copy_from_slice(c);
476                *n = u64::from_le_bytes(z);
477            });
478
479        let c0 = Fp::from_raw_unchecked(xc0);
480        let c1 = Fp::from_raw_unchecked(xc1);
481        let x = Fp2 { c0, c1 };
482
483        let c0 = Fp::from_raw_unchecked(yc0);
484        let c1 = Fp::from_raw_unchecked(yc1);
485        let y = Fp2 { c0, c1 };
486
487        let infinity = if bytes.len() >= Self::RAW_SIZE {
488            bytes[Self::RAW_SIZE - 1].into()
489        } else {
490            0u8.into()
491        };
492
493        Self { x, y, infinity }
494    }
495
496    /// Returns true if this element is the identity (the point at infinity).
497    #[inline]
498    pub fn is_identity(&self) -> Choice {
499        self.infinity
500    }
501
502    /// Returns true if this point is free of an $h$-torsion component, and so it
503    /// exists within the $q$-order subgroup $\mathbb{G}_2$. This should always return true
504    /// unless an "unchecked" API was used.
505    pub fn is_torsion_free(&self) -> Choice {
506        const FQ_MODULUS_BYTES: [u8; 32] = [
507            1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8,
508            216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115,
509        ];
510
511        // Clear the r-torsion from the point and check if it is the identity
512        G2Projective::from(*self)
513            .multiply(&FQ_MODULUS_BYTES)
514            .is_identity()
515    }
516
517    /// Returns true if this point is on the curve. This should always return
518    /// true unless an "unchecked" API was used.
519    pub fn is_on_curve(&self) -> Choice {
520        // y^2 - x^3 ?= 4(u + 1)
521        (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
522    }
523}
524
525/// This is an element of $\mathbb{G}_2$ represented in the projective coordinate space.
526#[derive(Copy, Clone, Debug)]
527#[cfg_attr(feature = "canon", derive(Canon))]
528pub struct G2Projective {
529    pub(crate) x: Fp2,
530    pub(crate) y: Fp2,
531    pub(crate) z: Fp2,
532}
533
534impl<'a> From<&'a G2Affine> for G2Projective {
535    fn from(p: &'a G2Affine) -> G2Projective {
536        G2Projective {
537            x: p.x,
538            y: p.y,
539            z: Fp2::conditional_select(&Fp2::one(), &Fp2::zero(), p.infinity),
540        }
541    }
542}
543
544impl From<G2Affine> for G2Projective {
545    fn from(p: G2Affine) -> G2Projective {
546        G2Projective::from(&p)
547    }
548}
549
550impl ConstantTimeEq for G2Projective {
551    fn ct_eq(&self, other: &Self) -> Choice {
552        // Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine?
553
554        let z = other.z.square();
555        let x1 = self.x * z;
556        let z = z * other.z;
557        let y1 = self.y * z;
558        let z = self.z.square();
559        let x2 = other.x * z;
560        let z = z * self.z;
561        let y2 = other.y * z;
562
563        let self_is_zero = self.z.is_zero();
564        let other_is_zero = other.z.is_zero();
565
566        (self_is_zero & other_is_zero) // Both point at infinity
567            | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
568        // Neither point at infinity, coordinates are the same
569    }
570}
571
572impl ConditionallySelectable for G2Projective {
573    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
574        G2Projective {
575            x: Fp2::conditional_select(&a.x, &b.x, choice),
576            y: Fp2::conditional_select(&a.y, &b.y, choice),
577            z: Fp2::conditional_select(&a.z, &b.z, choice),
578        }
579    }
580}
581
582impl Eq for G2Projective {}
583impl PartialEq for G2Projective {
584    #[inline]
585    fn eq(&self, other: &Self) -> bool {
586        bool::from(self.ct_eq(other))
587    }
588}
589
590impl<'a> Neg for &'a G2Projective {
591    type Output = G2Projective;
592
593    #[inline]
594    fn neg(self) -> G2Projective {
595        G2Projective {
596            x: self.x,
597            y: -self.y,
598            z: self.z,
599        }
600    }
601}
602
603impl Neg for G2Projective {
604    type Output = G2Projective;
605
606    #[inline]
607    fn neg(self) -> G2Projective {
608        -&self
609    }
610}
611
612impl<'a, 'b> Add<&'b G2Projective> for &'a G2Projective {
613    type Output = G2Projective;
614
615    #[inline]
616    fn add(self, rhs: &'b G2Projective) -> G2Projective {
617        self.add(rhs)
618    }
619}
620
621impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Projective {
622    type Output = G2Projective;
623
624    #[inline]
625    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
626        self + (-rhs)
627    }
628}
629
630impl<'a, 'b> Mul<&'b BlsScalar> for &'a G2Projective {
631    type Output = G2Projective;
632
633    fn mul(self, other: &'b BlsScalar) -> Self::Output {
634        self.multiply(&other.to_bytes())
635    }
636}
637
638impl<'a, 'b> Mul<&'b BlsScalar> for &'a G2Affine {
639    type Output = G2Projective;
640
641    fn mul(self, other: &'b BlsScalar) -> Self::Output {
642        G2Projective::from(self).multiply(&other.to_bytes())
643    }
644}
645
646impl_binops_additive!(G2Projective, G2Projective);
647impl_binops_multiplicative!(G2Projective, BlsScalar);
648impl_binops_multiplicative_mixed!(G2Affine, BlsScalar, G2Projective);
649
650impl G2Projective {
651    /// Returns the identity of the group: the point at infinity.
652    pub fn identity() -> G2Projective {
653        G2Projective {
654            x: Fp2::zero(),
655            y: Fp2::one(),
656            z: Fp2::zero(),
657        }
658    }
659
660    /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
661    /// for how this generator is chosen.
662    pub fn generator() -> G2Projective {
663        G2Projective {
664            x: Fp2 {
665                c0: Fp::from_raw_unchecked([
666                    0xf5f28fa202940a10,
667                    0xb3f5fb2687b4961a,
668                    0xa1a893b53e2ae580,
669                    0x9894999d1a3caee9,
670                    0x6f67b7631863366b,
671                    0x58191924350bcd7,
672                ]),
673                c1: Fp::from_raw_unchecked([
674                    0xa5a9c0759e23f606,
675                    0xaaa0c59dbccd60c3,
676                    0x3bb17e18e2867806,
677                    0x1b1ab6cc8541b367,
678                    0xc2b6ed0ef2158547,
679                    0x11922a097360edf3,
680                ]),
681            },
682            y: Fp2 {
683                c0: Fp::from_raw_unchecked([
684                    0x4c730af860494c4a,
685                    0x597cfa1f5e369c5a,
686                    0xe7e6856caa0a635a,
687                    0xbbefb5e96e0d495f,
688                    0x7d3a975f0ef25a2,
689                    0x83fd8e7e80dae5,
690                ]),
691                c1: Fp::from_raw_unchecked([
692                    0xadc0fc92df64b05d,
693                    0x18aa270a2b1461dc,
694                    0x86adac6a3be4eba0,
695                    0x79495c4ec93da33a,
696                    0xe7175850a43ccaed,
697                    0xb2bc2a163de1bf2,
698                ]),
699            },
700            z: Fp2::one(),
701        }
702    }
703
704    /// Computes the doubling of this point.
705    pub fn double(&self) -> G2Projective {
706        // http://www.hyperelliptic.org/EFD/g2p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
707        //
708        // There are no points of order 2.
709
710        let a = self.x.square();
711        let b = self.y.square();
712        let c = b.square();
713        let d = self.x + b;
714        let d = d.square();
715        let d = d - a - c;
716        let d = d + d;
717        let e = a + a + a;
718        let f = e.square();
719        let z3 = self.z * self.y;
720        let z3 = z3 + z3;
721        let x3 = f - (d + d);
722        let c = c + c;
723        let c = c + c;
724        let c = c + c;
725        let y3 = e * (d - x3) - c;
726
727        let tmp = G2Projective {
728            x: x3,
729            y: y3,
730            z: z3,
731        };
732
733        G2Projective::conditional_select(&tmp, &G2Projective::identity(), self.is_identity())
734    }
735
736    /// Adds this point to another point.
737    pub fn add(&self, rhs: &G2Projective) -> G2Projective {
738        // This Jacobian point addition technique is based on the implementation in libsecp256k1,
739        // which assumes that rhs has z=1. Let's address the case of zero z-coordinates generally.
740
741        // If self is the identity, return rhs. Otherwise, return self. The other cases will be
742        // predicated on neither self nor rhs being the identity.
743        let f1 = self.is_identity();
744        let res = G2Projective::conditional_select(self, rhs, f1);
745        let f2 = rhs.is_identity();
746
747        // If neither are the identity but x1 = x2 and y1 != y2, then return the identity
748        let z = rhs.z.square();
749        let u1 = self.x * z;
750        let z = z * rhs.z;
751        let s1 = self.y * z;
752        let z = self.z.square();
753        let u2 = rhs.x * z;
754        let z = z * self.z;
755        let s2 = rhs.y * z;
756        let f3 = u1.ct_eq(&u2) & (!s1.ct_eq(&s2));
757        let res =
758            G2Projective::conditional_select(&res, &G2Projective::identity(), (!f1) & (!f2) & f3);
759
760        let t = u1 + u2;
761        let m = s1 + s2;
762        let rr = t.square();
763        let m_alt = -u2;
764        let tt = u1 * m_alt;
765        let rr = rr + tt;
766
767        // Correct for x1 != x2 but y1 = -y2, which can occur because p - 1 is divisible by 3.
768        // libsecp256k1 does this by substituting in an alternative (defined) expression for lambda.
769        let degenerate = m.is_zero() & rr.is_zero();
770        let rr_alt = s1 + s1;
771        let m_alt = m_alt + u1;
772        let rr_alt = Fp2::conditional_select(&rr_alt, &rr, !degenerate);
773        let m_alt = Fp2::conditional_select(&m_alt, &m, !degenerate);
774
775        let n = m_alt.square();
776        let q = n * t;
777
778        let n = n.square();
779        let n = Fp2::conditional_select(&n, &m, degenerate);
780        let t = rr_alt.square();
781        let z3 = m_alt * self.z * rhs.z; // We allow rhs.z != 1, so we must account for this.
782        let z3 = z3 + z3;
783        let q = -q;
784        let t = t + q;
785        let x3 = t;
786        let t = t + t;
787        let t = t + q;
788        let t = t * rr_alt;
789        let t = t + n;
790        let y3 = -t;
791        let x3 = x3 + x3;
792        let x3 = x3 + x3;
793        let y3 = y3 + y3;
794        let y3 = y3 + y3;
795
796        let tmp = G2Projective {
797            x: x3,
798            y: y3,
799            z: z3,
800        };
801
802        G2Projective::conditional_select(&res, &tmp, (!f1) & (!f2) & (!f3))
803    }
804
805    /// Adds this point to another point in the affine model.
806    pub fn add_mixed(&self, rhs: &G2Affine) -> G2Projective {
807        // This Jacobian point addition technique is based on the implementation in libsecp256k1,
808        // which assumes that rhs has z=1. Let's address the case of zero z-coordinates generally.
809
810        // If self is the identity, return rhs. Otherwise, return self. The other cases will be
811        // predicated on neither self nor rhs being the identity.
812        let f1 = self.is_identity();
813        let res = G2Projective::conditional_select(self, &G2Projective::from(rhs), f1);
814        let f2 = rhs.is_identity();
815
816        // If neither are the identity but x1 = x2 and y1 != y2, then return the identity
817        let u1 = self.x;
818        let s1 = self.y;
819        let z = self.z.square();
820        let u2 = rhs.x * z;
821        let z = z * self.z;
822        let s2 = rhs.y * z;
823        let f3 = u1.ct_eq(&u2) & (!s1.ct_eq(&s2));
824        let res =
825            G2Projective::conditional_select(&res, &G2Projective::identity(), (!f1) & (!f2) & f3);
826
827        let t = u1 + u2;
828        let m = s1 + s2;
829        let rr = t.square();
830        let m_alt = -u2;
831        let tt = u1 * m_alt;
832        let rr = rr + tt;
833
834        // Correct for x1 != x2 but y1 = -y2, which can occur because p - 1 is divisible by 3.
835        // libsecp256k1 does this by substituting in an alternative (defined) expression for lambda.
836        let degenerate = m.is_zero() & rr.is_zero();
837        let rr_alt = s1 + s1;
838        let m_alt = m_alt + u1;
839        let rr_alt = Fp2::conditional_select(&rr_alt, &rr, !degenerate);
840        let m_alt = Fp2::conditional_select(&m_alt, &m, !degenerate);
841
842        let n = m_alt.square();
843        let q = n * t;
844
845        let n = n.square();
846        let n = Fp2::conditional_select(&n, &m, degenerate);
847        let t = rr_alt.square();
848        let z3 = m_alt * self.z;
849        let z3 = z3 + z3;
850        let q = -q;
851        let t = t + q;
852        let x3 = t;
853        let t = t + t;
854        let t = t + q;
855        let t = t * rr_alt;
856        let t = t + n;
857        let y3 = -t;
858        let x3 = x3 + x3;
859        let x3 = x3 + x3;
860        let y3 = y3 + y3;
861        let y3 = y3 + y3;
862
863        let tmp = G2Projective {
864            x: x3,
865            y: y3,
866            z: z3,
867        };
868
869        G2Projective::conditional_select(&res, &tmp, (!f1) & (!f2) & (!f3))
870    }
871
872    fn multiply(&self, by: &[u8]) -> G2Projective {
873        let mut acc = G2Projective::identity();
874
875        // This is a simple double-and-add implementation of point
876        // multiplication, moving from most significant to least
877        // significant bit of the scalar.
878        //
879        // We skip the leading bit because it's always unset for Fq
880        // elements.
881        for bit in by
882            .iter()
883            .rev()
884            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
885            .skip(1)
886        {
887            acc = acc.double();
888            acc = G2Projective::conditional_select(&acc, &(acc + self), bit);
889        }
890
891        acc
892    }
893
894    #[cfg(feature = "endo")]
895    fn psi(&self) -> G2Projective {
896        // 1 / ((u+1) ^ ((q-1)/3))
897        let psi_coeff_x = Fp2 {
898            c0: Fp::zero(),
899            c1: Fp::from_raw_unchecked([
900                0x890dc9e4867545c3,
901                0x2af322533285a5d5,
902                0x50880866309b7e2c,
903                0xa20d1b8c7e881024,
904                0x14e4f04fe2db9068,
905                0x14e56d3f1564853a,
906            ]),
907        };
908        // 1 / ((u+1) ^ (p-1)/2)
909        let psi_coeff_y = Fp2 {
910            c0: Fp::from_raw_unchecked([
911                0x3e2f585da55c9ad1,
912                0x4294213d86c18183,
913                0x382844c88b623732,
914                0x92ad2afd19103e18,
915                0x1d794e4fac7cf0b9,
916                0x0bd592fc7d825ec8,
917            ]),
918            c1: Fp::from_raw_unchecked([
919                0x7bcfa7a25aa30fda,
920                0xdc17dec12a927e7c,
921                0x2f088dd86b4ebef1,
922                0xd1ca2087da74d4a7,
923                0x2da2596696cebc1d,
924                0x0e2b7eedbbfd87d2,
925            ]),
926        };
927
928        G2Projective {
929            // x = frobenius(x)/((u+1)^((p-1)/3))
930            x: self.x.frobenius_map() * psi_coeff_x,
931            // y = frobenius(y)/(u+1)^((p-1)/2)
932            y: self.y.frobenius_map() * psi_coeff_y,
933            // z = frobenius(z)
934            z: self.z.frobenius_map(),
935        }
936    }
937
938    #[cfg(feature = "endo")]
939    fn psi2(&self) -> G2Projective {
940        // 1 / 2 ^ ((q-1)/3)
941        let psi2_coeff_x = Fp2 {
942            c0: Fp::from_raw_unchecked([
943                0xcd03c9e48671f071,
944                0x5dab22461fcda5d2,
945                0x587042afd3851b95,
946                0x8eb60ebe01bacb9e,
947                0x03f97d6e83d050d2,
948                0x18f0206554638741,
949            ]),
950            c1: Fp::zero(),
951        };
952
953        G2Projective {
954            // x = frobenius^2(x)/2^((p-1)/3)
955            x: self.x.frobenius_map().frobenius_map() * psi2_coeff_x,
956            // y = -frobenius^2(y)
957            y: self.y.frobenius_map().frobenius_map().neg(),
958            // z = z
959            z: self.z,
960        }
961    }
962
963    /// Multiply `self` by `crate::BLS_X`, using double and add.
964    #[cfg(feature = "endo")]
965    fn mul_by_x(&self) -> G2Projective {
966        let mut xself = G2Projective::identity();
967        // NOTE: in BLS12-381 we can just skip the first bit.
968        let mut x = crate::BLS_X >> 1;
969        let mut acc = *self;
970        while x != 0 {
971            acc = acc.double();
972            if x % 2 == 1 {
973                xself += acc;
974            }
975            x >>= 1;
976        }
977        // finally, flip the sign
978        if crate::BLS_X_IS_NEGATIVE {
979            xself = -xself;
980        }
981        xself
982    }
983
984    /// Clears the cofactor, using [Budroni-Pintore](https://ia.cr/2017/419).
985    /// This is equivalent to multiplying by $h\_\textrm{eff} = 3(z^2 - 1) \cdot
986    /// h_2$, where $h_2$ is the cofactor of $\mathbb{G}\_2$ and $z$ is the
987    /// parameter of BLS12-381.
988    ///
989    /// The endomorphism is only actually used if the crate feature `endo` is
990    /// enabled, and it is disabled by default to mitigate potential patent
991    /// issues.
992    pub fn clear_cofactor(&self) -> G2Projective {
993        #[cfg(feature = "endo")]
994        fn clear_cofactor(this: &G2Projective) -> G2Projective {
995            let t1 = this.mul_by_x(); // [x] P
996            let t2 = this.psi(); // psi(P)
997
998            this.double().psi2() // psi^2(2P)
999                + (t1 + t2).mul_by_x() // psi^2(2P) + [x^2] P + [x] psi(P)
1000                - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P)
1001                - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P)
1002                - this // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P)
1003        }
1004
1005        #[cfg(not(feature = "endo"))]
1006        fn clear_cofactor(this: &G2Projective) -> G2Projective {
1007            this.multiply(&[
1008                0x51, 0x55, 0xa9, 0xaa, 0x5, 0x0, 0x2, 0xe8, 0xb4, 0xf6, 0xbb, 0xde, 0xa, 0x4c,
1009                0x89, 0x59, 0xa3, 0xf6, 0x89, 0x66, 0xc0, 0xcb, 0x54, 0xe9, 0x1a, 0x7c, 0x47, 0xd7,
1010                0x69, 0xec, 0xc0, 0x2e, 0xb0, 0x12, 0x12, 0x5d, 0x1, 0xbf, 0x82, 0x6d, 0x95, 0xdb,
1011                0x31, 0x87, 0x17, 0x2f, 0x9c, 0x32, 0xe1, 0xff, 0x8, 0x15, 0x3, 0xff, 0x86, 0x99,
1012                0x68, 0xd7, 0x5a, 0x14, 0xe9, 0xa8, 0xe2, 0x88, 0x28, 0x35, 0x1b, 0xa9, 0xe, 0x6a,
1013                0x4c, 0x58, 0xb3, 0x75, 0xee, 0xf2, 0x8, 0x9f, 0xc6, 0xb,
1014            ])
1015        }
1016
1017        clear_cofactor(self)
1018    }
1019
1020    /// Converts a batch of `G2Projective` elements into `G2Affine` elements. This
1021    /// function will panic if `p.len() != q.len()`.
1022    pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) {
1023        assert_eq!(p.len(), q.len());
1024
1025        let mut acc = Fp2::one();
1026        for (p, q) in p.iter().zip(q.iter_mut()) {
1027            // We use the `x` field of `G2Affine` to store the product
1028            // of previous z-coordinates seen.
1029            q.x = acc;
1030
1031            // We will end up skipping all identities in p
1032            acc = Fp2::conditional_select(&(acc * p.z), &acc, p.is_identity());
1033        }
1034
1035        // This is the inverse, as all z-coordinates are nonzero and the ones
1036        // that are not are skipped.
1037        acc = acc.invert().unwrap();
1038
1039        for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
1040            let skip = p.is_identity();
1041
1042            // Compute tmp = 1/z
1043            let tmp = q.x * acc;
1044
1045            // Cancel out z-coordinate in denominator of `acc`
1046            acc = Fp2::conditional_select(&(acc * p.z), &acc, skip);
1047
1048            // Set the coordinates to the correct value
1049            let tmp2 = tmp.square();
1050            let tmp3 = tmp2 * tmp;
1051
1052            q.x = p.x * tmp2;
1053            q.y = p.y * tmp3;
1054            q.infinity = Choice::from(0u8);
1055
1056            *q = G2Affine::conditional_select(&q, &G2Affine::identity(), skip);
1057        }
1058    }
1059
1060    /// Returns true if this element is the identity (the point at infinity).
1061    #[inline]
1062    pub fn is_identity(&self) -> Choice {
1063        self.z.is_zero()
1064    }
1065
1066    /// Returns true if this point is on the curve. This should always return
1067    /// true unless an "unchecked" API was used.
1068    pub fn is_on_curve(&self) -> Choice {
1069        // Y^2 - X^3 = 4(u + 1)(Z^6)
1070
1071        (self.y.square() - (self.x.square() * self.x))
1072            .ct_eq(&((self.z.square() * self.z).square() * B))
1073            | self.z.is_zero()
1074    }
1075}
1076
1077#[cfg(test)]
1078mod tests {
1079    use super::*;
1080
1081    #[test]
1082    fn test_is_on_curve() {
1083        assert!(bool::from(G2Affine::identity().is_on_curve()));
1084        assert!(bool::from(G2Affine::generator().is_on_curve()));
1085        assert!(bool::from(G2Projective::identity().is_on_curve()));
1086        assert!(bool::from(G2Projective::generator().is_on_curve()));
1087
1088        let z = Fp2 {
1089            c0: Fp::from_raw_unchecked([
1090                0xba7afa1f9a6fe250,
1091                0xfa0f5b595eafe731,
1092                0x3bdc477694c306e7,
1093                0x2149be4b3949fa24,
1094                0x64aa6e0649b2078c,
1095                0x12b108ac33643c3e,
1096            ]),
1097            c1: Fp::from_raw_unchecked([
1098                0x125325df3d35b5a8,
1099                0xdc469ef5555d7fe3,
1100                0x2d716d2443106a9,
1101                0x5a1db59a6ff37d0,
1102                0x7cf7784e5300bb8f,
1103                0x16a88922c7a5e844,
1104            ]),
1105        };
1106
1107        let gen = G2Affine::generator();
1108        let mut test = G2Projective {
1109            x: gen.x * (z.square()),
1110            y: gen.y * (z.square() * z),
1111            z,
1112        };
1113
1114        assert!(bool::from(test.is_on_curve()));
1115
1116        test.x = z;
1117        assert!(!bool::from(test.is_on_curve()));
1118    }
1119
1120    #[test]
1121    fn test_affine_point_equality() {
1122        let a = G2Affine::generator();
1123        let b = G2Affine::identity();
1124
1125        assert!(a == a);
1126        assert!(b == b);
1127        assert!(a != b);
1128        assert!(b != a);
1129    }
1130
1131    #[test]
1132    fn test_projective_point_equality() {
1133        let a = G2Projective::generator();
1134        let b = G2Projective::identity();
1135
1136        assert!(a == a);
1137        assert!(b == b);
1138        assert!(a != b);
1139        assert!(b != a);
1140
1141        let z = Fp2 {
1142            c0: Fp::from_raw_unchecked([
1143                0xba7afa1f9a6fe250,
1144                0xfa0f5b595eafe731,
1145                0x3bdc477694c306e7,
1146                0x2149be4b3949fa24,
1147                0x64aa6e0649b2078c,
1148                0x12b108ac33643c3e,
1149            ]),
1150            c1: Fp::from_raw_unchecked([
1151                0x125325df3d35b5a8,
1152                0xdc469ef5555d7fe3,
1153                0x2d716d2443106a9,
1154                0x5a1db59a6ff37d0,
1155                0x7cf7784e5300bb8f,
1156                0x16a88922c7a5e844,
1157            ]),
1158        };
1159
1160        let mut c = G2Projective {
1161            x: a.x * (z.square()),
1162            y: a.y * (z.square() * z),
1163            z,
1164        };
1165        assert!(bool::from(c.is_on_curve()));
1166
1167        assert!(a == c);
1168        assert!(b != c);
1169        assert!(c == a);
1170        assert!(c != b);
1171
1172        c.y = -c.y;
1173        assert!(bool::from(c.is_on_curve()));
1174
1175        assert!(a != c);
1176        assert!(b != c);
1177        assert!(c != a);
1178        assert!(c != b);
1179
1180        c.y = -c.y;
1181        c.x = z;
1182        assert!(!bool::from(c.is_on_curve()));
1183        assert!(a != b);
1184        assert!(a != c);
1185        assert!(b != c);
1186    }
1187
1188    #[test]
1189    fn test_conditionally_select_affine() {
1190        let a = G2Affine::generator();
1191        let b = G2Affine::identity();
1192
1193        assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(0u8)), a);
1194        assert_eq!(G2Affine::conditional_select(&a, &b, Choice::from(1u8)), b);
1195    }
1196
1197    #[test]
1198    fn test_conditionally_select_projective() {
1199        let a = G2Projective::generator();
1200        let b = G2Projective::identity();
1201
1202        assert_eq!(
1203            G2Projective::conditional_select(&a, &b, Choice::from(0u8)),
1204            a
1205        );
1206        assert_eq!(
1207            G2Projective::conditional_select(&a, &b, Choice::from(1u8)),
1208            b
1209        );
1210    }
1211
1212    #[test]
1213    fn test_projective_to_affine() {
1214        let a = G2Projective::generator();
1215        let b = G2Projective::identity();
1216
1217        assert!(bool::from(G2Affine::from(a).is_on_curve()));
1218        assert!(!bool::from(G2Affine::from(a).is_identity()));
1219        assert!(bool::from(G2Affine::from(b).is_on_curve()));
1220        assert!(bool::from(G2Affine::from(b).is_identity()));
1221
1222        let z = Fp2 {
1223            c0: Fp::from_raw_unchecked([
1224                0xba7afa1f9a6fe250,
1225                0xfa0f5b595eafe731,
1226                0x3bdc477694c306e7,
1227                0x2149be4b3949fa24,
1228                0x64aa6e0649b2078c,
1229                0x12b108ac33643c3e,
1230            ]),
1231            c1: Fp::from_raw_unchecked([
1232                0x125325df3d35b5a8,
1233                0xdc469ef5555d7fe3,
1234                0x2d716d2443106a9,
1235                0x5a1db59a6ff37d0,
1236                0x7cf7784e5300bb8f,
1237                0x16a88922c7a5e844,
1238            ]),
1239        };
1240
1241        let c = G2Projective {
1242            x: a.x * (z.square()),
1243            y: a.y * (z.square() * z),
1244            z,
1245        };
1246
1247        assert_eq!(G2Affine::from(c), G2Affine::generator());
1248    }
1249
1250    #[test]
1251    fn test_affine_to_projective() {
1252        let a = G2Affine::generator();
1253        let b = G2Affine::identity();
1254
1255        assert!(bool::from(G2Projective::from(a).is_on_curve()));
1256        assert!(!bool::from(G2Projective::from(a).is_identity()));
1257        assert!(bool::from(G2Projective::from(b).is_on_curve()));
1258        assert!(bool::from(G2Projective::from(b).is_identity()));
1259    }
1260
1261    #[test]
1262    fn test_doubling() {
1263        {
1264            let tmp = G2Projective::identity().double();
1265            assert!(bool::from(tmp.is_identity()));
1266            assert!(bool::from(tmp.is_on_curve()));
1267        }
1268        {
1269            let tmp = G2Projective::generator().double();
1270            assert!(!bool::from(tmp.is_identity()));
1271            assert!(bool::from(tmp.is_on_curve()));
1272
1273            assert_eq!(
1274                G2Affine::from(tmp),
1275                G2Affine {
1276                    x: Fp2 {
1277                        c0: Fp::from_raw_unchecked([
1278                            0xe9d9e2da9620f98b,
1279                            0x54f1199346b97f36,
1280                            0x3db3b820376bed27,
1281                            0xcfdb31c9b0b64f4c,
1282                            0x41d7c12786354493,
1283                            0x5710794c255c064
1284                        ]),
1285                        c1: Fp::from_raw_unchecked([
1286                            0xd6c1d3ca6ea0d06e,
1287                            0xda0cbd905595489f,
1288                            0x4f5352d43479221d,
1289                            0x8ade5d736f8c97e0,
1290                            0x48cc8433925ef70e,
1291                            0x8d7ea71ea91ef81
1292                        ]),
1293                    },
1294                    y: Fp2 {
1295                        c0: Fp::from_raw_unchecked([
1296                            0x15ba26eb4b0d186f,
1297                            0xd086d64b7e9e01e,
1298                            0xc8b848dd652f4c78,
1299                            0xeecf46a6123bae4f,
1300                            0x255e8dd8b6dc812a,
1301                            0x164142af21dcf93f
1302                        ]),
1303                        c1: Fp::from_raw_unchecked([
1304                            0xf9b4a1a895984db4,
1305                            0xd417b114cccff748,
1306                            0x6856301fc89f086e,
1307                            0x41c777878931e3da,
1308                            0x3556b155066a2105,
1309                            0xacf7d325cb89cf
1310                        ]),
1311                    },
1312                    infinity: Choice::from(0u8)
1313                }
1314            );
1315        }
1316    }
1317
1318    #[test]
1319    fn test_projective_addition() {
1320        {
1321            let a = G2Projective::identity();
1322            let b = G2Projective::identity();
1323            let c = a + b;
1324            assert!(bool::from(c.is_identity()));
1325            assert!(bool::from(c.is_on_curve()));
1326        }
1327        {
1328            let a = G2Projective::identity();
1329            let mut b = G2Projective::generator();
1330            {
1331                let z = Fp2 {
1332                    c0: Fp::from_raw_unchecked([
1333                        0xba7afa1f9a6fe250,
1334                        0xfa0f5b595eafe731,
1335                        0x3bdc477694c306e7,
1336                        0x2149be4b3949fa24,
1337                        0x64aa6e0649b2078c,
1338                        0x12b108ac33643c3e,
1339                    ]),
1340                    c1: Fp::from_raw_unchecked([
1341                        0x125325df3d35b5a8,
1342                        0xdc469ef5555d7fe3,
1343                        0x2d716d2443106a9,
1344                        0x5a1db59a6ff37d0,
1345                        0x7cf7784e5300bb8f,
1346                        0x16a88922c7a5e844,
1347                    ]),
1348                };
1349
1350                b = G2Projective {
1351                    x: b.x * (z.square()),
1352                    y: b.y * (z.square() * z),
1353                    z,
1354                };
1355            }
1356            let c = a + b;
1357            assert!(!bool::from(c.is_identity()));
1358            assert!(bool::from(c.is_on_curve()));
1359            assert!(c == G2Projective::generator());
1360        }
1361        {
1362            let a = G2Projective::identity();
1363            let mut b = G2Projective::generator();
1364            {
1365                let z = Fp2 {
1366                    c0: Fp::from_raw_unchecked([
1367                        0xba7afa1f9a6fe250,
1368                        0xfa0f5b595eafe731,
1369                        0x3bdc477694c306e7,
1370                        0x2149be4b3949fa24,
1371                        0x64aa6e0649b2078c,
1372                        0x12b108ac33643c3e,
1373                    ]),
1374                    c1: Fp::from_raw_unchecked([
1375                        0x125325df3d35b5a8,
1376                        0xdc469ef5555d7fe3,
1377                        0x2d716d2443106a9,
1378                        0x5a1db59a6ff37d0,
1379                        0x7cf7784e5300bb8f,
1380                        0x16a88922c7a5e844,
1381                    ]),
1382                };
1383
1384                b = G2Projective {
1385                    x: b.x * (z.square()),
1386                    y: b.y * (z.square() * z),
1387                    z,
1388                };
1389            }
1390            let c = b + a;
1391            assert!(!bool::from(c.is_identity()));
1392            assert!(bool::from(c.is_on_curve()));
1393            assert!(c == G2Projective::generator());
1394        }
1395        {
1396            let a = G2Projective::generator().double().double(); // 4P
1397            let b = G2Projective::generator().double(); // 2P
1398            let c = a + b;
1399
1400            let mut d = G2Projective::generator();
1401            for _ in 0..5 {
1402                d = d + G2Projective::generator();
1403            }
1404            assert!(!bool::from(c.is_identity()));
1405            assert!(bool::from(c.is_on_curve()));
1406            assert!(!bool::from(d.is_identity()));
1407            assert!(bool::from(d.is_on_curve()));
1408            assert_eq!(c, d);
1409        }
1410
1411        // Degenerate case
1412        {
1413            let beta = Fp2 {
1414                c0: Fp::from_raw_unchecked([
1415                    0xcd03c9e48671f071,
1416                    0x5dab22461fcda5d2,
1417                    0x587042afd3851b95,
1418                    0x8eb60ebe01bacb9e,
1419                    0x3f97d6e83d050d2,
1420                    0x18f0206554638741,
1421                ]),
1422                c1: Fp::zero(),
1423            };
1424            let beta = beta.square();
1425            let a = G2Projective::generator().double().double();
1426            let b = G2Projective {
1427                x: a.x * beta,
1428                y: -a.y,
1429                z: a.z,
1430            };
1431            assert!(bool::from(a.is_on_curve()));
1432            assert!(bool::from(b.is_on_curve()));
1433
1434            let c = a + b;
1435            assert_eq!(
1436                G2Affine::from(c),
1437                G2Affine::from(G2Projective {
1438                    x: Fp2 {
1439                        c0: Fp::from_raw_unchecked([
1440                            0x705abc799ca773d3,
1441                            0xfe132292c1d4bf08,
1442                            0xf37ece3e07b2b466,
1443                            0x887e1c43f447e301,
1444                            0x1e0970d033bc77e8,
1445                            0x1985c81e20a693f2
1446                        ]),
1447                        c1: Fp::from_raw_unchecked([
1448                            0x1d79b25db36ab924,
1449                            0x23948e4d529639d3,
1450                            0x471ba7fb0d006297,
1451                            0x2c36d4b4465dc4c0,
1452                            0x82bbc3cfec67f538,
1453                            0x51d2728b67bf952
1454                        ])
1455                    },
1456                    y: Fp2 {
1457                        c0: Fp::from_raw_unchecked([
1458                            0x41b1bbf6576c0abf,
1459                            0xb6cc93713f7a0f9a,
1460                            0x6b65b43e48f3f01f,
1461                            0xfb7a4cfcaf81be4f,
1462                            0x3e32dadc6ec22cb6,
1463                            0xbb0fc49d79807e3
1464                        ]),
1465                        c1: Fp::from_raw_unchecked([
1466                            0x7d1397788f5f2ddf,
1467                            0xab2907144ff0d8e8,
1468                            0x5b7573e0cdb91f92,
1469                            0x4cb8932dd31daf28,
1470                            0x62bbfac6db052a54,
1471                            0x11f95c16d14c3bbe
1472                        ])
1473                    },
1474                    z: Fp2::one()
1475                })
1476            );
1477            assert!(!bool::from(c.is_identity()));
1478            assert!(bool::from(c.is_on_curve()));
1479        }
1480    }
1481
1482    #[test]
1483    fn test_mixed_addition() {
1484        {
1485            let a = G2Affine::identity();
1486            let b = G2Projective::identity();
1487            let c = a + b;
1488            assert!(bool::from(c.is_identity()));
1489            assert!(bool::from(c.is_on_curve()));
1490        }
1491        {
1492            let a = G2Affine::identity();
1493            let mut b = G2Projective::generator();
1494            {
1495                let z = Fp2 {
1496                    c0: Fp::from_raw_unchecked([
1497                        0xba7afa1f9a6fe250,
1498                        0xfa0f5b595eafe731,
1499                        0x3bdc477694c306e7,
1500                        0x2149be4b3949fa24,
1501                        0x64aa6e0649b2078c,
1502                        0x12b108ac33643c3e,
1503                    ]),
1504                    c1: Fp::from_raw_unchecked([
1505                        0x125325df3d35b5a8,
1506                        0xdc469ef5555d7fe3,
1507                        0x2d716d2443106a9,
1508                        0x5a1db59a6ff37d0,
1509                        0x7cf7784e5300bb8f,
1510                        0x16a88922c7a5e844,
1511                    ]),
1512                };
1513
1514                b = G2Projective {
1515                    x: b.x * (z.square()),
1516                    y: b.y * (z.square() * z),
1517                    z,
1518                };
1519            }
1520            let c = a + b;
1521            assert!(!bool::from(c.is_identity()));
1522            assert!(bool::from(c.is_on_curve()));
1523            assert!(c == G2Projective::generator());
1524        }
1525        {
1526            let a = G2Affine::identity();
1527            let mut b = G2Projective::generator();
1528            {
1529                let z = Fp2 {
1530                    c0: Fp::from_raw_unchecked([
1531                        0xba7afa1f9a6fe250,
1532                        0xfa0f5b595eafe731,
1533                        0x3bdc477694c306e7,
1534                        0x2149be4b3949fa24,
1535                        0x64aa6e0649b2078c,
1536                        0x12b108ac33643c3e,
1537                    ]),
1538                    c1: Fp::from_raw_unchecked([
1539                        0x125325df3d35b5a8,
1540                        0xdc469ef5555d7fe3,
1541                        0x2d716d2443106a9,
1542                        0x5a1db59a6ff37d0,
1543                        0x7cf7784e5300bb8f,
1544                        0x16a88922c7a5e844,
1545                    ]),
1546                };
1547
1548                b = G2Projective {
1549                    x: b.x * (z.square()),
1550                    y: b.y * (z.square() * z),
1551                    z,
1552                };
1553            }
1554            let c = b + a;
1555            assert!(!bool::from(c.is_identity()));
1556            assert!(bool::from(c.is_on_curve()));
1557            assert!(c == G2Projective::generator());
1558        }
1559        {
1560            let a = G2Projective::generator().double().double(); // 4P
1561            let b = G2Projective::generator().double(); // 2P
1562            let c = a + b;
1563
1564            let mut d = G2Projective::generator();
1565            for _ in 0..5 {
1566                d = d + G2Affine::generator();
1567            }
1568            assert!(!bool::from(c.is_identity()));
1569            assert!(bool::from(c.is_on_curve()));
1570            assert!(!bool::from(d.is_identity()));
1571            assert!(bool::from(d.is_on_curve()));
1572            assert_eq!(c, d);
1573        }
1574
1575        // Degenerate case
1576        {
1577            let beta = Fp2 {
1578                c0: Fp::from_raw_unchecked([
1579                    0xcd03c9e48671f071,
1580                    0x5dab22461fcda5d2,
1581                    0x587042afd3851b95,
1582                    0x8eb60ebe01bacb9e,
1583                    0x3f97d6e83d050d2,
1584                    0x18f0206554638741,
1585                ]),
1586                c1: Fp::zero(),
1587            };
1588            let beta = beta.square();
1589            let a = G2Projective::generator().double().double();
1590            let b = G2Projective {
1591                x: a.x * beta,
1592                y: -a.y,
1593                z: a.z,
1594            };
1595            let a = G2Affine::from(a);
1596            assert!(bool::from(a.is_on_curve()));
1597            assert!(bool::from(b.is_on_curve()));
1598
1599            let c = a + b;
1600            assert_eq!(
1601                G2Affine::from(c),
1602                G2Affine::from(G2Projective {
1603                    x: Fp2 {
1604                        c0: Fp::from_raw_unchecked([
1605                            0x705abc799ca773d3,
1606                            0xfe132292c1d4bf08,
1607                            0xf37ece3e07b2b466,
1608                            0x887e1c43f447e301,
1609                            0x1e0970d033bc77e8,
1610                            0x1985c81e20a693f2
1611                        ]),
1612                        c1: Fp::from_raw_unchecked([
1613                            0x1d79b25db36ab924,
1614                            0x23948e4d529639d3,
1615                            0x471ba7fb0d006297,
1616                            0x2c36d4b4465dc4c0,
1617                            0x82bbc3cfec67f538,
1618                            0x51d2728b67bf952
1619                        ])
1620                    },
1621                    y: Fp2 {
1622                        c0: Fp::from_raw_unchecked([
1623                            0x41b1bbf6576c0abf,
1624                            0xb6cc93713f7a0f9a,
1625                            0x6b65b43e48f3f01f,
1626                            0xfb7a4cfcaf81be4f,
1627                            0x3e32dadc6ec22cb6,
1628                            0xbb0fc49d79807e3
1629                        ]),
1630                        c1: Fp::from_raw_unchecked([
1631                            0x7d1397788f5f2ddf,
1632                            0xab2907144ff0d8e8,
1633                            0x5b7573e0cdb91f92,
1634                            0x4cb8932dd31daf28,
1635                            0x62bbfac6db052a54,
1636                            0x11f95c16d14c3bbe
1637                        ])
1638                    },
1639                    z: Fp2::one()
1640                })
1641            );
1642            assert!(!bool::from(c.is_identity()));
1643            assert!(bool::from(c.is_on_curve()));
1644        }
1645    }
1646
1647    #[test]
1648    fn test_projective_negation_and_subtraction() {
1649        let a = G2Projective::generator().double();
1650        assert_eq!(a + (-a), G2Projective::identity());
1651        assert_eq!(a + (-a), a - a);
1652    }
1653
1654    #[test]
1655    fn test_affine_negation_and_subtraction() {
1656        let a = G2Affine::generator();
1657        assert_eq!(G2Projective::from(a) + (-a), G2Projective::identity());
1658        assert_eq!(G2Projective::from(a) + (-a), G2Projective::from(a) - a);
1659    }
1660
1661    #[test]
1662    fn test_projective_scalar_multiplication() {
1663        let g = G2Projective::generator();
1664        let a = BlsScalar::from_raw([
1665            0x2b568297a56da71c,
1666            0xd8c39ecb0ef375d1,
1667            0x435c38da67bfbf96,
1668            0x8088a05026b659b2,
1669        ]);
1670        let b = BlsScalar::from_raw([
1671            0x785fdd9b26ef8b85,
1672            0xc997f25837695c18,
1673            0x4c8dbc39e7b756c1,
1674            0x70d9b6cc6d87df20,
1675        ]);
1676        let c = a * b;
1677
1678        assert_eq!((g * a) * b, g * c);
1679    }
1680
1681    #[test]
1682    fn test_affine_scalar_multiplication() {
1683        let g = G2Affine::generator();
1684        let a = BlsScalar::from_raw([
1685            0x2b568297a56da71c,
1686            0xd8c39ecb0ef375d1,
1687            0x435c38da67bfbf96,
1688            0x8088a05026b659b2,
1689        ]);
1690        let b = BlsScalar::from_raw([
1691            0x785fdd9b26ef8b85,
1692            0xc997f25837695c18,
1693            0x4c8dbc39e7b756c1,
1694            0x70d9b6cc6d87df20,
1695        ]);
1696        let c = a * b;
1697
1698        assert_eq!(G2Affine::from(g * a) * b, g * c);
1699    }
1700
1701    #[test]
1702    fn test_is_torsion_free() {
1703        let a = G2Affine {
1704            x: Fp2 {
1705                c0: Fp::from_raw_unchecked([
1706                    0x89f550c813db6431,
1707                    0xa50be8c456cd8a1a,
1708                    0xa45b374114cae851,
1709                    0xbb6190f5bf7fff63,
1710                    0x970ca02c3ba80bc7,
1711                    0x2b85d24e840fbac,
1712                ]),
1713                c1: Fp::from_raw_unchecked([
1714                    0x6888bc53d70716dc,
1715                    0x3dea6b4117682d70,
1716                    0xd8f5f930500ca354,
1717                    0x6b5ecb6556f5c155,
1718                    0xc96bef0434778ab0,
1719                    0x5081505515006ad,
1720                ]),
1721            },
1722            y: Fp2 {
1723                c0: Fp::from_raw_unchecked([
1724                    0x3cf1ea0d434b0f40,
1725                    0x1a0dc610e603e333,
1726                    0x7f89956160c72fa0,
1727                    0x25ee03decf6431c5,
1728                    0xeee8e206ec0fe137,
1729                    0x97592b226dfef28,
1730                ]),
1731                c1: Fp::from_raw_unchecked([
1732                    0x71e8bb5f29247367,
1733                    0xa5fe049e211831ce,
1734                    0xce6b354502a3896,
1735                    0x93b012000997314e,
1736                    0x6759f3b6aa5b42ac,
1737                    0x156944c4dfe92bbb,
1738                ]),
1739            },
1740            infinity: Choice::from(0u8),
1741        };
1742        assert!(!bool::from(a.is_torsion_free()));
1743
1744        assert!(bool::from(G2Affine::identity().is_torsion_free()));
1745        assert!(bool::from(G2Affine::generator().is_torsion_free()));
1746    }
1747
1748    #[cfg(feature = "endo")]
1749    #[test]
1750    fn test_mul_by_x() {
1751        // multiplying by `x` a point in G2 is the same as multiplying by
1752        // the equivalent scalar.
1753        let generator = G2Projective::generator();
1754        let x = if crate::BLS_X_IS_NEGATIVE {
1755            -BlsScalar::from(crate::BLS_X)
1756        } else {
1757            BlsScalar::from(crate::BLS_X)
1758        };
1759        assert_eq!(generator.mul_by_x(), generator * x);
1760
1761        let point = G2Projective::generator() * BlsScalar::from(42);
1762        assert_eq!(point.mul_by_x(), point * x);
1763    }
1764
1765    #[cfg(feature = "endo")]
1766    #[test]
1767    fn test_psi() {
1768        let generator = G2Projective::generator();
1769
1770        // `point` is a random point in the curve
1771        let point = G2Projective {
1772            x: Fp2 {
1773                c0: Fp::from_raw_unchecked([
1774                    0xee4c8cb7c047eaf2,
1775                    0x44ca22eee036b604,
1776                    0x33b3affb2aefe101,
1777                    0x15d3e45bbafaeb02,
1778                    0x7bfc2154cd7419a4,
1779                    0x0a2d0c2b756e5edc,
1780                ]),
1781                c1: Fp::from_raw_unchecked([
1782                    0xfc224361029a8777,
1783                    0x4cbf2baab8740924,
1784                    0xc5008c6ec6592c89,
1785                    0xecc2c57b472a9c2d,
1786                    0x8613eafd9d81ffb1,
1787                    0x10fe54daa2d3d495,
1788                ]),
1789            },
1790            y: Fp2 {
1791                c0: Fp::from_raw_unchecked([
1792                    0x7de7edc43953b75c,
1793                    0x58be1d2de35e87dc,
1794                    0x5731d30b0e337b40,
1795                    0xbe93b60cfeaae4c9,
1796                    0x8b22c203764bedca,
1797                    0x01616c8d1033b771,
1798                ]),
1799                c1: Fp::from_raw_unchecked([
1800                    0xea126fe476b5733b,
1801                    0x85cee68b5dae1652,
1802                    0x98247779f7272b04,
1803                    0xa649c8b468c6e808,
1804                    0xb5b9a62dff0c4e45,
1805                    0x1555b67fc7bbe73d,
1806                ]),
1807            },
1808            z: Fp2 {
1809                c0: Fp::from_raw_unchecked([
1810                    0x0ef2ddffab187c0a,
1811                    0x2424522b7d5ecbfc,
1812                    0xc6f341a3398054f4,
1813                    0x5523ddf409502df0,
1814                    0xd55c0b5a88e0dd97,
1815                    0x066428d704923e52,
1816                ]),
1817                c1: Fp::from_raw_unchecked([
1818                    0x538bbe0c95b4878d,
1819                    0xad04a50379522881,
1820                    0x6d5c05bf5c12fb64,
1821                    0x4ce4a069a2d34787,
1822                    0x59ea6c8d0dffaeaf,
1823                    0x0d42a083a75bd6f3,
1824                ]),
1825            },
1826        };
1827        assert!(bool::from(point.is_on_curve()));
1828
1829        // psi2(P) = psi(psi(P))
1830        assert_eq!(generator.psi2(), generator.psi().psi());
1831        assert_eq!(point.psi2(), point.psi().psi());
1832        // psi(P) is a morphism
1833        assert_eq!(generator.double().psi(), generator.psi().double());
1834        assert_eq!(point.psi() + generator.psi(), (point + generator).psi());
1835        // psi(P) behaves in the same way on the same projective point
1836        let mut normalized_point = [G2Affine::identity()];
1837        G2Projective::batch_normalize(&[point], &mut normalized_point);
1838        let normalized_point = G2Projective::from(normalized_point[0]);
1839        assert_eq!(point.psi(), normalized_point.psi());
1840        assert_eq!(point.psi2(), normalized_point.psi2());
1841    }
1842
1843    #[test]
1844    fn test_clear_cofactor() {
1845        // `point` is a random point in the curve
1846        let point = G2Projective {
1847            x: Fp2 {
1848                c0: Fp::from_raw_unchecked([
1849                    0xee4c8cb7c047eaf2,
1850                    0x44ca22eee036b604,
1851                    0x33b3affb2aefe101,
1852                    0x15d3e45bbafaeb02,
1853                    0x7bfc2154cd7419a4,
1854                    0x0a2d0c2b756e5edc,
1855                ]),
1856                c1: Fp::from_raw_unchecked([
1857                    0xfc224361029a8777,
1858                    0x4cbf2baab8740924,
1859                    0xc5008c6ec6592c89,
1860                    0xecc2c57b472a9c2d,
1861                    0x8613eafd9d81ffb1,
1862                    0x10fe54daa2d3d495,
1863                ]),
1864            },
1865            y: Fp2 {
1866                c0: Fp::from_raw_unchecked([
1867                    0x7de7edc43953b75c,
1868                    0x58be1d2de35e87dc,
1869                    0x5731d30b0e337b40,
1870                    0xbe93b60cfeaae4c9,
1871                    0x8b22c203764bedca,
1872                    0x01616c8d1033b771,
1873                ]),
1874                c1: Fp::from_raw_unchecked([
1875                    0xea126fe476b5733b,
1876                    0x85cee68b5dae1652,
1877                    0x98247779f7272b04,
1878                    0xa649c8b468c6e808,
1879                    0xb5b9a62dff0c4e45,
1880                    0x1555b67fc7bbe73d,
1881                ]),
1882            },
1883            z: Fp2 {
1884                c0: Fp::from_raw_unchecked([
1885                    0x0ef2ddffab187c0a,
1886                    0x2424522b7d5ecbfc,
1887                    0xc6f341a3398054f4,
1888                    0x5523ddf409502df0,
1889                    0xd55c0b5a88e0dd97,
1890                    0x066428d704923e52,
1891                ]),
1892                c1: Fp::from_raw_unchecked([
1893                    0x538bbe0c95b4878d,
1894                    0xad04a50379522881,
1895                    0x6d5c05bf5c12fb64,
1896                    0x4ce4a069a2d34787,
1897                    0x59ea6c8d0dffaeaf,
1898                    0x0d42a083a75bd6f3,
1899                ]),
1900            },
1901        };
1902
1903        assert!(bool::from(point.is_on_curve()));
1904        assert!(!bool::from(G2Affine::from(point).is_torsion_free()));
1905        let cleared_point = point.clear_cofactor();
1906
1907        assert!(bool::from(cleared_point.is_on_curve()));
1908        assert!(bool::from(G2Affine::from(cleared_point).is_torsion_free()));
1909
1910        // the generator (and the identity) are always on the curve,
1911        // even after clearing the cofactor
1912        let generator = G2Projective::generator();
1913        assert!(bool::from(generator.clear_cofactor().is_on_curve()));
1914        let id = G2Projective::identity();
1915        assert!(bool::from(id.clear_cofactor().is_on_curve()));
1916
1917        // test the effect on q-torsion points multiplying by h_eff modulo |BlsScalar|
1918        // h_eff % q = 0x2b116900400069009a40200040001ffff
1919        let h_eff_modq: [u8; 32] = [
1920            0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90,
1921            0x16, 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1922            0x00, 0x00, 0x00, 0x00,
1923        ];
1924        assert_eq!(generator.clear_cofactor(), generator.multiply(&h_eff_modq));
1925        assert_eq!(
1926            cleared_point.clear_cofactor(),
1927            cleared_point.multiply(&h_eff_modq)
1928        );
1929    }
1930
1931    #[test]
1932    fn test_batch_normalize() {
1933        let a = G2Projective::generator().double();
1934        let b = a.double();
1935        let c = b.double();
1936
1937        for a_identity in (0..1).map(|n| n == 1) {
1938            for b_identity in (0..1).map(|n| n == 1) {
1939                for c_identity in (0..1).map(|n| n == 1) {
1940                    let mut v = [a, b, c];
1941                    if a_identity {
1942                        v[0] = G2Projective::identity()
1943                    }
1944                    if b_identity {
1945                        v[1] = G2Projective::identity()
1946                    }
1947                    if c_identity {
1948                        v[2] = G2Projective::identity()
1949                    }
1950
1951                    let mut t = [
1952                        G2Affine::identity(),
1953                        G2Affine::identity(),
1954                        G2Affine::identity(),
1955                    ];
1956                    let expected = [
1957                        G2Affine::from(v[0]),
1958                        G2Affine::from(v[1]),
1959                        G2Affine::from(v[2]),
1960                    ];
1961
1962                    G2Projective::batch_normalize(&v[..], &mut t[..]);
1963
1964                    assert_eq!(&t[..], &expected[..]);
1965                }
1966            }
1967        }
1968    }
1969
1970    #[test]
1971    #[cfg(feature = "serde_req")]
1972    fn g2_affine_serde_roundtrip() {
1973        use bincode;
1974
1975        let gen = G2Affine::generator();
1976        let ser = bincode::serialize(&gen).unwrap();
1977        let deser: G2Affine = bincode::deserialize(&ser).unwrap();
1978
1979        assert_eq!(gen, deser);
1980    }
1981
1982    #[test]
1983    fn g2_affine_bytes_unchecked() {
1984        let gen = G2Affine::generator();
1985        let ident = G2Affine::identity();
1986
1987        let gen_p = gen.to_raw_bytes();
1988        let gen_p = unsafe { G2Affine::from_slice_unchecked(&gen_p) };
1989
1990        let ident_p = ident.to_raw_bytes();
1991        let ident_p = unsafe { G2Affine::from_slice_unchecked(&ident_p) };
1992
1993        assert_eq!(gen, gen_p);
1994        assert_eq!(ident, ident_p);
1995    }
1996
1997    #[test]
1998    fn g2_affine_hex() {
1999        use dusk_bytes::ParseHexStr;
2000
2001        let gen = G2Affine::generator();
2002        let ident = G2Affine::identity();
2003
2004        let gen_p = format!("{:x}", gen);
2005        let gen_p = G2Affine::from_hex_str(gen_p.as_str()).unwrap();
2006
2007        let ident_p = format!("{:x}", ident);
2008        let ident_p = G2Affine::from_hex_str(ident_p.as_str()).unwrap();
2009
2010        assert_eq!(gen, gen_p);
2011        assert_eq!(ident, ident_p);
2012    }
2013}