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