bls12_381/
g1.rs

1//! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.
2
3use core::borrow::Borrow;
4use core::fmt;
5use core::iter::Sum;
6use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use group::{
8    prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
9    Curve, Group, GroupEncoding, UncompressedEncoding,
10};
11use rand_core::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
13
14#[cfg(feature = "alloc")]
15use group::WnafGroup;
16
17use crate::fp::Fp;
18use crate::Scalar;
19
20/// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space.
21/// It is ideal to keep elements in this representation to reduce memory usage and
22/// improve performance through the use of mixed curve model arithmetic.
23///
24/// Values of `G1Affine` are guaranteed to be in the $q$-order subgroup unless an
25/// "unchecked" API was misused.
26#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
27#[derive(Copy, Clone, Debug)]
28pub struct G1Affine {
29    pub(crate) x: Fp,
30    pub(crate) y: Fp,
31    infinity: Choice,
32}
33
34impl Default for G1Affine {
35    fn default() -> G1Affine {
36        G1Affine::identity()
37    }
38}
39
40#[cfg(feature = "zeroize")]
41impl zeroize::DefaultIsZeroes for G1Affine {}
42
43impl fmt::Display for G1Affine {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        write!(f, "{:?}", self)
46    }
47}
48
49impl<'a> From<&'a G1Projective> for G1Affine {
50    fn from(p: &'a G1Projective) -> G1Affine {
51        let zinv = p.z.invert().unwrap_or(Fp::zero());
52        let x = p.x * zinv;
53        let y = p.y * zinv;
54
55        let tmp = G1Affine {
56            x,
57            y,
58            infinity: Choice::from(0u8),
59        };
60
61        G1Affine::conditional_select(&tmp, &G1Affine::identity(), zinv.is_zero())
62    }
63}
64
65impl From<G1Projective> for G1Affine {
66    fn from(p: G1Projective) -> G1Affine {
67        G1Affine::from(&p)
68    }
69}
70
71impl ConstantTimeEq for G1Affine {
72    fn ct_eq(&self, other: &Self) -> Choice {
73        // The only cases in which two points are equal are
74        // 1. infinity is set on both
75        // 2. infinity is not set on both, and their coordinates are equal
76
77        (self.infinity & other.infinity)
78            | ((!self.infinity)
79                & (!other.infinity)
80                & self.x.ct_eq(&other.x)
81                & self.y.ct_eq(&other.y))
82    }
83}
84
85impl ConditionallySelectable for G1Affine {
86    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
87        G1Affine {
88            x: Fp::conditional_select(&a.x, &b.x, choice),
89            y: Fp::conditional_select(&a.y, &b.y, choice),
90            infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
91        }
92    }
93}
94
95impl Eq for G1Affine {}
96impl PartialEq for G1Affine {
97    #[inline]
98    fn eq(&self, other: &Self) -> bool {
99        bool::from(self.ct_eq(other))
100    }
101}
102
103impl<'a> Neg for &'a G1Affine {
104    type Output = G1Affine;
105
106    #[inline]
107    fn neg(self) -> G1Affine {
108        G1Affine {
109            x: self.x,
110            y: Fp::conditional_select(&-self.y, &Fp::one(), self.infinity),
111            infinity: self.infinity,
112        }
113    }
114}
115
116impl Neg for G1Affine {
117    type Output = G1Affine;
118
119    #[inline]
120    fn neg(self) -> G1Affine {
121        -&self
122    }
123}
124
125impl<'a, 'b> Add<&'b G1Projective> for &'a G1Affine {
126    type Output = G1Projective;
127
128    #[inline]
129    fn add(self, rhs: &'b G1Projective) -> G1Projective {
130        rhs.add_mixed(self)
131    }
132}
133
134impl<'a, 'b> Add<&'b G1Affine> for &'a G1Projective {
135    type Output = G1Projective;
136
137    #[inline]
138    fn add(self, rhs: &'b G1Affine) -> G1Projective {
139        self.add_mixed(rhs)
140    }
141}
142
143impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Affine {
144    type Output = G1Projective;
145
146    #[inline]
147    fn sub(self, rhs: &'b G1Projective) -> G1Projective {
148        self + (-rhs)
149    }
150}
151
152impl<'a, 'b> Sub<&'b G1Affine> for &'a G1Projective {
153    type Output = G1Projective;
154
155    #[inline]
156    fn sub(self, rhs: &'b G1Affine) -> G1Projective {
157        self + (-rhs)
158    }
159}
160
161impl<T> Sum<T> for G1Projective
162where
163    T: Borrow<G1Projective>,
164{
165    fn sum<I>(iter: I) -> Self
166    where
167        I: Iterator<Item = T>,
168    {
169        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
170    }
171}
172
173impl_binops_additive!(G1Projective, G1Affine);
174impl_binops_additive_specify_output!(G1Affine, G1Projective, G1Projective);
175
176const B: Fp = Fp::from_raw_unchecked([
177    0xaa27_0000_000c_fff3,
178    0x53cc_0032_fc34_000a,
179    0x478f_e97a_6b0a_807f,
180    0xb1d3_7ebe_e6ba_24d7,
181    0x8ec9_733b_bf78_ab2f,
182    0x09d6_4551_3d83_de7e,
183]);
184
185impl G1Affine {
186    /// Returns the identity of the group: the point at infinity.
187    pub fn identity() -> G1Affine {
188        G1Affine {
189            x: Fp::zero(),
190            y: Fp::one(),
191            infinity: Choice::from(1u8),
192        }
193    }
194
195    /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
196    /// for how this generator is chosen.
197    pub fn generator() -> G1Affine {
198        G1Affine {
199            x: Fp::from_raw_unchecked([
200                0x5cb3_8790_fd53_0c16,
201                0x7817_fc67_9976_fff5,
202                0x154f_95c7_143b_a1c1,
203                0xf0ae_6acd_f3d0_e747,
204                0xedce_6ecc_21db_f440,
205                0x1201_7741_9e0b_fb75,
206            ]),
207            y: Fp::from_raw_unchecked([
208                0xbaac_93d5_0ce7_2271,
209                0x8c22_631a_7918_fd8e,
210                0xdd59_5f13_5707_25ce,
211                0x51ac_5829_5040_5194,
212                0x0e1c_8c3f_ad00_59c0,
213                0x0bbc_3efc_5008_a26a,
214            ]),
215            infinity: Choice::from(0u8),
216        }
217    }
218
219    /// Serializes this element into compressed form. See [`notes::serialization`](crate::notes::serialization)
220    /// for details about how group elements are serialized.
221    pub fn to_compressed(&self) -> [u8; 48] {
222        // Strictly speaking, self.x is zero already when self.infinity is true, but
223        // to guard against implementation mistakes we do not assume this.
224        let mut res = Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes();
225
226        // This point is in compressed form, so we set the most significant bit.
227        res[0] |= 1u8 << 7;
228
229        // Is this point at infinity? If so, set the second-most significant bit.
230        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
231
232        // Is the y-coordinate the lexicographically largest of the two associated with the
233        // x-coordinate? If so, set the third-most significant bit so long as this is not
234        // the point at infinity.
235        res[0] |= u8::conditional_select(
236            &0u8,
237            &(1u8 << 5),
238            (!self.infinity) & self.y.lexicographically_largest(),
239        );
240
241        res
242    }
243
244    /// Serializes this element into uncompressed form. See [`notes::serialization`](crate::notes::serialization)
245    /// for details about how group elements are serialized.
246    pub fn to_uncompressed(&self) -> [u8; 96] {
247        let mut res = [0; 96];
248
249        res[0..48].copy_from_slice(
250            &Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes()[..],
251        );
252        res[48..96].copy_from_slice(
253            &Fp::conditional_select(&self.y, &Fp::zero(), self.infinity).to_bytes()[..],
254        );
255
256        // Is this point at infinity? If so, set the second-most significant bit.
257        res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
258
259        res
260    }
261
262    /// Attempts to deserialize an uncompressed element. See [`notes::serialization`](crate::notes::serialization)
263    /// for details about how group elements are serialized.
264    pub fn from_uncompressed(bytes: &[u8; 96]) -> CtOption<Self> {
265        Self::from_uncompressed_unchecked(bytes)
266            .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
267    }
268
269    /// Attempts to deserialize an uncompressed element, not checking if the
270    /// element is on the curve and not checking if it is in the correct subgroup.
271    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
272    /// API invariants may be broken.** Please consider using `from_uncompressed()` instead.
273    pub fn from_uncompressed_unchecked(bytes: &[u8; 96]) -> CtOption<Self> {
274        // Obtain the three flags from the start of the byte sequence
275        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
276        let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
277        let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
278
279        // Attempt to obtain the x-coordinate
280        let x = {
281            let mut tmp = [0; 48];
282            tmp.copy_from_slice(&bytes[0..48]);
283
284            // Mask away the flag bits
285            tmp[0] &= 0b0001_1111;
286
287            Fp::from_bytes(&tmp)
288        };
289
290        // Attempt to obtain the y-coordinate
291        let y = {
292            let mut tmp = [0; 48];
293            tmp.copy_from_slice(&bytes[48..96]);
294
295            Fp::from_bytes(&tmp)
296        };
297
298        x.and_then(|x| {
299            y.and_then(|y| {
300                // Create a point representing this value
301                let p = G1Affine::conditional_select(
302                    &G1Affine {
303                        x,
304                        y,
305                        infinity: infinity_flag_set,
306                    },
307                    &G1Affine::identity(),
308                    infinity_flag_set,
309                );
310
311                CtOption::new(
312                    p,
313                    // If the infinity flag is set, the x and y coordinates should have been zero.
314                    ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero())) &
315                    // The compression flag should not have been set, as this is an uncompressed element
316                    (!compression_flag_set) &
317                    // The sort flag should not have been set, as this is an uncompressed element
318                    (!sort_flag_set),
319                )
320            })
321        })
322    }
323
324    /// Attempts to deserialize a compressed element. See [`notes::serialization`](crate::notes::serialization)
325    /// for details about how group elements are serialized.
326    pub fn from_compressed(bytes: &[u8; 48]) -> CtOption<Self> {
327        // We already know the point is on the curve because this is established
328        // by the y-coordinate recovery procedure in from_compressed_unchecked().
329
330        Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_torsion_free()))
331    }
332
333    /// Attempts to deserialize an uncompressed element, not checking if the
334    /// element is in the correct subgroup.
335    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
336    /// API invariants may be broken.** Please consider using `from_compressed()` instead.
337    pub fn from_compressed_unchecked(bytes: &[u8; 48]) -> CtOption<Self> {
338        // Obtain the three flags from the start of the byte sequence
339        let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
340        let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
341        let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
342
343        // Attempt to obtain the x-coordinate
344        let x = {
345            let mut tmp = [0; 48];
346            tmp.copy_from_slice(&bytes[0..48]);
347
348            // Mask away the flag bits
349            tmp[0] &= 0b0001_1111;
350
351            Fp::from_bytes(&tmp)
352        };
353
354        x.and_then(|x| {
355            // If the infinity flag is set, return the value assuming
356            // the x-coordinate is zero and the sort bit is not set.
357            //
358            // Otherwise, return a recovered point (assuming the correct
359            // y-coordinate can be found) so long as the infinity flag
360            // was not set.
361            CtOption::new(
362                G1Affine::identity(),
363                infinity_flag_set & // Infinity flag should be set
364                compression_flag_set & // Compression flag should be set
365                (!sort_flag_set) & // Sort flag should not be set
366                x.is_zero(), // The x-coordinate should be zero
367            )
368            .or_else(|| {
369                // Recover a y-coordinate given x by y = sqrt(x^3 + 4)
370                ((x.square() * x) + B).sqrt().and_then(|y| {
371                    // Switch to the correct y-coordinate if necessary.
372                    let y = Fp::conditional_select(
373                        &y,
374                        &-y,
375                        y.lexicographically_largest() ^ sort_flag_set,
376                    );
377
378                    CtOption::new(
379                        G1Affine {
380                            x,
381                            y,
382                            infinity: infinity_flag_set,
383                        },
384                        (!infinity_flag_set) & // Infinity flag should not be set
385                        compression_flag_set, // Compression flag should be set
386                    )
387                })
388            })
389        })
390    }
391
392    /// Returns true if this element is the identity (the point at infinity).
393    #[inline]
394    pub fn is_identity(&self) -> Choice {
395        self.infinity
396    }
397
398    /// Returns true if this point is free of an $h$-torsion component, and so it
399    /// exists within the $q$-order subgroup $\mathbb{G}_1$. This should always return true
400    /// unless an "unchecked" API was used.
401    pub fn is_torsion_free(&self) -> Choice {
402        // Algorithm from Section 6 of https://eprint.iacr.org/2021/1130
403        // Updated proof of correctness in https://eprint.iacr.org/2022/352
404        //
405        // Check that endomorphism_p(P) == -[x^2] P
406
407        let minus_x_squared_times_p = G1Projective::from(self).mul_by_x().mul_by_x().neg();
408        let endomorphism_p = endomorphism(self);
409        minus_x_squared_times_p.ct_eq(&G1Projective::from(endomorphism_p))
410    }
411
412    /// Returns true if this point is on the curve. This should always return
413    /// true unless an "unchecked" API was used.
414    pub fn is_on_curve(&self) -> Choice {
415        // y^2 - x^3 ?= 4
416        (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
417    }
418}
419
420/// A nontrivial third root of unity in Fp
421pub const BETA: Fp = Fp::from_raw_unchecked([
422    0x30f1_361b_798a_64e8,
423    0xf3b8_ddab_7ece_5a2a,
424    0x16a8_ca3a_c615_77f7,
425    0xc26a_2ff8_74fd_029b,
426    0x3636_b766_6070_1c6e,
427    0x051b_a4ab_241b_6160,
428]);
429
430fn endomorphism(p: &G1Affine) -> G1Affine {
431    // Endomorphism of the points on the curve.
432    // endomorphism_p(x,y) = (BETA * x, y)
433    // where BETA is a non-trivial cubic root of unity in Fq.
434    let mut res = *p;
435    res.x *= BETA;
436    res
437}
438
439/// This is an element of $\mathbb{G}_1$ represented in the projective coordinate space.
440#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
441#[derive(Copy, Clone, Debug)]
442pub struct G1Projective {
443    pub(crate) x: Fp,
444    pub(crate) y: Fp,
445    pub(crate) z: Fp,
446}
447
448impl Default for G1Projective {
449    fn default() -> G1Projective {
450        G1Projective::identity()
451    }
452}
453
454#[cfg(feature = "zeroize")]
455impl zeroize::DefaultIsZeroes for G1Projective {}
456
457impl fmt::Display for G1Projective {
458    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
459        write!(f, "{:?}", self)
460    }
461}
462
463impl<'a> From<&'a G1Affine> for G1Projective {
464    fn from(p: &'a G1Affine) -> G1Projective {
465        G1Projective {
466            x: p.x,
467            y: p.y,
468            z: Fp::conditional_select(&Fp::one(), &Fp::zero(), p.infinity),
469        }
470    }
471}
472
473impl From<G1Affine> for G1Projective {
474    fn from(p: G1Affine) -> G1Projective {
475        G1Projective::from(&p)
476    }
477}
478
479impl ConstantTimeEq for G1Projective {
480    fn ct_eq(&self, other: &Self) -> Choice {
481        // Is (xz, yz, z) equal to (x'z', y'z', z') when converted to affine?
482
483        let x1 = self.x * other.z;
484        let x2 = other.x * self.z;
485
486        let y1 = self.y * other.z;
487        let y2 = other.y * self.z;
488
489        let self_is_zero = self.z.is_zero();
490        let other_is_zero = other.z.is_zero();
491
492        (self_is_zero & other_is_zero) // Both point at infinity
493            | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
494        // Neither point at infinity, coordinates are the same
495    }
496}
497
498impl ConditionallySelectable for G1Projective {
499    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
500        G1Projective {
501            x: Fp::conditional_select(&a.x, &b.x, choice),
502            y: Fp::conditional_select(&a.y, &b.y, choice),
503            z: Fp::conditional_select(&a.z, &b.z, choice),
504        }
505    }
506}
507
508impl Eq for G1Projective {}
509impl PartialEq for G1Projective {
510    #[inline]
511    fn eq(&self, other: &Self) -> bool {
512        bool::from(self.ct_eq(other))
513    }
514}
515
516impl<'a> Neg for &'a G1Projective {
517    type Output = G1Projective;
518
519    #[inline]
520    fn neg(self) -> G1Projective {
521        G1Projective {
522            x: self.x,
523            y: -self.y,
524            z: self.z,
525        }
526    }
527}
528
529impl Neg for G1Projective {
530    type Output = G1Projective;
531
532    #[inline]
533    fn neg(self) -> G1Projective {
534        -&self
535    }
536}
537
538impl<'a, 'b> Add<&'b G1Projective> for &'a G1Projective {
539    type Output = G1Projective;
540
541    #[inline]
542    fn add(self, rhs: &'b G1Projective) -> G1Projective {
543        self.add(rhs)
544    }
545}
546
547impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Projective {
548    type Output = G1Projective;
549
550    #[inline]
551    fn sub(self, rhs: &'b G1Projective) -> G1Projective {
552        self + (-rhs)
553    }
554}
555
556impl<'a, 'b> Mul<&'b Scalar> for &'a G1Projective {
557    type Output = G1Projective;
558
559    fn mul(self, other: &'b Scalar) -> Self::Output {
560        self.multiply(&other.to_bytes())
561    }
562}
563
564impl<'a, 'b> Mul<&'b G1Projective> for &'a Scalar {
565    type Output = G1Projective;
566
567    #[inline]
568    fn mul(self, rhs: &'b G1Projective) -> Self::Output {
569        rhs * self
570    }
571}
572
573impl<'a, 'b> Mul<&'b Scalar> for &'a G1Affine {
574    type Output = G1Projective;
575
576    fn mul(self, other: &'b Scalar) -> Self::Output {
577        G1Projective::from(self).multiply(&other.to_bytes())
578    }
579}
580
581impl<'a, 'b> Mul<&'b G1Affine> for &'a Scalar {
582    type Output = G1Projective;
583
584    #[inline]
585    fn mul(self, rhs: &'b G1Affine) -> Self::Output {
586        rhs * self
587    }
588}
589
590impl_binops_additive!(G1Projective, G1Projective);
591impl_binops_multiplicative!(G1Projective, Scalar);
592impl_binops_multiplicative_mixed!(G1Affine, Scalar, G1Projective);
593impl_binops_multiplicative_mixed!(Scalar, G1Affine, G1Projective);
594impl_binops_multiplicative_mixed!(Scalar, G1Projective, G1Projective);
595
596#[inline(always)]
597fn mul_by_3b(a: Fp) -> Fp {
598    let a = a + a; // 2
599    let a = a + a; // 4
600    a + a + a // 12
601}
602
603impl G1Projective {
604    /// Returns the identity of the group: the point at infinity.
605    pub fn identity() -> G1Projective {
606        G1Projective {
607            x: Fp::zero(),
608            y: Fp::one(),
609            z: Fp::zero(),
610        }
611    }
612
613    /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
614    /// for how this generator is chosen.
615    pub fn generator() -> G1Projective {
616        G1Projective {
617            x: Fp::from_raw_unchecked([
618                0x5cb3_8790_fd53_0c16,
619                0x7817_fc67_9976_fff5,
620                0x154f_95c7_143b_a1c1,
621                0xf0ae_6acd_f3d0_e747,
622                0xedce_6ecc_21db_f440,
623                0x1201_7741_9e0b_fb75,
624            ]),
625            y: Fp::from_raw_unchecked([
626                0xbaac_93d5_0ce7_2271,
627                0x8c22_631a_7918_fd8e,
628                0xdd59_5f13_5707_25ce,
629                0x51ac_5829_5040_5194,
630                0x0e1c_8c3f_ad00_59c0,
631                0x0bbc_3efc_5008_a26a,
632            ]),
633            z: Fp::one(),
634        }
635    }
636
637    /// Computes the doubling of this point.
638    pub fn double(&self) -> G1Projective {
639        // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf
640
641        let t0 = self.y.square();
642        let z3 = t0 + t0;
643        let z3 = z3 + z3;
644        let z3 = z3 + z3;
645        let t1 = self.y * self.z;
646        let t2 = self.z.square();
647        let t2 = mul_by_3b(t2);
648        let x3 = t2 * z3;
649        let y3 = t0 + t2;
650        let z3 = t1 * z3;
651        let t1 = t2 + t2;
652        let t2 = t1 + t2;
653        let t0 = t0 - t2;
654        let y3 = t0 * y3;
655        let y3 = x3 + y3;
656        let t1 = self.x * self.y;
657        let x3 = t0 * t1;
658        let x3 = x3 + x3;
659
660        let tmp = G1Projective {
661            x: x3,
662            y: y3,
663            z: z3,
664        };
665
666        G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity())
667    }
668
669    /// Adds this point to another point.
670    pub fn add(&self, rhs: &G1Projective) -> G1Projective {
671        // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf
672
673        let t0 = self.x * rhs.x;
674        let t1 = self.y * rhs.y;
675        let t2 = self.z * rhs.z;
676        let t3 = self.x + self.y;
677        let t4 = rhs.x + rhs.y;
678        let t3 = t3 * t4;
679        let t4 = t0 + t1;
680        let t3 = t3 - t4;
681        let t4 = self.y + self.z;
682        let x3 = rhs.y + rhs.z;
683        let t4 = t4 * x3;
684        let x3 = t1 + t2;
685        let t4 = t4 - x3;
686        let x3 = self.x + self.z;
687        let y3 = rhs.x + rhs.z;
688        let x3 = x3 * y3;
689        let y3 = t0 + t2;
690        let y3 = x3 - y3;
691        let x3 = t0 + t0;
692        let t0 = x3 + t0;
693        let t2 = mul_by_3b(t2);
694        let z3 = t1 + t2;
695        let t1 = t1 - t2;
696        let y3 = mul_by_3b(y3);
697        let x3 = t4 * y3;
698        let t2 = t3 * t1;
699        let x3 = t2 - x3;
700        let y3 = y3 * t0;
701        let t1 = t1 * z3;
702        let y3 = t1 + y3;
703        let t0 = t0 * t3;
704        let z3 = z3 * t4;
705        let z3 = z3 + t0;
706
707        G1Projective {
708            x: x3,
709            y: y3,
710            z: z3,
711        }
712    }
713
714    /// Adds this point to another point in the affine model.
715    pub fn add_mixed(&self, rhs: &G1Affine) -> G1Projective {
716        // Algorithm 8, https://eprint.iacr.org/2015/1060.pdf
717
718        let t0 = self.x * rhs.x;
719        let t1 = self.y * rhs.y;
720        let t3 = rhs.x + rhs.y;
721        let t4 = self.x + self.y;
722        let t3 = t3 * t4;
723        let t4 = t0 + t1;
724        let t3 = t3 - t4;
725        let t4 = rhs.y * self.z;
726        let t4 = t4 + self.y;
727        let y3 = rhs.x * self.z;
728        let y3 = y3 + self.x;
729        let x3 = t0 + t0;
730        let t0 = x3 + t0;
731        let t2 = mul_by_3b(self.z);
732        let z3 = t1 + t2;
733        let t1 = t1 - t2;
734        let y3 = mul_by_3b(y3);
735        let x3 = t4 * y3;
736        let t2 = t3 * t1;
737        let x3 = t2 - x3;
738        let y3 = y3 * t0;
739        let t1 = t1 * z3;
740        let y3 = t1 + y3;
741        let t0 = t0 * t3;
742        let z3 = z3 * t4;
743        let z3 = z3 + t0;
744
745        let tmp = G1Projective {
746            x: x3,
747            y: y3,
748            z: z3,
749        };
750
751        G1Projective::conditional_select(&tmp, self, rhs.is_identity())
752    }
753
754    fn multiply(&self, by: &[u8; 32]) -> G1Projective {
755        let mut acc = G1Projective::identity();
756
757        // This is a simple double-and-add implementation of point
758        // multiplication, moving from most significant to least
759        // significant bit of the scalar.
760        //
761        // We skip the leading bit because it's always unset for Fq
762        // elements.
763        for bit in by
764            .iter()
765            .rev()
766            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
767            .skip(1)
768        {
769            acc = acc.double();
770            acc = G1Projective::conditional_select(&acc, &(acc + self), bit);
771        }
772
773        acc
774    }
775
776    /// Multiply `self` by `crate::BLS_X`, using double and add.
777    fn mul_by_x(&self) -> G1Projective {
778        let mut xself = G1Projective::identity();
779        // NOTE: in BLS12-381 we can just skip the first bit.
780        let mut x = crate::BLS_X >> 1;
781        let mut tmp = *self;
782        while x != 0 {
783            tmp = tmp.double();
784
785            if x % 2 == 1 {
786                xself += tmp;
787            }
788            x >>= 1;
789        }
790        // finally, flip the sign
791        if crate::BLS_X_IS_NEGATIVE {
792            xself = -xself;
793        }
794        xself
795    }
796
797    /// Multiplies by $(1 - z)$, where $z$ is the parameter of BLS12-381, which
798    /// [suffices to clear](https://ia.cr/2019/403) the cofactor and map
799    /// elliptic curve points to elements of $\mathbb{G}\_1$.
800    pub fn clear_cofactor(&self) -> G1Projective {
801        self - self.mul_by_x()
802    }
803
804    /// Converts a batch of `G1Projective` elements into `G1Affine` elements. This
805    /// function will panic if `p.len() != q.len()`.
806    pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) {
807        assert_eq!(p.len(), q.len());
808
809        let mut acc = Fp::one();
810        for (p, q) in p.iter().zip(q.iter_mut()) {
811            // We use the `x` field of `G1Affine` to store the product
812            // of previous z-coordinates seen.
813            q.x = acc;
814
815            // We will end up skipping all identities in p
816            acc = Fp::conditional_select(&(acc * p.z), &acc, p.is_identity());
817        }
818
819        // This is the inverse, as all z-coordinates are nonzero and the ones
820        // that are not are skipped.
821        acc = acc.invert().unwrap();
822
823        for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
824            let skip = p.is_identity();
825
826            // Compute tmp = 1/z
827            let tmp = q.x * acc;
828
829            // Cancel out z-coordinate in denominator of `acc`
830            acc = Fp::conditional_select(&(acc * p.z), &acc, skip);
831
832            // Set the coordinates to the correct value
833            q.x = p.x * tmp;
834            q.y = p.y * tmp;
835            q.infinity = Choice::from(0u8);
836
837            *q = G1Affine::conditional_select(q, &G1Affine::identity(), skip);
838        }
839    }
840
841    /// Returns true if this element is the identity (the point at infinity).
842    #[inline]
843    pub fn is_identity(&self) -> Choice {
844        self.z.is_zero()
845    }
846
847    /// Returns true if this point is on the curve. This should always return
848    /// true unless an "unchecked" API was used.
849    pub fn is_on_curve(&self) -> Choice {
850        // Y^2 Z = X^3 + b Z^3
851
852        (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
853            | self.z.is_zero()
854    }
855}
856
857#[derive(Clone, Copy)]
858pub struct G1Compressed([u8; 48]);
859
860impl fmt::Debug for G1Compressed {
861    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
862        self.0[..].fmt(f)
863    }
864}
865
866impl Default for G1Compressed {
867    fn default() -> Self {
868        G1Compressed([0; 48])
869    }
870}
871
872#[cfg(feature = "zeroize")]
873impl zeroize::DefaultIsZeroes for G1Compressed {}
874
875impl AsRef<[u8]> for G1Compressed {
876    fn as_ref(&self) -> &[u8] {
877        &self.0
878    }
879}
880
881impl AsMut<[u8]> for G1Compressed {
882    fn as_mut(&mut self) -> &mut [u8] {
883        &mut self.0
884    }
885}
886
887impl ConstantTimeEq for G1Compressed {
888    fn ct_eq(&self, other: &Self) -> Choice {
889        self.0.ct_eq(&other.0)
890    }
891}
892
893impl Eq for G1Compressed {}
894impl PartialEq for G1Compressed {
895    #[inline]
896    fn eq(&self, other: &Self) -> bool {
897        bool::from(self.ct_eq(other))
898    }
899}
900
901#[derive(Clone, Copy)]
902pub struct G1Uncompressed([u8; 96]);
903
904impl fmt::Debug for G1Uncompressed {
905    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
906        self.0[..].fmt(f)
907    }
908}
909
910impl Default for G1Uncompressed {
911    fn default() -> Self {
912        G1Uncompressed([0; 96])
913    }
914}
915
916#[cfg(feature = "zeroize")]
917impl zeroize::DefaultIsZeroes for G1Uncompressed {}
918
919impl AsRef<[u8]> for G1Uncompressed {
920    fn as_ref(&self) -> &[u8] {
921        &self.0
922    }
923}
924
925impl AsMut<[u8]> for G1Uncompressed {
926    fn as_mut(&mut self) -> &mut [u8] {
927        &mut self.0
928    }
929}
930
931impl ConstantTimeEq for G1Uncompressed {
932    fn ct_eq(&self, other: &Self) -> Choice {
933        self.0.ct_eq(&other.0)
934    }
935}
936
937impl Eq for G1Uncompressed {}
938impl PartialEq for G1Uncompressed {
939    #[inline]
940    fn eq(&self, other: &Self) -> bool {
941        bool::from(self.ct_eq(other))
942    }
943}
944
945impl Group for G1Projective {
946    type Scalar = Scalar;
947
948    fn random(mut rng: impl RngCore) -> Self {
949        loop {
950            let x = Fp::random(&mut rng);
951            let flip_sign = rng.next_u32() % 2 != 0;
952
953            // Obtain the corresponding y-coordinate given x as y = sqrt(x^3 + 4)
954            let p = ((x.square() * x) + B).sqrt().map(|y| G1Affine {
955                x,
956                y: if flip_sign { -y } else { y },
957                infinity: 0.into(),
958            });
959
960            if p.is_some().into() {
961                let p = p.unwrap().to_curve().clear_cofactor();
962
963                if bool::from(!p.is_identity()) {
964                    return p;
965                }
966            }
967        }
968    }
969
970    fn identity() -> Self {
971        Self::identity()
972    }
973
974    fn generator() -> Self {
975        Self::generator()
976    }
977
978    fn is_identity(&self) -> Choice {
979        self.is_identity()
980    }
981
982    #[must_use]
983    fn double(&self) -> Self {
984        self.double()
985    }
986}
987
988#[cfg(feature = "alloc")]
989impl WnafGroup for G1Projective {
990    fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
991        const RECOMMENDATIONS: [usize; 12] =
992            [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
993
994        let mut ret = 4;
995        for r in &RECOMMENDATIONS {
996            if num_scalars > *r {
997                ret += 1;
998            } else {
999                break;
1000            }
1001        }
1002
1003        ret
1004    }
1005}
1006
1007impl PrimeGroup for G1Projective {}
1008
1009impl Curve for G1Projective {
1010    type AffineRepr = G1Affine;
1011
1012    fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
1013        Self::batch_normalize(p, q);
1014    }
1015
1016    fn to_affine(&self) -> Self::AffineRepr {
1017        self.into()
1018    }
1019}
1020
1021impl PrimeCurve for G1Projective {
1022    type Affine = G1Affine;
1023}
1024
1025impl PrimeCurveAffine for G1Affine {
1026    type Scalar = Scalar;
1027    type Curve = G1Projective;
1028
1029    fn identity() -> Self {
1030        Self::identity()
1031    }
1032
1033    fn generator() -> Self {
1034        Self::generator()
1035    }
1036
1037    fn is_identity(&self) -> Choice {
1038        self.is_identity()
1039    }
1040
1041    fn to_curve(&self) -> Self::Curve {
1042        self.into()
1043    }
1044}
1045
1046impl GroupEncoding for G1Projective {
1047    type Repr = G1Compressed;
1048
1049    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1050        G1Affine::from_bytes(bytes).map(Self::from)
1051    }
1052
1053    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1054        G1Affine::from_bytes_unchecked(bytes).map(Self::from)
1055    }
1056
1057    fn to_bytes(&self) -> Self::Repr {
1058        G1Affine::from(self).to_bytes()
1059    }
1060}
1061
1062impl GroupEncoding for G1Affine {
1063    type Repr = G1Compressed;
1064
1065    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1066        Self::from_compressed(&bytes.0)
1067    }
1068
1069    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1070        Self::from_compressed_unchecked(&bytes.0)
1071    }
1072
1073    fn to_bytes(&self) -> Self::Repr {
1074        G1Compressed(self.to_compressed())
1075    }
1076}
1077
1078impl UncompressedEncoding for G1Affine {
1079    type Uncompressed = G1Uncompressed;
1080
1081    fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
1082        Self::from_uncompressed(&bytes.0)
1083    }
1084
1085    fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
1086        Self::from_uncompressed_unchecked(&bytes.0)
1087    }
1088
1089    fn to_uncompressed(&self) -> Self::Uncompressed {
1090        G1Uncompressed(self.to_uncompressed())
1091    }
1092}
1093
1094#[test]
1095fn test_beta() {
1096    assert_eq!(
1097        BETA,
1098        Fp::from_bytes(&[
1099            0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x19, 0x67, 0x2f, 0xdf, 0x76,
1100            0xce, 0x51, 0xba, 0x69, 0xc6, 0x07, 0x6a, 0x0f, 0x77, 0xea, 0xdd, 0xb3, 0xa9, 0x3b,
1101            0xe6, 0xf8, 0x96, 0x88, 0xde, 0x17, 0xd8, 0x13, 0x62, 0x0a, 0x00, 0x02, 0x2e, 0x01,
1102            0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe
1103        ])
1104        .unwrap()
1105    );
1106    assert_ne!(BETA, Fp::one());
1107    assert_ne!(BETA * BETA, Fp::one());
1108    assert_eq!(BETA * BETA * BETA, Fp::one());
1109}
1110#[test]
1111fn test_is_on_curve() {
1112    assert!(bool::from(G1Affine::identity().is_on_curve()));
1113    assert!(bool::from(G1Affine::generator().is_on_curve()));
1114    assert!(bool::from(G1Projective::identity().is_on_curve()));
1115    assert!(bool::from(G1Projective::generator().is_on_curve()));
1116
1117    let z = Fp::from_raw_unchecked([
1118        0xba7a_fa1f_9a6f_e250,
1119        0xfa0f_5b59_5eaf_e731,
1120        0x3bdc_4776_94c3_06e7,
1121        0x2149_be4b_3949_fa24,
1122        0x64aa_6e06_49b2_078c,
1123        0x12b1_08ac_3364_3c3e,
1124    ]);
1125
1126    let gen = G1Affine::generator();
1127    let mut test = G1Projective {
1128        x: gen.x * z,
1129        y: gen.y * z,
1130        z,
1131    };
1132
1133    assert!(bool::from(test.is_on_curve()));
1134
1135    test.x = z;
1136    assert!(!bool::from(test.is_on_curve()));
1137}
1138
1139#[test]
1140#[allow(clippy::eq_op)]
1141fn test_affine_point_equality() {
1142    let a = G1Affine::generator();
1143    let b = G1Affine::identity();
1144
1145    assert!(a == a);
1146    assert!(b == b);
1147    assert!(a != b);
1148    assert!(b != a);
1149}
1150
1151#[test]
1152#[allow(clippy::eq_op)]
1153fn test_projective_point_equality() {
1154    let a = G1Projective::generator();
1155    let b = G1Projective::identity();
1156
1157    assert!(a == a);
1158    assert!(b == b);
1159    assert!(a != b);
1160    assert!(b != a);
1161
1162    let z = Fp::from_raw_unchecked([
1163        0xba7a_fa1f_9a6f_e250,
1164        0xfa0f_5b59_5eaf_e731,
1165        0x3bdc_4776_94c3_06e7,
1166        0x2149_be4b_3949_fa24,
1167        0x64aa_6e06_49b2_078c,
1168        0x12b1_08ac_3364_3c3e,
1169    ]);
1170
1171    let mut c = G1Projective {
1172        x: a.x * z,
1173        y: a.y * z,
1174        z,
1175    };
1176    assert!(bool::from(c.is_on_curve()));
1177
1178    assert!(a == c);
1179    assert!(b != c);
1180    assert!(c == a);
1181    assert!(c != b);
1182
1183    c.y = -c.y;
1184    assert!(bool::from(c.is_on_curve()));
1185
1186    assert!(a != c);
1187    assert!(b != c);
1188    assert!(c != a);
1189    assert!(c != b);
1190
1191    c.y = -c.y;
1192    c.x = z;
1193    assert!(!bool::from(c.is_on_curve()));
1194    assert!(a != b);
1195    assert!(a != c);
1196    assert!(b != c);
1197}
1198
1199#[test]
1200fn test_conditionally_select_affine() {
1201    let a = G1Affine::generator();
1202    let b = G1Affine::identity();
1203
1204    assert_eq!(G1Affine::conditional_select(&a, &b, Choice::from(0u8)), a);
1205    assert_eq!(G1Affine::conditional_select(&a, &b, Choice::from(1u8)), b);
1206}
1207
1208#[test]
1209fn test_conditionally_select_projective() {
1210    let a = G1Projective::generator();
1211    let b = G1Projective::identity();
1212
1213    assert_eq!(
1214        G1Projective::conditional_select(&a, &b, Choice::from(0u8)),
1215        a
1216    );
1217    assert_eq!(
1218        G1Projective::conditional_select(&a, &b, Choice::from(1u8)),
1219        b
1220    );
1221}
1222
1223#[test]
1224fn test_projective_to_affine() {
1225    let a = G1Projective::generator();
1226    let b = G1Projective::identity();
1227
1228    assert!(bool::from(G1Affine::from(a).is_on_curve()));
1229    assert!(!bool::from(G1Affine::from(a).is_identity()));
1230    assert!(bool::from(G1Affine::from(b).is_on_curve()));
1231    assert!(bool::from(G1Affine::from(b).is_identity()));
1232
1233    let z = Fp::from_raw_unchecked([
1234        0xba7a_fa1f_9a6f_e250,
1235        0xfa0f_5b59_5eaf_e731,
1236        0x3bdc_4776_94c3_06e7,
1237        0x2149_be4b_3949_fa24,
1238        0x64aa_6e06_49b2_078c,
1239        0x12b1_08ac_3364_3c3e,
1240    ]);
1241
1242    let c = G1Projective {
1243        x: a.x * z,
1244        y: a.y * z,
1245        z,
1246    };
1247
1248    assert_eq!(G1Affine::from(c), G1Affine::generator());
1249}
1250
1251#[test]
1252fn test_affine_to_projective() {
1253    let a = G1Affine::generator();
1254    let b = G1Affine::identity();
1255
1256    assert!(bool::from(G1Projective::from(a).is_on_curve()));
1257    assert!(!bool::from(G1Projective::from(a).is_identity()));
1258    assert!(bool::from(G1Projective::from(b).is_on_curve()));
1259    assert!(bool::from(G1Projective::from(b).is_identity()));
1260}
1261
1262#[test]
1263fn test_doubling() {
1264    {
1265        let tmp = G1Projective::identity().double();
1266        assert!(bool::from(tmp.is_identity()));
1267        assert!(bool::from(tmp.is_on_curve()));
1268    }
1269    {
1270        let tmp = G1Projective::generator().double();
1271        assert!(!bool::from(tmp.is_identity()));
1272        assert!(bool::from(tmp.is_on_curve()));
1273
1274        assert_eq!(
1275            G1Affine::from(tmp),
1276            G1Affine {
1277                x: Fp::from_raw_unchecked([
1278                    0x53e9_78ce_58a9_ba3c,
1279                    0x3ea0_583c_4f3d_65f9,
1280                    0x4d20_bb47_f001_2960,
1281                    0xa54c_664a_e5b2_b5d9,
1282                    0x26b5_52a3_9d7e_b21f,
1283                    0x0008_895d_26e6_8785,
1284                ]),
1285                y: Fp::from_raw_unchecked([
1286                    0x7011_0b32_9829_3940,
1287                    0xda33_c539_3f1f_6afc,
1288                    0xb86e_dfd1_6a5a_a785,
1289                    0xaec6_d1c9_e7b1_c895,
1290                    0x25cf_c2b5_22d1_1720,
1291                    0x0636_1c83_f8d0_9b15,
1292                ]),
1293                infinity: Choice::from(0u8)
1294            }
1295        );
1296    }
1297}
1298
1299#[test]
1300fn test_projective_addition() {
1301    {
1302        let a = G1Projective::identity();
1303        let b = G1Projective::identity();
1304        let c = a + b;
1305        assert!(bool::from(c.is_identity()));
1306        assert!(bool::from(c.is_on_curve()));
1307    }
1308    {
1309        let a = G1Projective::identity();
1310        let mut b = G1Projective::generator();
1311        {
1312            let z = Fp::from_raw_unchecked([
1313                0xba7a_fa1f_9a6f_e250,
1314                0xfa0f_5b59_5eaf_e731,
1315                0x3bdc_4776_94c3_06e7,
1316                0x2149_be4b_3949_fa24,
1317                0x64aa_6e06_49b2_078c,
1318                0x12b1_08ac_3364_3c3e,
1319            ]);
1320
1321            b = G1Projective {
1322                x: b.x * z,
1323                y: b.y * z,
1324                z,
1325            };
1326        }
1327        let c = a + b;
1328        assert!(!bool::from(c.is_identity()));
1329        assert!(bool::from(c.is_on_curve()));
1330        assert!(c == G1Projective::generator());
1331    }
1332    {
1333        let a = G1Projective::identity();
1334        let mut b = G1Projective::generator();
1335        {
1336            let z = Fp::from_raw_unchecked([
1337                0xba7a_fa1f_9a6f_e250,
1338                0xfa0f_5b59_5eaf_e731,
1339                0x3bdc_4776_94c3_06e7,
1340                0x2149_be4b_3949_fa24,
1341                0x64aa_6e06_49b2_078c,
1342                0x12b1_08ac_3364_3c3e,
1343            ]);
1344
1345            b = G1Projective {
1346                x: b.x * z,
1347                y: b.y * z,
1348                z,
1349            };
1350        }
1351        let c = b + a;
1352        assert!(!bool::from(c.is_identity()));
1353        assert!(bool::from(c.is_on_curve()));
1354        assert!(c == G1Projective::generator());
1355    }
1356    {
1357        let a = G1Projective::generator().double().double(); // 4P
1358        let b = G1Projective::generator().double(); // 2P
1359        let c = a + b;
1360
1361        let mut d = G1Projective::generator();
1362        for _ in 0..5 {
1363            d += G1Projective::generator();
1364        }
1365        assert!(!bool::from(c.is_identity()));
1366        assert!(bool::from(c.is_on_curve()));
1367        assert!(!bool::from(d.is_identity()));
1368        assert!(bool::from(d.is_on_curve()));
1369        assert_eq!(c, d);
1370    }
1371
1372    // Degenerate case
1373    {
1374        let beta = Fp::from_raw_unchecked([
1375            0xcd03_c9e4_8671_f071,
1376            0x5dab_2246_1fcd_a5d2,
1377            0x5870_42af_d385_1b95,
1378            0x8eb6_0ebe_01ba_cb9e,
1379            0x03f9_7d6e_83d0_50d2,
1380            0x18f0_2065_5463_8741,
1381        ]);
1382        let beta = beta.square();
1383        let a = G1Projective::generator().double().double();
1384        let b = G1Projective {
1385            x: a.x * beta,
1386            y: -a.y,
1387            z: a.z,
1388        };
1389        assert!(bool::from(a.is_on_curve()));
1390        assert!(bool::from(b.is_on_curve()));
1391
1392        let c = a + b;
1393        assert_eq!(
1394            G1Affine::from(c),
1395            G1Affine::from(G1Projective {
1396                x: Fp::from_raw_unchecked([
1397                    0x29e1_e987_ef68_f2d0,
1398                    0xc5f3_ec53_1db0_3233,
1399                    0xacd6_c4b6_ca19_730f,
1400                    0x18ad_9e82_7bc2_bab7,
1401                    0x46e3_b2c5_785c_c7a9,
1402                    0x07e5_71d4_2d22_ddd6,
1403                ]),
1404                y: Fp::from_raw_unchecked([
1405                    0x94d1_17a7_e5a5_39e7,
1406                    0x8e17_ef67_3d4b_5d22,
1407                    0x9d74_6aaf_508a_33ea,
1408                    0x8c6d_883d_2516_c9a2,
1409                    0x0bc3_b8d5_fb04_47f7,
1410                    0x07bf_a4c7_210f_4f44,
1411                ]),
1412                z: Fp::one()
1413            })
1414        );
1415        assert!(!bool::from(c.is_identity()));
1416        assert!(bool::from(c.is_on_curve()));
1417    }
1418}
1419
1420#[test]
1421fn test_mixed_addition() {
1422    {
1423        let a = G1Affine::identity();
1424        let b = G1Projective::identity();
1425        let c = a + b;
1426        assert!(bool::from(c.is_identity()));
1427        assert!(bool::from(c.is_on_curve()));
1428    }
1429    {
1430        let a = G1Affine::identity();
1431        let mut b = G1Projective::generator();
1432        {
1433            let z = Fp::from_raw_unchecked([
1434                0xba7a_fa1f_9a6f_e250,
1435                0xfa0f_5b59_5eaf_e731,
1436                0x3bdc_4776_94c3_06e7,
1437                0x2149_be4b_3949_fa24,
1438                0x64aa_6e06_49b2_078c,
1439                0x12b1_08ac_3364_3c3e,
1440            ]);
1441
1442            b = G1Projective {
1443                x: b.x * z,
1444                y: b.y * z,
1445                z,
1446            };
1447        }
1448        let c = a + b;
1449        assert!(!bool::from(c.is_identity()));
1450        assert!(bool::from(c.is_on_curve()));
1451        assert!(c == G1Projective::generator());
1452    }
1453    {
1454        let a = G1Affine::identity();
1455        let mut b = G1Projective::generator();
1456        {
1457            let z = Fp::from_raw_unchecked([
1458                0xba7a_fa1f_9a6f_e250,
1459                0xfa0f_5b59_5eaf_e731,
1460                0x3bdc_4776_94c3_06e7,
1461                0x2149_be4b_3949_fa24,
1462                0x64aa_6e06_49b2_078c,
1463                0x12b1_08ac_3364_3c3e,
1464            ]);
1465
1466            b = G1Projective {
1467                x: b.x * z,
1468                y: b.y * z,
1469                z,
1470            };
1471        }
1472        let c = b + a;
1473        assert!(!bool::from(c.is_identity()));
1474        assert!(bool::from(c.is_on_curve()));
1475        assert!(c == G1Projective::generator());
1476    }
1477    {
1478        let a = G1Projective::generator().double().double(); // 4P
1479        let b = G1Projective::generator().double(); // 2P
1480        let c = a + b;
1481
1482        let mut d = G1Projective::generator();
1483        for _ in 0..5 {
1484            d += G1Affine::generator();
1485        }
1486        assert!(!bool::from(c.is_identity()));
1487        assert!(bool::from(c.is_on_curve()));
1488        assert!(!bool::from(d.is_identity()));
1489        assert!(bool::from(d.is_on_curve()));
1490        assert_eq!(c, d);
1491    }
1492
1493    // Degenerate case
1494    {
1495        let beta = Fp::from_raw_unchecked([
1496            0xcd03_c9e4_8671_f071,
1497            0x5dab_2246_1fcd_a5d2,
1498            0x5870_42af_d385_1b95,
1499            0x8eb6_0ebe_01ba_cb9e,
1500            0x03f9_7d6e_83d0_50d2,
1501            0x18f0_2065_5463_8741,
1502        ]);
1503        let beta = beta.square();
1504        let a = G1Projective::generator().double().double();
1505        let b = G1Projective {
1506            x: a.x * beta,
1507            y: -a.y,
1508            z: a.z,
1509        };
1510        let a = G1Affine::from(a);
1511        assert!(bool::from(a.is_on_curve()));
1512        assert!(bool::from(b.is_on_curve()));
1513
1514        let c = a + b;
1515        assert_eq!(
1516            G1Affine::from(c),
1517            G1Affine::from(G1Projective {
1518                x: Fp::from_raw_unchecked([
1519                    0x29e1_e987_ef68_f2d0,
1520                    0xc5f3_ec53_1db0_3233,
1521                    0xacd6_c4b6_ca19_730f,
1522                    0x18ad_9e82_7bc2_bab7,
1523                    0x46e3_b2c5_785c_c7a9,
1524                    0x07e5_71d4_2d22_ddd6,
1525                ]),
1526                y: Fp::from_raw_unchecked([
1527                    0x94d1_17a7_e5a5_39e7,
1528                    0x8e17_ef67_3d4b_5d22,
1529                    0x9d74_6aaf_508a_33ea,
1530                    0x8c6d_883d_2516_c9a2,
1531                    0x0bc3_b8d5_fb04_47f7,
1532                    0x07bf_a4c7_210f_4f44,
1533                ]),
1534                z: Fp::one()
1535            })
1536        );
1537        assert!(!bool::from(c.is_identity()));
1538        assert!(bool::from(c.is_on_curve()));
1539    }
1540}
1541
1542#[test]
1543#[allow(clippy::eq_op)]
1544fn test_projective_negation_and_subtraction() {
1545    let a = G1Projective::generator().double();
1546    assert_eq!(a + (-a), G1Projective::identity());
1547    assert_eq!(a + (-a), a - a);
1548}
1549
1550#[test]
1551fn test_affine_negation_and_subtraction() {
1552    let a = G1Affine::generator();
1553    assert_eq!(G1Projective::from(a) + (-a), G1Projective::identity());
1554    assert_eq!(G1Projective::from(a) + (-a), G1Projective::from(a) - a);
1555}
1556
1557#[test]
1558fn test_projective_scalar_multiplication() {
1559    let g = G1Projective::generator();
1560    let a = Scalar::from_raw([
1561        0x2b56_8297_a56d_a71c,
1562        0xd8c3_9ecb_0ef3_75d1,
1563        0x435c_38da_67bf_bf96,
1564        0x8088_a050_26b6_59b2,
1565    ]);
1566    let b = Scalar::from_raw([
1567        0x785f_dd9b_26ef_8b85,
1568        0xc997_f258_3769_5c18,
1569        0x4c8d_bc39_e7b7_56c1,
1570        0x70d9_b6cc_6d87_df20,
1571    ]);
1572    let c = a * b;
1573
1574    assert_eq!((g * a) * b, g * c);
1575}
1576
1577#[test]
1578fn test_affine_scalar_multiplication() {
1579    let g = G1Affine::generator();
1580    let a = Scalar::from_raw([
1581        0x2b56_8297_a56d_a71c,
1582        0xd8c3_9ecb_0ef3_75d1,
1583        0x435c_38da_67bf_bf96,
1584        0x8088_a050_26b6_59b2,
1585    ]);
1586    let b = Scalar::from_raw([
1587        0x785f_dd9b_26ef_8b85,
1588        0xc997_f258_3769_5c18,
1589        0x4c8d_bc39_e7b7_56c1,
1590        0x70d9_b6cc_6d87_df20,
1591    ]);
1592    let c = a * b;
1593
1594    assert_eq!(G1Affine::from(g * a) * b, g * c);
1595}
1596
1597#[test]
1598fn test_is_torsion_free() {
1599    let a = G1Affine {
1600        x: Fp::from_raw_unchecked([
1601            0x0aba_f895_b97e_43c8,
1602            0xba4c_6432_eb9b_61b0,
1603            0x1250_6f52_adfe_307f,
1604            0x7502_8c34_3933_6b72,
1605            0x8474_4f05_b8e9_bd71,
1606            0x113d_554f_b095_54f7,
1607        ]),
1608        y: Fp::from_raw_unchecked([
1609            0x73e9_0e88_f5cf_01c0,
1610            0x3700_7b65_dd31_97e2,
1611            0x5cf9_a199_2f0d_7c78,
1612            0x4f83_c10b_9eb3_330d,
1613            0xf6a6_3f6f_07f6_0961,
1614            0x0c53_b5b9_7e63_4df3,
1615        ]),
1616        infinity: Choice::from(0u8),
1617    };
1618    assert!(!bool::from(a.is_torsion_free()));
1619
1620    assert!(bool::from(G1Affine::identity().is_torsion_free()));
1621    assert!(bool::from(G1Affine::generator().is_torsion_free()));
1622}
1623
1624#[test]
1625fn test_mul_by_x() {
1626    // multiplying by `x` a point in G1 is the same as multiplying by
1627    // the equivalent scalar.
1628    let generator = G1Projective::generator();
1629    let x = if crate::BLS_X_IS_NEGATIVE {
1630        -Scalar::from(crate::BLS_X)
1631    } else {
1632        Scalar::from(crate::BLS_X)
1633    };
1634    assert_eq!(generator.mul_by_x(), generator * x);
1635
1636    let point = G1Projective::generator() * Scalar::from(42);
1637    assert_eq!(point.mul_by_x(), point * x);
1638}
1639
1640#[test]
1641fn test_clear_cofactor() {
1642    // the generator (and the identity) are always on the curve,
1643    // even after clearing the cofactor
1644    let generator = G1Projective::generator();
1645    assert!(bool::from(generator.clear_cofactor().is_on_curve()));
1646    let id = G1Projective::identity();
1647    assert!(bool::from(id.clear_cofactor().is_on_curve()));
1648
1649    let z = Fp::from_raw_unchecked([
1650        0x3d2d1c670671394e,
1651        0x0ee3a800a2f7c1ca,
1652        0x270f4f21da2e5050,
1653        0xe02840a53f1be768,
1654        0x55debeb597512690,
1655        0x08bd25353dc8f791,
1656    ]);
1657
1658    let point = G1Projective {
1659        x: Fp::from_raw_unchecked([
1660            0x48af5ff540c817f0,
1661            0xd73893acaf379d5a,
1662            0xe6c43584e18e023c,
1663            0x1eda39c30f188b3e,
1664            0xf618c6d3ccc0f8d8,
1665            0x0073542cd671e16c,
1666        ]) * z,
1667        y: Fp::from_raw_unchecked([
1668            0x57bf8be79461d0ba,
1669            0xfc61459cee3547c3,
1670            0x0d23567df1ef147b,
1671            0x0ee187bcce1d9b64,
1672            0xb0c8cfbe9dc8fdc1,
1673            0x1328661767ef368b,
1674        ]),
1675        z: z.square() * z,
1676    };
1677
1678    assert!(bool::from(point.is_on_curve()));
1679    assert!(!bool::from(G1Affine::from(point).is_torsion_free()));
1680    let cleared_point = point.clear_cofactor();
1681    assert!(bool::from(cleared_point.is_on_curve()));
1682    assert!(bool::from(G1Affine::from(cleared_point).is_torsion_free()));
1683
1684    // in BLS12-381 the cofactor in G1 can be
1685    // cleared multiplying by (1-x)
1686    let h_eff = Scalar::from(1) + Scalar::from(crate::BLS_X);
1687    assert_eq!(point.clear_cofactor(), point * h_eff);
1688}
1689
1690#[test]
1691fn test_batch_normalize() {
1692    let a = G1Projective::generator().double();
1693    let b = a.double();
1694    let c = b.double();
1695
1696    for a_identity in (0..=1).map(|n| n == 1) {
1697        for b_identity in (0..=1).map(|n| n == 1) {
1698            for c_identity in (0..=1).map(|n| n == 1) {
1699                let mut v = [a, b, c];
1700                if a_identity {
1701                    v[0] = G1Projective::identity()
1702                }
1703                if b_identity {
1704                    v[1] = G1Projective::identity()
1705                }
1706                if c_identity {
1707                    v[2] = G1Projective::identity()
1708                }
1709
1710                let mut t = [
1711                    G1Affine::identity(),
1712                    G1Affine::identity(),
1713                    G1Affine::identity(),
1714                ];
1715                let expected = [
1716                    G1Affine::from(v[0]),
1717                    G1Affine::from(v[1]),
1718                    G1Affine::from(v[2]),
1719                ];
1720
1721                G1Projective::batch_normalize(&v[..], &mut t[..]);
1722
1723                assert_eq!(&t[..], &expected[..]);
1724            }
1725        }
1726    }
1727}
1728
1729#[cfg(feature = "zeroize")]
1730#[test]
1731fn test_zeroize() {
1732    use zeroize::Zeroize;
1733
1734    let mut a = G1Affine::generator();
1735    a.zeroize();
1736    assert!(bool::from(a.is_identity()));
1737
1738    let mut a = G1Projective::generator();
1739    a.zeroize();
1740    assert!(bool::from(a.is_identity()));
1741
1742    let mut a = GroupEncoding::to_bytes(&G1Affine::generator());
1743    a.zeroize();
1744    assert_eq!(&a, &G1Compressed::default());
1745
1746    let mut a = UncompressedEncoding::to_uncompressed(&G1Affine::generator());
1747    a.zeroize();
1748    assert_eq!(&a, &G1Uncompressed::default());
1749}
1750
1751#[test]
1752fn test_commutative_scalar_subgroup_multiplication() {
1753    let a = Scalar::from_raw([
1754        0x1fff_3231_233f_fffd,
1755        0x4884_b7fa_0003_4802,
1756        0x998c_4fef_ecbc_4ff3,
1757        0x1824_b159_acc5_0562,
1758    ]);
1759
1760    let g1_a = G1Affine::generator();
1761    let g1_p = G1Projective::generator();
1762
1763    // By reference.
1764    assert_eq!(&g1_a * &a, &a * &g1_a);
1765    assert_eq!(&g1_p * &a, &a * &g1_p);
1766
1767    // Mixed
1768    assert_eq!(&g1_a * a.clone(), a.clone() * &g1_a);
1769    assert_eq!(&g1_p * a.clone(), a.clone() * &g1_p);
1770    assert_eq!(g1_a.clone() * &a, &a * g1_a.clone());
1771    assert_eq!(g1_p.clone() * &a, &a * g1_p.clone());
1772
1773    // By value.
1774    assert_eq!(g1_p * a, a * g1_p);
1775    assert_eq!(g1_a * a, a * g1_a);
1776}