dcrypt_algorithms/ec/bls12_381/
g2.rs

1//! G₂ group implementation for BLS12-381.
2
3use core::borrow::Borrow;
4use core::fmt;
5use core::iter::Sum;
6use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use rand_core::RngCore;
8use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
9
10use super::field::fp::Fp;
11use super::field::fp2::Fp2;
12use super::Scalar;
13
14/// G₂ affine point representation.
15#[derive(Copy, Clone, Debug)]
16pub struct G2Affine {
17    pub(crate) x: Fp2,
18    pub(crate) y: Fp2,
19    infinity: Choice,
20}
21
22impl Default for G2Affine {
23    fn default() -> G2Affine {
24        G2Affine::identity()
25    }
26}
27
28#[cfg(feature = "zeroize")]
29impl zeroize::DefaultIsZeroes for G2Affine {}
30
31impl fmt::Display for G2Affine {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        write!(f, "{:?}", self)
34    }
35}
36
37impl<'a> From<&'a G2Projective> for G2Affine {
38    fn from(p: &'a G2Projective) -> G2Affine {
39        let zinv = p.z.invert().unwrap_or(Fp2::zero());
40        let x = p.x * zinv;
41        let y = p.y * zinv;
42
43        let tmp = G2Affine {
44            x,
45            y,
46            infinity: Choice::from(0u8),
47        };
48
49        G2Affine::conditional_select(&tmp, &G2Affine::identity(), zinv.is_zero())
50    }
51}
52
53impl From<G2Projective> for G2Affine {
54    fn from(p: G2Projective) -> G2Affine {
55        G2Affine::from(&p)
56    }
57}
58
59impl ConstantTimeEq for G2Affine {
60    fn ct_eq(&self, other: &Self) -> Choice {
61        (self.infinity & other.infinity)
62            | ((!self.infinity)
63                & (!other.infinity)
64                & self.x.ct_eq(&other.x)
65                & self.y.ct_eq(&other.y))
66    }
67}
68
69impl ConditionallySelectable for G2Affine {
70    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
71        G2Affine {
72            x: Fp2::conditional_select(&a.x, &b.x, choice),
73            y: Fp2::conditional_select(&a.y, &b.y, choice),
74            infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
75        }
76    }
77}
78
79impl Eq for G2Affine {}
80impl PartialEq for G2Affine {
81    #[inline]
82    fn eq(&self, other: &Self) -> bool {
83        bool::from(self.ct_eq(other))
84    }
85}
86
87impl<'a> Neg for &'a G2Affine {
88    type Output = G2Affine;
89
90    #[inline]
91    fn neg(self) -> G2Affine {
92        G2Affine {
93            x: self.x,
94            y: Fp2::conditional_select(&-self.y, &Fp2::one(), self.infinity),
95            infinity: self.infinity,
96        }
97    }
98}
99
100impl Neg for G2Affine {
101    type Output = G2Affine;
102
103    #[inline]
104    fn neg(self) -> G2Affine {
105        -&self
106    }
107}
108
109impl<'a, 'b> Add<&'b G2Projective> for &'a G2Affine {
110    type Output = G2Projective;
111
112    #[inline]
113    fn add(self, rhs: &'b G2Projective) -> G2Projective {
114        rhs.add_mixed(self)
115    }
116}
117
118impl<'a, 'b> Add<&'b G2Affine> for &'a G2Projective {
119    type Output = G2Projective;
120
121    #[inline]
122    fn add(self, rhs: &'b G2Affine) -> G2Projective {
123        self.add_mixed(rhs)
124    }
125}
126
127impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Affine {
128    type Output = G2Projective;
129
130    #[inline]
131    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
132        self + &(-rhs)
133    }
134}
135
136impl<'a, 'b> Sub<&'b G2Affine> for &'a G2Projective {
137    type Output = G2Projective;
138
139    #[inline]
140    fn sub(self, rhs: &'b G2Affine) -> G2Projective {
141        self + &(-rhs)
142    }
143}
144
145impl<T> Sum<T> for G2Projective
146where
147    T: Borrow<G2Projective>,
148{
149    fn sum<I>(iter: I) -> Self
150    where
151        I: Iterator<Item = T>,
152    {
153        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
154    }
155}
156
157// Binop implementations for G2Projective + G2Affine
158impl<'b> Add<&'b G2Affine> for G2Projective {
159    type Output = G2Projective;
160    #[inline]
161    fn add(self, rhs: &'b G2Affine) -> G2Projective {
162        &self + rhs
163    }
164}
165impl<'a> Add<G2Affine> for &'a G2Projective {
166    type Output = G2Projective;
167    #[inline]
168    fn add(self, rhs: G2Affine) -> G2Projective {
169        self + &rhs
170    }
171}
172impl Add<G2Affine> for G2Projective {
173    type Output = G2Projective;
174    #[inline]
175    fn add(self, rhs: G2Affine) -> G2Projective {
176        &self + &rhs
177    }
178}
179impl<'b> Sub<&'b G2Affine> for G2Projective {
180    type Output = G2Projective;
181    #[inline]
182    fn sub(self, rhs: &'b G2Affine) -> G2Projective {
183        &self - rhs
184    }
185}
186impl<'a> Sub<G2Affine> for &'a G2Projective {
187    type Output = G2Projective;
188    #[inline]
189    fn sub(self, rhs: G2Affine) -> G2Projective {
190        self - &rhs
191    }
192}
193impl Sub<G2Affine> for G2Projective {
194    type Output = G2Projective;
195    #[inline]
196    fn sub(self, rhs: G2Affine) -> G2Projective {
197        &self - &rhs
198    }
199}
200impl SubAssign<G2Affine> for G2Projective {
201    #[inline]
202    fn sub_assign(&mut self, rhs: G2Affine) {
203        *self = &*self - &rhs;
204    }
205}
206impl AddAssign<G2Affine> for G2Projective {
207    #[inline]
208    fn add_assign(&mut self, rhs: G2Affine) {
209        *self = &*self + &rhs;
210    }
211}
212impl<'b> SubAssign<&'b G2Affine> for G2Projective {
213    #[inline]
214    fn sub_assign(&mut self, rhs: &'b G2Affine) {
215        *self = &*self - rhs;
216    }
217}
218impl<'b> AddAssign<&'b G2Affine> for G2Projective {
219    #[inline]
220    fn add_assign(&mut self, rhs: &'b G2Affine) {
221        *self = &*self + rhs;
222    }
223}
224
225// Binop implementations for G2Affine + G2Projective
226impl<'b> Add<&'b G2Projective> for G2Affine {
227    type Output = G2Projective;
228    #[inline]
229    fn add(self, rhs: &'b G2Projective) -> G2Projective {
230        &self + rhs
231    }
232}
233impl<'a> Add<G2Projective> for &'a G2Affine {
234    type Output = G2Projective;
235    #[inline]
236    fn add(self, rhs: G2Projective) -> G2Projective {
237        self + &rhs
238    }
239}
240impl Add<G2Projective> for G2Affine {
241    type Output = G2Projective;
242    #[inline]
243    fn add(self, rhs: G2Projective) -> G2Projective {
244        &self + &rhs
245    }
246}
247impl<'b> Sub<&'b G2Projective> for G2Affine {
248    type Output = G2Projective;
249    #[inline]
250    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
251        &self - rhs
252    }
253}
254impl<'a> Sub<G2Projective> for &'a G2Affine {
255    type Output = G2Projective;
256    #[inline]
257    fn sub(self, rhs: G2Projective) -> G2Projective {
258        self - &rhs
259    }
260}
261impl Sub<G2Projective> for G2Affine {
262    type Output = G2Projective;
263    #[inline]
264    fn sub(self, rhs: G2Projective) -> G2Projective {
265        &self - &rhs
266    }
267}
268
269/// Curve constant B = 4(u+1)
270const B: Fp2 = Fp2 {
271    c0: Fp::from_raw_unchecked([
272        0xaa27_0000_000c_fff3,
273        0x53cc_0032_fc34_000a,
274        0x478f_e97a_6b0a_807f,
275        0xb1d3_7ebe_e6ba_24d7,
276        0x8ec9_733b_bf78_ab2f,
277        0x09d6_4551_3d83_de7e,
278    ]),
279    c1: Fp::from_raw_unchecked([
280        0xaa27_0000_000c_fff3,
281        0x53cc_0032_fc34_000a,
282        0x478f_e97a_6b0a_807f,
283        0xb1d3_7ebe_e6ba_24d7,
284        0x8ec9_733b_bf78_ab2f,
285        0x09d6_4551_3d83_de7e,
286    ]),
287};
288
289/// 3B for efficient doubling
290const B3: Fp2 = Fp2::add(&Fp2::add(&B, &B), &B);
291
292#[inline(always)]
293fn mul_by_3b(a: Fp2) -> Fp2 {
294    a * B3
295}
296
297impl G2Affine {
298    /// Point at infinity.
299    pub fn identity() -> G2Affine {
300        G2Affine {
301            x: Fp2::zero(),
302            y: Fp2::one(),
303            infinity: Choice::from(1u8),
304        }
305    }
306
307    /// Fixed generator.
308    pub fn generator() -> G2Affine {
309        G2Affine {
310            x: Fp2 {
311                c0: Fp::from_raw_unchecked([
312                    0xf5f2_8fa2_0294_0a10,
313                    0xb3f5_fb26_87b4_961a,
314                    0xa1a8_93b5_3e2a_e580,
315                    0x9894_999d_1a3c_aee9,
316                    0x6f67_b763_1863_366b,
317                    0x0581_9192_4350_bcd7,
318                ]),
319                c1: Fp::from_raw_unchecked([
320                    0xa5a9_c075_9e23_f606,
321                    0xaaa0_c59d_bccd_60c3,
322                    0x3bb1_7e18_e286_7806,
323                    0x1b1a_b6cc_8541_b367,
324                    0xc2b6_ed0e_f215_8547,
325                    0x1192_2a09_7360_edf3,
326                ]),
327            },
328            y: Fp2 {
329                c0: Fp::from_raw_unchecked([
330                    0x4c73_0af8_6049_4c4a,
331                    0x597c_fa1f_5e36_9c5a,
332                    0xe7e6_856c_aa0a_635a,
333                    0xbbef_b5e9_6e0d_495f,
334                    0x07d3_a975_f0ef_25a2,
335                    0x0083_fd8e_7e80_dae5,
336                ]),
337                c1: Fp::from_raw_unchecked([
338                    0xadc0_fc92_df64_b05d,
339                    0x18aa_270a_2b14_61dc,
340                    0x86ad_ac6a_3be4_eba0,
341                    0x7949_5c4e_c93d_a33a,
342                    0xe717_5850_a43c_caed,
343                    0x0b2b_c2a1_63de_1bf2,
344                ]),
345            },
346            infinity: Choice::from(0u8),
347        }
348    }
349
350    /// Compress to 96 bytes.
351    pub fn to_compressed(&self) -> [u8; 96] {
352        let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
353        let mut res = [0; 96];
354
355        res[0..48].copy_from_slice(&x.c1.to_bytes());
356        res[48..96].copy_from_slice(&x.c0.to_bytes());
357
358        res[0] |= 1u8 << 7;  // Compression flag
359        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);  // Infinity flag
360        res[0] |= u8::conditional_select(
361            &0u8,
362            &(1u8 << 5),
363            (!self.infinity) & self.y.lexicographically_largest(),  // Sort flag
364        );
365        res
366    }
367
368    /// Serialize to 192 bytes uncompressed.
369    pub fn to_uncompressed(&self) -> [u8; 192] {
370        let mut res = [0; 192];
371        let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity);
372        let y = Fp2::conditional_select(&self.y, &Fp2::zero(), self.infinity);
373
374        res[0..48].copy_from_slice(&x.c1.to_bytes());
375        res[48..96].copy_from_slice(&x.c0.to_bytes());
376        res[96..144].copy_from_slice(&y.c1.to_bytes());
377        res[144..192].copy_from_slice(&y.c0.to_bytes());
378
379        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
380        res
381    }
382
383    /// Deserialize from uncompressed bytes with validation.
384    pub fn from_uncompressed(bytes: &[u8; 192]) -> CtOption<Self> {
385        Self::from_uncompressed_unchecked(bytes)
386            .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
387    }
388
389    /// Deserialize from uncompressed bytes without validation.
390    pub fn from_uncompressed_unchecked(bytes: &[u8; 192]) -> CtOption<Self> {
391        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
392        let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
393        let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
394
395        let xc1 = {
396            let mut tmp = [0; 48];
397            tmp.copy_from_slice(&bytes[0..48]);
398            tmp[0] &= 0b0001_1111;
399            Fp::from_bytes(&tmp)
400        };
401        let xc0 = Fp::from_bytes(<&[u8; 48]>::try_from(&bytes[48..96]).unwrap());
402        let yc1 = Fp::from_bytes(<&[u8; 48]>::try_from(&bytes[96..144]).unwrap());
403        let yc0 = Fp::from_bytes(<&[u8; 48]>::try_from(&bytes[144..192]).unwrap());
404
405        xc1.and_then(|xc1| {
406            xc0.and_then(|xc0| {
407                yc1.and_then(|yc1| {
408                    yc0.and_then(|yc0| {
409                        let x = Fp2 {c0: xc0, c1: xc1};
410                        let y = Fp2 {c0: yc0, c1: yc1};
411
412                        let p = G2Affine::conditional_select(
413                            &G2Affine {
414                                x,
415                                y,
416                                infinity: infinity_flag_set,
417                            },
418                            &G2Affine::identity(),
419                            infinity_flag_set,
420                        );
421                        CtOption::new(
422                            p,
423                            ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero()))
424                                & (!compression_flag_set)
425                                & (!sort_flag_set),
426                        )
427                    })
428                })
429            })
430        })
431    }
432
433    /// Deserialize from compressed bytes with validation.
434    pub fn from_compressed(bytes: &[u8; 96]) -> CtOption<Self> {
435        Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_torsion_free()))
436    }
437
438    /// Deserialize from compressed bytes without validation.
439    pub fn from_compressed_unchecked(bytes: &[u8; 96]) -> CtOption<Self> {
440        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
441        let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
442        let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
443
444        let xc1 = {
445            let mut tmp = [0; 48];
446            tmp.copy_from_slice(&bytes[0..48]);
447            tmp[0] &= 0b0001_1111;
448            Fp::from_bytes(&tmp)
449        };
450        let xc0 = Fp::from_bytes(<&[u8; 48]>::try_from(&bytes[48..96]).unwrap());
451
452        xc1.and_then(|xc1| {
453            xc0.and_then(|xc0| {
454                let x = Fp2 {c0: xc0, c1: xc1};
455                CtOption::new(
456                    G2Affine::identity(),
457                    infinity_flag_set & compression_flag_set & (!sort_flag_set) & x.is_zero(),
458                )
459                .or_else(|| {
460                    ((x.square() * x) + B).sqrt().and_then(|y| {
461                        let y = Fp2::conditional_select(
462                            &y,
463                            &-y,
464                            y.lexicographically_largest() ^ sort_flag_set,
465                        );
466                        CtOption::new(
467                            G2Affine {
468                                x,
469                                y,
470                                infinity: infinity_flag_set,
471                            },
472                            (!infinity_flag_set) & compression_flag_set,
473                        )
474                    })
475                })
476            })
477        })
478    }
479
480    /// Check if point at infinity.
481    #[inline]
482    pub fn is_identity(&self) -> Choice {
483        self.infinity
484    }
485
486    /// Check if on curve y² = x³ + B.
487    pub fn is_on_curve(&self) -> Choice {
488        (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
489    }
490
491    /// Check subgroup membership using psi endomorphism.
492    pub fn is_torsion_free(&self) -> Choice {
493        // Algorithm from Section 4 of https://eprint.iacr.org/2021/1130
494        // Updated proof: https://eprint.iacr.org/2022/352
495        let p = G2Projective::from(*self);
496        p.psi().ct_eq(&p.mul_by_x())
497    }
498}
499
500/// G₂ projective point representation.
501#[derive(Copy, Clone, Debug)]
502pub struct G2Projective {
503    pub(crate) x: Fp2,
504    pub(crate) y: Fp2,
505    pub(crate) z: Fp2,
506}
507
508impl Default for G2Projective {
509    fn default() -> G2Projective {
510        G2Projective::identity()
511    }
512}
513
514#[cfg(feature = "zeroize")]
515impl zeroize::DefaultIsZeroes for G2Projective {}
516
517impl fmt::Display for G2Projective {
518    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
519        write!(f, "{:?}", self)
520    }
521}
522
523impl<'a> From<&'a G2Affine> for G2Projective {
524    fn from(p: &'a G2Affine) -> G2Projective {
525        G2Projective {
526            x: p.x,
527            y: p.y,
528            z: Fp2::conditional_select(&Fp2::one(), &Fp2::zero(), p.infinity),
529        }
530    }
531}
532
533impl From<G2Affine> for G2Projective {
534    fn from(p: G2Affine) -> G2Projective {
535        G2Projective::from(&p)
536    }
537}
538
539impl ConstantTimeEq for G2Projective {
540    fn ct_eq(&self, other: &Self) -> Choice {
541        let x1 = self.x * other.z;
542        let x2 = other.x * self.z;
543        let y1 = self.y * other.z;
544        let y2 = other.y * self.z;
545        let self_is_zero = self.z.is_zero();
546        let other_is_zero = other.z.is_zero();
547
548        (self_is_zero & other_is_zero)
549            | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
550    }
551}
552
553impl ConditionallySelectable for G2Projective {
554    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
555        G2Projective {
556            x: Fp2::conditional_select(&a.x, &b.x, choice),
557            y: Fp2::conditional_select(&a.y, &b.y, choice),
558            z: Fp2::conditional_select(&a.z, &b.z, choice),
559        }
560    }
561}
562
563impl Eq for G2Projective {}
564impl PartialEq for G2Projective {
565    #[inline]
566    fn eq(&self, other: &Self) -> bool {
567        bool::from(self.ct_eq(other))
568    }
569}
570
571impl<'a> Neg for &'a G2Projective {
572    type Output = G2Projective;
573
574    #[inline]
575    fn neg(self) -> G2Projective {
576        G2Projective {
577            x: self.x,
578            y: -self.y,
579            z: self.z,
580        }
581    }
582}
583
584impl Neg for G2Projective {
585    type Output = G2Projective;
586
587    #[inline]
588    fn neg(self) -> G2Projective {
589        -&self
590    }
591}
592
593impl<'a, 'b> Add<&'b G2Projective> for &'a G2Projective {
594    type Output = G2Projective;
595
596    #[inline]
597    fn add(self, rhs: &'b G2Projective) -> G2Projective {
598        self.add(rhs)
599    }
600}
601
602impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Projective {
603    type Output = G2Projective;
604
605    #[inline]
606    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
607        self + &(-rhs)
608    }
609}
610
611impl<'a, 'b> Mul<&'b Scalar> for &'a G2Projective {
612    type Output = G2Projective;
613
614    fn mul(self, other: &'b Scalar) -> Self::Output {
615        self.multiply(&other.to_bytes())
616    }
617}
618
619impl<'a, 'b> Mul<&'b G2Projective> for &'a Scalar {
620    type Output = G2Projective;
621
622    #[inline]
623    fn mul(self, rhs: &'b G2Projective) -> Self::Output {
624        rhs * self
625    }
626}
627
628impl<'a, 'b> Mul<&'b Scalar> for &'a G2Affine {
629    type Output = G2Projective;
630
631    fn mul(self, other: &'b Scalar) -> Self::Output {
632        G2Projective::from(self).multiply(&other.to_bytes())
633    }
634}
635
636impl<'a, 'b> Mul<&'b G2Affine> for &'a Scalar {
637    type Output = G2Projective;
638
639    #[inline]
640    fn mul(self, rhs: &'b G2Affine) -> Self::Output {
641        rhs * self
642    }
643}
644
645// Binop implementations for G2Projective
646impl<'b> Add<&'b G2Projective> for G2Projective {
647    type Output = G2Projective;
648    #[inline]
649    fn add(self, rhs: &'b G2Projective) -> G2Projective {
650        &self + rhs
651    }
652}
653impl<'a> Add<G2Projective> for &'a G2Projective {
654    type Output = G2Projective;
655    #[inline]
656    fn add(self, rhs: G2Projective) -> G2Projective {
657        self + &rhs
658    }
659}
660impl Add<G2Projective> for G2Projective {
661    type Output = G2Projective;
662    #[inline]
663    fn add(self, rhs: G2Projective) -> G2Projective {
664        &self + &rhs
665    }
666}
667impl<'b> Sub<&'b G2Projective> for G2Projective {
668    type Output = G2Projective;
669    #[inline]
670    fn sub(self, rhs: &'b G2Projective) -> G2Projective {
671        &self - rhs
672    }
673}
674impl<'a> Sub<G2Projective> for &'a G2Projective {
675    type Output = G2Projective;
676    #[inline]
677    fn sub(self, rhs: G2Projective) -> G2Projective {
678        self - &rhs
679    }
680}
681impl Sub<G2Projective> for G2Projective {
682    type Output = G2Projective;
683    #[inline]
684    fn sub(self, rhs: G2Projective) -> G2Projective {
685        &self - &rhs
686    }
687}
688impl SubAssign<G2Projective> for G2Projective {
689    #[inline]
690    fn sub_assign(&mut self, rhs: G2Projective) {
691        *self = &*self - &rhs;
692    }
693}
694impl AddAssign<G2Projective> for G2Projective {
695    #[inline]
696    fn add_assign(&mut self, rhs: G2Projective) {
697        *self = &*self + &rhs;
698    }
699}
700impl<'b> SubAssign<&'b G2Projective> for G2Projective {
701    #[inline]
702    fn sub_assign(&mut self, rhs: &'b G2Projective) {
703        *self = &*self - rhs;
704    }
705}
706impl<'b> AddAssign<&'b G2Projective> for G2Projective {
707    #[inline]
708    fn add_assign(&mut self, rhs: &'b G2Projective) {
709        *self = &*self + rhs;
710    }
711}
712
713// Scalar multiplication implementations
714impl<'b> Mul<&'b Scalar> for G2Projective {
715    type Output = G2Projective;
716    #[inline]
717    fn mul(self, rhs: &'b Scalar) -> G2Projective {
718        &self * rhs
719    }
720}
721impl<'a> Mul<Scalar> for &'a G2Projective {
722    type Output = G2Projective;
723    #[inline]
724    fn mul(self, rhs: Scalar) -> G2Projective {
725        self * &rhs
726    }
727}
728impl Mul<Scalar> for G2Projective {
729    type Output = G2Projective;
730    #[inline]
731    fn mul(self, rhs: Scalar) -> G2Projective {
732        &self * &rhs
733    }
734}
735impl MulAssign<Scalar> for G2Projective {
736    #[inline]
737    fn mul_assign(&mut self, rhs: Scalar) {
738        *self = &*self * &rhs;
739    }
740}
741impl<'b> MulAssign<&'b Scalar> for G2Projective {
742    #[inline]
743    fn mul_assign(&mut self, rhs: &'b Scalar) {
744        *self = &*self * rhs;
745    }
746}
747
748// Mixed scalar multiplication for G2Affine
749impl<'b> Mul<&'b Scalar> for G2Affine {
750    type Output = G2Projective;
751    #[inline]
752    fn mul(self, rhs: &'b Scalar) -> G2Projective {
753        &self * rhs
754    }
755}
756impl<'a> Mul<Scalar> for &'a G2Affine {
757    type Output = G2Projective;
758    #[inline]
759    fn mul(self, rhs: Scalar) -> G2Projective {
760        self * &rhs
761    }
762}
763impl Mul<Scalar> for G2Affine {
764    type Output = G2Projective;
765    #[inline]
766    fn mul(self, rhs: Scalar) -> G2Projective {
767        &self * &rhs
768    }
769}
770
771// Scalar * G2Affine
772impl<'b> Mul<&'b G2Affine> for Scalar {
773    type Output = G2Projective;
774    #[inline]
775    fn mul(self, rhs: &'b G2Affine) -> G2Projective {
776        &self * rhs
777    }
778}
779impl<'a> Mul<G2Affine> for &'a Scalar {
780    type Output = G2Projective;
781    #[inline]
782    fn mul(self, rhs: G2Affine) -> G2Projective {
783        self * &rhs
784    }
785}
786impl Mul<G2Affine> for Scalar {
787    type Output = G2Projective;
788    #[inline]
789    fn mul(self, rhs: G2Affine) -> G2Projective {
790        &self * &rhs
791    }
792}
793
794// Scalar * G2Projective
795impl<'b> Mul<&'b G2Projective> for Scalar {
796    type Output = G2Projective;
797    #[inline]
798    fn mul(self, rhs: &'b G2Projective) -> G2Projective {
799        &self * rhs
800    }
801}
802impl<'a> Mul<G2Projective> for &'a Scalar {
803    type Output = G2Projective;
804    #[inline]
805    fn mul(self, rhs: G2Projective) -> G2Projective {
806        self * &rhs
807    }
808}
809impl Mul<G2Projective> for Scalar {
810    type Output = G2Projective;
811    #[inline]
812    fn mul(self, rhs: G2Projective) -> G2Projective {
813        &self * &rhs
814    }
815}
816
817impl G2Projective {
818    /// Point at infinity.
819    pub fn identity() -> G2Projective {
820        G2Projective {
821            x: Fp2::zero(),
822            y: Fp2::one(),
823            z: Fp2::zero(),
824        }
825    }
826
827    /// Fixed generator.
828    pub fn generator() -> G2Projective {
829        G2Projective {
830            x: G2Affine::generator().x,
831            y: G2Affine::generator().y,
832            z: Fp2::one(),
833        }
834    }
835
836    /// Random non-identity element.
837    pub fn random(mut rng: impl RngCore) -> Self {
838        loop {
839            let x = Fp2::random(&mut rng);
840            let flip_sign = rng.next_u32() % 2 != 0;
841
842            let p = ((x.square() * x) + B).sqrt().map(|y| G2Affine {
843                x,
844                y: if flip_sign { -y } else { y },
845                infinity: 0.into(),
846            });
847
848            if p.is_some().into() {
849                let p_proj = G2Projective::from(p.unwrap());
850                let p_cleared = p_proj.clear_cofactor();
851                if !bool::from(p_cleared.is_identity()) {
852                    return p_cleared;
853                }
854            }
855        }
856    }
857
858    /// Point doubling.
859    pub fn double(&self) -> G2Projective {
860        let t0 = self.y.square();
861        let z3 = t0 + t0;
862        let z3 = z3 + z3;
863        let z3 = z3 + z3;
864        let t1 = self.y * self.z;
865        let t2 = self.z.square();
866        let t2 = mul_by_3b(t2);
867        let x3 = t2 * z3;
868        let y3 = t0 + t2;
869        let z3 = t1 * z3;
870        let t1 = t2 + t2;
871        let t2 = t1 + t2;
872        let t0 = t0 - t2;
873        let y3 = t0 * y3;
874        let y3 = x3 + y3;
875        let t1 = self.x * self.y;
876        let x3 = t0 * t1;
877        let x3 = x3 + x3;
878
879        let tmp = G2Projective { x: x3, y: y3, z: z3 };
880        G2Projective::conditional_select(&tmp, &G2Projective::identity(), self.is_identity())
881    }
882
883    /// Point addition.
884    pub fn add(&self, rhs: &G2Projective) -> G2Projective {
885        let t0 = self.x * rhs.x;
886        let t1 = self.y * rhs.y;
887        let t2 = self.z * rhs.z;
888        let t3 = self.x + self.y;
889        let t4 = rhs.x + rhs.y;
890        let t3 = t3 * t4;
891        let t4 = t0 + t1;
892        let t3 = t3 - t4;
893        let t4 = self.y + self.z;
894        let x3 = rhs.y + rhs.z;
895        let t4 = t4 * x3;
896        let x3 = t1 + t2;
897        let t4 = t4 - x3;
898        let x3 = self.x + self.z;
899        let y3 = rhs.x + rhs.z;
900        let x3 = x3 * y3;
901        let y3 = t0 + t2;
902        let y3 = x3 - y3;
903        let x3 = t0 + t0;
904        let t0 = x3 + t0;
905        let t2 = mul_by_3b(t2);
906        let z3 = t1 + t2;
907        let t1 = t1 - t2;
908        let y3 = mul_by_3b(y3);
909        let x3 = t4 * y3;
910        let t2 = t3 * t1;
911        let x3 = t2 - x3;
912        let y3 = y3 * t0;
913        let t1 = t1 * z3;
914        let y3 = t1 + y3;
915        let t0 = t0 * t3;
916        let z3 = z3 * t4;
917        let z3 = z3 + t0;
918
919        G2Projective { x: x3, y: y3, z: z3 }
920    }
921
922    /// Mixed addition with affine point.
923    pub fn add_mixed(&self, rhs: &G2Affine) -> G2Projective {
924        let t0 = self.x * rhs.x;
925        let t1 = self.y * rhs.y;
926        let t3 = rhs.x + rhs.y;
927        let t4 = self.x + self.y;
928        let t3 = t3 * t4;
929        let t4 = t0 + t1;
930        let t3 = t3 - t4;
931        let t4 = rhs.y * self.z;
932        let t4 = t4 + self.y;
933        let y3 = rhs.x * self.z;
934        let y3 = y3 + self.x;
935        let x3 = t0 + t0;
936        let t0 = x3 + t0;
937        let t2 = mul_by_3b(self.z);
938        let z3 = t1 + t2;
939        let t1 = t1 - t2;
940        let y3 = mul_by_3b(y3);
941        let x3 = t4 * y3;
942        let t2 = t3 * t1;
943        let x3 = t2 - x3;
944        let y3 = y3 * t0;
945        let t1 = t1 * z3;
946        let y3 = t1 + y3;
947        let t0 = t0 * t3;
948        let z3 = z3 * t4;
949        let z3 = z3 + t0;
950
951        let tmp = G2Projective { x: x3, y: y3, z: z3 };
952        G2Projective::conditional_select(&tmp, self, rhs.is_identity())
953    }
954
955    /// Scalar multiplication.
956    fn multiply(&self, by: &[u8; 32]) -> G2Projective {
957        let mut acc = G2Projective::identity();
958        for &byte in by.iter().rev() {
959            for i in (0..8).rev() {
960                acc = acc.double();
961                let bit = Choice::from((byte >> i) & 1u8);
962                acc = G2Projective::conditional_select(&acc, &(acc + self), bit);
963            }
964        }
965        acc
966    }
967
968    /// Clear cofactor.
969    pub fn clear_cofactor(&self) -> G2Projective {
970        let t1 = self.mul_by_x();
971        let t2 = self.psi();
972        self.double().psi2() + (t1 + t2).mul_by_x() - t1 - t2 - *self
973    }
974
975    /// Multiply by curve parameter x.
976    fn mul_by_x(&self) -> G2Projective {
977        let mut xself = G2Projective::identity();
978        let mut x = super::BLS_X >> 1;
979        let mut acc = *self;
980        while x != 0 {
981            acc = acc.double();
982            if x % 2 == 1 {
983                xself += acc;
984            }
985            x >>= 1;
986        }
987        if super::BLS_X_IS_NEGATIVE {
988            xself = -xself;
989        }
990        xself
991    }
992
993    /// Apply psi endomorphism.
994    fn psi(&self) -> G2Projective {
995        // 1 / ((u+1) ^ ((q-1)/3))
996        let psi_coeff_x = Fp2 {
997            c0: Fp::zero(),
998            c1: Fp::from_raw_unchecked([
999                0x890d_c9e4_8675_45c3,
1000                0x2af3_2253_3285_a5d5,
1001                0x5088_0866_309b_7e2c,
1002                0xa20d_1b8c_7e88_1024,
1003                0x14e4_f04f_e2db_9068,
1004                0x14e5_6d3f_1564_853a,
1005            ]),
1006        };
1007        // 1 / ((u+1) ^ (p-1)/2)
1008        let psi_coeff_y = Fp2 {
1009            c0: Fp::from_raw_unchecked([
1010                0x3e2f_585d_a55c_9ad1,
1011                0x4294_213d_86c1_8183,
1012                0x3828_44c8_8b62_3732,
1013                0x92ad_2afd_1910_3e18,
1014                0x1d79_4e4f_ac7c_f0b9,
1015                0x0bd5_92fc_7d82_5ec8,
1016            ]),
1017            c1: Fp::from_raw_unchecked([
1018                0x7bcf_a7a2_5aa3_0fda,
1019                0xdc17_dec1_2a92_7e7c,
1020                0x2f08_8dd8_6b4e_bef1,
1021                0xd1ca_2087_da74_d4a7,
1022                0x2da2_5966_96ce_bc1d,
1023                0x0e2b_7eed_bbfd_87d2,
1024            ]),
1025        };
1026
1027        G2Projective {
1028            x: self.x.frobenius_map() * psi_coeff_x,
1029            y: self.y.frobenius_map() * psi_coeff_y,
1030            z: self.z.frobenius_map(),
1031        }
1032    }
1033
1034    /// Apply psi^2 endomorphism.
1035    fn psi2(&self) -> G2Projective {
1036        // 1 / 2 ^ ((q-1)/3)
1037        let psi2_coeff_x = Fp2 {
1038            c0: Fp::from_raw_unchecked([
1039                0xcd03_c9e4_8671_f071,
1040                0x5dab_2246_1fcd_a5d2,
1041                0x5870_42af_d385_1b95,
1042                0x8eb6_0ebe_01ba_cb9e,
1043                0x03f9_7d6e_83d0_50d2,
1044                0x18f0_2065_5463_8741,
1045            ]),
1046            c1: Fp::zero(),
1047        };
1048
1049        G2Projective {
1050            x: self.x * psi2_coeff_x,
1051            y: self.y.neg(),
1052            z: self.z,
1053        }
1054    }
1055
1056    /// Batch conversion to affine.
1057    pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) {
1058        assert_eq!(p.len(), q.len());
1059        let mut acc = Fp2::one();
1060        for (p, q) in p.iter().zip(q.iter_mut()) {
1061            q.x = acc;
1062            acc = Fp2::conditional_select(&(acc * p.z), &acc, p.is_identity());
1063        }
1064        acc = acc.invert().unwrap();
1065        for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
1066            let skip = p.is_identity();
1067            let tmp = q.x * acc;
1068            acc = Fp2::conditional_select(&(acc * p.z), &acc, skip);
1069            q.x = p.x * tmp;
1070            q.y = p.y * tmp;
1071            q.infinity = Choice::from(0u8);
1072            *q = G2Affine::conditional_select(q, &G2Affine::identity(), skip);
1073        }
1074    }
1075
1076    /// Check if point at infinity.
1077    #[inline]
1078    pub fn is_identity(&self) -> Choice {
1079        self.z.is_zero()
1080    }
1081
1082    /// Check if on curve y² = x³ + B.
1083    pub fn is_on_curve(&self) -> Choice {
1084        (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
1085            | self.z.is_zero()
1086    }
1087
1088    /// Deserialize from compressed bytes.
1089    pub fn from_bytes(bytes: &[u8; 96]) -> CtOption<Self> {
1090        G2Affine::from_compressed(bytes).map(G2Projective::from)
1091    }
1092
1093    /// Deserialize without validation.
1094    pub fn from_bytes_unchecked(bytes: &[u8; 96]) -> CtOption<Self> {
1095        G2Affine::from_compressed_unchecked(bytes).map(G2Projective::from)
1096    }
1097
1098    /// Serialize to compressed bytes.
1099    pub fn to_bytes(&self) -> [u8; 96] {
1100        G2Affine::from(self).to_compressed()
1101    }
1102}