Skip to main content

nam_blstrs/
g1.rs

1//! An implementation of the $\mathbb{G}_1$ group of BLS12-381.
2
3use core::{
4    borrow::Borrow,
5    fmt,
6    iter::Sum,
7    ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9use std::io::Read;
10
11use blst::*;
12use group::{
13    Curve, Group, GroupEncoding, UncompressedEncoding, WnafGroup,
14    prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
15};
16use rand_core::RngCore;
17use subtle::{Choice, ConditionallySelectable, CtOption};
18use zeroize::Zeroize;
19
20use crate::{Bls12, Engine, G2Affine, Gt, PairingCurveAffine, Scalar, fp::Fp};
21
22/// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space.
23/// It is ideal to keep elements in this representation to reduce memory usage and
24/// improve performance through the use of mixed curve model arithmetic.
25#[derive(Copy, Clone, Zeroize)]
26#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
27#[repr(transparent)]
28pub struct G1Affine(pub(crate) blst_p1_affine);
29
30const COMPRESSED_SIZE: usize = 48;
31const UNCOMPRESSED_SIZE: usize = 96;
32
33impl fmt::Debug for G1Affine {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        let is_ident: bool = self.is_identity().into();
36        f.debug_struct("G1Affine")
37            .field("x", &self.x())
38            .field("y", &self.y())
39            .field("infinity", &is_ident)
40            .finish()
41    }
42}
43
44impl fmt::Display for G1Affine {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        if self.is_identity().into() {
47            write!(f, "G1Affine(Infinity)")
48        } else {
49            write!(f, "G1Affine(x={}, y={})", self.x(), self.y())
50        }
51    }
52}
53
54impl Default for G1Affine {
55    fn default() -> G1Affine {
56        G1Affine::identity()
57    }
58}
59
60impl From<&G1Projective> for G1Affine {
61    fn from(p: &G1Projective) -> G1Affine {
62        let mut out = blst_p1_affine::default();
63
64        unsafe { blst_p1_to_affine(&mut out, &p.0) };
65
66        G1Affine(out)
67    }
68}
69
70impl From<G1Projective> for G1Affine {
71    fn from(p: G1Projective) -> G1Affine {
72        G1Affine::from(&p)
73    }
74}
75
76impl AsRef<blst_p1_affine> for G1Affine {
77    fn as_ref(&self) -> &blst_p1_affine {
78        &self.0
79    }
80}
81
82impl AsMut<blst_p1_affine> for G1Affine {
83    fn as_mut(&mut self) -> &mut blst_p1_affine {
84        &mut self.0
85    }
86}
87
88impl Eq for G1Affine {}
89impl PartialEq for G1Affine {
90    #[inline]
91    fn eq(&self, other: &Self) -> bool {
92        unsafe { blst_p1_affine_is_equal(&self.0, &other.0) }
93    }
94}
95
96impl Neg for &G1Projective {
97    type Output = G1Projective;
98
99    #[inline]
100    fn neg(self) -> G1Projective {
101        -*self
102    }
103}
104
105impl Neg for G1Projective {
106    type Output = G1Projective;
107
108    #[inline]
109    fn neg(mut self) -> G1Projective {
110        unsafe { blst_p1_cneg(&mut self.0, true) };
111        self
112    }
113}
114
115impl Neg for &G1Affine {
116    type Output = G1Affine;
117
118    #[inline]
119    fn neg(self) -> G1Affine {
120        -*self
121    }
122}
123
124impl Neg for G1Affine {
125    type Output = G1Affine;
126
127    #[inline]
128    fn neg(mut self) -> G1Affine {
129        // Missing for affine in blst
130        if (!self.is_identity()).into() {
131            unsafe {
132                blst_fp_cneg(&mut self.0.y, &self.0.y, true);
133            }
134        }
135        self
136    }
137}
138
139impl Add<&G1Projective> for &G1Projective {
140    type Output = G1Projective;
141
142    #[inline]
143    fn add(self, rhs: &G1Projective) -> G1Projective {
144        let mut out = blst_p1::default();
145        unsafe { blst_p1_add_or_double(&mut out, &self.0, &rhs.0) };
146        G1Projective(out)
147    }
148}
149
150impl Add<&G1Projective> for &G1Affine {
151    type Output = G1Projective;
152
153    #[inline]
154    fn add(self, rhs: &G1Projective) -> G1Projective {
155        rhs.add_mixed(self)
156    }
157}
158
159impl Add<&G1Affine> for &G1Projective {
160    type Output = G1Projective;
161
162    #[inline]
163    fn add(self, rhs: &G1Affine) -> G1Projective {
164        self.add_mixed(rhs)
165    }
166}
167
168impl Sub<&G1Projective> for &G1Projective {
169    type Output = G1Projective;
170
171    #[inline]
172    fn sub(self, rhs: &G1Projective) -> G1Projective {
173        self + (-rhs)
174    }
175}
176
177impl Sub<&G1Projective> for &G1Affine {
178    type Output = G1Projective;
179
180    #[inline]
181    fn sub(self, rhs: &G1Projective) -> G1Projective {
182        self + (-rhs)
183    }
184}
185
186impl Sub<&G1Affine> for &G1Projective {
187    type Output = G1Projective;
188
189    #[inline]
190    fn sub(self, rhs: &G1Affine) -> G1Projective {
191        self + (-rhs)
192    }
193}
194
195impl AddAssign<&G1Projective> for G1Projective {
196    #[inline]
197    fn add_assign(&mut self, rhs: &G1Projective) {
198        unsafe { blst_p1_add_or_double(&mut self.0, &self.0, &rhs.0) };
199    }
200}
201
202impl SubAssign<&G1Projective> for G1Projective {
203    #[inline]
204    fn sub_assign(&mut self, rhs: &G1Projective) {
205        *self += &-rhs;
206    }
207}
208
209impl AddAssign<&G1Affine> for G1Projective {
210    #[inline]
211    fn add_assign(&mut self, rhs: &G1Affine) {
212        unsafe { blst_p1_add_or_double_affine(&mut self.0, &self.0, &rhs.0) };
213    }
214}
215
216impl SubAssign<&G1Affine> for G1Projective {
217    #[inline]
218    fn sub_assign(&mut self, rhs: &G1Affine) {
219        *self += &-rhs;
220    }
221}
222
223impl Mul<&Scalar> for &G1Projective {
224    type Output = G1Projective;
225
226    fn mul(self, scalar: &Scalar) -> Self::Output {
227        self.multiply(scalar)
228    }
229}
230
231impl Mul<&Scalar> for &G1Affine {
232    type Output = G1Projective;
233
234    fn mul(self, scalar: &Scalar) -> Self::Output {
235        G1Projective::from(self).multiply(scalar)
236    }
237}
238
239impl MulAssign<&Scalar> for G1Projective {
240    #[inline]
241    fn mul_assign(&mut self, rhs: &Scalar) {
242        *self = *self * rhs;
243    }
244}
245
246impl MulAssign<&Scalar> for G1Affine {
247    #[inline]
248    fn mul_assign(&mut self, rhs: &Scalar) {
249        *self = (*self * rhs).into();
250    }
251}
252
253impl_add_sub!(G1Projective);
254impl_add_sub!(G1Projective, G1Affine);
255impl_add_sub!(G1Affine, G1Projective, G1Projective);
256
257impl_add_sub_assign!(G1Projective);
258impl_add_sub_assign!(G1Projective, G1Affine);
259
260impl_mul!(G1Projective, Scalar);
261impl_mul!(G1Affine, Scalar, G1Projective);
262
263impl_mul_assign!(G1Projective, Scalar);
264impl_mul_assign!(G1Affine, Scalar);
265
266impl<T> Sum<T> for G1Projective
267where
268    T: Borrow<G1Projective>,
269{
270    fn sum<I>(iter: I) -> Self
271    where
272        I: Iterator<Item = T>,
273    {
274        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
275    }
276}
277
278impl ConditionallySelectable for G1Affine {
279    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
280        G1Affine(blst_p1_affine {
281            x: Fp::conditional_select(&a.x(), &b.x(), choice).0,
282            y: Fp::conditional_select(&a.y(), &b.y(), choice).0,
283        })
284    }
285}
286
287impl ConditionallySelectable for G1Projective {
288    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
289        G1Projective(blst_p1 {
290            x: Fp::conditional_select(&a.x(), &b.x(), choice).0,
291            y: Fp::conditional_select(&a.y(), &b.y(), choice).0,
292            z: Fp::conditional_select(&a.z(), &b.z(), choice).0,
293        })
294    }
295}
296
297impl G1Affine {
298    /// Serializes this element into compressed form.
299    pub fn to_compressed(&self) -> [u8; COMPRESSED_SIZE] {
300        let mut out = [0u8; COMPRESSED_SIZE];
301
302        unsafe {
303            blst_p1_affine_compress(out.as_mut_ptr(), &self.0);
304        }
305
306        out
307    }
308
309    /// Serializes this element into uncompressed form.
310    pub fn to_uncompressed(&self) -> [u8; UNCOMPRESSED_SIZE] {
311        let mut out = [0u8; UNCOMPRESSED_SIZE];
312
313        unsafe {
314            blst_p1_affine_serialize(out.as_mut_ptr(), &self.0);
315        }
316
317        out
318    }
319
320    /// Attempts to deserialize an uncompressed element.
321    pub fn from_uncompressed(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
322        G1Affine::from_uncompressed_unchecked(bytes)
323            .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
324    }
325
326    /// Attempts to deserialize an uncompressed element, not checking if the
327    /// element is on the curve and not checking if it is in the correct subgroup.
328    ///
329    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
330    /// API invariants may be broken.** Please consider using `from_uncompressed()` instead.
331    pub fn from_uncompressed_unchecked(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
332        let mut raw = blst_p1_affine::default();
333        let success =
334            unsafe { blst_p1_deserialize(&mut raw, bytes.as_ptr()) == BLST_ERROR::BLST_SUCCESS };
335        CtOption::new(G1Affine(raw), Choice::from(success as u8))
336    }
337
338    /// Attempts to deserialize a compressed element.
339    pub fn from_compressed(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
340        G1Affine::from_compressed_unchecked(bytes)
341            .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
342    }
343
344    /// Attempts to deserialize an uncompressed element, not checking if the
345    /// element is in the correct subgroup.
346    ///
347    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
348    /// API invariants may be broken.** Please consider using `from_compressed()` instead.
349    pub fn from_compressed_unchecked(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
350        let mut raw = blst_p1_affine::default();
351        let success =
352            unsafe { blst_p1_uncompress(&mut raw, bytes.as_ptr()) == BLST_ERROR::BLST_SUCCESS };
353        CtOption::new(G1Affine(raw), Choice::from(success as u8))
354    }
355
356    /// Returns true if this point is free of an $h$-torsion component, and so it
357    /// exists within the $q$-order subgroup $\mathbb{G}_1$. This should always return true
358    /// unless an "unchecked" API was used.
359    pub fn is_torsion_free(&self) -> Choice {
360        unsafe { Choice::from(blst_p1_affine_in_g1(&self.0) as u8) }
361    }
362
363    /// Returns true if this point is on the curve. This should always return
364    /// true unless an "unchecked" API was used.
365    pub fn is_on_curve(&self) -> Choice {
366        unsafe { Choice::from(blst_p1_affine_on_curve(&self.0) as u8) }
367    }
368
369    pub fn from_raw_unchecked(x: Fp, y: Fp, _infinity: bool) -> Self {
370        // FIXME: what about infinity?
371        let raw = blst_p1_affine { x: x.0, y: y.0 };
372
373        G1Affine(raw)
374    }
375
376    /// Returns the x coordinate.
377    pub fn x(&self) -> Fp {
378        Fp(self.0.x)
379    }
380
381    /// Returns the y coordinate.
382    pub fn y(&self) -> Fp {
383        Fp(self.0.y)
384    }
385
386    pub const fn uncompressed_size() -> usize {
387        UNCOMPRESSED_SIZE
388    }
389
390    pub const fn compressed_size() -> usize {
391        COMPRESSED_SIZE
392    }
393
394    #[inline]
395    pub fn raw_fmt_size() -> usize {
396        let s = G1Affine::uncompressed_size();
397        s + 1
398    }
399
400    pub fn write_raw<W: std::io::Write>(&self, mut writer: W) -> Result<usize, std::io::Error> {
401        if self.is_identity().into() {
402            writer.write_all(&[1])?;
403        } else {
404            writer.write_all(&[0])?;
405        }
406        let raw = self.to_uncompressed();
407        writer.write_all(&raw)?;
408
409        Ok(Self::raw_fmt_size())
410    }
411
412    pub fn read_raw<R: Read>(mut reader: R) -> Result<Self, std::io::Error> {
413        let mut buf = [0u8];
414        reader.read_exact(&mut buf)?;
415        let _infinity = buf[0] == 1;
416
417        let mut buf = [0u8; UNCOMPRESSED_SIZE];
418        reader.read_exact(&mut buf)?;
419        let res = Self::from_uncompressed_unchecked(&buf);
420        if res.is_some().into() {
421            Ok(res.unwrap())
422        } else {
423            Err(std::io::Error::new(
424                std::io::ErrorKind::InvalidData,
425                "not on curve",
426            ))
427        }
428    }
429
430    pub fn read_raw_checked<R: Read>(mut reader: R) -> Result<Self, std::io::Error> {
431        let mut buf = [0u8];
432        reader.read_exact(&mut buf)?;
433        let _infinity = buf[0] == 1;
434
435        let mut buf = [0u8; UNCOMPRESSED_SIZE];
436        reader.read_exact(&mut buf)?;
437        let res = Self::from_uncompressed(&buf);
438        if res.is_some().into() {
439            Ok(res.unwrap())
440        } else {
441            Err(std::io::Error::new(
442                std::io::ErrorKind::InvalidData,
443                "not on curve",
444            ))
445        }
446    }
447}
448
449/// This is an element of $\mathbb{G}_1$ represented in the projective coordinate space.
450#[derive(Copy, Clone, Zeroize)]
451#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
452#[repr(transparent)]
453pub struct G1Projective(pub(crate) blst_p1);
454
455impl fmt::Debug for G1Projective {
456    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
457        f.debug_struct("G1Projective")
458            .field("x", &self.x())
459            .field("y", &self.y())
460            .field("z", &self.z())
461            .finish()
462    }
463}
464
465impl fmt::Display for G1Projective {
466    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467        write!(f, "{}", G1Affine::from(self))
468    }
469}
470
471impl AsRef<blst_p1> for G1Projective {
472    fn as_ref(&self) -> &blst_p1 {
473        &self.0
474    }
475}
476
477impl AsMut<blst_p1> for G1Projective {
478    fn as_mut(&mut self) -> &mut blst_p1 {
479        &mut self.0
480    }
481}
482
483impl From<&G1Affine> for G1Projective {
484    fn from(p: &G1Affine) -> G1Projective {
485        let mut out = blst_p1::default();
486
487        unsafe { blst_p1_from_affine(&mut out, &p.0) };
488
489        G1Projective(out)
490    }
491}
492
493impl From<G1Affine> for G1Projective {
494    fn from(p: G1Affine) -> G1Projective {
495        G1Projective::from(&p)
496    }
497}
498
499impl Eq for G1Projective {}
500impl PartialEq for G1Projective {
501    #[inline]
502    fn eq(&self, other: &Self) -> bool {
503        let self_is_zero: bool = self.is_identity().into();
504        let other_is_zero: bool = other.is_identity().into();
505        (self_is_zero && other_is_zero)
506            || (!self_is_zero && !other_is_zero && unsafe { blst_p1_is_equal(&self.0, &other.0) })
507    }
508}
509
510impl G1Projective {
511    /// Serializes this element into compressed form.
512    pub fn to_compressed(&self) -> [u8; COMPRESSED_SIZE] {
513        let mut out = [0u8; COMPRESSED_SIZE];
514
515        unsafe {
516            blst_p1_compress(out.as_mut_ptr(), &self.0);
517        }
518
519        out
520    }
521
522    /// Serializes this element into uncompressed form.
523    pub fn to_uncompressed(&self) -> [u8; UNCOMPRESSED_SIZE] {
524        let mut out = [0u8; UNCOMPRESSED_SIZE];
525
526        unsafe {
527            blst_p1_serialize(out.as_mut_ptr(), &self.0);
528        }
529
530        out
531    }
532
533    /// Attempts to deserialize an uncompressed element.
534    pub fn from_uncompressed(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
535        G1Affine::from_uncompressed(bytes).map(Into::into)
536    }
537
538    /// Attempts to deserialize an uncompressed element, not checking if the
539    /// element is on the curve and not checking if it is in the correct subgroup.
540    ///
541    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
542    /// API invariants may be broken.** Please consider using `from_uncompressed()` instead.
543    pub fn from_uncompressed_unchecked(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
544        G1Affine::from_uncompressed_unchecked(bytes).map(Into::into)
545    }
546
547    /// Attempts to deserialize a compressed element.
548    pub fn from_compressed(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
549        G1Affine::from_compressed(bytes).map(Into::into)
550    }
551
552    /// Attempts to deserialize an uncompressed element, not checking if the
553    /// element is in the correct subgroup.
554    ///
555    /// **This is dangerous to call unless you trust the bytes you are reading; otherwise,
556    /// API invariants may be broken.** Please consider using `from_compressed()` instead.
557    pub fn from_compressed_unchecked(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
558        G1Affine::from_compressed_unchecked(bytes).map(Into::into)
559    }
560
561    /// Adds this point to another point in the affine model.
562    fn add_mixed(&self, rhs: &G1Affine) -> G1Projective {
563        let mut out = blst_p1::default();
564
565        unsafe { blst_p1_add_or_double_affine(&mut out, &self.0, &rhs.0) };
566
567        G1Projective(out)
568    }
569
570    /// Returns true if this point is on the curve. This should always return
571    /// true unless an "unchecked" API was used.
572    pub fn is_on_curve(&self) -> Choice {
573        let is_on_curve = unsafe { Choice::from(blst_p1_on_curve(&self.0) as u8) };
574        is_on_curve | self.is_identity()
575    }
576
577    fn multiply(&self, scalar: &Scalar) -> G1Projective {
578        let mut out = blst_p1::default();
579
580        // Scalar is 255 bits wide.
581        const NBITS: usize = 255;
582
583        unsafe { blst_p1_mult(&mut out, &self.0, scalar.to_bytes_le().as_ptr(), NBITS) };
584
585        G1Projective(out)
586    }
587
588    pub fn from_raw_unchecked(x: Fp, y: Fp, z: Fp) -> Self {
589        let raw = blst_p1 {
590            x: x.0,
591            y: y.0,
592            z: z.0,
593        };
594
595        G1Projective(raw)
596    }
597
598    /// Returns the x coordinate.
599    pub fn x(&self) -> Fp {
600        Fp(self.0.x)
601    }
602
603    /// Returns the y coordinate.
604    pub fn y(&self) -> Fp {
605        Fp(self.0.y)
606    }
607
608    /// Returns the z coordinate.
609    pub fn z(&self) -> Fp {
610        Fp(self.0.z)
611    }
612
613    /// Hash to curve algorithm.
614    pub fn hash_to_curve(msg: &[u8], dst: &[u8], aug: &[u8]) -> Self {
615        let mut res = Self::identity();
616        unsafe {
617            blst_hash_to_g1(
618                &mut res.0,
619                msg.as_ptr(),
620                msg.len(),
621                dst.as_ptr(),
622                dst.len(),
623                aug.as_ptr(),
624                aug.len(),
625            );
626        }
627        res
628    }
629
630    /// Perform a multi-exponentiation, aka "multi-scalar-multiplication" (MSM) using `blst`'s implementation of Pippenger's algorithm.
631    /// Note: `scalars` is cloned in this method.
632    pub fn multi_exp(points: &[Self], scalars: &[Scalar]) -> Self {
633        let n = if points.len() < scalars.len() {
634            points.len()
635        } else {
636            scalars.len()
637        };
638        let points =
639            unsafe { std::slice::from_raw_parts(points.as_ptr() as *const blst_p1, points.len()) };
640
641        let points = p1_affines::from(points);
642
643        let mut scalar_bytes: Vec<u8> = Vec::with_capacity(n * 32);
644        for a in scalars.iter().map(|s| s.to_bytes_le()) {
645            scalar_bytes.extend_from_slice(&a);
646        }
647
648        let res = points.mult(scalar_bytes.as_slice(), 255);
649
650        G1Projective(res)
651    }
652}
653
654impl Group for G1Projective {
655    type Scalar = Scalar;
656
657    fn random(mut rng: impl RngCore) -> Self {
658        let mut out = blst_p1::default();
659        let mut msg = [0u8; 64];
660        rng.fill_bytes(&mut msg);
661        const DST: [u8; 16] = [0; 16];
662        const AUG: [u8; 16] = [0; 16];
663
664        unsafe {
665            blst_encode_to_g1(
666                &mut out,
667                msg.as_ptr(),
668                msg.len(),
669                DST.as_ptr(),
670                DST.len(),
671                AUG.as_ptr(),
672                AUG.len(),
673            )
674        };
675
676        G1Projective(out)
677    }
678
679    fn identity() -> Self {
680        G1Projective(blst_p1::default())
681    }
682
683    fn generator() -> Self {
684        G1Projective(unsafe { *blst_p1_generator() })
685    }
686
687    fn is_identity(&self) -> Choice {
688        unsafe { Choice::from(blst_p1_is_inf(&self.0) as u8) }
689    }
690
691    fn double(&self) -> Self {
692        let mut double = blst_p1::default();
693        unsafe { blst_p1_double(&mut double, &self.0) };
694        G1Projective(double)
695    }
696}
697
698impl WnafGroup for G1Projective {
699    fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
700        const RECOMMENDATIONS: [usize; 12] =
701            [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
702
703        let mut ret = 4;
704        for r in &RECOMMENDATIONS {
705            if num_scalars > *r {
706                ret += 1;
707            } else {
708                break;
709            }
710        }
711
712        ret
713    }
714}
715
716impl PrimeGroup for G1Projective {}
717
718impl Curve for G1Projective {
719    type AffineRepr = G1Affine;
720
721    fn to_affine(&self) -> Self::AffineRepr {
722        self.into()
723    }
724}
725
726impl PrimeCurve for G1Projective {
727    type Affine = G1Affine;
728}
729
730impl PrimeCurveAffine for G1Affine {
731    type Scalar = Scalar;
732    type Curve = G1Projective;
733
734    fn identity() -> Self {
735        G1Affine(blst_p1_affine::default())
736    }
737
738    fn generator() -> Self {
739        G1Affine(unsafe { *blst_p1_affine_generator() })
740    }
741
742    fn is_identity(&self) -> Choice {
743        unsafe { Choice::from(blst_p1_affine_is_inf(&self.0) as u8) }
744    }
745
746    fn to_curve(&self) -> Self::Curve {
747        self.into()
748    }
749}
750
751impl GroupEncoding for G1Projective {
752    type Repr = G1Compressed;
753
754    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
755        Self::from_compressed(&bytes.0)
756    }
757
758    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
759        Self::from_compressed_unchecked(&bytes.0)
760    }
761
762    fn to_bytes(&self) -> Self::Repr {
763        G1Compressed(self.to_compressed())
764    }
765}
766
767impl GroupEncoding for G1Affine {
768    type Repr = G1Compressed;
769
770    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
771        Self::from_compressed(&bytes.0)
772    }
773
774    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
775        Self::from_compressed_unchecked(&bytes.0)
776    }
777
778    fn to_bytes(&self) -> Self::Repr {
779        G1Compressed(self.to_compressed())
780    }
781}
782
783impl UncompressedEncoding for G1Affine {
784    type Uncompressed = G1Uncompressed;
785
786    fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
787        Self::from_uncompressed(&bytes.0)
788    }
789
790    fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
791        Self::from_uncompressed_unchecked(&bytes.0)
792    }
793
794    fn to_uncompressed(&self) -> Self::Uncompressed {
795        G1Uncompressed(self.to_uncompressed())
796    }
797}
798
799#[derive(Copy, Clone, Zeroize)]
800#[repr(transparent)]
801pub struct G1Uncompressed([u8; UNCOMPRESSED_SIZE]);
802
803encoded_point_delegations!(G1Uncompressed);
804
805impl Default for G1Uncompressed {
806    fn default() -> Self {
807        G1Uncompressed([0u8; UNCOMPRESSED_SIZE])
808    }
809}
810
811impl fmt::Debug for G1Uncompressed {
812    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
813        self.0[..].fmt(formatter)
814    }
815}
816
817#[derive(Copy, Clone, Zeroize)]
818#[repr(transparent)]
819pub struct G1Compressed([u8; COMPRESSED_SIZE]);
820
821encoded_point_delegations!(G1Compressed);
822
823impl Default for G1Compressed {
824    fn default() -> Self {
825        G1Compressed([0u8; COMPRESSED_SIZE])
826    }
827}
828
829impl fmt::Debug for G1Compressed {
830    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
831        self.0[..].fmt(formatter)
832    }
833}
834
835impl PairingCurveAffine for G1Affine {
836    type Pair = G2Affine;
837    type PairingResult = Gt;
838
839    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
840        <Bls12 as Engine>::pairing(self, other)
841    }
842}
843
844#[cfg(feature = "gpu")]
845impl ec_gpu::GpuName for G1Affine {
846    fn name() -> String {
847        ec_gpu::name!()
848    }
849}
850
851#[cfg(test)]
852mod tests {
853    #![allow(clippy::eq_op)]
854
855    use super::*;
856
857    use ff::Field;
858    use rand_core::SeedableRng;
859    use rand_xorshift::XorShiftRng;
860
861    #[test]
862    fn curve_tests() {
863        let mut rng = XorShiftRng::from_seed([
864            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
865            0xbc, 0xe5,
866        ]);
867
868        {
869            let z = G1Projective::identity();
870            assert_eq!(z.is_identity().unwrap_u8(), 1);
871        }
872
873        // Negation edge case with zero.
874        {
875            let mut z = G1Projective::identity();
876            z = z.neg();
877            assert_eq!(z.is_identity().unwrap_u8(), 1);
878        }
879
880        // Doubling edge case with zero.
881        {
882            let mut z = G1Projective::identity();
883            z = z.double();
884            assert_eq!(z.is_identity().unwrap_u8(), 1);
885        }
886
887        // Addition edge cases with zero
888        {
889            let mut r = G1Projective::random(&mut rng);
890            let rcopy = r;
891            r += &G1Projective::identity();
892            assert_eq!(r, rcopy);
893            r += &G1Affine::identity();
894            assert_eq!(r, rcopy);
895
896            let mut z = G1Projective::identity();
897            z += &G1Projective::identity();
898            assert_eq!(z.is_identity().unwrap_u8(), 1);
899            z += &G1Affine::identity();
900            assert_eq!(z.is_identity().unwrap_u8(), 1);
901
902            let mut z2 = z;
903            z2 += &r;
904
905            z += &G1Affine::from(r);
906
907            assert_eq!(z, z2);
908            assert_eq!(z, r);
909        }
910
911        // Transformations
912        {
913            let a = G1Projective::random(&mut rng);
914            let b: G1Projective = G1Affine::from(a).into();
915            let c = G1Projective::from(G1Affine::from(G1Projective::from(G1Affine::from(a))));
916
917            assert_eq!(a, b);
918            assert_eq!(b, c);
919        }
920    }
921
922    #[test]
923    fn test_is_on_curve() {
924        assert_eq!(G1Projective::identity().is_on_curve().unwrap_u8(), 1);
925        assert_eq!(G1Projective::generator().is_on_curve().unwrap_u8(), 1);
926
927        assert_eq!(G1Affine::identity().is_on_curve().unwrap_u8(), 1);
928        assert_eq!(G1Affine::generator().is_on_curve().unwrap_u8(), 1);
929
930        let z = Fp::from_raw_unchecked([
931            0xba7afa1f9a6fe250,
932            0xfa0f5b595eafe731,
933            0x3bdc477694c306e7,
934            0x2149be4b3949fa24,
935            0x64aa6e0649b2078c,
936            0x12b108ac33643c3e,
937        ]);
938
939        let generator = G1Affine::generator();
940        let z2 = z.square();
941        let mut test =
942            G1Projective::from_raw_unchecked(generator.x() * z2, generator.y() * (z2 * z), z);
943
944        assert_eq!(test.is_on_curve().unwrap_u8(), 1);
945
946        test.0.x = z.0;
947        assert_eq!(test.is_on_curve().unwrap_u8(), 0);
948    }
949
950    #[test]
951    fn test_affine_point_equality() {
952        let a = G1Affine::generator();
953        let b = G1Affine::identity();
954
955        assert_eq!(a, a);
956        assert_eq!(b, b);
957        assert_ne!(a, b);
958        assert_ne!(b, a);
959    }
960
961    #[test]
962    fn test_projective_point_equality() {
963        let a = G1Projective::generator();
964        let b = G1Projective::identity();
965
966        assert_eq!(a, a);
967        assert_eq!(b, b);
968        assert_ne!(a, b);
969        assert_ne!(b, a);
970
971        let z = Fp::from_raw_unchecked([
972            0xba7afa1f9a6fe250,
973            0xfa0f5b595eafe731,
974            0x3bdc477694c306e7,
975            0x2149be4b3949fa24,
976            0x64aa6e0649b2078c,
977            0x12b108ac33643c3e,
978        ]);
979
980        let z2 = z.square();
981        let mut c = G1Projective::from_raw_unchecked(a.x() * z2, a.y() * (z2 * z), z);
982        assert_eq!(c.is_on_curve().unwrap_u8(), 1);
983
984        assert_eq!(a, c);
985        assert_eq!(c, a);
986        assert_ne!(b, c);
987        assert_ne!(c, b);
988
989        c.0.y = (-c.y()).0;
990        assert_eq!(c.is_on_curve().unwrap_u8(), 1);
991
992        assert_ne!(a, c);
993        assert_ne!(b, c);
994        assert_ne!(c, a);
995        assert_ne!(c, b);
996
997        c.0.y = (-c.y()).0;
998        c.0.x = z.0;
999        assert_eq!(c.is_on_curve().unwrap_u8(), 0);
1000        assert_ne!(a, b);
1001        assert_ne!(a, c);
1002        assert_ne!(b, c);
1003    }
1004
1005    #[test]
1006    fn test_projective_to_affine() {
1007        let a = G1Projective::generator();
1008        let b = G1Projective::identity();
1009
1010        assert_eq!(G1Affine::from(a).is_on_curve().unwrap_u8(), 1);
1011        assert_eq!(G1Affine::from(a).is_identity().unwrap_u8(), 0);
1012        assert_eq!(G1Affine::from(b).is_on_curve().unwrap_u8(), 1);
1013        assert_eq!(G1Affine::from(b).is_identity().unwrap_u8(), 1);
1014
1015        let z = Fp::from_raw_unchecked([
1016            0xba7afa1f9a6fe250,
1017            0xfa0f5b595eafe731,
1018            0x3bdc477694c306e7,
1019            0x2149be4b3949fa24,
1020            0x64aa6e0649b2078c,
1021            0x12b108ac33643c3e,
1022        ]);
1023
1024        let z2 = z.square();
1025        let c = G1Projective::from_raw_unchecked(a.x() * z2, a.y() * (z2 * z), z);
1026
1027        assert_eq!(G1Affine::from(c), G1Affine::generator());
1028    }
1029
1030    #[test]
1031    fn test_affine_to_projective() {
1032        let a = G1Affine::generator();
1033        let b = G1Affine::identity();
1034
1035        assert_eq!(G1Projective::from(a).is_on_curve().unwrap_u8(), 1);
1036        assert_eq!(G1Projective::from(a).is_identity().unwrap_u8(), 0);
1037        assert_eq!(G1Projective::from(b).is_on_curve().unwrap_u8(), 1);
1038        assert_eq!(G1Projective::from(b).is_identity().unwrap_u8(), 1);
1039    }
1040
1041    #[test]
1042    fn test_doubling() {
1043        {
1044            let tmp = G1Projective::identity().double();
1045            assert_eq!(tmp.is_identity().unwrap_u8(), 1);
1046            assert_eq!(tmp.is_on_curve().unwrap_u8(), 1);
1047        }
1048        {
1049            let tmp = G1Projective::generator().double();
1050            assert_eq!(tmp.is_identity().unwrap_u8(), 0);
1051            assert_eq!(tmp.is_on_curve().unwrap_u8(), 1);
1052
1053            assert_eq!(
1054                G1Affine::from(tmp),
1055                G1Affine::from_raw_unchecked(
1056                    Fp::from_raw_unchecked([
1057                        0x53e978ce58a9ba3c,
1058                        0x3ea0583c4f3d65f9,
1059                        0x4d20bb47f0012960,
1060                        0xa54c664ae5b2b5d9,
1061                        0x26b552a39d7eb21f,
1062                        0x8895d26e68785
1063                    ]),
1064                    Fp::from_raw_unchecked([
1065                        0x70110b3298293940,
1066                        0xda33c5393f1f6afc,
1067                        0xb86edfd16a5aa785,
1068                        0xaec6d1c9e7b1c895,
1069                        0x25cfc2b522d11720,
1070                        0x6361c83f8d09b15
1071                    ]),
1072                    false
1073                )
1074            );
1075        }
1076    }
1077
1078    #[test]
1079    fn test_projective_addition() {
1080        {
1081            let a = G1Projective::identity();
1082            let b = G1Projective::identity();
1083            let c = a + b;
1084            assert_eq!(c.is_identity().unwrap_u8(), 1);
1085            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1086        }
1087        {
1088            let a = G1Projective::identity();
1089            let mut b = G1Projective::generator();
1090            {
1091                let z = Fp::from_raw_unchecked([
1092                    0xba7afa1f9a6fe250,
1093                    0xfa0f5b595eafe731,
1094                    0x3bdc477694c306e7,
1095                    0x2149be4b3949fa24,
1096                    0x64aa6e0649b2078c,
1097                    0x12b108ac33643c3e,
1098                ]);
1099
1100                let z2 = z.square();
1101                b = G1Projective::from_raw_unchecked(b.x() * (z2), b.y() * (z2 * z), z);
1102            }
1103            let c = a + b;
1104            assert_eq!(c.is_identity().unwrap_u8(), 0);
1105            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1106            assert_eq!(c, G1Projective::generator());
1107        }
1108        {
1109            let a = G1Projective::identity();
1110            let mut b = G1Projective::generator();
1111            {
1112                let z = Fp::from_raw_unchecked([
1113                    0xba7afa1f9a6fe250,
1114                    0xfa0f5b595eafe731,
1115                    0x3bdc477694c306e7,
1116                    0x2149be4b3949fa24,
1117                    0x64aa6e0649b2078c,
1118                    0x12b108ac33643c3e,
1119                ]);
1120
1121                let z2 = z.square();
1122                b = G1Projective::from_raw_unchecked(b.x() * (z2), b.y() * (z2 * z), z);
1123            }
1124            let c = b + a;
1125            assert_eq!(c.is_identity().unwrap_u8(), 0);
1126            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1127            assert_eq!(c, G1Projective::generator());
1128        }
1129        {
1130            let a = G1Projective::generator().double().double(); // 4P
1131            let b = G1Projective::generator().double(); // 2P
1132            let c = a + b;
1133
1134            let mut d = G1Projective::generator();
1135            for _ in 0..5 {
1136                d += G1Projective::generator();
1137            }
1138            assert_eq!(c.is_identity().unwrap_u8(), 0);
1139            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1140            assert_eq!(d.is_identity().unwrap_u8(), 0);
1141            assert_eq!(d.is_on_curve().unwrap_u8(), 1);
1142            assert_eq!(c, d);
1143        }
1144
1145        // Degenerate case
1146        {
1147            let mut beta = Fp::from_raw_unchecked([
1148                0xcd03c9e48671f071,
1149                0x5dab22461fcda5d2,
1150                0x587042afd3851b95,
1151                0x8eb60ebe01bacb9e,
1152                0x3f97d6e83d050d2,
1153                0x18f0206554638741,
1154            ]);
1155            beta = beta.square();
1156            let a = G1Projective::generator().double().double();
1157            let b = G1Projective::from_raw_unchecked(a.x() * beta, -a.y(), a.z());
1158            assert_eq!(a.is_on_curve().unwrap_u8(), 1);
1159            assert_eq!(b.is_on_curve().unwrap_u8(), 1);
1160
1161            let c = a + b;
1162            assert_eq!(
1163                G1Affine::from(c),
1164                G1Affine::from(G1Projective::from_raw_unchecked(
1165                    Fp::from_raw_unchecked([
1166                        0x29e1e987ef68f2d0,
1167                        0xc5f3ec531db03233,
1168                        0xacd6c4b6ca19730f,
1169                        0x18ad9e827bc2bab7,
1170                        0x46e3b2c5785cc7a9,
1171                        0x7e571d42d22ddd6
1172                    ]),
1173                    Fp::from_raw_unchecked([
1174                        0x94d117a7e5a539e7,
1175                        0x8e17ef673d4b5d22,
1176                        0x9d746aaf508a33ea,
1177                        0x8c6d883d2516c9a2,
1178                        0xbc3b8d5fb0447f7,
1179                        0x7bfa4c7210f4f44
1180                    ]),
1181                    Fp::ONE,
1182                ))
1183            );
1184            assert_eq!(c.is_identity().unwrap_u8(), 0);
1185            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1186        }
1187    }
1188
1189    #[test]
1190    fn test_mixed_addition() {
1191        {
1192            let a = G1Affine::identity();
1193            let b = G1Projective::identity();
1194            let c = a + b;
1195            assert_eq!(c.is_identity().unwrap_u8(), 1);
1196            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1197        }
1198        {
1199            let a = G1Affine::identity();
1200            let mut b = G1Projective::generator();
1201            {
1202                let z = Fp::from_raw_unchecked([
1203                    0xba7afa1f9a6fe250,
1204                    0xfa0f5b595eafe731,
1205                    0x3bdc477694c306e7,
1206                    0x2149be4b3949fa24,
1207                    0x64aa6e0649b2078c,
1208                    0x12b108ac33643c3e,
1209                ]);
1210
1211                let z2 = z.square();
1212                b = G1Projective::from_raw_unchecked(b.x() * (z2), b.y() * (z2 * z), z);
1213            }
1214            let c = a + b;
1215            assert_eq!(c.is_identity().unwrap_u8(), 0);
1216            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1217            assert_eq!(c, G1Projective::generator());
1218        }
1219        {
1220            let a = G1Affine::identity();
1221            let mut b = G1Projective::generator();
1222            {
1223                let z = Fp::from_raw_unchecked([
1224                    0xba7afa1f9a6fe250,
1225                    0xfa0f5b595eafe731,
1226                    0x3bdc477694c306e7,
1227                    0x2149be4b3949fa24,
1228                    0x64aa6e0649b2078c,
1229                    0x12b108ac33643c3e,
1230                ]);
1231
1232                let z2 = z.square();
1233                b = G1Projective::from_raw_unchecked(b.x() * (z2), b.y() * (z2 * z), z);
1234            }
1235            let c = b + a;
1236            assert_eq!(c.is_identity().unwrap_u8(), 0);
1237            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1238            assert_eq!(c, G1Projective::generator());
1239        }
1240        {
1241            let a = G1Projective::generator().double().double(); // 4P
1242            let b = G1Projective::generator().double(); // 2P
1243            let c = a + b;
1244
1245            let mut d = G1Projective::generator();
1246            for _ in 0..5 {
1247                d += G1Affine::generator();
1248            }
1249            assert_eq!(c.is_identity().unwrap_u8(), 0);
1250            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1251            assert_eq!(d.is_identity().unwrap_u8(), 0);
1252            assert_eq!(d.is_on_curve().unwrap_u8(), 1);
1253            assert_eq!(c, d);
1254        }
1255
1256        // Degenerate case
1257        {
1258            let mut beta = Fp::from_raw_unchecked([
1259                0xcd03c9e48671f071,
1260                0x5dab22461fcda5d2,
1261                0x587042afd3851b95,
1262                0x8eb60ebe01bacb9e,
1263                0x3f97d6e83d050d2,
1264                0x18f0206554638741,
1265            ]);
1266            beta = beta.square();
1267            let a = G1Projective::generator().double().double();
1268            let b = G1Projective::from_raw_unchecked(a.x() * beta, -a.y(), a.z());
1269            let a = G1Affine::from(a);
1270            assert_eq!(a.is_on_curve().unwrap_u8(), 1);
1271            assert_eq!(b.is_on_curve().unwrap_u8(), 1);
1272
1273            let c = a + b;
1274            assert_eq!(
1275                G1Affine::from(c),
1276                G1Affine::from(G1Projective::from_raw_unchecked(
1277                    Fp::from_raw_unchecked([
1278                        0x29e1e987ef68f2d0,
1279                        0xc5f3ec531db03233,
1280                        0xacd6c4b6ca19730f,
1281                        0x18ad9e827bc2bab7,
1282                        0x46e3b2c5785cc7a9,
1283                        0x7e571d42d22ddd6
1284                    ]),
1285                    Fp::from_raw_unchecked([
1286                        0x94d117a7e5a539e7,
1287                        0x8e17ef673d4b5d22,
1288                        0x9d746aaf508a33ea,
1289                        0x8c6d883d2516c9a2,
1290                        0xbc3b8d5fb0447f7,
1291                        0x7bfa4c7210f4f44
1292                    ]),
1293                    Fp::ONE
1294                ))
1295            );
1296            assert_eq!(c.is_identity().unwrap_u8(), 0);
1297            assert_eq!(c.is_on_curve().unwrap_u8(), 1);
1298        }
1299    }
1300
1301    #[test]
1302    fn test_projective_negation_and_subtraction() {
1303        let a = G1Projective::generator().double();
1304        assert_eq!(a + (-a), G1Projective::identity());
1305        assert_eq!(a + (-a), a - a);
1306    }
1307
1308    #[test]
1309    fn test_affine_projective_negation_and_subtraction() {
1310        let a = G1Affine::generator();
1311        assert_eq!(G1Projective::from(a) + (-a), G1Projective::identity());
1312        assert_eq!(G1Projective::from(a) + (-a), G1Projective::from(a) - a);
1313    }
1314
1315    #[test]
1316    fn test_projective_scalar_multiplication() {
1317        let g = G1Projective::generator();
1318        let a = Scalar(blst::blst_fr {
1319            l: [
1320                0x2b568297a56da71c,
1321                0xd8c39ecb0ef375d1,
1322                0x435c38da67bfbf96,
1323                0x8088a05026b659b2,
1324            ],
1325        });
1326        let b = Scalar(blst_fr {
1327            l: [
1328                0x785fdd9b26ef8b85,
1329                0xc997f25837695c18,
1330                0x4c8dbc39e7b756c1,
1331                0x70d9b6cc6d87df20,
1332            ],
1333        });
1334        let c = a * b;
1335
1336        assert_eq!((g * a) * b, g * c);
1337    }
1338
1339    #[test]
1340    fn test_affine_scalar_multiplication() {
1341        let g = G1Affine::generator();
1342        let a = Scalar(blst::blst_fr {
1343            l: [
1344                0x2b568297a56da71c,
1345                0xd8c39ecb0ef375d1,
1346                0x435c38da67bfbf96,
1347                0x8088a05026b659b2,
1348            ],
1349        });
1350        let b = Scalar(blst::blst_fr {
1351            l: [
1352                0x785fdd9b26ef8b85,
1353                0xc997f25837695c18,
1354                0x4c8dbc39e7b756c1,
1355                0x70d9b6cc6d87df20,
1356            ],
1357        });
1358        let c = a * b;
1359
1360        assert_eq!(G1Affine::from(g * a) * b, g * c);
1361    }
1362
1363    #[test]
1364    fn g1_curve_tests() {
1365        use group::tests::curve_tests;
1366        curve_tests::<G1Projective>();
1367    }
1368
1369    #[test]
1370    fn test_g1_is_identity() {
1371        assert_eq!(G1Projective::identity().is_identity().unwrap_u8(), 1);
1372        assert_eq!(G1Projective::generator().is_identity().unwrap_u8(), 0);
1373        assert_eq!(G1Affine::identity().is_identity().unwrap_u8(), 1);
1374        assert_eq!(G1Affine::generator().is_identity().unwrap_u8(), 0);
1375    }
1376
1377    #[test]
1378    fn test_g1_serialization_roundtrip() {
1379        let mut rng = XorShiftRng::from_seed([
1380            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1381            0xbc, 0xe5,
1382        ]);
1383
1384        for _ in 0..100 {
1385            let el: G1Affine = G1Projective::random(&mut rng).into();
1386            let c = el.to_compressed();
1387            assert_eq!(G1Affine::from_compressed(&c).unwrap(), el);
1388            assert_eq!(G1Affine::from_compressed_unchecked(&c).unwrap(), el);
1389
1390            let u = el.to_uncompressed();
1391            assert_eq!(G1Affine::from_uncompressed(&u).unwrap(), el);
1392            assert_eq!(G1Affine::from_uncompressed_unchecked(&u).unwrap(), el);
1393
1394            let c = el.to_bytes();
1395            assert_eq!(G1Affine::from_bytes(&c).unwrap(), el);
1396            assert_eq!(G1Affine::from_bytes_unchecked(&c).unwrap(), el);
1397
1398            let el = G1Projective::random(&mut rng);
1399            let c = el.to_compressed();
1400            assert_eq!(G1Projective::from_compressed(&c).unwrap(), el);
1401            assert_eq!(G1Projective::from_compressed_unchecked(&c).unwrap(), el);
1402
1403            let u = el.to_uncompressed();
1404            assert_eq!(G1Projective::from_uncompressed(&u).unwrap(), el);
1405            assert_eq!(G1Projective::from_uncompressed_unchecked(&u).unwrap(), el);
1406
1407            let c = el.to_bytes();
1408            assert_eq!(G1Projective::from_bytes(&c).unwrap(), el);
1409            assert_eq!(G1Projective::from_bytes_unchecked(&c).unwrap(), el);
1410        }
1411    }
1412
1413    #[test]
1414    fn test_multi_exp() {
1415        const SIZE: usize = 10;
1416        let mut rng = XorShiftRng::from_seed([
1417            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
1418            0xbc, 0xe5,
1419        ]);
1420
1421        let points: Vec<G1Projective> = (0..SIZE).map(|_| G1Projective::random(&mut rng)).collect();
1422        let scalars: Vec<Scalar> = (0..SIZE).map(|_| Scalar::random(&mut rng)).collect();
1423
1424        let mut naive = points[0] * scalars[0];
1425        for i in 1..SIZE {
1426            naive += points[i] * scalars[i];
1427        }
1428
1429        let pippenger = G1Projective::multi_exp(points.as_slice(), scalars.as_slice());
1430
1431        assert_eq!(naive, pippenger);
1432    }
1433}