dcrypt_algorithms/ec/bls12_381/
g2.rs

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