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::Vec;
13#[cfg(feature = "alloc")]
14use alloc::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 { x, y, infinity: infinity_flag_set },
400                    &G1Affine::identity(),
401                    infinity_flag_set,
402                );
403                CtOption::new(
404                    p,
405                    ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero())) &
406                    (!compression_flag_set) &
407                    (!sort_flag_set),
408                )
409            })
410        })
411    }
412
413    /// Deserialize from compressed bytes with dcrypt error handling
414    pub fn from_compressed(bytes: &[u8; 48]) -> Result<Self> {
415        Self::from_compressed_unchecked(bytes)
416            .into_option()  // Convert CtOption to Option
417            .ok_or_else(|| Error::Parameter {
418                name: "compressed_bytes".into(),
419                reason: "invalid G1 point encoding".into(),
420            })
421            .and_then(|p| {
422                if !bool::from(p.is_torsion_free()) {
423                    Err(Error::param("point", "not in correct subgroup"))
424                } else {
425                    Ok(p)
426                }
427            })
428    }
429
430    /// Internal implementation keeping CtOption for constant-time operations
431    pub(crate) fn from_compressed_unchecked(bytes: &[u8; 48]) -> CtOption<Self> {
432        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
433        let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
434        let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
435        let x = {
436            let mut tmp = *bytes;
437            tmp[0] &= 0b0001_1111;
438            Fp::from_bytes(&tmp)
439        };
440
441        x.and_then(|x| {
442            CtOption::new(
443                G1Affine::identity(),
444                infinity_flag_set & compression_flag_set & (!sort_flag_set) & x.is_zero(),
445            )
446            .or_else(|| {
447                ((x.square() * x) + B).sqrt().and_then(|y| {
448                    let y = Fp::conditional_select(
449                        &y,
450                        &-y,
451                        y.lexicographically_largest() ^ sort_flag_set,
452                    );
453                    CtOption::new(
454                        G1Affine { x, y, infinity: infinity_flag_set },
455                        (!infinity_flag_set) & compression_flag_set,
456                    )
457                })
458            })
459        })
460    }
461}
462
463/// G₁ projective point representation.
464#[derive(Copy, Clone, Debug)]
465pub struct G1Projective {
466    pub(crate) x: Fp,
467    pub(crate) y: Fp,
468    pub(crate) z: Fp,
469}
470
471impl Default for G1Projective {
472    fn default() -> G1Projective {
473        G1Projective::identity()
474    }
475}
476
477#[cfg(feature = "zeroize")]
478impl zeroize::DefaultIsZeroes for G1Projective {}
479
480impl fmt::Display for G1Projective {
481    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
482        write!(f, "{:?}", self)
483    }
484}
485
486impl<'a> From<&'a G1Affine> for G1Projective {
487    fn from(p: &'a G1Affine) -> G1Projective {
488        G1Projective {
489            x: p.x,
490            y: p.y,
491            z: Fp::conditional_select(&Fp::one(), &Fp::zero(), p.infinity),
492        }
493    }
494}
495
496impl From<G1Affine> for G1Projective {
497    fn from(p: G1Affine) -> G1Projective {
498        G1Projective::from(&p)
499    }
500}
501
502impl ConstantTimeEq for G1Projective {
503    fn ct_eq(&self, other: &Self) -> Choice {
504        let x1 = self.x * other.z;
505        let x2 = other.x * self.z;
506        let y1 = self.y * other.z;
507        let y2 = other.y * self.z;
508        let self_is_zero = self.z.is_zero();
509        let other_is_zero = other.z.is_zero();
510
511        (self_is_zero & other_is_zero) | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
512    }
513}
514
515impl ConditionallySelectable for G1Projective {
516    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
517        G1Projective {
518            x: Fp::conditional_select(&a.x, &b.x, choice),
519            y: Fp::conditional_select(&a.y, &b.y, choice),
520            z: Fp::conditional_select(&a.z, &b.z, choice),
521        }
522    }
523}
524
525impl Eq for G1Projective {}
526impl PartialEq for G1Projective {
527    #[inline]
528    fn eq(&self, other: &Self) -> bool {
529        bool::from(self.ct_eq(other))
530    }
531}
532
533impl<'a> Neg for &'a G1Projective {
534    type Output = G1Projective;
535
536    #[inline]
537    fn neg(self) -> G1Projective {
538        G1Projective {
539            x: self.x,
540            y: -self.y,
541            z: self.z,
542        }
543    }
544}
545
546impl Neg for G1Projective {
547    type Output = G1Projective;
548
549    #[inline]
550    fn neg(self) -> G1Projective {
551        -&self
552    }
553}
554
555impl<'a, 'b> Add<&'b G1Projective> for &'a G1Projective {
556    type Output = G1Projective;
557
558    #[inline]
559    fn add(self, rhs: &'b G1Projective) -> G1Projective {
560        self.add(rhs)
561    }
562}
563
564impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Projective {
565    type Output = G1Projective;
566
567    #[inline]
568    fn sub(self, rhs: &'b G1Projective) -> G1Projective {
569        self + &(-rhs)
570    }
571}
572
573impl<'a, 'b> Mul<&'b Scalar> for &'a G1Projective {
574    type Output = G1Projective;
575
576    fn mul(self, other: &'b Scalar) -> Self::Output {
577        self.multiply(&other.to_bytes())
578    }
579}
580
581impl<'a, 'b> Mul<&'b G1Projective> for &'a Scalar {
582    type Output = G1Projective;
583
584    #[inline]
585    fn mul(self, rhs: &'b G1Projective) -> Self::Output {
586        rhs * self
587    }
588}
589
590impl<'a, 'b> Mul<&'b Scalar> for &'a G1Affine {
591    type Output = G1Projective;
592
593    fn mul(self, other: &'b Scalar) -> Self::Output {
594        G1Projective::from(self).multiply(&other.to_bytes())
595    }
596}
597
598impl<'a, 'b> Mul<&'b G1Affine> for &'a Scalar {
599    type Output = G1Projective;
600
601    #[inline]
602    fn mul(self, rhs: &'b G1Affine) -> Self::Output {
603        rhs * self
604    }
605}
606
607// Binop implementations for G1Projective
608impl<'b> Add<&'b G1Projective> for G1Projective {
609    type Output = G1Projective;
610    #[inline]
611    fn add(self, rhs: &'b G1Projective) -> G1Projective {
612        &self + rhs
613    }
614}
615impl<'a> Add<G1Projective> for &'a G1Projective {
616    type Output = G1Projective;
617    #[inline]
618    fn add(self, rhs: G1Projective) -> G1Projective {
619        self + &rhs
620    }
621}
622impl Add<G1Projective> for G1Projective {
623    type Output = G1Projective;
624    #[inline]
625    fn add(self, rhs: G1Projective) -> G1Projective {
626        &self + &rhs
627    }
628}
629impl<'b> Sub<&'b G1Projective> for G1Projective {
630    type Output = G1Projective;
631    #[inline]
632    fn sub(self, rhs: &'b G1Projective) -> G1Projective {
633        &self - rhs
634    }
635}
636impl<'a> Sub<G1Projective> for &'a G1Projective {
637    type Output = G1Projective;
638    #[inline]
639    fn sub(self, rhs: G1Projective) -> G1Projective {
640        self - &rhs
641    }
642}
643impl Sub<G1Projective> for G1Projective {
644    type Output = G1Projective;
645    #[inline]
646    fn sub(self, rhs: G1Projective) -> G1Projective {
647        &self - &rhs
648    }
649}
650impl SubAssign<G1Projective> for G1Projective {
651    #[inline]
652    fn sub_assign(&mut self, rhs: G1Projective) {
653        *self = &*self - &rhs;
654    }
655}
656impl AddAssign<G1Projective> for G1Projective {
657    #[inline]
658    fn add_assign(&mut self, rhs: G1Projective) {
659        *self = &*self + &rhs;
660    }
661}
662impl<'b> SubAssign<&'b G1Projective> for G1Projective {
663    #[inline]
664    fn sub_assign(&mut self, rhs: &'b G1Projective) {
665        *self = &*self - rhs;
666    }
667}
668impl<'b> AddAssign<&'b G1Projective> for G1Projective {
669    #[inline]
670    fn add_assign(&mut self, rhs: &'b G1Projective) {
671        *self = &*self + rhs;
672    }
673}
674
675// Scalar multiplication binops for G1Projective
676impl<'b> Mul<&'b Scalar> for G1Projective {
677    type Output = G1Projective;
678    #[inline]
679    fn mul(self, rhs: &'b Scalar) -> G1Projective {
680        &self * rhs
681    }
682}
683impl<'a> Mul<Scalar> for &'a G1Projective {
684    type Output = G1Projective;
685    #[inline]
686    fn mul(self, rhs: Scalar) -> G1Projective {
687        self * &rhs
688    }
689}
690impl Mul<Scalar> for G1Projective {
691    type Output = G1Projective;
692    #[inline]
693    fn mul(self, rhs: Scalar) -> G1Projective {
694        &self * &rhs
695    }
696}
697impl MulAssign<Scalar> for G1Projective {
698    #[inline]
699    fn mul_assign(&mut self, rhs: Scalar) {
700        *self = &*self * &rhs;
701    }
702}
703impl<'b> MulAssign<&'b Scalar> for G1Projective {
704    #[inline]
705    fn mul_assign(&mut self, rhs: &'b Scalar) {
706        *self = &*self * rhs;
707    }
708}
709
710// Scalar multiplication binops for G1Affine
711impl<'b> Mul<&'b Scalar> for G1Affine {
712    type Output = G1Projective;
713    #[inline]
714    fn mul(self, rhs: &'b Scalar) -> G1Projective {
715        &self * rhs
716    }
717}
718impl<'a> Mul<Scalar> for &'a G1Affine {
719    type Output = G1Projective;
720    #[inline]
721    fn mul(self, rhs: Scalar) -> G1Projective {
722        self * &rhs
723    }
724}
725impl Mul<Scalar> for G1Affine {
726    type Output = G1Projective;
727    #[inline]
728    fn mul(self, rhs: Scalar) -> G1Projective {
729        &self * &rhs
730    }
731}
732
733// Scalar * G1Affine binops
734impl<'b> Mul<&'b G1Affine> for Scalar {
735    type Output = G1Projective;
736    #[inline]
737    fn mul(self, rhs: &'b G1Affine) -> G1Projective {
738        &self * rhs
739    }
740}
741impl<'a> Mul<G1Affine> for &'a Scalar {
742    type Output = G1Projective;
743    #[inline]
744    fn mul(self, rhs: G1Affine) -> G1Projective {
745        self * &rhs
746    }
747}
748impl Mul<G1Affine> for Scalar {
749    type Output = G1Projective;
750    #[inline]
751    fn mul(self, rhs: G1Affine) -> G1Projective {
752        &self * &rhs
753    }
754}
755
756// Scalar * G1Projective binops
757impl<'b> Mul<&'b G1Projective> for Scalar {
758    type Output = G1Projective;
759    #[inline]
760    fn mul(self, rhs: &'b G1Projective) -> G1Projective {
761        &self * rhs
762    }
763}
764impl<'a> Mul<G1Projective> for &'a Scalar {
765    type Output = G1Projective;
766    #[inline]
767    fn mul(self, rhs: G1Projective) -> G1Projective {
768        self * &rhs
769    }
770}
771impl Mul<G1Projective> for Scalar {
772    type Output = G1Projective;
773    #[inline]
774    fn mul(self, rhs: G1Projective) -> G1Projective {
775        &self * &rhs
776    }
777}
778
779#[inline(always)]
780fn mul_by_3b(a: Fp) -> Fp {
781    let a = a + a; // 2
782    let a = a + a; // 4
783    a + a + a // 12
784}
785
786impl G1Projective {
787    /// Point at infinity.
788    pub fn identity() -> G1Projective {
789        G1Projective {
790            x: Fp::zero(),
791            y: Fp::one(),
792            z: Fp::zero(),
793        }
794    }
795
796    /// Fixed generator.
797    pub fn generator() -> G1Projective {
798        G1Projective {
799            x: G1Affine::generator().x,
800            y: G1Affine::generator().y,
801            z: Fp::one(),
802        }
803    }
804
805    /// Random point generation.
806    pub fn random(mut rng: impl RngCore) -> Self {
807        loop {
808            let x = Fp::random(&mut rng);
809            let flip_sign = rng.next_u32() % 2 != 0;
810
811            let p = ((x.square() * x) + B).sqrt().map(|y| G1Affine {
812                x,
813                y: if flip_sign { -y } else { y },
814                infinity: 0.into(),
815            });
816
817            if p.is_some().into() {
818                let p_proj = G1Projective::from(p.unwrap());
819                let p_cleared = p_proj.clear_cofactor();
820                if !bool::from(p_cleared.is_identity()) {
821                    return p_cleared;
822                }
823            }
824        }
825    }
826    
827    // ============================================================================
828    // START: New MSM Implementation
829    // ============================================================================
830
831    /// Multi-scalar multiplication using a variable-time Pippenger's algorithm.
832    ///
833    /// This method is faster for non-sensitive operations where timing side-channels
834    /// are not a concern, as it contains input-dependent branches.
835    ///
836    /// # Panics
837    /// Panics if `points.len() != scalars.len()`.
838    #[cfg(feature = "alloc")]
839    pub fn msm_vartime(
840        points: &[G1Affine],
841        scalars: &[Scalar],
842    ) -> Result<Self> {
843        if points.len() != scalars.len() {
844            return Err(Error::Parameter {
845                name: "points/scalars".into(),
846                reason: "Input slices must have the same length".into(),
847            });
848        }
849        Ok(Self::pippenger(points, scalars, true))
850    }
851
852    /// Multi-scalar multiplication using a constant-time Pippenger's algorithm.
853    ///
854    /// This method is suitable for cryptographic operations where resistance to
855    /// timing side-channels is required.
856    ///
857    /// # Panics
858    /// Panics if `points.len() != scalars.len()`.
859    #[cfg(feature = "alloc")]
860    pub fn msm(
861        points: &[G1Affine],
862        scalars: &[Scalar],
863    ) -> Result<Self> {
864        if points.len() != scalars.len() {
865            return Err(Error::Parameter {
866                name: "points/scalars".into(),
867                reason: "Input slices must have the same length".into(),
868            });
869        }
870        Ok(Self::pippenger(points, scalars, false))
871    }
872    
873    /// Internal Pippenger's algorithm implementation.
874    #[cfg(feature = "alloc")]
875    fn pippenger(points: &[G1Affine], scalars: &[Scalar], is_vartime: bool) -> Self {
876        if points.is_empty() {
877            return Self::identity();
878        }
879
880        let num_entries = points.len();
881        let scalar_bits = 255; // BLS12-381 scalar size
882
883        // 1. Choose window size `c`.
884        // If constant-time, we limit window size to avoid excessive bucket scanning.
885        let c = if is_vartime {
886             if num_entries < 32 {
887                3
888            } else {
889                // Integer log2 equivalent: floor(log2(n))
890                // Works in no_std without libm
891                let log2 = (usize::BITS - num_entries.leading_zeros() - 1) as usize;
892                log2 + 2
893            }
894        } else {
895            // Fixed window size for constant time to ensure predictable performance.
896            // c=4 means 16 buckets.
897            4
898        };
899
900        let num_windows = (scalar_bits + c - 1) / c;
901        let num_buckets = 1 << c;
902        let mut global_acc = Self::identity();
903
904        // 2. Iterate through each window
905        for w in (0..num_windows).rev() {
906            let mut window_acc = Self::identity();
907            let mut buckets = vec![Self::identity(); num_buckets];
908
909            // 3. Populate buckets for the current window
910            for i in 0..num_entries {
911                let scalar_bytes = scalars[i].to_bytes();
912                
913                // Extract c-bit window from scalar
914                let mut k = 0;
915                for bit_idx in 0..c {
916                    let total_bit_idx = w * c + bit_idx;
917                    if total_bit_idx < scalar_bits {
918                        let byte_idx = total_bit_idx / 8;
919                        let inner_bit_idx = total_bit_idx % 8;
920                        let byte = scalar_bytes[byte_idx];
921                        let bit = (byte >> inner_bit_idx) & 1;
922                        k |= (bit as usize) << bit_idx;
923                    }
924                }
925                
926                if is_vartime {
927                    if k > 0 {
928                        buckets[k - 1] = buckets[k - 1].add_mixed(&points[i]);
929                    }
930                } else {
931                    // Constant-time bucket accumulation
932                    // Iterate all buckets, conditionally add point if bucket index matches k-1.
933                    // If k=0 (scalar chunk is 0), we don't add to any bucket (add identity).
934                    
935                    for b in 0..num_buckets {
936                        let bucket_idx = b + 1;
937                        // Check if k == bucket_idx in constant time using subtle
938                        let choice = k.ct_eq(&bucket_idx);
939                        
940                        let res = buckets[b].add_mixed(&points[i]);
941                        buckets[b] = G1Projective::conditional_select(&buckets[b], &res, choice);
942                    }
943                }
944            }
945
946            // 4. Sum up buckets to get the window result
947            let mut running_sum = Self::identity();
948            for i in (0..num_buckets).rev() {
949                running_sum = running_sum.add(&buckets[i]);
950                window_acc = window_acc.add(&running_sum);
951            }
952
953            // 5. Add to global accumulator
954            global_acc = global_acc.add(&window_acc);
955
956            // Scale accumulator for next window if not the last one
957            if w > 0 {
958                for _ in 0..c {
959                    global_acc = global_acc.double();
960                }
961            }
962        }
963
964        global_acc
965    }
966
967    // ============================================================================
968    // END: New MSM Implementation
969    // ============================================================================
970
971
972    /// Point doubling.
973    pub fn double(&self) -> G1Projective {
974        // Algorithm 9 from https://eprint.iacr.org/2015/1060.pdf
975        let t0 = self.y.square();
976        let z3 = t0 + t0;
977        let z3 = z3 + z3;
978        let z3 = z3 + z3;
979        let t1 = self.y * self.z;
980        let t2 = self.z.square();
981        let t2 = mul_by_3b(t2);
982        let x3 = t2 * z3;
983        let y3 = t0 + t2;
984        let z3 = t1 * z3;
985        let t1 = t2 + t2;
986        let t2 = t1 + t2;
987        let t0 = t0 - t2;
988        let y3 = t0 * y3;
989        let y3 = x3 + y3;
990        let t1 = self.x * self.y;
991        let x3 = t0 * t1;
992        let x3 = x3 + x3;
993
994        let tmp = G1Projective { x: x3, y: y3, z: z3 };
995        G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity())
996    }
997
998    /// Point addition.
999    pub fn add(&self, rhs: &G1Projective) -> G1Projective {
1000        // Algorithm 7 from https://eprint.iacr.org/2015/1060.pdf
1001        let t0 = self.x * rhs.x;
1002        let t1 = self.y * rhs.y;
1003        let t2 = self.z * rhs.z;
1004        let t3 = self.x + self.y;
1005        let t4 = rhs.x + rhs.y;
1006        let t3 = t3 * t4;
1007        let t4 = t0 + t1;
1008        let t3 = t3 - t4;
1009        let t4 = self.y + self.z;
1010        let x3 = rhs.y + rhs.z;
1011        let t4 = t4 * x3;
1012        let x3 = t1 + t2;
1013        let t4 = t4 - x3;
1014        let x3 = self.x + self.z;
1015        let y3 = rhs.x + rhs.z;
1016        let x3 = x3 * y3;
1017        let y3 = t0 + t2;
1018        let y3 = x3 - y3;
1019        let x3 = t0 + t0;
1020        let t0 = x3 + t0;
1021        let t2 = mul_by_3b(t2);
1022        let z3 = t1 + t2;
1023        let t1 = t1 - t2;
1024        let y3 = mul_by_3b(y3);
1025        let x3 = t4 * y3;
1026        let t2 = t3 * t1;
1027        let x3 = t2 - x3;
1028        let y3 = y3 * t0;
1029        let t1 = t1 * z3;
1030        let y3 = t1 + y3;
1031        let t0 = t0 * t3;
1032        let z3 = z3 * t4;
1033        let z3 = z3 + t0;
1034
1035        G1Projective { x: x3, y: y3, z: z3 }
1036    }
1037
1038    /// Mixed addition with affine point.
1039    pub fn add_mixed(&self, rhs: &G1Affine) -> G1Projective {
1040        // Algorithm 8 from https://eprint.iacr.org/2015/1060.pdf
1041        let t0 = self.x * rhs.x;
1042        let t1 = self.y * rhs.y;
1043        let t3 = rhs.x + rhs.y;
1044        let t4 = self.x + self.y;
1045        let t3 = t3 * t4;
1046        let t4 = t0 + t1;
1047        let t3 = t3 - t4;
1048        let t4 = rhs.y * self.z;
1049        let t4 = t4 + self.y;
1050        let y3 = rhs.x * self.z;
1051        let y3 = y3 + self.x;
1052        let x3 = t0 + t0;
1053        let t0 = x3 + t0;
1054        let t2 = mul_by_3b(self.z);
1055        let z3 = t1 + t2;
1056        let t1 = t1 - t2;
1057        let y3 = mul_by_3b(y3);
1058        let x3 = t4 * y3;
1059        let t2 = t3 * t1;
1060        let x3 = t2 - x3;
1061        let y3 = y3 * t0;
1062        let t1 = t1 * z3;
1063        let y3 = t1 + y3;
1064        let t0 = t0 * t3;
1065        let z3 = z3 * t4;
1066        let z3 = z3 + t0;
1067
1068        let tmp = G1Projective { x: x3, y: y3, z: z3 };
1069        G1Projective::conditional_select(&tmp, self, rhs.is_identity())
1070    }
1071
1072    fn multiply(&self, by: &[u8; 32]) -> G1Projective {
1073        let mut acc = G1Projective::identity();
1074        for &byte in by.iter().rev() {
1075            for i in (0..8).rev() {
1076                acc = acc.double();
1077                let bit = Choice::from((byte >> i) & 1u8);
1078                acc = G1Projective::conditional_select(&acc, &(acc + self), bit);
1079            }
1080        }
1081        acc
1082    }
1083
1084    fn mul_by_x(&self) -> G1Projective {
1085        let mut xself = G1Projective::identity();
1086        let mut x = super::BLS_X >> 1;
1087        let mut tmp = *self;
1088        while x != 0 {
1089            tmp = tmp.double();
1090            if x % 2 == 1 {
1091                xself += tmp;
1092            }
1093            x >>= 1;
1094        }
1095        if super::BLS_X_IS_NEGATIVE {
1096            xself = -xself;
1097        }
1098        xself
1099    }
1100
1101    /// Clear cofactor using [x - 1] method.
1102    pub fn clear_cofactor(&self) -> G1Projective {
1103        self - &self.mul_by_x()
1104    }
1105
1106    /// Batch affine conversion.
1107    pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) {
1108        assert_eq!(p.len(), q.len());
1109
1110        let mut acc = Fp::one();
1111        for (p, q) in p.iter().zip(q.iter_mut()) {
1112            q.x = acc;
1113            acc = Fp::conditional_select(&(acc * p.z), &acc, p.is_identity());
1114        }
1115
1116        acc = acc.invert().unwrap();
1117
1118        for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
1119            let skip = p.is_identity();
1120            let tmp = q.x * acc;
1121            acc = Fp::conditional_select(&(acc * p.z), &acc, skip);
1122            q.x = p.x * tmp;
1123            q.y = p.y * tmp;
1124            q.infinity = Choice::from(0u8);
1125            *q = G1Affine::conditional_select(q, &G1Affine::identity(), skip);
1126        }
1127    }
1128
1129    /// Check if point at infinity.
1130    #[inline]
1131    pub fn is_identity(&self) -> Choice {
1132        self.z.is_zero()
1133    }
1134
1135    /// Curve membership check.
1136    pub fn is_on_curve(&self) -> Choice {
1137        (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
1138            | self.z.is_zero()
1139    }
1140
1141    /// Deserialize from compressed bytes.
1142    pub fn from_bytes(bytes: &[u8; 48]) -> CtOption<Self> {
1143        G1Affine::from_compressed_unchecked(bytes).map(G1Projective::from)
1144    }
1145
1146    /// Deserialize without validation.
1147    pub fn from_bytes_unchecked(bytes: &[u8; 48]) -> CtOption<Self> {
1148        G1Affine::from_compressed_unchecked(bytes).map(G1Projective::from)
1149    }
1150
1151    /// Deserialize from compressed bytes with dcrypt error handling and validation.
1152    pub fn from_bytes_validated(bytes: &[u8]) -> Result<Self> {
1153        // Use dcrypt validation
1154        validate::length("G1Projective::from_bytes", bytes.len(), 48)?;
1155
1156        let mut array = [0u8; 48];
1157        array.copy_from_slice(bytes);
1158
1159        Self::from_bytes_unchecked(&array)
1160            .into_option()  // Convert CtOption to Option
1161            .ok_or_else(|| Error::Processing {
1162                operation: "G1 deserialization",
1163                details: "invalid point encoding",
1164            })
1165            .and_then(|p| {
1166                validate::parameter(
1167                    bool::from(p.is_on_curve()),
1168                    "point",
1169                    "not on curve"
1170                )?;
1171                Ok(p)
1172            })
1173    }
1174
1175    /// Serialize to compressed bytes.
1176    pub fn to_bytes(&self) -> [u8; 48] {
1177        G1Affine::from(self).to_compressed()
1178    }
1179}
1180
1181
1182#[cfg(test)]
1183mod tests {
1184    use super::*;
1185    
1186    #[test]
1187    fn test_g1_msm() {
1188        let g = G1Affine::generator();
1189        let s1 = Scalar::from(2u64);
1190        let s2 = Scalar::from(3u64);
1191        let s3 = Scalar::from(4u64);
1192
1193        let p1 = G1Affine::from(G1Projective::from(g) * s1); // [2]G
1194        let p2 = G1Affine::from(G1Projective::from(g) * s2); // [3]G
1195        let p3 = G1Affine::from(G1Projective::from(g) * s3); // [4]G
1196
1197        let scalars = vec![s1, s2, s3];
1198        let points = vec![p1, p2, p3];
1199
1200        // Expected result: 2*[2]G + 3*[3]G + 4*[4]G = (4 + 9 + 16)[G] = [29]G
1201        let expected = G1Projective::from(g) * Scalar::from(29u64);
1202
1203        // Naive MSM for comparison
1204        let naive_result = (p1 * s1) + (p2 * s2) + (p3 * s3);
1205        assert_eq!(G1Affine::from(naive_result), G1Affine::from(expected));
1206
1207        // Test msm_vartime
1208        let msm_result_vartime = G1Projective::msm_vartime(&points, &scalars).unwrap();
1209        assert_eq!(G1Affine::from(msm_result_vartime), G1Affine::from(expected));
1210
1211        // Test msm
1212        let msm_result = G1Projective::msm(&points, &scalars).unwrap();
1213        assert_eq!(G1Affine::from(msm_result), G1Affine::from(expected));
1214
1215        // Test empty input
1216        let empty_res = G1Projective::msm(&[], &[]).unwrap();
1217        assert_eq!(empty_res, G1Projective::identity());
1218    }
1219}