1#![allow(clippy::op_ref)]
4
5use super::{AffinePoint, CURVE_EQUATION_B_SINGLE, FieldElement, Scalar};
6use crate::{CompressedPoint, PublicKey, Sec1Point, Secp256k1};
7use core::{
8 iter::Sum,
9 ops::{Add, AddAssign, Neg, Sub, SubAssign},
10};
11use elliptic_curve::{
12 BatchNormalize, CurveGroup, Error, Generate, Result,
13 array::{Array, ArraySize},
14 ctutils,
15 group::{
16 CurveAffine, Group, GroupEncoding,
17 cofactor::CofactorGroup,
18 prime::{PrimeCurve, PrimeGroup},
19 },
20 ops::{BatchInvert, Double},
21 point::NonIdentity,
22 rand_core::{TryCryptoRng, TryRng},
23 sec1::{FromSec1Point, ToSec1Point},
24 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
25 zeroize::DefaultIsZeroes,
26};
27
28#[cfg(feature = "alloc")]
29use alloc::vec::Vec;
30
31#[rustfmt::skip]
32const ENDOMORPHISM_BETA: FieldElement = FieldElement::from_bytes_unchecked(&[
33 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10,
34 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9,
35 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95,
36 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee,
37]);
38
39#[derive(Clone, Copy, Debug)]
41pub struct ProjectivePoint {
42 x: FieldElement,
43 y: FieldElement,
44 pub(super) z: FieldElement,
45}
46
47impl ProjectivePoint {
48 pub const IDENTITY: Self = Self {
50 x: FieldElement::ZERO,
51 y: FieldElement::ONE,
52 z: FieldElement::ZERO,
53 };
54
55 pub const GENERATOR: Self = Self {
57 x: AffinePoint::GENERATOR.x,
58 y: AffinePoint::GENERATOR.y,
59 z: FieldElement::ONE,
60 };
61
62 #[must_use]
64 pub fn to_affine(&self) -> AffinePoint {
65 self.z
66 .invert()
67 .map(|zinv| self.to_affine_internal(zinv))
68 .unwrap_or_else(|| AffinePoint::IDENTITY)
69 }
70
71 pub(super) fn to_affine_internal(self, zinv: FieldElement) -> AffinePoint {
72 let x = self.x * &zinv;
73 let y = self.y * &zinv;
74 AffinePoint::new(x.normalize(), y.normalize())
75 }
76
77 #[inline]
79 fn neg(&self) -> ProjectivePoint {
80 ProjectivePoint {
81 x: self.x,
82 y: self.y.negate(1).normalize_weak(),
83 z: self.z,
84 }
85 }
86
87 #[inline]
89 fn add(&self, other: &ProjectivePoint) -> ProjectivePoint {
90 let mut ret = *self;
91 ret.add_assign(other);
92 ret
93 }
94
95 fn add_assign(&mut self, other: &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 self.x = ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(); self.y = ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak();
130 self.z = ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak();
131 }
132
133 #[inline]
135 fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
136 let mut ret = *self;
137 ret.add_assign_mixed(other);
138 ret
139 }
140
141 fn add_assign_mixed(&mut self, other: &AffinePoint) {
143 let xx = self.x * &other.x;
147 let yy = self.y * &other.y;
148 let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) + &(xx + &yy).negate(2);
149 let yz_pairs = (other.y * &self.z) + &self.y;
150 let xz_pairs = (other.x * &self.z) + &self.x;
151
152 let bzz = &self.z.mul_single(CURVE_EQUATION_B_SINGLE);
153 let bzz3 = (bzz.double() + bzz).normalize_weak();
154
155 let yy_m_bzz3 = yy + &bzz3.negate(1);
156 let yy_p_bzz3 = yy + &bzz3;
157
158 let byz = &yz_pairs
159 .mul_single(CURVE_EQUATION_B_SINGLE)
160 .normalize_weak();
161 let byz3 = (byz.double() + byz).normalize_weak();
162
163 let xx3 = xx.double() + &xx;
164 let bxx9 = &(xx3.double() + &xx3)
165 .normalize_weak()
166 .mul_single(CURVE_EQUATION_B_SINGLE)
167 .normalize_weak();
168
169 let x = ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak();
170 let y = ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak();
171 let z = ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak();
172
173 self.x.conditional_assign(&x, !other.is_identity());
174 self.y.conditional_assign(&y, !other.is_identity());
175 self.z.conditional_assign(&z, !other.is_identity());
176 }
177
178 #[inline]
180 #[must_use]
181 pub fn double(&self) -> ProjectivePoint {
182 let mut ret = *self;
183 ret.double_in_place();
184 ret
185 }
186
187 #[inline]
189 pub fn double_in_place(&mut self) {
190 let yy = self.y.square();
194 let zz = self.z.square();
195 let xy2 = (self.x * &self.y).double();
196
197 let bzz = &zz.mul_single(CURVE_EQUATION_B_SINGLE);
198 let bzz3 = (bzz.double() + bzz).normalize_weak();
199 let bzz9 = (bzz3.double() + &bzz3).normalize_weak();
200
201 let yy_m_bzz9 = yy + &bzz9.negate(1);
202 let yy_p_bzz3 = yy + &bzz3;
203
204 let yy_zz = yy * &zz;
205 let yy_zz8 = yy_zz.double().double().double();
206 let t = (yy_zz8.double() + &yy_zz8)
207 .normalize_weak()
208 .mul_single(CURVE_EQUATION_B_SINGLE);
209
210 self.x = xy2 * &yy_m_bzz9;
211 self.z = ((yy * &self.y) * &self.z)
212 .double()
213 .double()
214 .double()
215 .normalize_weak();
216 self.y = ((yy_m_bzz9 * &yy_p_bzz3) + &t).normalize_weak();
217 }
218
219 fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint {
221 self.add(&other.neg())
222 }
223
224 fn sub_assign(&mut self, other: &ProjectivePoint) {
226 self.add_assign(&other.neg());
227 }
228
229 fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
231 self.add_mixed(&other.neg())
232 }
233
234 fn sub_assign_mixed(&mut self, other: &AffinePoint) {
236 self.add_assign_mixed(&other.neg());
237 }
238
239 #[must_use]
241 pub fn endomorphism(&self) -> Self {
242 Self {
243 x: self.x * &ENDOMORPHISM_BETA,
244 y: self.y,
245 z: self.z,
246 }
247 }
248
249 #[must_use]
254 pub fn eq_affine(&self, other: &AffinePoint) -> Choice {
255 let both_identity = self.is_identity() & other.is_identity();
258 let rhs_identity = other.is_identity();
259 let rhs_x = &other.x * &self.z;
260 let x_eq = rhs_x.negate(1).add(&self.x).normalizes_to_zero();
261
262 let rhs_y = &other.y * &self.z;
263 let y_eq = rhs_y.negate(1).add(&self.y).normalizes_to_zero();
264
265 both_identity | (!rhs_identity & x_eq & y_eq)
266 }
267}
268
269impl Double for ProjectivePoint {
270 #[inline]
271 fn double(&self) -> Self {
272 self.double()
273 }
274
275 #[inline]
276 fn double_in_place(&mut self) {
277 self.double_in_place();
278 }
279}
280
281impl From<AffinePoint> for ProjectivePoint {
282 fn from(p: AffinePoint) -> Self {
283 let projective = ProjectivePoint {
284 x: p.x,
285 y: p.y,
286 z: FieldElement::ONE,
287 };
288 Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity())
289 }
290}
291
292impl Generate for ProjectivePoint {
293 fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
294 rng: &mut R,
295 ) -> core::result::Result<Self, R::Error> {
296 AffinePoint::try_generate_from_rng(rng).map(Into::into)
297 }
298}
299
300impl<const N: usize> BatchNormalize<[ProjectivePoint; N]> for ProjectivePoint {
301 type Output = [AffinePoint; N];
302
303 #[inline]
304 fn batch_normalize(points: &[Self; N]) -> [AffinePoint; N] {
305 let mut zs = [FieldElement::ZERO; N];
306 let mut scratch = [FieldElement::ZERO; N];
307 let mut affine_points = [AffinePoint::IDENTITY; N];
308 batch_normalize(points, &mut zs, &mut scratch, &mut affine_points);
309 affine_points
310 }
311
312 #[inline]
313 fn batch_normalize_vartime(points: &[Self; N]) -> [AffinePoint; N] {
314 let mut zs = [FieldElement::ZERO; N];
315 let mut scratch = [FieldElement::ZERO; N];
316 let mut affine_points = [AffinePoint::IDENTITY; N];
317 batch_normalize_vartime(points, &mut zs, &mut scratch, &mut affine_points);
318 affine_points
319 }
320}
321
322impl<U: ArraySize> BatchNormalize<Array<ProjectivePoint, U>> for ProjectivePoint {
323 type Output = Array<AffinePoint, U>;
324
325 #[inline]
326 fn batch_normalize(points: &Array<Self, U>) -> Array<AffinePoint, U> {
327 let mut zs = Array::<FieldElement, U>::default();
328 let mut scratch = Array::<FieldElement, U>::default();
329 let mut affine_points = Array::<AffinePoint, U>::default();
330 batch_normalize(points, &mut zs, &mut scratch, &mut affine_points);
331 affine_points
332 }
333
334 #[inline]
335 fn batch_normalize_vartime(points: &Array<Self, U>) -> Array<AffinePoint, U> {
336 let mut zs = Array::<FieldElement, U>::default();
337 let mut scratch = Array::<FieldElement, U>::default();
338 let mut affine_points = Array::<AffinePoint, U>::default();
339 batch_normalize_vartime(points, &mut zs, &mut scratch, &mut affine_points);
340 affine_points
341 }
342}
343
344#[cfg(feature = "alloc")]
345impl BatchNormalize<[ProjectivePoint]> for ProjectivePoint {
346 type Output = Vec<AffinePoint>;
347
348 #[inline]
349 fn batch_normalize(points: &[Self]) -> Vec<AffinePoint> {
350 let mut zs = vec![FieldElement::ZERO; points.len()];
351 let mut scratch = vec![FieldElement::ZERO; points.len()];
352 let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
353 batch_normalize(points, &mut zs, &mut scratch, &mut affine_points);
354 affine_points
355 }
356
357 #[inline]
358 fn batch_normalize_vartime(points: &[Self]) -> Vec<AffinePoint> {
359 let mut zs = vec![FieldElement::ZERO; points.len()];
360 let mut scratch = vec![FieldElement::ZERO; points.len()];
361 let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
362 batch_normalize_vartime(points, &mut zs, &mut scratch, &mut affine_points);
363 affine_points
364 }
365}
366
367fn batch_normalize(
368 points: &[ProjectivePoint],
369 zs: &mut [FieldElement],
370 scratch: &mut [FieldElement],
371 out: &mut [AffinePoint],
372) {
373 debug_assert_eq!(points.len(), zs.len());
374 debug_assert_eq!(points.len(), scratch.len());
375 debug_assert_eq!(points.len(), out.len());
376
377 for (z, point) in zs.iter_mut().zip(points) {
378 *z = point.z;
379 }
380
381 let _ = FieldElement::batch_invert_in_place(zs, scratch);
383
384 for i in 0..out.len() {
385 out[i] = AffinePoint::conditional_select(
386 &points[i].to_affine_internal(zs[i]),
387 &AffinePoint::IDENTITY,
388 points[i].z.normalizes_to_zero(),
389 );
390 }
391}
392
393fn batch_normalize_vartime(
394 points: &[ProjectivePoint],
395 zs: &mut [FieldElement],
396 scratch: &mut [FieldElement],
397 out: &mut [AffinePoint],
398) {
399 debug_assert_eq!(points.len(), zs.len());
400 debug_assert_eq!(points.len(), scratch.len());
401 debug_assert_eq!(points.len(), out.len());
402
403 for (z, point) in zs.iter_mut().zip(points) {
404 *z = point.z;
405 }
406
407 let _ = FieldElement::batch_invert_in_place_vartime(zs, scratch);
409
410 for i in 0..out.len() {
411 out[i] = if bool::from(points[i].z.normalizes_to_zero()) {
412 AffinePoint::IDENTITY
413 } else {
414 points[i].to_affine_internal(zs[i])
415 };
416 }
417}
418
419impl From<&AffinePoint> for ProjectivePoint {
420 fn from(p: &AffinePoint) -> Self {
421 Self::from(*p)
422 }
423}
424
425impl From<NonIdentity<ProjectivePoint>> for ProjectivePoint {
426 fn from(p: NonIdentity<ProjectivePoint>) -> Self {
427 p.to_point()
428 }
429}
430
431impl From<ProjectivePoint> for AffinePoint {
432 fn from(p: ProjectivePoint) -> AffinePoint {
433 p.to_affine()
434 }
435}
436
437impl From<&ProjectivePoint> for AffinePoint {
438 fn from(p: &ProjectivePoint) -> AffinePoint {
439 p.to_affine()
440 }
441}
442
443impl FromSec1Point<Secp256k1> for ProjectivePoint {
444 fn from_sec1_point(p: &Sec1Point) -> ctutils::CtOption<Self> {
445 AffinePoint::from_sec1_point(p).map(ProjectivePoint::from)
446 }
447}
448
449impl ToSec1Point<Secp256k1> for ProjectivePoint {
450 fn to_sec1_point(&self, compress: bool) -> Sec1Point {
451 self.to_affine().to_sec1_point(compress)
452 }
453}
454
455impl ConditionallySelectable for ProjectivePoint {
456 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
457 ProjectivePoint {
458 x: FieldElement::conditional_select(&a.x, &b.x, choice),
459 y: FieldElement::conditional_select(&a.y, &b.y, choice),
460 z: FieldElement::conditional_select(&a.z, &b.z, choice),
461 }
462 }
463}
464
465impl ConstantTimeEq for ProjectivePoint {
466 fn ct_eq(&self, other: &Self) -> Choice {
467 let lhs_x = self.x * &other.z;
482 let rhs_x = other.x * &self.z;
483 let x_eq = rhs_x.negate(1).add(&lhs_x).normalizes_to_zero();
484
485 let lhs_y = self.y * &other.z;
486 let rhs_y = other.y * &self.z;
487 let y_eq = rhs_y.negate(1).add(&lhs_y).normalizes_to_zero();
488 x_eq & y_eq
489 }
490}
491
492impl ctutils::CtEq for ProjectivePoint {
493 fn ct_eq(&self, other: &Self) -> ctutils::Choice {
494 ConstantTimeEq::ct_eq(self, other).into()
495 }
496}
497
498impl ctutils::CtSelect for ProjectivePoint {
499 fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self {
500 ConditionallySelectable::conditional_select(self, other, choice.into())
501 }
502}
503
504impl Default for ProjectivePoint {
505 fn default() -> Self {
506 Self::IDENTITY
507 }
508}
509
510impl DefaultIsZeroes for ProjectivePoint {}
511
512impl Eq for ProjectivePoint {}
513
514impl PartialEq for ProjectivePoint {
515 fn eq(&self, other: &Self) -> bool {
516 self.ct_eq(other).into()
517 }
518}
519
520impl PartialEq<AffinePoint> for ProjectivePoint {
521 fn eq(&self, other: &AffinePoint) -> bool {
522 self.eq_affine(other).into()
523 }
524}
525
526impl PartialEq<ProjectivePoint> for AffinePoint {
527 fn eq(&self, other: &ProjectivePoint) -> bool {
528 other.eq_affine(self).into()
529 }
530}
531
532impl CofactorGroup for ProjectivePoint {
538 type Subgroup = Self;
539
540 fn clear_cofactor(&self) -> Self::Subgroup {
541 *self
542 }
543
544 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
545 CtOption::new(self, Choice::from(1))
546 }
547
548 fn is_torsion_free(&self) -> Choice {
549 Choice::from(1)
550 }
551}
552
553impl CurveGroup for ProjectivePoint {
554 type Affine = AffinePoint;
555
556 fn to_affine(&self) -> AffinePoint {
557 ProjectivePoint::to_affine(self)
558 }
559
560 #[cfg(feature = "alloc")]
561 #[inline]
562 fn batch_normalize(projective: &[Self], affine: &mut [Self::Affine]) {
563 assert_eq!(projective.len(), affine.len());
564 let mut zs = vec![FieldElement::ZERO; projective.len()];
565 let mut scratch = vec![FieldElement::ZERO; projective.len()];
566 batch_normalize(projective, &mut zs, &mut scratch, affine);
567 }
568}
569
570impl Group for ProjectivePoint {
571 type Scalar = Scalar;
572
573 fn try_random<R: TryRng + ?Sized>(rng: &mut R) -> core::result::Result<Self, R::Error> {
574 AffinePoint::try_random(rng).map(Self::from)
575 }
576
577 fn identity() -> Self {
578 Self::IDENTITY
579 }
580
581 fn generator() -> Self {
582 Self::GENERATOR
583 }
584
585 fn is_identity(&self) -> Choice {
586 self.z.normalizes_to_zero()
587 }
588
589 #[inline]
590 fn double(&self) -> Self {
591 Self::double(self)
592 }
593
594 #[inline]
595 fn mul_by_generator(k: &Scalar) -> Self {
596 Self::mul_by_generator(k)
597 }
598}
599
600impl GroupEncoding for ProjectivePoint {
601 type Repr = CompressedPoint;
602
603 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
604 <AffinePoint as GroupEncoding>::from_bytes(bytes).map(Into::into)
605 }
606
607 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
608 Self::from_bytes(bytes)
610 }
611
612 fn to_bytes(&self) -> Self::Repr {
613 self.to_affine().to_bytes()
614 }
615}
616
617impl PrimeCurve for ProjectivePoint {}
618impl PrimeGroup for ProjectivePoint {}
619
620impl Add<&ProjectivePoint> for &ProjectivePoint {
625 type Output = ProjectivePoint;
626
627 #[inline]
628 fn add(self, rhs: &ProjectivePoint) -> ProjectivePoint {
629 ProjectivePoint::add(self, rhs)
630 }
631}
632
633impl Add<ProjectivePoint> for ProjectivePoint {
634 type Output = ProjectivePoint;
635
636 #[inline]
637 fn add(self, rhs: ProjectivePoint) -> ProjectivePoint {
638 ProjectivePoint::add(&self, &rhs)
639 }
640}
641
642impl Add<&ProjectivePoint> for ProjectivePoint {
643 type Output = ProjectivePoint;
644
645 #[inline]
646 fn add(self, rhs: &ProjectivePoint) -> ProjectivePoint {
647 ProjectivePoint::add(&self, rhs)
648 }
649}
650
651impl AddAssign<ProjectivePoint> for ProjectivePoint {
652 #[inline]
653 fn add_assign(&mut self, rhs: ProjectivePoint) {
654 ProjectivePoint::add_assign(self, &rhs);
655 }
656}
657
658impl AddAssign<&ProjectivePoint> for ProjectivePoint {
659 #[inline]
660 fn add_assign(&mut self, rhs: &ProjectivePoint) {
661 ProjectivePoint::add_assign(self, rhs);
662 }
663}
664
665impl Add<AffinePoint> for ProjectivePoint {
666 type Output = ProjectivePoint;
667
668 #[inline]
669 fn add(self, rhs: AffinePoint) -> ProjectivePoint {
670 ProjectivePoint::add_mixed(&self, &rhs)
671 }
672}
673
674impl Add<&AffinePoint> for &ProjectivePoint {
675 type Output = ProjectivePoint;
676
677 #[inline]
678 fn add(self, rhs: &AffinePoint) -> ProjectivePoint {
679 ProjectivePoint::add_mixed(self, rhs)
680 }
681}
682
683impl Add<&AffinePoint> for ProjectivePoint {
684 type Output = ProjectivePoint;
685
686 #[inline]
687 fn add(self, rhs: &AffinePoint) -> ProjectivePoint {
688 ProjectivePoint::add_mixed(&self, rhs)
689 }
690}
691
692impl AddAssign<AffinePoint> for ProjectivePoint {
693 #[inline]
694 fn add_assign(&mut self, rhs: AffinePoint) {
695 ProjectivePoint::add_assign_mixed(self, &rhs);
696 }
697}
698
699impl AddAssign<&AffinePoint> for ProjectivePoint {
700 #[inline]
701 fn add_assign(&mut self, rhs: &AffinePoint) {
702 ProjectivePoint::add_assign_mixed(self, rhs);
703 }
704}
705
706impl Sum for ProjectivePoint {
707 #[inline]
708 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
709 iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b)
710 }
711}
712
713impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint {
714 #[inline]
715 fn sum<I: Iterator<Item = &'a ProjectivePoint>>(iter: I) -> Self {
716 iter.cloned().sum()
717 }
718}
719
720impl Sub<ProjectivePoint> for ProjectivePoint {
721 type Output = ProjectivePoint;
722
723 #[inline]
724 fn sub(self, rhs: ProjectivePoint) -> ProjectivePoint {
725 ProjectivePoint::sub(&self, &rhs)
726 }
727}
728
729impl Sub<&ProjectivePoint> for &ProjectivePoint {
730 type Output = ProjectivePoint;
731
732 #[inline]
733 fn sub(self, rhs: &ProjectivePoint) -> ProjectivePoint {
734 ProjectivePoint::sub(self, rhs)
735 }
736}
737
738impl Sub<&ProjectivePoint> for ProjectivePoint {
739 type Output = ProjectivePoint;
740
741 #[inline]
742 fn sub(self, rhs: &ProjectivePoint) -> ProjectivePoint {
743 ProjectivePoint::sub(&self, rhs)
744 }
745}
746
747impl SubAssign<ProjectivePoint> for ProjectivePoint {
748 #[inline]
749 fn sub_assign(&mut self, rhs: ProjectivePoint) {
750 ProjectivePoint::sub_assign(self, &rhs);
751 }
752}
753
754impl SubAssign<&ProjectivePoint> for ProjectivePoint {
755 #[inline]
756 fn sub_assign(&mut self, rhs: &ProjectivePoint) {
757 ProjectivePoint::sub_assign(self, rhs);
758 }
759}
760
761impl Sub<AffinePoint> for ProjectivePoint {
762 type Output = ProjectivePoint;
763
764 #[inline]
765 fn sub(self, rhs: AffinePoint) -> ProjectivePoint {
766 ProjectivePoint::sub_mixed(&self, &rhs)
767 }
768}
769
770impl Sub<&AffinePoint> for &ProjectivePoint {
771 type Output = ProjectivePoint;
772
773 #[inline]
774 fn sub(self, rhs: &AffinePoint) -> ProjectivePoint {
775 ProjectivePoint::sub_mixed(self, rhs)
776 }
777}
778
779impl Sub<&AffinePoint> for ProjectivePoint {
780 type Output = ProjectivePoint;
781
782 #[inline]
783 fn sub(self, rhs: &AffinePoint) -> ProjectivePoint {
784 ProjectivePoint::sub_mixed(&self, rhs)
785 }
786}
787
788impl SubAssign<AffinePoint> for ProjectivePoint {
789 #[inline]
790 fn sub_assign(&mut self, rhs: AffinePoint) {
791 ProjectivePoint::sub_assign_mixed(self, &rhs);
792 }
793}
794
795impl SubAssign<&AffinePoint> for ProjectivePoint {
796 #[inline]
797 fn sub_assign(&mut self, rhs: &AffinePoint) {
798 ProjectivePoint::sub_assign_mixed(self, rhs);
799 }
800}
801
802impl Neg for ProjectivePoint {
803 type Output = ProjectivePoint;
804
805 #[inline]
806 fn neg(self) -> ProjectivePoint {
807 ProjectivePoint::neg(&self)
808 }
809}
810
811impl Neg for &ProjectivePoint {
812 type Output = ProjectivePoint;
813
814 #[inline]
815 fn neg(self) -> ProjectivePoint {
816 ProjectivePoint::neg(self)
817 }
818}
819
820impl From<PublicKey> for ProjectivePoint {
821 fn from(public_key: PublicKey) -> ProjectivePoint {
822 AffinePoint::from(public_key).into()
823 }
824}
825
826impl From<&PublicKey> for ProjectivePoint {
827 fn from(public_key: &PublicKey) -> ProjectivePoint {
828 AffinePoint::from(public_key).into()
829 }
830}
831
832impl TryFrom<ProjectivePoint> for NonIdentity<ProjectivePoint> {
834 type Error = Error;
835
836 fn try_from(point: ProjectivePoint) -> Result<Self> {
837 NonIdentity::new(point).into_option().ok_or(Error)
838 }
839}
840
841impl TryFrom<ProjectivePoint> for PublicKey {
842 type Error = Error;
843
844 fn try_from(point: ProjectivePoint) -> Result<PublicKey> {
845 AffinePoint::from(point).try_into()
846 }
847}
848
849impl TryFrom<&ProjectivePoint> for PublicKey {
850 type Error = Error;
851
852 fn try_from(point: &ProjectivePoint) -> Result<PublicKey> {
853 AffinePoint::from(point).try_into()
854 }
855}
856
857#[cfg(test)]
858mod tests {
859 use super::{AffinePoint, ProjectivePoint};
860 use crate::{
861 Scalar,
862 test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS},
863 };
864 use elliptic_curve::group::{CurveAffine, ff::PrimeField};
865
866 #[cfg(all(feature = "alloc", feature = "getrandom"))]
867 use alloc::vec::Vec;
868 #[cfg(feature = "getrandom")]
869 use elliptic_curve::{BatchNormalize, CurveGroup, Generate};
870
871 #[test]
872 fn affine_to_projective() {
873 let basepoint_affine = AffinePoint::GENERATOR;
874 let basepoint_projective = ProjectivePoint::GENERATOR;
875
876 assert_eq!(
877 ProjectivePoint::from(basepoint_affine),
878 basepoint_projective,
879 );
880 assert_eq!(basepoint_projective.to_affine(), basepoint_affine);
881 assert!(!bool::from(basepoint_projective.to_affine().is_identity()));
882
883 assert!(bool::from(
884 ProjectivePoint::IDENTITY.to_affine().is_identity()
885 ));
886 }
887
888 #[test]
889 #[cfg(feature = "getrandom")]
890 fn batch_normalize_array() {
891 let k = Scalar::generate();
892 let l = Scalar::generate();
893 let g = ProjectivePoint::mul_by_generator(&k);
894 let h = ProjectivePoint::mul_by_generator(&l);
895
896 let mut res = [AffinePoint::IDENTITY; 2];
897 let expected = [g.to_affine(), h.to_affine()];
898 assert_eq!(
899 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(&[g, h]),
900 expected
901 );
902
903 <ProjectivePoint as CurveGroup>::batch_normalize(&[g, h], &mut res);
904 assert_eq!(res, expected);
905
906 let mut res = [AffinePoint::IDENTITY; 3];
907 let non_normalized_identity = ProjectivePoint::IDENTITY * Scalar::generate();
908 let expected = [g.to_affine(), AffinePoint::IDENTITY, AffinePoint::IDENTITY];
909 assert_eq!(
910 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(&[
911 g,
912 ProjectivePoint::IDENTITY,
913 non_normalized_identity,
914 ]),
915 expected
916 );
917
918 <ProjectivePoint as CurveGroup>::batch_normalize(
919 &[g, ProjectivePoint::IDENTITY, non_normalized_identity],
920 &mut res,
921 );
922 assert_eq!(res, expected);
923 }
924
925 #[test]
926 #[cfg(all(feature = "alloc", feature = "getrandom"))]
927 fn batch_normalize_slice() {
928 let k: Scalar = Scalar::generate();
929 let l: Scalar = Scalar::generate();
930 let g = ProjectivePoint::mul_by_generator(&k);
931 let h = ProjectivePoint::mul_by_generator(&l);
932
933 let expected = vec![g.to_affine(), h.to_affine()];
934 let scalars = vec![g, h];
935 let mut res: Vec<_> =
936 <ProjectivePoint as BatchNormalize<_>>::batch_normalize(scalars.as_slice());
937 assert_eq!(res, expected);
938
939 <ProjectivePoint as CurveGroup>::batch_normalize(&[g, h], res.as_mut());
940 assert_eq!(res.to_vec(), expected);
941
942 let expected = vec![g.to_affine(), AffinePoint::IDENTITY];
943 let scalars = vec![g, ProjectivePoint::IDENTITY];
944 res = <ProjectivePoint as BatchNormalize<_>>::batch_normalize(scalars.as_slice());
945
946 assert_eq!(res, expected);
947
948 <ProjectivePoint as CurveGroup>::batch_normalize(
949 &[g, ProjectivePoint::IDENTITY],
950 res.as_mut(),
951 );
952 assert_eq!(res.to_vec(), expected);
953 }
954
955 #[test]
956 fn projective_identity_addition() {
957 let identity = ProjectivePoint::IDENTITY;
958 let generator = ProjectivePoint::GENERATOR;
959
960 assert_eq!(identity + &generator, generator);
961 assert_eq!(generator + &identity, generator);
962 }
963
964 #[test]
965 fn projective_mixed_addition() {
966 let identity = ProjectivePoint::IDENTITY;
967 let basepoint_affine = AffinePoint::GENERATOR;
968 let basepoint_projective = ProjectivePoint::GENERATOR;
969
970 assert_eq!(identity + &basepoint_affine, basepoint_projective);
971 assert_eq!(
972 basepoint_projective + &basepoint_affine,
973 basepoint_projective + &basepoint_projective
974 );
975 }
976
977 #[test]
978 fn test_vector_repeated_add() {
979 let generator = ProjectivePoint::GENERATOR;
980 let mut p = generator;
981
982 for i in 0..ADD_TEST_VECTORS.len() {
983 let affine = p.to_affine();
984
985 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
986 assert_eq!(affine.x.to_bytes(), expected_x);
987 assert_eq!(affine.y.to_bytes(), expected_y);
988
989 p += &generator;
990 }
991 }
992
993 #[test]
994 fn test_vector_repeated_add_mixed() {
995 let generator = AffinePoint::GENERATOR;
996 let mut p = ProjectivePoint::GENERATOR;
997
998 for i in 0..ADD_TEST_VECTORS.len() {
999 let affine = p.to_affine();
1000
1001 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
1002 assert_eq!(affine.x.to_bytes(), expected_x);
1003 assert_eq!(affine.y.to_bytes(), expected_y);
1004
1005 p += &generator;
1006 }
1007 }
1008
1009 #[test]
1010 fn test_vector_add_mixed_identity() {
1011 let generator = ProjectivePoint::GENERATOR;
1012 let p0 = generator + ProjectivePoint::IDENTITY;
1013 let p1 = generator + AffinePoint::IDENTITY;
1014 assert_eq!(p0, p1);
1015 }
1016
1017 #[test]
1018 fn test_vector_double_generator() {
1019 let generator = ProjectivePoint::GENERATOR;
1020 let mut p = generator;
1021
1022 for i in 0..2 {
1023 let affine = p.to_affine();
1024
1025 let (expected_x, expected_y) = ADD_TEST_VECTORS[i];
1026 assert_eq!(affine.x.to_bytes(), expected_x);
1027 assert_eq!(affine.y.to_bytes(), expected_y);
1028
1029 p = p.double();
1030 }
1031 }
1032
1033 #[test]
1034 fn projective_add_vs_double() {
1035 let generator = ProjectivePoint::GENERATOR;
1036
1037 let r1 = generator + &generator;
1038 let r2 = generator.double();
1039 assert_eq!(r1, r2);
1040
1041 let r1 = (generator + &generator) + &(generator + &generator);
1042 let r2 = generator.double().double();
1043 assert_eq!(r1, r2);
1044 }
1045
1046 #[test]
1047 fn projective_add_and_sub() {
1048 let basepoint_affine = AffinePoint::GENERATOR;
1049 let basepoint_projective = ProjectivePoint::GENERATOR;
1050
1051 assert_eq!(
1052 (basepoint_projective + &basepoint_projective) - &basepoint_projective,
1053 basepoint_projective
1054 );
1055 assert_eq!(
1056 (basepoint_projective + &basepoint_affine) - &basepoint_affine,
1057 basepoint_projective
1058 );
1059 }
1060
1061 #[test]
1062 fn projective_double_and_sub() {
1063 let generator = ProjectivePoint::GENERATOR;
1064 assert_eq!(generator.double() - &generator, generator);
1065 }
1066
1067 #[test]
1068 #[allow(clippy::cast_possible_truncation, reason = "test")]
1069 fn test_vector_scalar_mult() {
1070 let generator = ProjectivePoint::GENERATOR;
1071
1072 for (k, coords) in ADD_TEST_VECTORS
1073 .iter()
1074 .enumerate()
1075 .map(|(k, coords)| (Scalar::from(k as u32 + 1), *coords))
1076 .chain(
1077 MUL_TEST_VECTORS
1078 .iter()
1079 .cloned()
1080 .map(|(k, x, y)| (Scalar::from_repr(k.into()).unwrap(), (x, y))),
1081 )
1082 {
1083 let res = (generator * &k).to_affine();
1084 assert_eq!(res.x.to_bytes(), coords.0);
1085 assert_eq!(res.y.to_bytes(), coords.1);
1086 }
1087 }
1088
1089 #[test]
1090 fn projective_equality() {
1091 use core::ops::Neg;
1092 assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::IDENTITY);
1093 assert_ne!(ProjectivePoint::IDENTITY, ProjectivePoint::GENERATOR);
1094 assert_eq!(ProjectivePoint::IDENTITY, ProjectivePoint::IDENTITY);
1095 assert_eq!(ProjectivePoint::IDENTITY.neg(), ProjectivePoint::IDENTITY);
1096 assert_eq!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR);
1097 assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR.neg());
1098
1099 assert_ne!(ProjectivePoint::GENERATOR, AffinePoint::IDENTITY);
1100 assert_ne!(ProjectivePoint::IDENTITY, AffinePoint::GENERATOR);
1101 assert_eq!(ProjectivePoint::IDENTITY, AffinePoint::IDENTITY);
1102 assert_eq!(ProjectivePoint::IDENTITY.neg(), AffinePoint::IDENTITY);
1103 assert_eq!(ProjectivePoint::GENERATOR, AffinePoint::GENERATOR);
1104 assert_ne!(ProjectivePoint::GENERATOR.neg(), AffinePoint::GENERATOR);
1105 assert_eq!(
1106 ProjectivePoint::GENERATOR.neg(),
1107 AffinePoint::GENERATOR.neg()
1108 );
1109 }
1110}