Skip to main content

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