Skip to main content

dcrypt_algorithms/ec/bls12_381/
g2.rs

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