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};
18use zeroize::Zeroize;
19
20use crate::{Bls12, Engine, G2Affine, Gt, PairingCurveAffine, Scalar, fp::Fp};
21
22#[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 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 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 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 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 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 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 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 pub fn is_torsion_free(&self) -> Choice {
360 unsafe { Choice::from(blst_p1_affine_in_g1(&self.0) as u8) }
361 }
362
363 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 let raw = blst_p1_affine { x: x.0, y: y.0 };
372
373 G1Affine(raw)
374 }
375
376 pub fn x(&self) -> Fp {
378 Fp(self.0.x)
379 }
380
381 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#[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 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 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 pub fn from_uncompressed(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
535 G1Affine::from_uncompressed(bytes).map(Into::into)
536 }
537
538 pub fn from_uncompressed_unchecked(bytes: &[u8; UNCOMPRESSED_SIZE]) -> CtOption<Self> {
544 G1Affine::from_uncompressed_unchecked(bytes).map(Into::into)
545 }
546
547 pub fn from_compressed(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
549 G1Affine::from_compressed(bytes).map(Into::into)
550 }
551
552 pub fn from_compressed_unchecked(bytes: &[u8; COMPRESSED_SIZE]) -> CtOption<Self> {
558 G1Affine::from_compressed_unchecked(bytes).map(Into::into)
559 }
560
561 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 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 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 pub fn x(&self) -> Fp {
600 Fp(self.0.x)
601 }
602
603 pub fn y(&self) -> Fp {
605 Fp(self.0.y)
606 }
607
608 pub fn z(&self) -> Fp {
610 Fp(self.0.z)
611 }
612
613 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 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 {
875 let mut z = G1Projective::identity();
876 z = z.neg();
877 assert_eq!(z.is_identity().unwrap_u8(), 1);
878 }
879
880 {
882 let mut z = G1Projective::identity();
883 z = z.double();
884 assert_eq!(z.is_identity().unwrap_u8(), 1);
885 }
886
887 {
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 {
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(); let b = G1Projective::generator().double(); 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 {
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(); let b = G1Projective::generator().double(); 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 {
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}