1#![allow(clippy::op_ref)]
4
5use super::{AffinePoint, FieldElement, Scalar, CURVE_EQUATION_B_SINGLE};
6use crate::{CompressedPoint, EncodedPoint, PublicKey, Secp256k1};
7use core::{
8 iter::Sum,
9 ops::{Add, AddAssign, Neg, Sub, SubAssign},
10};
11use elliptic_curve::ops::BatchInvert;
12use elliptic_curve::{
13 group::{
14 ff::Field,
15 prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
16 Curve, Group, GroupEncoding,
17 },
18 rand_core::RngCore,
19 sec1::{FromEncodedPoint, ToEncodedPoint},
20 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
21 zeroize::DefaultIsZeroes,
22 BatchNormalize, Error, Result,
23};
24
25#[cfg(feature = "alloc")]
26use alloc::vec::Vec;
27
28#[rustfmt::skip]
29const ENDOMORPHISM_BETA: FieldElement = FieldElement::from_bytes_unchecked(&[
30 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10,
31 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9,
32 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95,
33 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee,
34]);
35
36#[derive(Clone, Copy, Debug)]
38pub struct ProjectivePoint {
39 x: FieldElement,
40 y: FieldElement,
41 pub(super) z: FieldElement,
42}
43
44impl ProjectivePoint {
45 pub const IDENTITY: Self = Self {
47 x: FieldElement::ZERO,
48 y: FieldElement::ONE,
49 z: FieldElement::ZERO,
50 };
51
52 pub const GENERATOR: Self = Self {
54 x: AffinePoint::GENERATOR.x,
55 y: AffinePoint::GENERATOR.y,
56 z: FieldElement::ONE,
57 };
58
59 #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::IDENTITY` instead")]
62 pub const fn identity() -> ProjectivePoint {
63 Self::IDENTITY
64 }
65
66 #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::GENERATOR` instead")]
68 pub fn generator() -> ProjectivePoint {
69 Self::GENERATOR
70 }
71
72 pub fn to_affine(&self) -> AffinePoint {
74 self.z
75 .invert()
76 .map(|zinv| self.to_affine_internal(zinv))
77 .unwrap_or_else(|| AffinePoint::IDENTITY)
78 }
79
80 pub(super) fn to_affine_internal(self, zinv: FieldElement) -> AffinePoint {
81 let x = self.x * &zinv;
82 let y = self.y * &zinv;
83 AffinePoint::new(x.normalize(), y.normalize())
84 }
85
86 fn neg(&self) -> ProjectivePoint {
88 ProjectivePoint {
89 x: self.x,
90 y: self.y.negate(1).normalize_weak(),
91 z: self.z,
92 }
93 }
94
95 fn add(&self, other: &ProjectivePoint) -> ProjectivePoint {
97 let xx = self.x * &other.x;
101 let yy = self.y * &other.y;
102 let zz = self.z * &other.z;
103
104 let n_xx_yy = (xx + &yy).negate(2);
105 let n_yy_zz = (yy + &zz).negate(2);
106 let n_xx_zz = (xx + &zz).negate(2);
107 let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) + &n_xx_yy;
108 let yz_pairs = ((self.y + &self.z) * &(other.y + &other.z)) + &n_yy_zz;
109 let xz_pairs = ((self.x + &self.z) * &(other.x + &other.z)) + &n_xx_zz;
110
111 let bzz = zz.mul_single(CURVE_EQUATION_B_SINGLE);
112 let bzz3 = (bzz.double() + &bzz).normalize_weak();
113
114 let yy_m_bzz3 = yy + &bzz3.negate(1);
115 let yy_p_bzz3 = yy + &bzz3;
116
117 let byz = &yz_pairs
118 .mul_single(CURVE_EQUATION_B_SINGLE)
119 .normalize_weak();
120 let byz3 = (byz.double() + byz).normalize_weak();
121
122 let xx3 = xx.double() + &xx;
123 let bxx9 = (xx3.double() + &xx3)
124 .normalize_weak()
125 .mul_single(CURVE_EQUATION_B_SINGLE)
126 .normalize_weak();
127
128 let new_x = ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(); let new_y = ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak();
130 let new_z = ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak();
131
132 ProjectivePoint {
133 x: new_x,
134 y: new_y,
135 z: new_z,
136 }
137 }
138
139 fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
141 let xx = self.x * &other.x;
145 let yy = self.y * &other.y;
146 let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) + &(xx + &yy).negate(2);
147 let yz_pairs = (other.y * &self.z) + &self.y;
148 let xz_pairs = (other.x * &self.z) + &self.x;
149
150 let bzz = &self.z.mul_single(CURVE_EQUATION_B_SINGLE);
151 let bzz3 = (bzz.double() + bzz).normalize_weak();
152
153 let yy_m_bzz3 = yy + &bzz3.negate(1);
154 let yy_p_bzz3 = yy + &bzz3;
155
156 let byz = &yz_pairs
157 .mul_single(CURVE_EQUATION_B_SINGLE)
158 .normalize_weak();
159 let byz3 = (byz.double() + byz).normalize_weak();
160
161 let xx3 = xx.double() + &xx;
162 let bxx9 = &(xx3.double() + &xx3)
163 .normalize_weak()
164 .mul_single(CURVE_EQUATION_B_SINGLE)
165 .normalize_weak();
166
167 let mut ret = ProjectivePoint {
168 x: ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(),
169 y: ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak(),
170 z: ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak(),
171 };
172 ret.conditional_assign(self, other.is_identity());
173 ret
174 }
175
176 #[inline]
178 pub fn double(&self) -> ProjectivePoint {
179 let yy = self.y.square();
183 let zz = self.z.square();
184 let xy2 = (self.x * &self.y).double();
185
186 let bzz = &zz.mul_single(CURVE_EQUATION_B_SINGLE);
187 let bzz3 = (bzz.double() + bzz).normalize_weak();
188 let bzz9 = (bzz3.double() + &bzz3).normalize_weak();
189
190 let yy_m_bzz9 = yy + &bzz9.negate(1);
191 let yy_p_bzz3 = yy + &bzz3;
192
193 let yy_zz = yy * &zz;
194 let yy_zz8 = yy_zz.double().double().double();
195 let t = (yy_zz8.double() + &yy_zz8)
196 .normalize_weak()
197 .mul_single(CURVE_EQUATION_B_SINGLE);
198
199 ProjectivePoint {
200 x: xy2 * &yy_m_bzz9,
201 y: ((yy_m_bzz9 * &yy_p_bzz3) + &t).normalize_weak(),
202 z: ((yy * &self.y) * &self.z)
203 .double()
204 .double()
205 .double()
206 .normalize_weak(),
207 }
208 }
209
210 fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint {
212 self.add(&other.neg())
213 }
214
215 fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
217 self.add_mixed(&other.neg())
218 }
219
220 pub fn endomorphism(&self) -> Self {
222 Self {
223 x: self.x * &ENDOMORPHISM_BETA,
224 y: self.y,
225 z: self.z,
226 }
227 }
228
229 pub fn eq_affine(&self, other: &AffinePoint) -> Choice {
234 let both_identity = self.is_identity() & other.is_identity();
237 let rhs_identity = other.is_identity();
238 let rhs_x = &other.x * &self.z;
239 let x_eq = rhs_x.negate(1).add(&self.x).normalizes_to_zero();
240
241 let rhs_y = &other.y * &self.z;
242 let y_eq = rhs_y.negate(1).add(&self.y).normalizes_to_zero();
243
244 both_identity | (!rhs_identity & x_eq & y_eq)
245 }
246}
247
248impl From<AffinePoint> for ProjectivePoint {
249 fn from(p: AffinePoint) -> Self {
250 let projective = ProjectivePoint {
251 x: p.x,
252 y: p.y,
253 z: FieldElement::ONE,
254 };
255 Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity())
256 }
257}
258
259impl<const N: usize> BatchNormalize<[ProjectivePoint; N]> for ProjectivePoint {
260 type Output = [Self::AffineRepr; N];
261
262 #[inline]
263 fn batch_normalize(points: &[Self; N]) -> [Self::AffineRepr; N] {
264 let mut zs = [FieldElement::ONE; N];
265 let mut affine_points = [AffinePoint::IDENTITY; N];
266 batch_normalize_generic(points, &mut zs, &mut affine_points);
267 affine_points
268 }
269}
270
271#[cfg(feature = "alloc")]
272impl BatchNormalize<[ProjectivePoint]> for ProjectivePoint {
273 type Output = Vec<Self::AffineRepr>;
274
275 #[inline]
276 fn batch_normalize(points: &[Self]) -> Vec<Self::AffineRepr> {
277 let mut zs = vec![FieldElement::ONE; points.len()];
278 let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
279 batch_normalize_generic(points, zs.as_mut_slice(), &mut affine_points);
280 affine_points
281 }
282}
283
284fn batch_normalize_generic<P, Z, O>(points: &P, zs: &mut Z, out: &mut O)
285where
286 FieldElement: BatchInvert<Z>,
287 P: AsRef<[ProjectivePoint]> + ?Sized,
288 Z: AsMut<[FieldElement]> + ?Sized,
289 O: AsMut<[AffinePoint]> + ?Sized,
290{
291 let points = points.as_ref();
292 let out = out.as_mut();
293
294 for i in 0..points.len() {
295 zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&FieldElement::ZERO));
299 }
300
301 let zs_inverses = <FieldElement as BatchInvert<Z>>::batch_invert(zs).unwrap();
303
304 for i in 0..out.len() {
305 out[i] = AffinePoint::conditional_select(
308 &points[i].to_affine_internal(zs_inverses.as_ref()[i]),
309 &AffinePoint::IDENTITY,
310 points[i].z.ct_eq(&FieldElement::ZERO),
311 );
312 }
313}
314
315impl From<&AffinePoint> for ProjectivePoint {
316 fn from(p: &AffinePoint) -> Self {
317 Self::from(*p)
318 }
319}
320
321impl From<ProjectivePoint> for AffinePoint {
322 fn from(p: ProjectivePoint) -> AffinePoint {
323 p.to_affine()
324 }
325}
326
327impl From<&ProjectivePoint> for AffinePoint {
328 fn from(p: &ProjectivePoint) -> AffinePoint {
329 p.to_affine()
330 }
331}
332
333impl FromEncodedPoint<Secp256k1> for ProjectivePoint {
334 fn from_encoded_point(p: &EncodedPoint) -> CtOption<Self> {
335 AffinePoint::from_encoded_point(p).map(ProjectivePoint::from)
336 }
337}
338
339impl ToEncodedPoint<Secp256k1> for ProjectivePoint {
340 fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
341 self.to_affine().to_encoded_point(compress)
342 }
343}
344
345impl ConditionallySelectable for ProjectivePoint {
346 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
347 ProjectivePoint {
348 x: FieldElement::conditional_select(&a.x, &b.x, choice),
349 y: FieldElement::conditional_select(&a.y, &b.y, choice),
350 z: FieldElement::conditional_select(&a.z, &b.z, choice),
351 }
352 }
353}
354
355impl ConstantTimeEq for ProjectivePoint {
356 fn ct_eq(&self, other: &Self) -> Choice {
357 let lhs_x = self.x * &other.z;
372 let rhs_x = other.x * &self.z;
373 let x_eq = rhs_x.negate(1).add(&lhs_x).normalizes_to_zero();
374
375 let lhs_y = self.y * &other.z;
376 let rhs_y = other.y * &self.z;
377 let y_eq = rhs_y.negate(1).add(&lhs_y).normalizes_to_zero();
378 x_eq & y_eq
379 }
380}
381
382impl PartialEq for ProjectivePoint {
383 fn eq(&self, other: &Self) -> bool {
384 self.ct_eq(other).into()
385 }
386}
387
388impl PartialEq<AffinePoint> for ProjectivePoint {
389 fn eq(&self, other: &AffinePoint) -> bool {
390 self.eq_affine(other).into()
391 }
392}
393
394impl PartialEq<ProjectivePoint> for AffinePoint {
395 fn eq(&self, other: &ProjectivePoint) -> bool {
396 other.eq_affine(self).into()
397 }
398}
399
400impl Eq for ProjectivePoint {}
401
402impl Group for ProjectivePoint {
403 type Scalar = Scalar;
404
405 fn random(mut rng: impl RngCore) -> Self {
406 Self::GENERATOR * Scalar::random(&mut rng)
407 }
408
409 fn identity() -> Self {
410 Self::IDENTITY
411 }
412
413 fn generator() -> Self {
414 Self::GENERATOR
415 }
416
417 fn is_identity(&self) -> Choice {
418 self.z.normalizes_to_zero()
419 }
420
421 #[must_use]
422 fn double(&self) -> Self {
423 Self::double(self)
424 }
425}
426
427impl GroupEncoding for ProjectivePoint {
428 type Repr = CompressedPoint;
429
430 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
431 <AffinePoint as GroupEncoding>::from_bytes(bytes).map(Into::into)
432 }
433
434 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
435 Self::from_bytes(bytes)
437 }
438
439 fn to_bytes(&self) -> Self::Repr {
440 self.to_affine().to_bytes()
441 }
442}
443
444impl PrimeGroup for ProjectivePoint {}
445
446impl Curve for ProjectivePoint {
447 type AffineRepr = AffinePoint;
448
449 fn to_affine(&self) -> AffinePoint {
450 ProjectivePoint::to_affine(self)
451 }
452
453 #[cfg(feature = "alloc")]
454 #[inline]
455 fn batch_normalize(projective: &[Self], affine: &mut [Self::AffineRepr]) {
456 assert_eq!(projective.len(), affine.len());
457 let mut zs = vec![FieldElement::ONE; projective.len()];
458 batch_normalize_generic(projective, zs.as_mut_slice(), affine);
459 }
460}
461
462impl PrimeCurve for ProjectivePoint {
463 type Affine = AffinePoint;
464}
465
466impl Default for ProjectivePoint {
467 fn default() -> Self {
468 Self::IDENTITY
469 }
470}
471
472impl DefaultIsZeroes for ProjectivePoint {}
473
474impl Add<&ProjectivePoint> for &ProjectivePoint {
475 type Output = ProjectivePoint;
476
477 fn add(self, other: &ProjectivePoint) -> ProjectivePoint {
478 ProjectivePoint::add(self, other)
479 }
480}
481
482impl Add<ProjectivePoint> for ProjectivePoint {
483 type Output = ProjectivePoint;
484
485 fn add(self, other: ProjectivePoint) -> ProjectivePoint {
486 ProjectivePoint::add(&self, &other)
487 }
488}
489
490impl Add<&ProjectivePoint> for ProjectivePoint {
491 type Output = ProjectivePoint;
492
493 fn add(self, other: &ProjectivePoint) -> ProjectivePoint {
494 ProjectivePoint::add(&self, other)
495 }
496}
497
498impl AddAssign<ProjectivePoint> for ProjectivePoint {
499 fn add_assign(&mut self, rhs: ProjectivePoint) {
500 *self = ProjectivePoint::add(self, &rhs);
501 }
502}
503
504impl AddAssign<&ProjectivePoint> for ProjectivePoint {
505 fn add_assign(&mut self, rhs: &ProjectivePoint) {
506 *self = ProjectivePoint::add(self, rhs);
507 }
508}
509
510impl Add<AffinePoint> for ProjectivePoint {
511 type Output = ProjectivePoint;
512
513 fn add(self, other: AffinePoint) -> ProjectivePoint {
514 ProjectivePoint::add_mixed(&self, &other)
515 }
516}
517
518impl Add<&AffinePoint> for &ProjectivePoint {
519 type Output = ProjectivePoint;
520
521 fn add(self, other: &AffinePoint) -> ProjectivePoint {
522 ProjectivePoint::add_mixed(self, other)
523 }
524}
525
526impl Add<&AffinePoint> for ProjectivePoint {
527 type Output = ProjectivePoint;
528
529 fn add(self, other: &AffinePoint) -> ProjectivePoint {
530 ProjectivePoint::add_mixed(&self, other)
531 }
532}
533
534impl AddAssign<AffinePoint> for ProjectivePoint {
535 fn add_assign(&mut self, rhs: AffinePoint) {
536 *self = ProjectivePoint::add_mixed(self, &rhs);
537 }
538}
539
540impl AddAssign<&AffinePoint> for ProjectivePoint {
541 fn add_assign(&mut self, rhs: &AffinePoint) {
542 *self = ProjectivePoint::add_mixed(self, rhs);
543 }
544}
545
546impl Sum for ProjectivePoint {
547 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
548 iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b)
549 }
550}
551
552impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint {
553 fn sum<I: Iterator<Item = &'a ProjectivePoint>>(iter: I) -> Self {
554 iter.cloned().sum()
555 }
556}
557
558impl Sub<ProjectivePoint> for ProjectivePoint {
559 type Output = ProjectivePoint;
560
561 fn sub(self, other: ProjectivePoint) -> ProjectivePoint {
562 ProjectivePoint::sub(&self, &other)
563 }
564}
565
566impl Sub<&ProjectivePoint> for &ProjectivePoint {
567 type Output = ProjectivePoint;
568
569 fn sub(self, other: &ProjectivePoint) -> ProjectivePoint {
570 ProjectivePoint::sub(self, other)
571 }
572}
573
574impl Sub<&ProjectivePoint> for ProjectivePoint {
575 type Output = ProjectivePoint;
576
577 fn sub(self, other: &ProjectivePoint) -> ProjectivePoint {
578 ProjectivePoint::sub(&self, other)
579 }
580}
581
582impl SubAssign<ProjectivePoint> for ProjectivePoint {
583 fn sub_assign(&mut self, rhs: ProjectivePoint) {
584 *self = ProjectivePoint::sub(self, &rhs);
585 }
586}
587
588impl SubAssign<&ProjectivePoint> for ProjectivePoint {
589 fn sub_assign(&mut self, rhs: &ProjectivePoint) {
590 *self = ProjectivePoint::sub(self, rhs);
591 }
592}
593
594impl Sub<AffinePoint> for ProjectivePoint {
595 type Output = ProjectivePoint;
596
597 fn sub(self, other: AffinePoint) -> ProjectivePoint {
598 ProjectivePoint::sub_mixed(&self, &other)
599 }
600}
601
602impl Sub<&AffinePoint> for &ProjectivePoint {
603 type Output = ProjectivePoint;
604
605 fn sub(self, other: &AffinePoint) -> ProjectivePoint {
606 ProjectivePoint::sub_mixed(self, other)
607 }
608}
609
610impl Sub<&AffinePoint> for ProjectivePoint {
611 type Output = ProjectivePoint;
612
613 fn sub(self, other: &AffinePoint) -> ProjectivePoint {
614 ProjectivePoint::sub_mixed(&self, other)
615 }
616}
617
618impl SubAssign<AffinePoint> for ProjectivePoint {
619 fn sub_assign(&mut self, rhs: AffinePoint) {
620 *self = ProjectivePoint::sub_mixed(self, &rhs);
621 }
622}
623
624impl SubAssign<&AffinePoint> for ProjectivePoint {
625 fn sub_assign(&mut self, rhs: &AffinePoint) {
626 *self = ProjectivePoint::sub_mixed(self, rhs);
627 }
628}
629
630impl Neg for ProjectivePoint {
631 type Output = ProjectivePoint;
632
633 fn neg(self) -> ProjectivePoint {
634 ProjectivePoint::neg(&self)
635 }
636}
637
638impl<'a> Neg for &'a ProjectivePoint {
639 type Output = ProjectivePoint;
640
641 fn neg(self) -> ProjectivePoint {
642 ProjectivePoint::neg(self)
643 }
644}
645
646impl From<PublicKey> for ProjectivePoint {
647 fn from(public_key: PublicKey) -> ProjectivePoint {
648 AffinePoint::from(public_key).into()
649 }
650}
651
652impl From<&PublicKey> for ProjectivePoint {
653 fn from(public_key: &PublicKey) -> ProjectivePoint {
654 AffinePoint::from(public_key).into()
655 }
656}
657
658impl TryFrom<ProjectivePoint> for PublicKey {
659 type Error = Error;
660
661 fn try_from(point: ProjectivePoint) -> Result<PublicKey> {
662 AffinePoint::from(point).try_into()
663 }
664}
665
666impl TryFrom<&ProjectivePoint> for PublicKey {
667 type Error = Error;
668
669 fn try_from(point: &ProjectivePoint) -> Result<PublicKey> {
670 AffinePoint::from(point).try_into()
671 }
672}
673
674#[cfg(test)]
675mod tests {
676 use super::{AffinePoint, ProjectivePoint};
677 use crate::{
678 test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS},
679 Scalar,
680 };
681 use elliptic_curve::group::{ff::PrimeField, prime::PrimeCurveAffine};
682 use elliptic_curve::ops::MulByGenerator;
683 use elliptic_curve::Field;
684 use elliptic_curve::{group, BatchNormalize};
685 use rand_core::OsRng;
686
687 #[cfg(feature = "alloc")]
688 use alloc::vec::Vec;
689
690 #[test]
691 fn affine_to_projective() {
692 let basepoint_affine = AffinePoint::GENERATOR;
693 let basepoint_projective = ProjectivePoint::GENERATOR;
694
695 assert_eq!(
696 ProjectivePoint::from(basepoint_affine),
697 basepoint_projective,
698 );
699 assert_eq!(basepoint_projective.to_affine(), basepoint_affine);
700 assert!(!bool::from(basepoint_projective.to_affine().is_identity()));
701
702 assert!(bool::from(
703 ProjectivePoint::IDENTITY.to_affine().is_identity()
704 ));
705 }
706
707 #[test]
708 fn batch_normalize_array() {
709 let k: Scalar = Scalar::random(&mut OsRng);
710 let l: Scalar = Scalar::random(&mut OsRng);
711 let g = ProjectivePoint::mul_by_generator(&k);
712 let h = ProjectivePoint::mul_by_generator(&l);
713
714 let mut res = [AffinePoint::IDENTITY; 2];
715 let expected = [g.to_affine(), h.to_affine()];
716 assert_eq!(
717 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(&[g, h]),
718 expected
719 );
720
721 <ProjectivePoint as group::Curve>::batch_normalize(&[g, h], &mut res);
722 assert_eq!(res, expected);
723
724 let expected = [g.to_affine(), AffinePoint::IDENTITY];
725 assert_eq!(
726 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(&[
727 g,
728 ProjectivePoint::IDENTITY
729 ]),
730 expected
731 );
732
733 <ProjectivePoint as group::Curve>::batch_normalize(
734 &[g, ProjectivePoint::IDENTITY],
735 &mut res,
736 );
737 assert_eq!(res, expected);
738 }
739
740 #[test]
741 #[cfg(feature = "alloc")]
742 fn batch_normalize_slice() {
743 let k: Scalar = Scalar::random(&mut OsRng);
744 let l: Scalar = Scalar::random(&mut OsRng);
745 let g = ProjectivePoint::mul_by_generator(&k);
746 let h = ProjectivePoint::mul_by_generator(&l);
747
748 let expected = vec![g.to_affine(), h.to_affine()];
749 let scalars = vec![g, h];
750 let mut res: Vec<_> =
751 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(scalars.as_slice());
752 assert_eq!(res, expected);
753
754 <ProjectivePoint as group::Curve>::batch_normalize(&[g, h], res.as_mut());
755 assert_eq!(res.to_vec(), expected);
756
757 let expected = vec![g.to_affine(), AffinePoint::IDENTITY];
758 let scalars = vec![g, ProjectivePoint::IDENTITY];
759 res = <ProjectivePoint as BatchNormalize<_>>::batch_normalize(scalars.as_slice());
760
761 assert_eq!(res, expected);
762
763 <ProjectivePoint as group::Curve>::batch_normalize(
764 &[g, ProjectivePoint::IDENTITY],
765 res.as_mut(),
766 );
767 assert_eq!(res.to_vec(), expected);
768 }
769
770 #[test]
771 fn projective_identity_addition() {
772 let identity = ProjectivePoint::IDENTITY;
773 let generator = ProjectivePoint::GENERATOR;
774
775 assert_eq!(identity + &generator, generator);
776 assert_eq!(generator + &identity, generator);
777 }
778
779 #[test]
780 fn projective_mixed_addition() {
781 let identity = ProjectivePoint::IDENTITY;
782 let basepoint_affine = AffinePoint::GENERATOR;
783 let basepoint_projective = ProjectivePoint::GENERATOR;
784
785 assert_eq!(identity + &basepoint_affine, basepoint_projective);
786 assert_eq!(
787 basepoint_projective + &basepoint_affine,
788 basepoint_projective + &basepoint_projective
789 );
790 }
791
792 #[test]
793 fn test_vector_repeated_add() {
794 let generator = ProjectivePoint::GENERATOR;
795 let mut p = generator;
796
797 for i in 0..ADD_TEST_VECTORS.len() {
798 let affine = p.to_affine();
799
800 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
801 assert_eq!(affine.x.to_bytes(), expected_x.into());
802 assert_eq!(affine.y.to_bytes(), expected_y.into());
803
804 p += &generator;
805 }
806 }
807
808 #[test]
809 fn test_vector_repeated_add_mixed() {
810 let generator = AffinePoint::GENERATOR;
811 let mut p = ProjectivePoint::GENERATOR;
812
813 for i in 0..ADD_TEST_VECTORS.len() {
814 let affine = p.to_affine();
815
816 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
817 assert_eq!(affine.x.to_bytes(), expected_x.into());
818 assert_eq!(affine.y.to_bytes(), expected_y.into());
819
820 p += &generator;
821 }
822 }
823
824 #[test]
825 fn test_vector_add_mixed_identity() {
826 let generator = ProjectivePoint::GENERATOR;
827 let p0 = generator + ProjectivePoint::IDENTITY;
828 let p1 = generator + AffinePoint::IDENTITY;
829 assert_eq!(p0, p1);
830 }
831
832 #[test]
833 fn test_vector_double_generator() {
834 let generator = ProjectivePoint::GENERATOR;
835 let mut p = generator;
836
837 for i in 0..2 {
838 let affine = p.to_affine();
839
840 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
841 assert_eq!(affine.x.to_bytes(), expected_x.into());
842 assert_eq!(affine.y.to_bytes(), expected_y.into());
843
844 p = p.double();
845 }
846 }
847
848 #[test]
849 fn projective_add_vs_double() {
850 let generator = ProjectivePoint::GENERATOR;
851
852 let r1 = generator + &generator;
853 let r2 = generator.double();
854 assert_eq!(r1, r2);
855
856 let r1 = (generator + &generator) + &(generator + &generator);
857 let r2 = generator.double().double();
858 assert_eq!(r1, r2);
859 }
860
861 #[test]
862 fn projective_add_and_sub() {
863 let basepoint_affine = AffinePoint::GENERATOR;
864 let basepoint_projective = ProjectivePoint::GENERATOR;
865
866 assert_eq!(
867 (basepoint_projective + &basepoint_projective) - &basepoint_projective,
868 basepoint_projective
869 );
870 assert_eq!(
871 (basepoint_projective + &basepoint_affine) - &basepoint_affine,
872 basepoint_projective
873 );
874 }
875
876 #[test]
877 fn projective_double_and_sub() {
878 let generator = ProjectivePoint::GENERATOR;
879 assert_eq!(generator.double() - &generator, generator);
880 }
881
882 #[test]
883 fn test_vector_scalar_mult() {
884 let generator = ProjectivePoint::GENERATOR;
885
886 for (k, coords) in ADD_TEST_VECTORS
887 .iter()
888 .enumerate()
889 .map(|(k, coords)| (Scalar::from(k as u32 + 1), *coords))
890 .chain(
891 MUL_TEST_VECTORS
892 .iter()
893 .cloned()
894 .map(|(k, x, y)| (Scalar::from_repr(k.into()).unwrap(), (x, y))),
895 )
896 {
897 let res = (generator * &k).to_affine();
898 assert_eq!(res.x.to_bytes(), coords.0.into());
899 assert_eq!(res.y.to_bytes(), coords.1.into());
900 }
901 }
902
903 #[test]
904 fn projective_equality() {
905 use core::ops::Neg;
906 assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::IDENTITY);
907 assert_ne!(ProjectivePoint::IDENTITY, ProjectivePoint::GENERATOR);
908 assert_eq!(ProjectivePoint::IDENTITY, ProjectivePoint::IDENTITY);
909 assert_eq!(ProjectivePoint::IDENTITY.neg(), ProjectivePoint::IDENTITY);
910 assert_eq!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR);
911 assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR.neg());
912
913 assert_ne!(ProjectivePoint::GENERATOR, AffinePoint::IDENTITY);
914 assert_ne!(ProjectivePoint::IDENTITY, AffinePoint::GENERATOR);
915 assert_eq!(ProjectivePoint::IDENTITY, AffinePoint::IDENTITY);
916 assert_eq!(ProjectivePoint::IDENTITY.neg(), AffinePoint::IDENTITY);
917 assert_eq!(ProjectivePoint::GENERATOR, AffinePoint::GENERATOR);
918 assert_ne!(ProjectivePoint::GENERATOR.neg(), AffinePoint::GENERATOR);
919 assert_eq!(
920 ProjectivePoint::GENERATOR.neg(),
921 AffinePoint::GENERATOR.neg()
922 );
923 }
924}