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