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    /// Point doubling.
823    pub fn double(&self) -> G1Projective {
824        // Algorithm 9 from https://eprint.iacr.org/2015/1060.pdf
825        let t0 = self.y.square();
826        let z3 = t0 + t0;
827        let z3 = z3 + z3;
828        let z3 = z3 + z3;
829        let t1 = self.y * self.z;
830        let t2 = self.z.square();
831        let t2 = mul_by_3b(t2);
832        let x3 = t2 * z3;
833        let y3 = t0 + t2;
834        let z3 = t1 * z3;
835        let t1 = t2 + t2;
836        let t2 = t1 + t2;
837        let t0 = t0 - t2;
838        let y3 = t0 * y3;
839        let y3 = x3 + y3;
840        let t1 = self.x * self.y;
841        let x3 = t0 * t1;
842        let x3 = x3 + x3;
843
844        let tmp = G1Projective { x: x3, y: y3, z: z3 };
845        G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity())
846    }
847
848    /// Point addition.
849    pub fn add(&self, rhs: &G1Projective) -> G1Projective {
850        // Algorithm 7 from https://eprint.iacr.org/2015/1060.pdf
851        let t0 = self.x * rhs.x;
852        let t1 = self.y * rhs.y;
853        let t2 = self.z * rhs.z;
854        let t3 = self.x + self.y;
855        let t4 = rhs.x + rhs.y;
856        let t3 = t3 * t4;
857        let t4 = t0 + t1;
858        let t3 = t3 - t4;
859        let t4 = self.y + self.z;
860        let x3 = rhs.y + rhs.z;
861        let t4 = t4 * x3;
862        let x3 = t1 + t2;
863        let t4 = t4 - x3;
864        let x3 = self.x + self.z;
865        let y3 = rhs.x + rhs.z;
866        let x3 = x3 * y3;
867        let y3 = t0 + t2;
868        let y3 = x3 - y3;
869        let x3 = t0 + t0;
870        let t0 = x3 + t0;
871        let t2 = mul_by_3b(t2);
872        let z3 = t1 + t2;
873        let t1 = t1 - t2;
874        let y3 = mul_by_3b(y3);
875        let x3 = t4 * y3;
876        let t2 = t3 * t1;
877        let x3 = t2 - x3;
878        let y3 = y3 * t0;
879        let t1 = t1 * z3;
880        let y3 = t1 + y3;
881        let t0 = t0 * t3;
882        let z3 = z3 * t4;
883        let z3 = z3 + t0;
884
885        G1Projective { x: x3, y: y3, z: z3 }
886    }
887
888    /// Mixed addition with affine point.
889    pub fn add_mixed(&self, rhs: &G1Affine) -> G1Projective {
890        // Algorithm 8 from https://eprint.iacr.org/2015/1060.pdf
891        let t0 = self.x * rhs.x;
892        let t1 = self.y * rhs.y;
893        let t3 = rhs.x + rhs.y;
894        let t4 = self.x + self.y;
895        let t3 = t3 * t4;
896        let t4 = t0 + t1;
897        let t3 = t3 - t4;
898        let t4 = rhs.y * self.z;
899        let t4 = t4 + self.y;
900        let y3 = rhs.x * self.z;
901        let y3 = y3 + self.x;
902        let x3 = t0 + t0;
903        let t0 = x3 + t0;
904        let t2 = mul_by_3b(self.z);
905        let z3 = t1 + t2;
906        let t1 = t1 - t2;
907        let y3 = mul_by_3b(y3);
908        let x3 = t4 * y3;
909        let t2 = t3 * t1;
910        let x3 = t2 - x3;
911        let y3 = y3 * t0;
912        let t1 = t1 * z3;
913        let y3 = t1 + y3;
914        let t0 = t0 * t3;
915        let z3 = z3 * t4;
916        let z3 = z3 + t0;
917
918        let tmp = G1Projective { x: x3, y: y3, z: z3 };
919        G1Projective::conditional_select(&tmp, self, rhs.is_identity())
920    }
921
922    fn multiply(&self, by: &[u8; 32]) -> G1Projective {
923        let mut acc = G1Projective::identity();
924        for &byte in by.iter().rev() {
925            for i in (0..8).rev() {
926                acc = acc.double();
927                let bit = Choice::from((byte >> i) & 1u8);
928                acc = G1Projective::conditional_select(&acc, &(acc + self), bit);
929            }
930        }
931        acc
932    }
933
934    fn mul_by_x(&self) -> G1Projective {
935        let mut xself = G1Projective::identity();
936        let mut x = super::BLS_X >> 1;
937        let mut tmp = *self;
938        while x != 0 {
939            tmp = tmp.double();
940            if x % 2 == 1 {
941                xself += tmp;
942            }
943            x >>= 1;
944        }
945        if super::BLS_X_IS_NEGATIVE {
946            xself = -xself;
947        }
948        xself
949    }
950
951    /// Clear cofactor using [x - 1] method.
952    pub fn clear_cofactor(&self) -> G1Projective {
953        self - &self.mul_by_x()
954    }
955
956    /// Batch affine conversion.
957    pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) {
958        assert_eq!(p.len(), q.len());
959
960        let mut acc = Fp::one();
961        for (p, q) in p.iter().zip(q.iter_mut()) {
962            q.x = acc;
963            acc = Fp::conditional_select(&(acc * p.z), &acc, p.is_identity());
964        }
965
966        acc = acc.invert().unwrap();
967
968        for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
969            let skip = p.is_identity();
970            let tmp = q.x * acc;
971            acc = Fp::conditional_select(&(acc * p.z), &acc, skip);
972            q.x = p.x * tmp;
973            q.y = p.y * tmp;
974            q.infinity = Choice::from(0u8);
975            *q = G1Affine::conditional_select(q, &G1Affine::identity(), skip);
976        }
977    }
978
979    /// Check if point at infinity.
980    #[inline]
981    pub fn is_identity(&self) -> Choice {
982        self.z.is_zero()
983    }
984
985    /// Curve membership check.
986    pub fn is_on_curve(&self) -> Choice {
987        (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
988            | self.z.is_zero()
989    }
990
991    /// Deserialize from compressed bytes.
992    pub fn from_bytes(bytes: &[u8; 48]) -> CtOption<Self> {
993        G1Affine::from_compressed_unchecked(bytes).map(G1Projective::from)
994    }
995
996    /// Deserialize without validation.
997    pub fn from_bytes_unchecked(bytes: &[u8; 48]) -> CtOption<Self> {
998        G1Affine::from_compressed_unchecked(bytes).map(G1Projective::from)
999    }
1000
1001    /// Deserialize from compressed bytes with dcrypt error handling and validation.
1002    pub fn from_bytes_validated(bytes: &[u8]) -> Result<Self> {
1003        // Use dcrypt validation
1004        validate::length("G1Projective::from_bytes", bytes.len(), 48)?;
1005
1006        let mut array = [0u8; 48];
1007        array.copy_from_slice(bytes);
1008
1009        Self::from_bytes_unchecked(&array)
1010            .into_option()  // Convert CtOption to Option
1011            .ok_or_else(|| Error::Processing {
1012                operation: "G1 deserialization",
1013                details: "invalid point encoding",
1014            })
1015            .and_then(|p| {
1016                validate::parameter(
1017                    bool::from(p.is_on_curve()),
1018                    "point",
1019                    "not on curve"
1020                )?;
1021                Ok(p)
1022            })
1023    }
1024
1025    /// Serialize to compressed bytes.
1026    pub fn to_bytes(&self) -> [u8; 48] {
1027        G1Affine::from(self).to_compressed()
1028    }
1029}