1use core::borrow::Borrow;
4use core::fmt;
5use core::iter::Sum;
6use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use group::{
8 prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
9 Curve, Group, GroupEncoding, UncompressedEncoding,
10};
11use rand_core::RngCore;
12use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
13
14#[cfg(feature = "alloc")]
15use group::WnafGroup;
16
17use crate::fp::Fp;
18use crate::Scalar;
19
20#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
27#[derive(Copy, Clone, Debug)]
28pub struct G1Affine {
29 pub(crate) x: Fp,
30 pub(crate) y: Fp,
31 infinity: Choice,
32}
33
34impl Default for G1Affine {
35 fn default() -> G1Affine {
36 G1Affine::identity()
37 }
38}
39
40#[cfg(feature = "zeroize")]
41impl zeroize::DefaultIsZeroes for G1Affine {}
42
43impl fmt::Display for G1Affine {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 write!(f, "{:?}", self)
46 }
47}
48
49impl<'a> From<&'a G1Projective> for G1Affine {
50 fn from(p: &'a G1Projective) -> G1Affine {
51 let zinv = p.z.invert().unwrap_or(Fp::zero());
52 let x = p.x * zinv;
53 let y = p.y * zinv;
54
55 let tmp = G1Affine {
56 x,
57 y,
58 infinity: Choice::from(0u8),
59 };
60
61 G1Affine::conditional_select(&tmp, &G1Affine::identity(), zinv.is_zero())
62 }
63}
64
65impl From<G1Projective> for G1Affine {
66 fn from(p: G1Projective) -> G1Affine {
67 G1Affine::from(&p)
68 }
69}
70
71impl ConstantTimeEq for G1Affine {
72 fn ct_eq(&self, other: &Self) -> Choice {
73 (self.infinity & other.infinity)
78 | ((!self.infinity)
79 & (!other.infinity)
80 & self.x.ct_eq(&other.x)
81 & self.y.ct_eq(&other.y))
82 }
83}
84
85impl ConditionallySelectable for G1Affine {
86 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
87 G1Affine {
88 x: Fp::conditional_select(&a.x, &b.x, choice),
89 y: Fp::conditional_select(&a.y, &b.y, choice),
90 infinity: Choice::conditional_select(&a.infinity, &b.infinity, choice),
91 }
92 }
93}
94
95impl Eq for G1Affine {}
96impl PartialEq for G1Affine {
97 #[inline]
98 fn eq(&self, other: &Self) -> bool {
99 bool::from(self.ct_eq(other))
100 }
101}
102
103impl<'a> Neg for &'a G1Affine {
104 type Output = G1Affine;
105
106 #[inline]
107 fn neg(self) -> G1Affine {
108 G1Affine {
109 x: self.x,
110 y: Fp::conditional_select(&-self.y, &Fp::one(), self.infinity),
111 infinity: self.infinity,
112 }
113 }
114}
115
116impl Neg for G1Affine {
117 type Output = G1Affine;
118
119 #[inline]
120 fn neg(self) -> G1Affine {
121 -&self
122 }
123}
124
125impl<'a, 'b> Add<&'b G1Projective> for &'a G1Affine {
126 type Output = G1Projective;
127
128 #[inline]
129 fn add(self, rhs: &'b G1Projective) -> G1Projective {
130 rhs.add_mixed(self)
131 }
132}
133
134impl<'a, 'b> Add<&'b G1Affine> for &'a G1Projective {
135 type Output = G1Projective;
136
137 #[inline]
138 fn add(self, rhs: &'b G1Affine) -> G1Projective {
139 self.add_mixed(rhs)
140 }
141}
142
143impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Affine {
144 type Output = G1Projective;
145
146 #[inline]
147 fn sub(self, rhs: &'b G1Projective) -> G1Projective {
148 self + (-rhs)
149 }
150}
151
152impl<'a, 'b> Sub<&'b G1Affine> for &'a G1Projective {
153 type Output = G1Projective;
154
155 #[inline]
156 fn sub(self, rhs: &'b G1Affine) -> G1Projective {
157 self + (-rhs)
158 }
159}
160
161impl<T> Sum<T> for G1Projective
162where
163 T: Borrow<G1Projective>,
164{
165 fn sum<I>(iter: I) -> Self
166 where
167 I: Iterator<Item = T>,
168 {
169 iter.fold(Self::identity(), |acc, item| acc + item.borrow())
170 }
171}
172
173impl_binops_additive!(G1Projective, G1Affine);
174impl_binops_additive_specify_output!(G1Affine, G1Projective, G1Projective);
175
176const B: Fp = Fp::from_raw_unchecked([
177 0xaa27_0000_000c_fff3,
178 0x53cc_0032_fc34_000a,
179 0x478f_e97a_6b0a_807f,
180 0xb1d3_7ebe_e6ba_24d7,
181 0x8ec9_733b_bf78_ab2f,
182 0x09d6_4551_3d83_de7e,
183]);
184
185impl G1Affine {
186 pub fn identity() -> G1Affine {
188 G1Affine {
189 x: Fp::zero(),
190 y: Fp::one(),
191 infinity: Choice::from(1u8),
192 }
193 }
194
195 pub fn generator() -> G1Affine {
198 G1Affine {
199 x: Fp::from_raw_unchecked([
200 0x5cb3_8790_fd53_0c16,
201 0x7817_fc67_9976_fff5,
202 0x154f_95c7_143b_a1c1,
203 0xf0ae_6acd_f3d0_e747,
204 0xedce_6ecc_21db_f440,
205 0x1201_7741_9e0b_fb75,
206 ]),
207 y: Fp::from_raw_unchecked([
208 0xbaac_93d5_0ce7_2271,
209 0x8c22_631a_7918_fd8e,
210 0xdd59_5f13_5707_25ce,
211 0x51ac_5829_5040_5194,
212 0x0e1c_8c3f_ad00_59c0,
213 0x0bbc_3efc_5008_a26a,
214 ]),
215 infinity: Choice::from(0u8),
216 }
217 }
218
219 pub fn to_compressed(&self) -> [u8; 48] {
222 let mut res = Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes();
225
226 res[0] |= 1u8 << 7;
228
229 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
231
232 res[0] |= u8::conditional_select(
236 &0u8,
237 &(1u8 << 5),
238 (!self.infinity) & self.y.lexicographically_largest(),
239 );
240
241 res
242 }
243
244 pub fn to_uncompressed(&self) -> [u8; 96] {
247 let mut res = [0; 96];
248
249 res[0..48].copy_from_slice(
250 &Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes()[..],
251 );
252 res[48..96].copy_from_slice(
253 &Fp::conditional_select(&self.y, &Fp::zero(), self.infinity).to_bytes()[..],
254 );
255
256 res[0] |= u8::conditional_select(&0u8, &(1u8 << 6), self.infinity);
258
259 res
260 }
261
262 pub fn from_uncompressed(bytes: &[u8; 96]) -> CtOption<Self> {
265 Self::from_uncompressed_unchecked(bytes)
266 .and_then(|p| CtOption::new(p, p.is_on_curve() & p.is_torsion_free()))
267 }
268
269 pub fn from_uncompressed_unchecked(bytes: &[u8; 96]) -> CtOption<Self> {
274 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
276 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
277 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
278
279 let x = {
281 let mut tmp = [0; 48];
282 tmp.copy_from_slice(&bytes[0..48]);
283
284 tmp[0] &= 0b0001_1111;
286
287 Fp::from_bytes(&tmp)
288 };
289
290 let y = {
292 let mut tmp = [0; 48];
293 tmp.copy_from_slice(&bytes[48..96]);
294
295 Fp::from_bytes(&tmp)
296 };
297
298 x.and_then(|x| {
299 y.and_then(|y| {
300 let p = G1Affine::conditional_select(
302 &G1Affine {
303 x,
304 y,
305 infinity: infinity_flag_set,
306 },
307 &G1Affine::identity(),
308 infinity_flag_set,
309 );
310
311 CtOption::new(
312 p,
313 ((!infinity_flag_set) | (infinity_flag_set & x.is_zero() & y.is_zero())) &
315 (!compression_flag_set) &
317 (!sort_flag_set),
319 )
320 })
321 })
322 }
323
324 pub fn from_compressed(bytes: &[u8; 48]) -> CtOption<Self> {
327 Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_torsion_free()))
331 }
332
333 pub fn from_compressed_unchecked(bytes: &[u8; 48]) -> CtOption<Self> {
338 let compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
340 let infinity_flag_set = Choice::from((bytes[0] >> 6) & 1);
341 let sort_flag_set = Choice::from((bytes[0] >> 5) & 1);
342
343 let x = {
345 let mut tmp = [0; 48];
346 tmp.copy_from_slice(&bytes[0..48]);
347
348 tmp[0] &= 0b0001_1111;
350
351 Fp::from_bytes(&tmp)
352 };
353
354 x.and_then(|x| {
355 CtOption::new(
362 G1Affine::identity(),
363 infinity_flag_set & compression_flag_set & (!sort_flag_set) & x.is_zero(), )
368 .or_else(|| {
369 ((x.square() * x) + B).sqrt().and_then(|y| {
371 let y = Fp::conditional_select(
373 &y,
374 &-y,
375 y.lexicographically_largest() ^ sort_flag_set,
376 );
377
378 CtOption::new(
379 G1Affine {
380 x,
381 y,
382 infinity: infinity_flag_set,
383 },
384 (!infinity_flag_set) & compression_flag_set, )
387 })
388 })
389 })
390 }
391
392 #[inline]
394 pub fn is_identity(&self) -> Choice {
395 self.infinity
396 }
397
398 pub fn is_torsion_free(&self) -> Choice {
402 let minus_x_squared_times_p = G1Projective::from(self).mul_by_x().mul_by_x().neg();
408 let endomorphism_p = endomorphism(self);
409 minus_x_squared_times_p.ct_eq(&G1Projective::from(endomorphism_p))
410 }
411
412 pub fn is_on_curve(&self) -> Choice {
415 (self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
417 }
418}
419
420pub const BETA: Fp = Fp::from_raw_unchecked([
422 0x30f1_361b_798a_64e8,
423 0xf3b8_ddab_7ece_5a2a,
424 0x16a8_ca3a_c615_77f7,
425 0xc26a_2ff8_74fd_029b,
426 0x3636_b766_6070_1c6e,
427 0x051b_a4ab_241b_6160,
428]);
429
430fn endomorphism(p: &G1Affine) -> G1Affine {
431 let mut res = *p;
435 res.x *= BETA;
436 res
437}
438
439#[cfg_attr(docsrs, doc(cfg(feature = "groups")))]
441#[derive(Copy, Clone, Debug)]
442pub struct G1Projective {
443 pub(crate) x: Fp,
444 pub(crate) y: Fp,
445 pub(crate) z: Fp,
446}
447
448impl Default for G1Projective {
449 fn default() -> G1Projective {
450 G1Projective::identity()
451 }
452}
453
454#[cfg(feature = "zeroize")]
455impl zeroize::DefaultIsZeroes for G1Projective {}
456
457impl fmt::Display for G1Projective {
458 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
459 write!(f, "{:?}", self)
460 }
461}
462
463impl<'a> From<&'a G1Affine> for G1Projective {
464 fn from(p: &'a G1Affine) -> G1Projective {
465 G1Projective {
466 x: p.x,
467 y: p.y,
468 z: Fp::conditional_select(&Fp::one(), &Fp::zero(), p.infinity),
469 }
470 }
471}
472
473impl From<G1Affine> for G1Projective {
474 fn from(p: G1Affine) -> G1Projective {
475 G1Projective::from(&p)
476 }
477}
478
479impl ConstantTimeEq for G1Projective {
480 fn ct_eq(&self, other: &Self) -> Choice {
481 let x1 = self.x * other.z;
484 let x2 = other.x * self.z;
485
486 let y1 = self.y * other.z;
487 let y2 = other.y * self.z;
488
489 let self_is_zero = self.z.is_zero();
490 let other_is_zero = other.z.is_zero();
491
492 (self_is_zero & other_is_zero) | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
494 }
496}
497
498impl ConditionallySelectable for G1Projective {
499 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
500 G1Projective {
501 x: Fp::conditional_select(&a.x, &b.x, choice),
502 y: Fp::conditional_select(&a.y, &b.y, choice),
503 z: Fp::conditional_select(&a.z, &b.z, choice),
504 }
505 }
506}
507
508impl Eq for G1Projective {}
509impl PartialEq for G1Projective {
510 #[inline]
511 fn eq(&self, other: &Self) -> bool {
512 bool::from(self.ct_eq(other))
513 }
514}
515
516impl<'a> Neg for &'a G1Projective {
517 type Output = G1Projective;
518
519 #[inline]
520 fn neg(self) -> G1Projective {
521 G1Projective {
522 x: self.x,
523 y: -self.y,
524 z: self.z,
525 }
526 }
527}
528
529impl Neg for G1Projective {
530 type Output = G1Projective;
531
532 #[inline]
533 fn neg(self) -> G1Projective {
534 -&self
535 }
536}
537
538impl<'a, 'b> Add<&'b G1Projective> for &'a G1Projective {
539 type Output = G1Projective;
540
541 #[inline]
542 fn add(self, rhs: &'b G1Projective) -> G1Projective {
543 self.add(rhs)
544 }
545}
546
547impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Projective {
548 type Output = G1Projective;
549
550 #[inline]
551 fn sub(self, rhs: &'b G1Projective) -> G1Projective {
552 self + (-rhs)
553 }
554}
555
556impl<'a, 'b> Mul<&'b Scalar> for &'a G1Projective {
557 type Output = G1Projective;
558
559 fn mul(self, other: &'b Scalar) -> Self::Output {
560 self.multiply(&other.to_bytes())
561 }
562}
563
564impl<'a, 'b> Mul<&'b G1Projective> for &'a Scalar {
565 type Output = G1Projective;
566
567 #[inline]
568 fn mul(self, rhs: &'b G1Projective) -> Self::Output {
569 rhs * self
570 }
571}
572
573impl<'a, 'b> Mul<&'b Scalar> for &'a G1Affine {
574 type Output = G1Projective;
575
576 fn mul(self, other: &'b Scalar) -> Self::Output {
577 G1Projective::from(self).multiply(&other.to_bytes())
578 }
579}
580
581impl<'a, 'b> Mul<&'b G1Affine> for &'a Scalar {
582 type Output = G1Projective;
583
584 #[inline]
585 fn mul(self, rhs: &'b G1Affine) -> Self::Output {
586 rhs * self
587 }
588}
589
590impl_binops_additive!(G1Projective, G1Projective);
591impl_binops_multiplicative!(G1Projective, Scalar);
592impl_binops_multiplicative_mixed!(G1Affine, Scalar, G1Projective);
593impl_binops_multiplicative_mixed!(Scalar, G1Affine, G1Projective);
594impl_binops_multiplicative_mixed!(Scalar, G1Projective, G1Projective);
595
596#[inline(always)]
597fn mul_by_3b(a: Fp) -> Fp {
598 let a = a + a; let a = a + a; a + a + a }
602
603impl G1Projective {
604 pub fn identity() -> G1Projective {
606 G1Projective {
607 x: Fp::zero(),
608 y: Fp::one(),
609 z: Fp::zero(),
610 }
611 }
612
613 pub fn generator() -> G1Projective {
616 G1Projective {
617 x: Fp::from_raw_unchecked([
618 0x5cb3_8790_fd53_0c16,
619 0x7817_fc67_9976_fff5,
620 0x154f_95c7_143b_a1c1,
621 0xf0ae_6acd_f3d0_e747,
622 0xedce_6ecc_21db_f440,
623 0x1201_7741_9e0b_fb75,
624 ]),
625 y: Fp::from_raw_unchecked([
626 0xbaac_93d5_0ce7_2271,
627 0x8c22_631a_7918_fd8e,
628 0xdd59_5f13_5707_25ce,
629 0x51ac_5829_5040_5194,
630 0x0e1c_8c3f_ad00_59c0,
631 0x0bbc_3efc_5008_a26a,
632 ]),
633 z: Fp::one(),
634 }
635 }
636
637 pub fn double(&self) -> G1Projective {
639 let t0 = self.y.square();
642 let z3 = t0 + t0;
643 let z3 = z3 + z3;
644 let z3 = z3 + z3;
645 let t1 = self.y * self.z;
646 let t2 = self.z.square();
647 let t2 = mul_by_3b(t2);
648 let x3 = t2 * z3;
649 let y3 = t0 + t2;
650 let z3 = t1 * z3;
651 let t1 = t2 + t2;
652 let t2 = t1 + t2;
653 let t0 = t0 - t2;
654 let y3 = t0 * y3;
655 let y3 = x3 + y3;
656 let t1 = self.x * self.y;
657 let x3 = t0 * t1;
658 let x3 = x3 + x3;
659
660 let tmp = G1Projective {
661 x: x3,
662 y: y3,
663 z: z3,
664 };
665
666 G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity())
667 }
668
669 pub fn add(&self, rhs: &G1Projective) -> G1Projective {
671 let t0 = self.x * rhs.x;
674 let t1 = self.y * rhs.y;
675 let t2 = self.z * rhs.z;
676 let t3 = self.x + self.y;
677 let t4 = rhs.x + rhs.y;
678 let t3 = t3 * t4;
679 let t4 = t0 + t1;
680 let t3 = t3 - t4;
681 let t4 = self.y + self.z;
682 let x3 = rhs.y + rhs.z;
683 let t4 = t4 * x3;
684 let x3 = t1 + t2;
685 let t4 = t4 - x3;
686 let x3 = self.x + self.z;
687 let y3 = rhs.x + rhs.z;
688 let x3 = x3 * y3;
689 let y3 = t0 + t2;
690 let y3 = x3 - y3;
691 let x3 = t0 + t0;
692 let t0 = x3 + t0;
693 let t2 = mul_by_3b(t2);
694 let z3 = t1 + t2;
695 let t1 = t1 - t2;
696 let y3 = mul_by_3b(y3);
697 let x3 = t4 * y3;
698 let t2 = t3 * t1;
699 let x3 = t2 - x3;
700 let y3 = y3 * t0;
701 let t1 = t1 * z3;
702 let y3 = t1 + y3;
703 let t0 = t0 * t3;
704 let z3 = z3 * t4;
705 let z3 = z3 + t0;
706
707 G1Projective {
708 x: x3,
709 y: y3,
710 z: z3,
711 }
712 }
713
714 pub fn add_mixed(&self, rhs: &G1Affine) -> G1Projective {
716 let t0 = self.x * rhs.x;
719 let t1 = self.y * rhs.y;
720 let t3 = rhs.x + rhs.y;
721 let t4 = self.x + self.y;
722 let t3 = t3 * t4;
723 let t4 = t0 + t1;
724 let t3 = t3 - t4;
725 let t4 = rhs.y * self.z;
726 let t4 = t4 + self.y;
727 let y3 = rhs.x * self.z;
728 let y3 = y3 + self.x;
729 let x3 = t0 + t0;
730 let t0 = x3 + t0;
731 let t2 = mul_by_3b(self.z);
732 let z3 = t1 + t2;
733 let t1 = t1 - t2;
734 let y3 = mul_by_3b(y3);
735 let x3 = t4 * y3;
736 let t2 = t3 * t1;
737 let x3 = t2 - x3;
738 let y3 = y3 * t0;
739 let t1 = t1 * z3;
740 let y3 = t1 + y3;
741 let t0 = t0 * t3;
742 let z3 = z3 * t4;
743 let z3 = z3 + t0;
744
745 let tmp = G1Projective {
746 x: x3,
747 y: y3,
748 z: z3,
749 };
750
751 G1Projective::conditional_select(&tmp, self, rhs.is_identity())
752 }
753
754 fn multiply(&self, by: &[u8; 32]) -> G1Projective {
755 let mut acc = G1Projective::identity();
756
757 for bit in by
764 .iter()
765 .rev()
766 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
767 .skip(1)
768 {
769 acc = acc.double();
770 acc = G1Projective::conditional_select(&acc, &(acc + self), bit);
771 }
772
773 acc
774 }
775
776 fn mul_by_x(&self) -> G1Projective {
778 let mut xself = G1Projective::identity();
779 let mut x = crate::BLS_X >> 1;
781 let mut tmp = *self;
782 while x != 0 {
783 tmp = tmp.double();
784
785 if x % 2 == 1 {
786 xself += tmp;
787 }
788 x >>= 1;
789 }
790 if crate::BLS_X_IS_NEGATIVE {
792 xself = -xself;
793 }
794 xself
795 }
796
797 pub fn clear_cofactor(&self) -> G1Projective {
801 self - self.mul_by_x()
802 }
803
804 pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) {
807 assert_eq!(p.len(), q.len());
808
809 let mut acc = Fp::one();
810 for (p, q) in p.iter().zip(q.iter_mut()) {
811 q.x = acc;
814
815 acc = Fp::conditional_select(&(acc * p.z), &acc, p.is_identity());
817 }
818
819 acc = acc.invert().unwrap();
822
823 for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
824 let skip = p.is_identity();
825
826 let tmp = q.x * acc;
828
829 acc = Fp::conditional_select(&(acc * p.z), &acc, skip);
831
832 q.x = p.x * tmp;
834 q.y = p.y * tmp;
835 q.infinity = Choice::from(0u8);
836
837 *q = G1Affine::conditional_select(q, &G1Affine::identity(), skip);
838 }
839 }
840
841 #[inline]
843 pub fn is_identity(&self) -> Choice {
844 self.z.is_zero()
845 }
846
847 pub fn is_on_curve(&self) -> Choice {
850 (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B))
853 | self.z.is_zero()
854 }
855}
856
857#[derive(Clone, Copy)]
858pub struct G1Compressed([u8; 48]);
859
860impl fmt::Debug for G1Compressed {
861 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
862 self.0[..].fmt(f)
863 }
864}
865
866impl Default for G1Compressed {
867 fn default() -> Self {
868 G1Compressed([0; 48])
869 }
870}
871
872#[cfg(feature = "zeroize")]
873impl zeroize::DefaultIsZeroes for G1Compressed {}
874
875impl AsRef<[u8]> for G1Compressed {
876 fn as_ref(&self) -> &[u8] {
877 &self.0
878 }
879}
880
881impl AsMut<[u8]> for G1Compressed {
882 fn as_mut(&mut self) -> &mut [u8] {
883 &mut self.0
884 }
885}
886
887impl ConstantTimeEq for G1Compressed {
888 fn ct_eq(&self, other: &Self) -> Choice {
889 self.0.ct_eq(&other.0)
890 }
891}
892
893impl Eq for G1Compressed {}
894impl PartialEq for G1Compressed {
895 #[inline]
896 fn eq(&self, other: &Self) -> bool {
897 bool::from(self.ct_eq(other))
898 }
899}
900
901#[derive(Clone, Copy)]
902pub struct G1Uncompressed([u8; 96]);
903
904impl fmt::Debug for G1Uncompressed {
905 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
906 self.0[..].fmt(f)
907 }
908}
909
910impl Default for G1Uncompressed {
911 fn default() -> Self {
912 G1Uncompressed([0; 96])
913 }
914}
915
916#[cfg(feature = "zeroize")]
917impl zeroize::DefaultIsZeroes for G1Uncompressed {}
918
919impl AsRef<[u8]> for G1Uncompressed {
920 fn as_ref(&self) -> &[u8] {
921 &self.0
922 }
923}
924
925impl AsMut<[u8]> for G1Uncompressed {
926 fn as_mut(&mut self) -> &mut [u8] {
927 &mut self.0
928 }
929}
930
931impl ConstantTimeEq for G1Uncompressed {
932 fn ct_eq(&self, other: &Self) -> Choice {
933 self.0.ct_eq(&other.0)
934 }
935}
936
937impl Eq for G1Uncompressed {}
938impl PartialEq for G1Uncompressed {
939 #[inline]
940 fn eq(&self, other: &Self) -> bool {
941 bool::from(self.ct_eq(other))
942 }
943}
944
945impl Group for G1Projective {
946 type Scalar = Scalar;
947
948 fn random(mut rng: impl RngCore) -> Self {
949 loop {
950 let x = Fp::random(&mut rng);
951 let flip_sign = rng.next_u32() % 2 != 0;
952
953 let p = ((x.square() * x) + B).sqrt().map(|y| G1Affine {
955 x,
956 y: if flip_sign { -y } else { y },
957 infinity: 0.into(),
958 });
959
960 if p.is_some().into() {
961 let p = p.unwrap().to_curve().clear_cofactor();
962
963 if bool::from(!p.is_identity()) {
964 return p;
965 }
966 }
967 }
968 }
969
970 fn identity() -> Self {
971 Self::identity()
972 }
973
974 fn generator() -> Self {
975 Self::generator()
976 }
977
978 fn is_identity(&self) -> Choice {
979 self.is_identity()
980 }
981
982 #[must_use]
983 fn double(&self) -> Self {
984 self.double()
985 }
986}
987
988#[cfg(feature = "alloc")]
989impl WnafGroup for G1Projective {
990 fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
991 const RECOMMENDATIONS: [usize; 12] =
992 [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
993
994 let mut ret = 4;
995 for r in &RECOMMENDATIONS {
996 if num_scalars > *r {
997 ret += 1;
998 } else {
999 break;
1000 }
1001 }
1002
1003 ret
1004 }
1005}
1006
1007impl PrimeGroup for G1Projective {}
1008
1009impl Curve for G1Projective {
1010 type AffineRepr = G1Affine;
1011
1012 fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
1013 Self::batch_normalize(p, q);
1014 }
1015
1016 fn to_affine(&self) -> Self::AffineRepr {
1017 self.into()
1018 }
1019}
1020
1021impl PrimeCurve for G1Projective {
1022 type Affine = G1Affine;
1023}
1024
1025impl PrimeCurveAffine for G1Affine {
1026 type Scalar = Scalar;
1027 type Curve = G1Projective;
1028
1029 fn identity() -> Self {
1030 Self::identity()
1031 }
1032
1033 fn generator() -> Self {
1034 Self::generator()
1035 }
1036
1037 fn is_identity(&self) -> Choice {
1038 self.is_identity()
1039 }
1040
1041 fn to_curve(&self) -> Self::Curve {
1042 self.into()
1043 }
1044}
1045
1046impl GroupEncoding for G1Projective {
1047 type Repr = G1Compressed;
1048
1049 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1050 G1Affine::from_bytes(bytes).map(Self::from)
1051 }
1052
1053 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1054 G1Affine::from_bytes_unchecked(bytes).map(Self::from)
1055 }
1056
1057 fn to_bytes(&self) -> Self::Repr {
1058 G1Affine::from(self).to_bytes()
1059 }
1060}
1061
1062impl GroupEncoding for G1Affine {
1063 type Repr = G1Compressed;
1064
1065 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1066 Self::from_compressed(&bytes.0)
1067 }
1068
1069 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1070 Self::from_compressed_unchecked(&bytes.0)
1071 }
1072
1073 fn to_bytes(&self) -> Self::Repr {
1074 G1Compressed(self.to_compressed())
1075 }
1076}
1077
1078impl UncompressedEncoding for G1Affine {
1079 type Uncompressed = G1Uncompressed;
1080
1081 fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
1082 Self::from_uncompressed(&bytes.0)
1083 }
1084
1085 fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
1086 Self::from_uncompressed_unchecked(&bytes.0)
1087 }
1088
1089 fn to_uncompressed(&self) -> Self::Uncompressed {
1090 G1Uncompressed(self.to_uncompressed())
1091 }
1092}
1093
1094#[test]
1095fn test_beta() {
1096 assert_eq!(
1097 BETA,
1098 Fp::from_bytes(&[
1099 0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x19, 0x67, 0x2f, 0xdf, 0x76,
1100 0xce, 0x51, 0xba, 0x69, 0xc6, 0x07, 0x6a, 0x0f, 0x77, 0xea, 0xdd, 0xb3, 0xa9, 0x3b,
1101 0xe6, 0xf8, 0x96, 0x88, 0xde, 0x17, 0xd8, 0x13, 0x62, 0x0a, 0x00, 0x02, 0x2e, 0x01,
1102 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe
1103 ])
1104 .unwrap()
1105 );
1106 assert_ne!(BETA, Fp::one());
1107 assert_ne!(BETA * BETA, Fp::one());
1108 assert_eq!(BETA * BETA * BETA, Fp::one());
1109}
1110#[test]
1111fn test_is_on_curve() {
1112 assert!(bool::from(G1Affine::identity().is_on_curve()));
1113 assert!(bool::from(G1Affine::generator().is_on_curve()));
1114 assert!(bool::from(G1Projective::identity().is_on_curve()));
1115 assert!(bool::from(G1Projective::generator().is_on_curve()));
1116
1117 let z = Fp::from_raw_unchecked([
1118 0xba7a_fa1f_9a6f_e250,
1119 0xfa0f_5b59_5eaf_e731,
1120 0x3bdc_4776_94c3_06e7,
1121 0x2149_be4b_3949_fa24,
1122 0x64aa_6e06_49b2_078c,
1123 0x12b1_08ac_3364_3c3e,
1124 ]);
1125
1126 let gen = G1Affine::generator();
1127 let mut test = G1Projective {
1128 x: gen.x * z,
1129 y: gen.y * z,
1130 z,
1131 };
1132
1133 assert!(bool::from(test.is_on_curve()));
1134
1135 test.x = z;
1136 assert!(!bool::from(test.is_on_curve()));
1137}
1138
1139#[test]
1140#[allow(clippy::eq_op)]
1141fn test_affine_point_equality() {
1142 let a = G1Affine::generator();
1143 let b = G1Affine::identity();
1144
1145 assert!(a == a);
1146 assert!(b == b);
1147 assert!(a != b);
1148 assert!(b != a);
1149}
1150
1151#[test]
1152#[allow(clippy::eq_op)]
1153fn test_projective_point_equality() {
1154 let a = G1Projective::generator();
1155 let b = G1Projective::identity();
1156
1157 assert!(a == a);
1158 assert!(b == b);
1159 assert!(a != b);
1160 assert!(b != a);
1161
1162 let z = Fp::from_raw_unchecked([
1163 0xba7a_fa1f_9a6f_e250,
1164 0xfa0f_5b59_5eaf_e731,
1165 0x3bdc_4776_94c3_06e7,
1166 0x2149_be4b_3949_fa24,
1167 0x64aa_6e06_49b2_078c,
1168 0x12b1_08ac_3364_3c3e,
1169 ]);
1170
1171 let mut c = G1Projective {
1172 x: a.x * z,
1173 y: a.y * z,
1174 z,
1175 };
1176 assert!(bool::from(c.is_on_curve()));
1177
1178 assert!(a == c);
1179 assert!(b != c);
1180 assert!(c == a);
1181 assert!(c != b);
1182
1183 c.y = -c.y;
1184 assert!(bool::from(c.is_on_curve()));
1185
1186 assert!(a != c);
1187 assert!(b != c);
1188 assert!(c != a);
1189 assert!(c != b);
1190
1191 c.y = -c.y;
1192 c.x = z;
1193 assert!(!bool::from(c.is_on_curve()));
1194 assert!(a != b);
1195 assert!(a != c);
1196 assert!(b != c);
1197}
1198
1199#[test]
1200fn test_conditionally_select_affine() {
1201 let a = G1Affine::generator();
1202 let b = G1Affine::identity();
1203
1204 assert_eq!(G1Affine::conditional_select(&a, &b, Choice::from(0u8)), a);
1205 assert_eq!(G1Affine::conditional_select(&a, &b, Choice::from(1u8)), b);
1206}
1207
1208#[test]
1209fn test_conditionally_select_projective() {
1210 let a = G1Projective::generator();
1211 let b = G1Projective::identity();
1212
1213 assert_eq!(
1214 G1Projective::conditional_select(&a, &b, Choice::from(0u8)),
1215 a
1216 );
1217 assert_eq!(
1218 G1Projective::conditional_select(&a, &b, Choice::from(1u8)),
1219 b
1220 );
1221}
1222
1223#[test]
1224fn test_projective_to_affine() {
1225 let a = G1Projective::generator();
1226 let b = G1Projective::identity();
1227
1228 assert!(bool::from(G1Affine::from(a).is_on_curve()));
1229 assert!(!bool::from(G1Affine::from(a).is_identity()));
1230 assert!(bool::from(G1Affine::from(b).is_on_curve()));
1231 assert!(bool::from(G1Affine::from(b).is_identity()));
1232
1233 let z = Fp::from_raw_unchecked([
1234 0xba7a_fa1f_9a6f_e250,
1235 0xfa0f_5b59_5eaf_e731,
1236 0x3bdc_4776_94c3_06e7,
1237 0x2149_be4b_3949_fa24,
1238 0x64aa_6e06_49b2_078c,
1239 0x12b1_08ac_3364_3c3e,
1240 ]);
1241
1242 let c = G1Projective {
1243 x: a.x * z,
1244 y: a.y * z,
1245 z,
1246 };
1247
1248 assert_eq!(G1Affine::from(c), G1Affine::generator());
1249}
1250
1251#[test]
1252fn test_affine_to_projective() {
1253 let a = G1Affine::generator();
1254 let b = G1Affine::identity();
1255
1256 assert!(bool::from(G1Projective::from(a).is_on_curve()));
1257 assert!(!bool::from(G1Projective::from(a).is_identity()));
1258 assert!(bool::from(G1Projective::from(b).is_on_curve()));
1259 assert!(bool::from(G1Projective::from(b).is_identity()));
1260}
1261
1262#[test]
1263fn test_doubling() {
1264 {
1265 let tmp = G1Projective::identity().double();
1266 assert!(bool::from(tmp.is_identity()));
1267 assert!(bool::from(tmp.is_on_curve()));
1268 }
1269 {
1270 let tmp = G1Projective::generator().double();
1271 assert!(!bool::from(tmp.is_identity()));
1272 assert!(bool::from(tmp.is_on_curve()));
1273
1274 assert_eq!(
1275 G1Affine::from(tmp),
1276 G1Affine {
1277 x: Fp::from_raw_unchecked([
1278 0x53e9_78ce_58a9_ba3c,
1279 0x3ea0_583c_4f3d_65f9,
1280 0x4d20_bb47_f001_2960,
1281 0xa54c_664a_e5b2_b5d9,
1282 0x26b5_52a3_9d7e_b21f,
1283 0x0008_895d_26e6_8785,
1284 ]),
1285 y: Fp::from_raw_unchecked([
1286 0x7011_0b32_9829_3940,
1287 0xda33_c539_3f1f_6afc,
1288 0xb86e_dfd1_6a5a_a785,
1289 0xaec6_d1c9_e7b1_c895,
1290 0x25cf_c2b5_22d1_1720,
1291 0x0636_1c83_f8d0_9b15,
1292 ]),
1293 infinity: Choice::from(0u8)
1294 }
1295 );
1296 }
1297}
1298
1299#[test]
1300fn test_projective_addition() {
1301 {
1302 let a = G1Projective::identity();
1303 let b = G1Projective::identity();
1304 let c = a + b;
1305 assert!(bool::from(c.is_identity()));
1306 assert!(bool::from(c.is_on_curve()));
1307 }
1308 {
1309 let a = G1Projective::identity();
1310 let mut b = G1Projective::generator();
1311 {
1312 let z = Fp::from_raw_unchecked([
1313 0xba7a_fa1f_9a6f_e250,
1314 0xfa0f_5b59_5eaf_e731,
1315 0x3bdc_4776_94c3_06e7,
1316 0x2149_be4b_3949_fa24,
1317 0x64aa_6e06_49b2_078c,
1318 0x12b1_08ac_3364_3c3e,
1319 ]);
1320
1321 b = G1Projective {
1322 x: b.x * z,
1323 y: b.y * z,
1324 z,
1325 };
1326 }
1327 let c = a + b;
1328 assert!(!bool::from(c.is_identity()));
1329 assert!(bool::from(c.is_on_curve()));
1330 assert!(c == G1Projective::generator());
1331 }
1332 {
1333 let a = G1Projective::identity();
1334 let mut b = G1Projective::generator();
1335 {
1336 let z = Fp::from_raw_unchecked([
1337 0xba7a_fa1f_9a6f_e250,
1338 0xfa0f_5b59_5eaf_e731,
1339 0x3bdc_4776_94c3_06e7,
1340 0x2149_be4b_3949_fa24,
1341 0x64aa_6e06_49b2_078c,
1342 0x12b1_08ac_3364_3c3e,
1343 ]);
1344
1345 b = G1Projective {
1346 x: b.x * z,
1347 y: b.y * z,
1348 z,
1349 };
1350 }
1351 let c = b + a;
1352 assert!(!bool::from(c.is_identity()));
1353 assert!(bool::from(c.is_on_curve()));
1354 assert!(c == G1Projective::generator());
1355 }
1356 {
1357 let a = G1Projective::generator().double().double(); let b = G1Projective::generator().double(); let c = a + b;
1360
1361 let mut d = G1Projective::generator();
1362 for _ in 0..5 {
1363 d += G1Projective::generator();
1364 }
1365 assert!(!bool::from(c.is_identity()));
1366 assert!(bool::from(c.is_on_curve()));
1367 assert!(!bool::from(d.is_identity()));
1368 assert!(bool::from(d.is_on_curve()));
1369 assert_eq!(c, d);
1370 }
1371
1372 {
1374 let beta = Fp::from_raw_unchecked([
1375 0xcd03_c9e4_8671_f071,
1376 0x5dab_2246_1fcd_a5d2,
1377 0x5870_42af_d385_1b95,
1378 0x8eb6_0ebe_01ba_cb9e,
1379 0x03f9_7d6e_83d0_50d2,
1380 0x18f0_2065_5463_8741,
1381 ]);
1382 let beta = beta.square();
1383 let a = G1Projective::generator().double().double();
1384 let b = G1Projective {
1385 x: a.x * beta,
1386 y: -a.y,
1387 z: a.z,
1388 };
1389 assert!(bool::from(a.is_on_curve()));
1390 assert!(bool::from(b.is_on_curve()));
1391
1392 let c = a + b;
1393 assert_eq!(
1394 G1Affine::from(c),
1395 G1Affine::from(G1Projective {
1396 x: Fp::from_raw_unchecked([
1397 0x29e1_e987_ef68_f2d0,
1398 0xc5f3_ec53_1db0_3233,
1399 0xacd6_c4b6_ca19_730f,
1400 0x18ad_9e82_7bc2_bab7,
1401 0x46e3_b2c5_785c_c7a9,
1402 0x07e5_71d4_2d22_ddd6,
1403 ]),
1404 y: Fp::from_raw_unchecked([
1405 0x94d1_17a7_e5a5_39e7,
1406 0x8e17_ef67_3d4b_5d22,
1407 0x9d74_6aaf_508a_33ea,
1408 0x8c6d_883d_2516_c9a2,
1409 0x0bc3_b8d5_fb04_47f7,
1410 0x07bf_a4c7_210f_4f44,
1411 ]),
1412 z: Fp::one()
1413 })
1414 );
1415 assert!(!bool::from(c.is_identity()));
1416 assert!(bool::from(c.is_on_curve()));
1417 }
1418}
1419
1420#[test]
1421fn test_mixed_addition() {
1422 {
1423 let a = G1Affine::identity();
1424 let b = G1Projective::identity();
1425 let c = a + b;
1426 assert!(bool::from(c.is_identity()));
1427 assert!(bool::from(c.is_on_curve()));
1428 }
1429 {
1430 let a = G1Affine::identity();
1431 let mut b = G1Projective::generator();
1432 {
1433 let z = Fp::from_raw_unchecked([
1434 0xba7a_fa1f_9a6f_e250,
1435 0xfa0f_5b59_5eaf_e731,
1436 0x3bdc_4776_94c3_06e7,
1437 0x2149_be4b_3949_fa24,
1438 0x64aa_6e06_49b2_078c,
1439 0x12b1_08ac_3364_3c3e,
1440 ]);
1441
1442 b = G1Projective {
1443 x: b.x * z,
1444 y: b.y * z,
1445 z,
1446 };
1447 }
1448 let c = a + b;
1449 assert!(!bool::from(c.is_identity()));
1450 assert!(bool::from(c.is_on_curve()));
1451 assert!(c == G1Projective::generator());
1452 }
1453 {
1454 let a = G1Affine::identity();
1455 let mut b = G1Projective::generator();
1456 {
1457 let z = Fp::from_raw_unchecked([
1458 0xba7a_fa1f_9a6f_e250,
1459 0xfa0f_5b59_5eaf_e731,
1460 0x3bdc_4776_94c3_06e7,
1461 0x2149_be4b_3949_fa24,
1462 0x64aa_6e06_49b2_078c,
1463 0x12b1_08ac_3364_3c3e,
1464 ]);
1465
1466 b = G1Projective {
1467 x: b.x * z,
1468 y: b.y * z,
1469 z,
1470 };
1471 }
1472 let c = b + a;
1473 assert!(!bool::from(c.is_identity()));
1474 assert!(bool::from(c.is_on_curve()));
1475 assert!(c == G1Projective::generator());
1476 }
1477 {
1478 let a = G1Projective::generator().double().double(); let b = G1Projective::generator().double(); let c = a + b;
1481
1482 let mut d = G1Projective::generator();
1483 for _ in 0..5 {
1484 d += G1Affine::generator();
1485 }
1486 assert!(!bool::from(c.is_identity()));
1487 assert!(bool::from(c.is_on_curve()));
1488 assert!(!bool::from(d.is_identity()));
1489 assert!(bool::from(d.is_on_curve()));
1490 assert_eq!(c, d);
1491 }
1492
1493 {
1495 let beta = Fp::from_raw_unchecked([
1496 0xcd03_c9e4_8671_f071,
1497 0x5dab_2246_1fcd_a5d2,
1498 0x5870_42af_d385_1b95,
1499 0x8eb6_0ebe_01ba_cb9e,
1500 0x03f9_7d6e_83d0_50d2,
1501 0x18f0_2065_5463_8741,
1502 ]);
1503 let beta = beta.square();
1504 let a = G1Projective::generator().double().double();
1505 let b = G1Projective {
1506 x: a.x * beta,
1507 y: -a.y,
1508 z: a.z,
1509 };
1510 let a = G1Affine::from(a);
1511 assert!(bool::from(a.is_on_curve()));
1512 assert!(bool::from(b.is_on_curve()));
1513
1514 let c = a + b;
1515 assert_eq!(
1516 G1Affine::from(c),
1517 G1Affine::from(G1Projective {
1518 x: Fp::from_raw_unchecked([
1519 0x29e1_e987_ef68_f2d0,
1520 0xc5f3_ec53_1db0_3233,
1521 0xacd6_c4b6_ca19_730f,
1522 0x18ad_9e82_7bc2_bab7,
1523 0x46e3_b2c5_785c_c7a9,
1524 0x07e5_71d4_2d22_ddd6,
1525 ]),
1526 y: Fp::from_raw_unchecked([
1527 0x94d1_17a7_e5a5_39e7,
1528 0x8e17_ef67_3d4b_5d22,
1529 0x9d74_6aaf_508a_33ea,
1530 0x8c6d_883d_2516_c9a2,
1531 0x0bc3_b8d5_fb04_47f7,
1532 0x07bf_a4c7_210f_4f44,
1533 ]),
1534 z: Fp::one()
1535 })
1536 );
1537 assert!(!bool::from(c.is_identity()));
1538 assert!(bool::from(c.is_on_curve()));
1539 }
1540}
1541
1542#[test]
1543#[allow(clippy::eq_op)]
1544fn test_projective_negation_and_subtraction() {
1545 let a = G1Projective::generator().double();
1546 assert_eq!(a + (-a), G1Projective::identity());
1547 assert_eq!(a + (-a), a - a);
1548}
1549
1550#[test]
1551fn test_affine_negation_and_subtraction() {
1552 let a = G1Affine::generator();
1553 assert_eq!(G1Projective::from(a) + (-a), G1Projective::identity());
1554 assert_eq!(G1Projective::from(a) + (-a), G1Projective::from(a) - a);
1555}
1556
1557#[test]
1558fn test_projective_scalar_multiplication() {
1559 let g = G1Projective::generator();
1560 let a = Scalar::from_raw([
1561 0x2b56_8297_a56d_a71c,
1562 0xd8c3_9ecb_0ef3_75d1,
1563 0x435c_38da_67bf_bf96,
1564 0x8088_a050_26b6_59b2,
1565 ]);
1566 let b = Scalar::from_raw([
1567 0x785f_dd9b_26ef_8b85,
1568 0xc997_f258_3769_5c18,
1569 0x4c8d_bc39_e7b7_56c1,
1570 0x70d9_b6cc_6d87_df20,
1571 ]);
1572 let c = a * b;
1573
1574 assert_eq!((g * a) * b, g * c);
1575}
1576
1577#[test]
1578fn test_affine_scalar_multiplication() {
1579 let g = G1Affine::generator();
1580 let a = Scalar::from_raw([
1581 0x2b56_8297_a56d_a71c,
1582 0xd8c3_9ecb_0ef3_75d1,
1583 0x435c_38da_67bf_bf96,
1584 0x8088_a050_26b6_59b2,
1585 ]);
1586 let b = Scalar::from_raw([
1587 0x785f_dd9b_26ef_8b85,
1588 0xc997_f258_3769_5c18,
1589 0x4c8d_bc39_e7b7_56c1,
1590 0x70d9_b6cc_6d87_df20,
1591 ]);
1592 let c = a * b;
1593
1594 assert_eq!(G1Affine::from(g * a) * b, g * c);
1595}
1596
1597#[test]
1598fn test_is_torsion_free() {
1599 let a = G1Affine {
1600 x: Fp::from_raw_unchecked([
1601 0x0aba_f895_b97e_43c8,
1602 0xba4c_6432_eb9b_61b0,
1603 0x1250_6f52_adfe_307f,
1604 0x7502_8c34_3933_6b72,
1605 0x8474_4f05_b8e9_bd71,
1606 0x113d_554f_b095_54f7,
1607 ]),
1608 y: Fp::from_raw_unchecked([
1609 0x73e9_0e88_f5cf_01c0,
1610 0x3700_7b65_dd31_97e2,
1611 0x5cf9_a199_2f0d_7c78,
1612 0x4f83_c10b_9eb3_330d,
1613 0xf6a6_3f6f_07f6_0961,
1614 0x0c53_b5b9_7e63_4df3,
1615 ]),
1616 infinity: Choice::from(0u8),
1617 };
1618 assert!(!bool::from(a.is_torsion_free()));
1619
1620 assert!(bool::from(G1Affine::identity().is_torsion_free()));
1621 assert!(bool::from(G1Affine::generator().is_torsion_free()));
1622}
1623
1624#[test]
1625fn test_mul_by_x() {
1626 let generator = G1Projective::generator();
1629 let x = if crate::BLS_X_IS_NEGATIVE {
1630 -Scalar::from(crate::BLS_X)
1631 } else {
1632 Scalar::from(crate::BLS_X)
1633 };
1634 assert_eq!(generator.mul_by_x(), generator * x);
1635
1636 let point = G1Projective::generator() * Scalar::from(42);
1637 assert_eq!(point.mul_by_x(), point * x);
1638}
1639
1640#[test]
1641fn test_clear_cofactor() {
1642 let generator = G1Projective::generator();
1645 assert!(bool::from(generator.clear_cofactor().is_on_curve()));
1646 let id = G1Projective::identity();
1647 assert!(bool::from(id.clear_cofactor().is_on_curve()));
1648
1649 let z = Fp::from_raw_unchecked([
1650 0x3d2d1c670671394e,
1651 0x0ee3a800a2f7c1ca,
1652 0x270f4f21da2e5050,
1653 0xe02840a53f1be768,
1654 0x55debeb597512690,
1655 0x08bd25353dc8f791,
1656 ]);
1657
1658 let point = G1Projective {
1659 x: Fp::from_raw_unchecked([
1660 0x48af5ff540c817f0,
1661 0xd73893acaf379d5a,
1662 0xe6c43584e18e023c,
1663 0x1eda39c30f188b3e,
1664 0xf618c6d3ccc0f8d8,
1665 0x0073542cd671e16c,
1666 ]) * z,
1667 y: Fp::from_raw_unchecked([
1668 0x57bf8be79461d0ba,
1669 0xfc61459cee3547c3,
1670 0x0d23567df1ef147b,
1671 0x0ee187bcce1d9b64,
1672 0xb0c8cfbe9dc8fdc1,
1673 0x1328661767ef368b,
1674 ]),
1675 z: z.square() * z,
1676 };
1677
1678 assert!(bool::from(point.is_on_curve()));
1679 assert!(!bool::from(G1Affine::from(point).is_torsion_free()));
1680 let cleared_point = point.clear_cofactor();
1681 assert!(bool::from(cleared_point.is_on_curve()));
1682 assert!(bool::from(G1Affine::from(cleared_point).is_torsion_free()));
1683
1684 let h_eff = Scalar::from(1) + Scalar::from(crate::BLS_X);
1687 assert_eq!(point.clear_cofactor(), point * h_eff);
1688}
1689
1690#[test]
1691fn test_batch_normalize() {
1692 let a = G1Projective::generator().double();
1693 let b = a.double();
1694 let c = b.double();
1695
1696 for a_identity in (0..=1).map(|n| n == 1) {
1697 for b_identity in (0..=1).map(|n| n == 1) {
1698 for c_identity in (0..=1).map(|n| n == 1) {
1699 let mut v = [a, b, c];
1700 if a_identity {
1701 v[0] = G1Projective::identity()
1702 }
1703 if b_identity {
1704 v[1] = G1Projective::identity()
1705 }
1706 if c_identity {
1707 v[2] = G1Projective::identity()
1708 }
1709
1710 let mut t = [
1711 G1Affine::identity(),
1712 G1Affine::identity(),
1713 G1Affine::identity(),
1714 ];
1715 let expected = [
1716 G1Affine::from(v[0]),
1717 G1Affine::from(v[1]),
1718 G1Affine::from(v[2]),
1719 ];
1720
1721 G1Projective::batch_normalize(&v[..], &mut t[..]);
1722
1723 assert_eq!(&t[..], &expected[..]);
1724 }
1725 }
1726 }
1727}
1728
1729#[cfg(feature = "zeroize")]
1730#[test]
1731fn test_zeroize() {
1732 use zeroize::Zeroize;
1733
1734 let mut a = G1Affine::generator();
1735 a.zeroize();
1736 assert!(bool::from(a.is_identity()));
1737
1738 let mut a = G1Projective::generator();
1739 a.zeroize();
1740 assert!(bool::from(a.is_identity()));
1741
1742 let mut a = GroupEncoding::to_bytes(&G1Affine::generator());
1743 a.zeroize();
1744 assert_eq!(&a, &G1Compressed::default());
1745
1746 let mut a = UncompressedEncoding::to_uncompressed(&G1Affine::generator());
1747 a.zeroize();
1748 assert_eq!(&a, &G1Uncompressed::default());
1749}
1750
1751#[test]
1752fn test_commutative_scalar_subgroup_multiplication() {
1753 let a = Scalar::from_raw([
1754 0x1fff_3231_233f_fffd,
1755 0x4884_b7fa_0003_4802,
1756 0x998c_4fef_ecbc_4ff3,
1757 0x1824_b159_acc5_0562,
1758 ]);
1759
1760 let g1_a = G1Affine::generator();
1761 let g1_p = G1Projective::generator();
1762
1763 assert_eq!(&g1_a * &a, &a * &g1_a);
1765 assert_eq!(&g1_p * &a, &a * &g1_p);
1766
1767 assert_eq!(&g1_a * a.clone(), a.clone() * &g1_a);
1769 assert_eq!(&g1_p * a.clone(), a.clone() * &g1_p);
1770 assert_eq!(g1_a.clone() * &a, &a * g1_a.clone());
1771 assert_eq!(g1_p.clone() * &a, &a * g1_p.clone());
1772
1773 assert_eq!(g1_p * a, a * g1_p);
1775 assert_eq!(g1_a * a, a * g1_a);
1776}