Skip to main content

k256/arithmetic/
projective.rs

1//! Projective points
2
3#![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/// A point on the secp256k1 curve in projective coordinates.
40#[derive(Clone, Copy, Debug)]
41pub struct ProjectivePoint {
42    x: FieldElement,
43    y: FieldElement,
44    pub(super) z: FieldElement,
45}
46
47impl ProjectivePoint {
48    /// Additive identity of the group: the point at infinity.
49    pub const IDENTITY: Self = Self {
50        x: FieldElement::ZERO,
51        y: FieldElement::ONE,
52        z: FieldElement::ZERO,
53    };
54
55    /// Base point of secp256k1.
56    pub const GENERATOR: Self = Self {
57        x: AffinePoint::GENERATOR.x,
58        y: AffinePoint::GENERATOR.y,
59        z: FieldElement::ONE,
60    };
61
62    /// Returns the affine representation of this point.
63    #[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    /// Returns `-self`.
78    #[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    /// Returns `self + other`.
88    #[inline]
89    fn add(&self, other: &ProjectivePoint) -> ProjectivePoint {
90        let mut ret = *self;
91        ret.add_assign(other);
92        ret
93    }
94
95    /// Assign `self + other` to `self`.
96    fn add_assign(&mut self, other: &ProjectivePoint) {
97        // We implement the complete addition formula from Renes-Costello-Batina 2015
98        // (https://eprint.iacr.org/2015/1060 Algorithm 7).
99
100        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(); // m1
129        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    /// Returns `self + other`.
134    #[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    /// Assign `self + other` to `self`.
142    fn add_assign_mixed(&mut self, other: &AffinePoint) {
143        // We implement the complete addition formula from Renes-Costello-Batina 2015
144        // (https://eprint.iacr.org/2015/1060 Algorithm 8).
145
146        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    /// Doubles this point.
179    #[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    /// Doubles this point in-place.
188    #[inline]
189    pub fn double_in_place(&mut self) {
190        // We implement the complete addition formula from Renes-Costello-Batina 2015
191        // (https://eprint.iacr.org/2015/1060 Algorithm 9).
192
193        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    /// Returns `self - other`.
220    fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint {
221        self.add(&other.neg())
222    }
223
224    /// Assign `self - other` to `self`.
225    fn sub_assign(&mut self, other: &ProjectivePoint) {
226        self.add_assign(&other.neg());
227    }
228
229    /// Returns `self - other`.
230    fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
231        self.add_mixed(&other.neg())
232    }
233
234    /// Assign `self - other` to `self`.
235    fn sub_assign_mixed(&mut self, other: &AffinePoint) {
236        self.add_assign_mixed(&other.neg());
237    }
238
239    /// Calculates SECP256k1 endomorphism: `self * lambda`.
240    #[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    /// Check whether `self` is equal to an affine point.
250    ///
251    /// This is a lot faster than first converting `self` to an `AffinePoint` and then doing the
252    /// comparison. It is a little bit faster than converting `other` to a `ProjectivePoint` first.
253    #[must_use]
254    pub fn eq_affine(&self, other: &AffinePoint) -> Choice {
255        // For understanding of this algorithm see Projective equality comment. It's the same except
256        // that we know z = 1 for rhs and we have to check identity as a separate case.
257        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    // Zero `zs` (identity) are handled explicitly below, so the `Choice` here is informational only
382    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    // Zero `zs` (identity) are handled explicitly below, so the `Choice` here is informational only
408    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        // If both points are not equal to infinity then they are in the form:
468        //
469        // lhs: (x₁z₁, y₁z₁, z₁), rhs: (x₂z₂, y₂z₂, z₂) where z₁ ≠ 0 and z₂ ≠ 0.
470        // we want to know if x₁ == x₂ and y₁ == y₂
471        // So we multiply the x and y by the opposing z to get:
472        // lhs: (x₁z₁z₂, y₁z₁z₂) rhs: (x₂z₁z₂, y₂z₁z₂)
473        // and check lhs == rhs which implies x₁ == x₂ and y₁ == y₂.
474        //
475        // If one point is infinity it is always in the form (0, y, 0). Note that the above
476        // algorithm still works here. If They are both infinity then they'll both evaluate to (0,0).
477        // If for example the first point is infinity then the above will evaluate to (z₂ * 0, z₂ *
478        // y₂) = (0, z₂y₂) for the first point and (0 * x₂z₂, 0 * y₂z₂) = (0, 0) for the second.
479        //
480        // Since z₂y₂ will never be 0 they will not be equal in this case either.
481        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
532//
533// `group` trait impls
534//
535
536/// secp256k1 has a cofactor of 1.
537impl 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        // No unchecked conversion possible for compressed points
609        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
620//
621// `core::ops` trait impls
622//
623
624impl 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
832/// The constant-time alternative is available at [`NonIdentity::new()`].
833impl 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}