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