halo2curves_axiom/bls12_381/
g1.rs

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