k256/arithmetic/
projective.rs

1//! Projective points
2
3#![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/// A point on the secp256k1 curve in projective coordinates.
37#[derive(Clone, Copy, Debug)]
38pub struct ProjectivePoint {
39    x: FieldElement,
40    y: FieldElement,
41    pub(super) z: FieldElement,
42}
43
44impl ProjectivePoint {
45    /// Additive identity of the group: the point at infinity.
46    pub const IDENTITY: Self = Self {
47        x: FieldElement::ZERO,
48        y: FieldElement::ONE,
49        z: FieldElement::ZERO,
50    };
51
52    /// Base point of secp256k1.
53    pub const GENERATOR: Self = Self {
54        x: AffinePoint::GENERATOR.x,
55        y: AffinePoint::GENERATOR.y,
56        z: FieldElement::ONE,
57    };
58
59    /// Returns the additive identity of SECP256k1, also known as the "neutral element" or
60    /// "point at infinity".
61    #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::IDENTITY` instead")]
62    pub const fn identity() -> ProjectivePoint {
63        Self::IDENTITY
64    }
65
66    /// Returns the base point of SECP256k1.
67    #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::GENERATOR` instead")]
68    pub fn generator() -> ProjectivePoint {
69        Self::GENERATOR
70    }
71
72    /// Returns the affine representation of this point.
73    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    /// Returns `-self`.
87    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    /// Returns `self + other`.
96    fn add(&self, other: &ProjectivePoint) -> 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        let new_x = ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(); // m1
129        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    /// Returns `self + other`.
140    fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
141        // We implement the complete addition formula from Renes-Costello-Batina 2015
142        // (https://eprint.iacr.org/2015/1060 Algorithm 8).
143
144        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    /// Doubles this point.
177    #[inline]
178    pub fn double(&self) -> ProjectivePoint {
179        // We implement the complete addition formula from Renes-Costello-Batina 2015
180        // (https://eprint.iacr.org/2015/1060 Algorithm 9).
181
182        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    /// Returns `self - other`.
211    fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint {
212        self.add(&other.neg())
213    }
214
215    /// Returns `self - other`.
216    fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint {
217        self.add_mixed(&other.neg())
218    }
219
220    /// Calculates SECP256k1 endomorphism: `self * lambda`.
221    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    /// Check whether `self` is equal to an affine point.
230    ///
231    /// This is a lot faster than first converting `self` to an `AffinePoint` and then doing the
232    /// comparison. It is a little bit faster than converting `other` to a `ProjectivePoint` first.
233    pub fn eq_affine(&self, other: &AffinePoint) -> Choice {
234        // For understanding of this algorithm see Projective equality comment. It's the same except
235        // that we know z = 1 for rhs and we have to check identity as a separate case.
236        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        // Even a single zero value will fail inversion for the entire batch.
296        // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds
297        // and treat that case specially later-on.
298        zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&FieldElement::ZERO));
299    }
300
301    // This is safe to unwrap since we assured that all elements are non-zero
302    let zs_inverses = <FieldElement as BatchInvert<Z>>::batch_invert(zs).unwrap();
303
304    for i in 0..out.len() {
305        // If the `z` coordinate is non-zero, we can use it to invert;
306        // otherwise it defaults to the `IDENTITY` value.
307        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        // If both points are not equal to inifinity then they are in the form:
358        //
359        // lhs: (x₁z₁, y₁z₁, z₁), rhs: (x₂z₂, y₂z₂, z₂) where z₁ ≠ 0 and z₂ ≠ 0.
360        // we want to know if x₁ == x₂ and y₁ == y₂
361        // So we multiply the x and y by the opposing z to get:
362        // lhs: (x₁z₁z₂, y₁z₁z₂) rhs: (x₂z₁z₂, y₂z₁z₂)
363        // and check lhs == rhs which implies x₁ == x₂ and y₁ == y₂.
364        //
365        // If one point is infinity it is always in the form (0, y, 0). Note that the above
366        // algorithm still works here. If They are both infinity then they'll both evaluate to (0,0).
367        // If for example the first point is infinity then the above will evaluate to (z₂ * 0, z₂ *
368        // y₂) = (0, z₂y₂) for the first point and (0 * x₂z₂, 0 * y₂z₂) = (0, 0) for the second.
369        //
370        // Since z₂y₂ will never be 0 they will not be equal in this case either.
371        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        // No unchecked conversion possible for compressed points
436        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}