Skip to main content

primeorder/
projective.rs

1//! Projective curve points.
2
3#![allow(clippy::needless_range_loop, clippy::op_ref)]
4
5use crate::{
6    AffinePoint, Field, LookupTable, MulBackend, PrimeCurveParams, Radix16Decomposition,
7    Radix16Digits, point_arithmetic::PointArithmetic,
8};
9use core::{array, borrow::Borrow, iter::Sum, iter::zip};
10use elliptic_curve::{
11    BatchNormalize, CurveGroup, Error, Generate, PublicKey, Result, Scalar,
12    array::typenum::Unsigned,
13    ctutils,
14    group::{
15        Group, GroupEncoding,
16        cofactor::CofactorGroup,
17        prime::{PrimeCurve, PrimeGroup},
18    },
19    ops::{
20        Add, AddAssign, BatchInvert, Double, LinearCombination, Mul, MulAssign,
21        MulByGeneratorVartime, MulVartime, Neg, Sub, SubAssign,
22    },
23    point::NonIdentity,
24    rand_core::{TryCryptoRng, TryRng},
25    sec1::{CompressedPoint, FromSec1Point, Sec1Point, ToSec1Point},
26    subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
27    zeroize::DefaultIsZeroes,
28};
29
30#[cfg(feature = "alloc")]
31use alloc::vec::Vec;
32#[cfg(feature = "serde")]
33use serdect::serde::{Deserialize, Serialize, de, ser};
34
35/// Point on a Weierstrass curve in projective coordinates.
36#[derive(Clone, Copy, Debug)]
37pub struct ProjectivePoint<C: PrimeCurveParams> {
38    pub(crate) x: C::FieldElement,
39    pub(crate) y: C::FieldElement,
40    pub(crate) z: C::FieldElement,
41}
42
43impl<C> ProjectivePoint<C>
44where
45    C: PrimeCurveParams,
46{
47    /// Additive identity of the group a.k.a. the point at infinity.
48    pub const IDENTITY: Self = Self {
49        x: C::FieldElement::ZERO,
50        y: C::FieldElement::ONE,
51        z: C::FieldElement::ZERO,
52    };
53
54    /// Base point of the curve.
55    pub const GENERATOR: Self = Self {
56        x: C::GENERATOR.0,
57        y: C::GENERATOR.1,
58        z: C::FieldElement::ONE,
59    };
60
61    /// Returns the affine representation of this point, or `None` if it is the identity.
62    pub fn to_affine(&self) -> AffinePoint<C> {
63        <C::FieldElement as Field>::invert(&self.z)
64            .map(|zinv| self.to_affine_internal(zinv))
65            .unwrap_or(AffinePoint::IDENTITY)
66    }
67
68    pub(super) fn to_affine_internal(self, zinv: C::FieldElement) -> AffinePoint<C> {
69        AffinePoint {
70            x: self.x * &zinv,
71            y: self.y * &zinv,
72            infinity: 0,
73        }
74    }
75
76    /// Returns `-self`.
77    pub fn neg(&self) -> Self {
78        Self {
79            x: self.x,
80            y: -self.y,
81            z: self.z,
82        }
83    }
84
85    /// Returns `self + other`.
86    #[inline]
87    pub fn add(&self, other: &Self) -> Self {
88        let mut lhs = *self;
89        C::PointArithmetic::add_assign(&mut lhs, other);
90        lhs
91    }
92
93    /// Returns `self + other`.
94    #[inline]
95    fn add_mixed(&self, other: &AffinePoint<C>) -> Self {
96        let mut lhs = *self;
97        C::PointArithmetic::add_assign_mixed(&mut lhs, other);
98        lhs
99    }
100
101    /// Returns `self - other`.
102    pub fn sub(&self, other: &Self) -> Self {
103        self.add(&other.neg())
104    }
105
106    /// Returns `self - other`.
107    fn sub_mixed(&self, other: &AffinePoint<C>) -> Self {
108        self.add_mixed(&-other)
109    }
110
111    /// Returns `[k] self`.
112    pub fn mul(&self, k: &Scalar<C>) -> Self {
113        let table = LookupTable::new(*self);
114        let digits = Radix16Decomposition::new(k);
115        lincomb::<C>(&[table], &[digits])
116    }
117
118    /// Returns `[k] self` computed in variable time.
119    pub fn mul_vartime(&self, k: &Scalar<C>) -> Self {
120        let table = LookupTable::new(*self);
121        let digits = Radix16Decomposition::new(k);
122        lincomb_vartime::<C>(&[table], &[digits])
123    }
124}
125
126impl<C> ConditionallySelectable for ProjectivePoint<C>
127where
128    C: PrimeCurveParams,
129{
130    #[inline(always)]
131    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
132        Self {
133            x: C::FieldElement::conditional_select(&a.x, &b.x, choice),
134            y: C::FieldElement::conditional_select(&a.y, &b.y, choice),
135            z: C::FieldElement::conditional_select(&a.z, &b.z, choice),
136        }
137    }
138}
139
140impl<C> ConstantTimeEq for ProjectivePoint<C>
141where
142    C: PrimeCurveParams,
143{
144    fn ct_eq(&self, other: &Self) -> Choice {
145        let x_eq = (self.x * other.z).ct_eq(&(other.x * self.z));
146        let y_eq = (self.y * other.z).ct_eq(&(other.y * self.z));
147
148        x_eq & y_eq
149    }
150}
151
152impl<C> ctutils::CtEq for ProjectivePoint<C>
153where
154    C: PrimeCurveParams,
155{
156    fn ct_eq(&self, other: &Self) -> ctutils::Choice {
157        ConstantTimeEq::ct_eq(self, other).into()
158    }
159}
160
161impl<C> ctutils::CtSelect for ProjectivePoint<C>
162where
163    C: PrimeCurveParams,
164{
165    fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self {
166        ConditionallySelectable::conditional_select(self, other, choice.into())
167    }
168}
169
170impl<C> Default for ProjectivePoint<C>
171where
172    C: PrimeCurveParams,
173{
174    fn default() -> Self {
175        Self::IDENTITY
176    }
177}
178
179impl<C> DefaultIsZeroes for ProjectivePoint<C> where C: PrimeCurveParams {}
180
181impl<C: PrimeCurveParams> Double for ProjectivePoint<C> {
182    #[inline]
183    fn double(&self) -> Self {
184        let mut ret = *self;
185        C::PointArithmetic::double_in_place(&mut ret);
186        ret
187    }
188
189    #[inline]
190    fn double_in_place(&mut self) {
191        C::PointArithmetic::double_in_place(self);
192    }
193}
194
195impl<C> Eq for ProjectivePoint<C> where C: PrimeCurveParams {}
196
197impl<C> From<AffinePoint<C>> for ProjectivePoint<C>
198where
199    C: PrimeCurveParams,
200{
201    fn from(p: AffinePoint<C>) -> Self {
202        let projective = ProjectivePoint {
203            x: p.x,
204            y: p.y,
205            z: C::FieldElement::ONE,
206        };
207        Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity())
208    }
209}
210
211impl<C> From<&AffinePoint<C>> for ProjectivePoint<C>
212where
213    C: PrimeCurveParams,
214{
215    fn from(p: &AffinePoint<C>) -> Self {
216        Self::from(*p)
217    }
218}
219
220impl<C> From<NonIdentity<ProjectivePoint<C>>> for ProjectivePoint<C>
221where
222    C: PrimeCurveParams,
223{
224    fn from(p: NonIdentity<ProjectivePoint<C>>) -> Self {
225        p.to_point()
226    }
227}
228
229impl<C> From<PublicKey<C>> for ProjectivePoint<C>
230where
231    C: PrimeCurveParams,
232{
233    fn from(public_key: PublicKey<C>) -> ProjectivePoint<C> {
234        AffinePoint::from(public_key).into()
235    }
236}
237
238impl<C> From<&PublicKey<C>> for ProjectivePoint<C>
239where
240    C: PrimeCurveParams,
241{
242    fn from(public_key: &PublicKey<C>) -> ProjectivePoint<C> {
243        AffinePoint::<C>::from(public_key).into()
244    }
245}
246
247impl<C> FromSec1Point<C> for ProjectivePoint<C>
248where
249    C: PrimeCurveParams,
250{
251    fn from_sec1_point(p: &Sec1Point<C>) -> ctutils::CtOption<Self> {
252        AffinePoint::<C>::from_sec1_point(p).map(Self::from)
253    }
254}
255
256impl<C> Generate for ProjectivePoint<C>
257where
258    C: PrimeCurveParams,
259{
260    fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
261        rng: &mut R,
262    ) -> core::result::Result<Self, R::Error> {
263        AffinePoint::try_generate_from_rng(rng).map(Self::from)
264    }
265}
266
267//
268// `group` trait impls
269//
270
271/// Prime order elliptic curves have a cofactor of 1.
272impl<C> CofactorGroup for ProjectivePoint<C>
273where
274    C: PrimeCurveParams,
275{
276    type Subgroup = ProjectivePoint<C>;
277
278    fn clear_cofactor(&self) -> Self::Subgroup {
279        *self
280    }
281
282    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
283        CtOption::new(self, Choice::from(1))
284    }
285
286    fn is_torsion_free(&self) -> Choice {
287        Choice::from(1)
288    }
289}
290
291impl<C> CurveGroup for ProjectivePoint<C>
292where
293    C: PrimeCurveParams,
294{
295    type Affine = AffinePoint<C>;
296
297    fn to_affine(&self) -> AffinePoint<C> {
298        ProjectivePoint::to_affine(self)
299    }
300
301    #[cfg(feature = "alloc")]
302    #[inline]
303    fn batch_normalize(projective: &[Self], affine: &mut [Self::Affine]) {
304        assert_eq!(projective.len(), affine.len());
305        let mut zs = vec![C::FieldElement::ZERO; projective.len()];
306        let mut scratch = vec![C::FieldElement::ZERO; projective.len()];
307        batch_normalize_generic(projective, &mut zs, &mut scratch, affine);
308    }
309}
310
311impl<C> Group for ProjectivePoint<C>
312where
313    C: PrimeCurveParams,
314{
315    type Scalar = Scalar<C>;
316
317    fn try_random<R: TryRng + ?Sized>(rng: &mut R) -> core::result::Result<Self, R::Error> {
318        AffinePoint::try_random(rng).map(Self::from)
319    }
320
321    fn identity() -> Self {
322        Self::IDENTITY
323    }
324
325    fn generator() -> Self {
326        Self::GENERATOR
327    }
328
329    fn is_identity(&self) -> Choice {
330        self.ct_eq(&Self::IDENTITY)
331    }
332
333    #[inline]
334    fn double(&self) -> Self {
335        Double::double(self)
336    }
337
338    #[inline]
339    fn mul_by_generator(scalar: &Self::Scalar) -> Self {
340        C::Backend::mul_by_generator(scalar)
341    }
342}
343
344impl<C> GroupEncoding for ProjectivePoint<C>
345where
346    C: PrimeCurveParams,
347{
348    type Repr = CompressedPoint<C>;
349
350    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
351        <AffinePoint<C> as GroupEncoding>::from_bytes(bytes).map(Into::into)
352    }
353
354    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
355        // No unchecked conversion possible for compressed points
356        Self::from_bytes(bytes)
357    }
358
359    fn to_bytes(&self) -> Self::Repr {
360        self.to_affine().to_bytes()
361    }
362}
363
364impl<C> PrimeCurve for ProjectivePoint<C> where C: PrimeCurveParams {}
365impl<C> PrimeGroup for ProjectivePoint<C> where C: PrimeCurveParams {}
366
367//
368// Batch trait impls
369//
370
371impl<const N: usize, C> BatchNormalize<[ProjectivePoint<C>; N]> for ProjectivePoint<C>
372where
373    C: PrimeCurveParams,
374{
375    type Output = [<Self as CurveGroup>::Affine; N];
376
377    #[inline]
378    fn batch_normalize(points: &[Self; N]) -> [<Self as CurveGroup>::Affine; N] {
379        let mut zs = [C::FieldElement::ZERO; N];
380        let mut scratch = [C::FieldElement::ZERO; N];
381        let mut affine_points = [C::AffinePoint::IDENTITY; N];
382        batch_normalize_generic(points, &mut zs, &mut scratch, &mut affine_points);
383        affine_points
384    }
385}
386
387#[cfg(feature = "alloc")]
388impl<C> BatchNormalize<[ProjectivePoint<C>]> for ProjectivePoint<C>
389where
390    C: PrimeCurveParams,
391{
392    type Output = Vec<<Self as CurveGroup>::Affine>;
393
394    #[inline]
395    fn batch_normalize(points: &[Self]) -> Vec<<Self as CurveGroup>::Affine> {
396        let mut zs = vec![C::FieldElement::ZERO; points.len()];
397        let mut scratch = vec![C::FieldElement::ZERO; points.len()];
398        let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
399        batch_normalize_generic(points, &mut zs, &mut scratch, &mut affine_points);
400        affine_points
401    }
402}
403
404/// Generic implementation of batch normalization.
405fn batch_normalize_generic<C>(
406    points: &[ProjectivePoint<C>],
407    zs: &mut [C::FieldElement],
408    scratch: &mut [C::FieldElement],
409    out: &mut [AffinePoint<C>],
410) where
411    C: PrimeCurveParams,
412{
413    debug_assert_eq!(points.len(), zs.len());
414    debug_assert_eq!(points.len(), scratch.len());
415    debug_assert_eq!(points.len(), out.len());
416
417    for (z, point) in zs.iter_mut().zip(points) {
418        *z = point.z;
419    }
420
421    // Zero `zs` (identity) are handled explicitly below, so the `Choice` here is informational only
422    let _ = C::FieldElement::batch_invert_in_place(zs, scratch);
423
424    for i in 0..out.len() {
425        out[i] = C::AffinePoint::conditional_select(
426            &points[i].to_affine_internal(zs[i]),
427            &C::AffinePoint::IDENTITY,
428            points[i].z.ct_eq(&C::FieldElement::ZERO),
429        );
430    }
431}
432
433impl<C> LinearCombination<[(Self, Scalar<C>)]> for ProjectivePoint<C>
434where
435    C: PrimeCurveParams,
436{
437    #[cfg(feature = "alloc")]
438    fn lincomb(points_and_scalars: &[(Self, Scalar<C>)]) -> Self {
439        let tables: Vec<_> = points_and_scalars
440            .iter()
441            .map(|(point, _)| LookupTable::new(*point))
442            .collect();
443        let digits: Vec<_> = points_and_scalars
444            .iter()
445            .map(|(_, scalar)| Radix16Decomposition::new(scalar))
446            .collect();
447
448        lincomb::<C>(&tables, &digits)
449    }
450
451    #[cfg(feature = "alloc")]
452    fn lincomb_vartime(points_and_scalars: &[(Self, Scalar<C>)]) -> Self {
453        let tables: Vec<_> = points_and_scalars
454            .iter()
455            .map(|(point, _)| LookupTable::new(*point))
456            .collect();
457        let digits: Vec<_> = points_and_scalars
458            .iter()
459            .map(|(_, scalar)| Radix16Decomposition::new(scalar))
460            .collect();
461
462        lincomb_vartime::<C>(&tables, &digits)
463    }
464}
465
466impl<C, const N: usize> LinearCombination<[(Self, Scalar<C>); N]> for ProjectivePoint<C>
467where
468    C: PrimeCurveParams,
469{
470    fn lincomb(points_and_scalars: &[(Self, Scalar<C>); N]) -> Self {
471        let tables: [_; N] = array::from_fn(|index| LookupTable::new(points_and_scalars[index].0));
472        let digits: [_; N] =
473            array::from_fn(|index| Radix16Decomposition::new(&points_and_scalars[index].1));
474
475        lincomb::<C>(&tables, &digits)
476    }
477
478    fn lincomb_vartime(points_and_scalars: &[(Self, Scalar<C>); N]) -> Self {
479        let tables: [_; N] = array::from_fn(|index| LookupTable::new(points_and_scalars[index].0));
480        let digits: [_; N] =
481            array::from_fn(|index| Radix16Decomposition::new(&points_and_scalars[index].1));
482
483        lincomb_vartime::<C>(&tables, &digits)
484    }
485}
486
487fn lincomb<C: PrimeCurveParams>(
488    tables: &[LookupTable<ProjectivePoint<C>>],
489    digits: &[Radix16Decomposition<Radix16Digits<C>>],
490) -> ProjectivePoint<C> {
491    debug_assert_eq!(tables.len(), digits.len());
492    debug_assert!(!digits.is_empty());
493
494    let d = Radix16Digits::<C>::USIZE;
495    let mut q = ProjectivePoint::IDENTITY;
496
497    for (table, digit) in zip(tables, digits) {
498        q = q.add(&table.select(digit[d - 1]));
499    }
500
501    for i in (0..d - 1).rev() {
502        for _ in 0..4 {
503            q.double_in_place();
504        }
505
506        for (table, digit) in zip(tables, digits) {
507            q = q.add(&table.select(digit[i]));
508        }
509    }
510
511    q
512}
513
514fn lincomb_vartime<C: PrimeCurveParams>(
515    tables: &[LookupTable<ProjectivePoint<C>>],
516    digits: &[Radix16Decomposition<Radix16Digits<C>>],
517) -> ProjectivePoint<C> {
518    debug_assert_eq!(tables.len(), digits.len());
519    debug_assert!(!digits.is_empty());
520
521    let d = Radix16Digits::<C>::USIZE;
522    let mut q = ProjectivePoint::IDENTITY;
523
524    for (table, digit) in zip(tables, digits) {
525        q = q.add(&table.select_vartime(digit[d - 1]));
526    }
527
528    for i in (0..d - 1).rev() {
529        for _ in 0..4 {
530            q.double_in_place();
531        }
532
533        for (table, digit) in zip(tables, digits) {
534            q = q.add(&table.select_vartime(digit[i]));
535        }
536    }
537
538    q
539}
540
541impl<C> PartialEq for ProjectivePoint<C>
542where
543    C: PrimeCurveParams,
544{
545    fn eq(&self, other: &Self) -> bool {
546        self.ct_eq(other).into()
547    }
548}
549
550impl<C> ToSec1Point<C> for ProjectivePoint<C>
551where
552    C: PrimeCurveParams,
553{
554    fn to_sec1_point(&self, compress: bool) -> Sec1Point<C> {
555        self.to_affine().to_sec1_point(compress)
556    }
557}
558
559/// The constant-time alternative is available at [`NonIdentity::new()`].
560impl<C> TryFrom<ProjectivePoint<C>> for NonIdentity<ProjectivePoint<C>>
561where
562    C: PrimeCurveParams,
563{
564    type Error = Error;
565
566    fn try_from(point: ProjectivePoint<C>) -> Result<Self> {
567        NonIdentity::new(point).into_option().ok_or(Error)
568    }
569}
570
571impl<C> TryFrom<ProjectivePoint<C>> for PublicKey<C>
572where
573    C: PrimeCurveParams,
574{
575    type Error = Error;
576
577    fn try_from(point: ProjectivePoint<C>) -> Result<PublicKey<C>> {
578        PublicKey::try_from(&point)
579    }
580}
581
582impl<C> TryFrom<&ProjectivePoint<C>> for PublicKey<C>
583where
584    C: PrimeCurveParams,
585{
586    type Error = Error;
587
588    fn try_from(point: &ProjectivePoint<C>) -> Result<PublicKey<C>> {
589        AffinePoint::<C>::from(point).try_into()
590    }
591}
592
593//
594// `core::ops` trait impls
595//
596
597impl<C> Add<ProjectivePoint<C>> for ProjectivePoint<C>
598where
599    C: PrimeCurveParams,
600{
601    type Output = ProjectivePoint<C>;
602
603    fn add(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
604        ProjectivePoint::add(&self, &other)
605    }
606}
607
608impl<C> Add<&ProjectivePoint<C>> for &ProjectivePoint<C>
609where
610    C: PrimeCurveParams,
611{
612    type Output = ProjectivePoint<C>;
613
614    fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
615        ProjectivePoint::add(self, other)
616    }
617}
618
619impl<C> Add<&ProjectivePoint<C>> for ProjectivePoint<C>
620where
621    C: PrimeCurveParams,
622{
623    type Output = ProjectivePoint<C>;
624
625    fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
626        ProjectivePoint::add(&self, other)
627    }
628}
629
630impl<C> AddAssign<ProjectivePoint<C>> for ProjectivePoint<C>
631where
632    C: PrimeCurveParams,
633{
634    #[inline]
635    fn add_assign(&mut self, rhs: ProjectivePoint<C>) {
636        C::PointArithmetic::add_assign(self, &rhs);
637    }
638}
639
640impl<C> AddAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
641where
642    C: PrimeCurveParams,
643{
644    #[inline]
645    fn add_assign(&mut self, rhs: &ProjectivePoint<C>) {
646        C::PointArithmetic::add_assign(self, rhs);
647    }
648}
649
650impl<C> Add<AffinePoint<C>> for ProjectivePoint<C>
651where
652    C: PrimeCurveParams,
653{
654    type Output = ProjectivePoint<C>;
655
656    fn add(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
657        ProjectivePoint::add_mixed(&self, &other)
658    }
659}
660
661impl<C> Add<&AffinePoint<C>> for &ProjectivePoint<C>
662where
663    C: PrimeCurveParams,
664{
665    type Output = ProjectivePoint<C>;
666
667    fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
668        ProjectivePoint::add_mixed(self, other)
669    }
670}
671
672impl<C> Add<&AffinePoint<C>> for ProjectivePoint<C>
673where
674    C: PrimeCurveParams,
675{
676    type Output = ProjectivePoint<C>;
677
678    fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
679        ProjectivePoint::add_mixed(&self, other)
680    }
681}
682
683impl<C> AddAssign<AffinePoint<C>> for ProjectivePoint<C>
684where
685    C: PrimeCurveParams,
686{
687    #[inline]
688    fn add_assign(&mut self, rhs: AffinePoint<C>) {
689        C::PointArithmetic::add_assign_mixed(self, &rhs);
690    }
691}
692
693impl<C> AddAssign<&AffinePoint<C>> for ProjectivePoint<C>
694where
695    C: PrimeCurveParams,
696{
697    #[inline]
698    fn add_assign(&mut self, rhs: &AffinePoint<C>) {
699        C::PointArithmetic::add_assign_mixed(self, rhs);
700    }
701}
702
703impl<C> Sum for ProjectivePoint<C>
704where
705    C: PrimeCurveParams,
706{
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, C> Sum<&'a ProjectivePoint<C>> for ProjectivePoint<C>
714where
715    C: PrimeCurveParams,
716{
717    #[inline]
718    fn sum<I: Iterator<Item = &'a ProjectivePoint<C>>>(iter: I) -> Self {
719        iter.cloned().sum()
720    }
721}
722
723impl<C> Sub<ProjectivePoint<C>> for ProjectivePoint<C>
724where
725    C: PrimeCurveParams,
726{
727    type Output = ProjectivePoint<C>;
728
729    fn sub(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
730        ProjectivePoint::sub(&self, &other)
731    }
732}
733
734impl<C> Sub<&ProjectivePoint<C>> for &ProjectivePoint<C>
735where
736    C: PrimeCurveParams,
737{
738    type Output = ProjectivePoint<C>;
739
740    fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
741        ProjectivePoint::sub(self, other)
742    }
743}
744
745impl<C> Sub<&ProjectivePoint<C>> for ProjectivePoint<C>
746where
747    C: PrimeCurveParams,
748{
749    type Output = ProjectivePoint<C>;
750
751    fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
752        ProjectivePoint::sub(&self, other)
753    }
754}
755
756impl<C> SubAssign<ProjectivePoint<C>> for ProjectivePoint<C>
757where
758    C: PrimeCurveParams,
759{
760    #[inline]
761    fn sub_assign(&mut self, rhs: ProjectivePoint<C>) {
762        C::PointArithmetic::add_assign(self, &-rhs);
763    }
764}
765
766impl<C> SubAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
767where
768    C: PrimeCurveParams,
769{
770    #[inline]
771    fn sub_assign(&mut self, rhs: &ProjectivePoint<C>) {
772        *self -= *rhs;
773    }
774}
775
776impl<C> Sub<AffinePoint<C>> for ProjectivePoint<C>
777where
778    C: PrimeCurveParams,
779{
780    type Output = ProjectivePoint<C>;
781
782    fn sub(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
783        ProjectivePoint::sub_mixed(&self, &other)
784    }
785}
786
787impl<C> Sub<&AffinePoint<C>> for &ProjectivePoint<C>
788where
789    C: PrimeCurveParams,
790{
791    type Output = ProjectivePoint<C>;
792
793    fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
794        ProjectivePoint::sub_mixed(self, other)
795    }
796}
797
798impl<C> Sub<&AffinePoint<C>> for ProjectivePoint<C>
799where
800    C: PrimeCurveParams,
801{
802    type Output = ProjectivePoint<C>;
803
804    fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
805        ProjectivePoint::sub_mixed(&self, other)
806    }
807}
808
809impl<C> SubAssign<AffinePoint<C>> for ProjectivePoint<C>
810where
811    C: PrimeCurveParams,
812{
813    #[inline]
814    fn sub_assign(&mut self, rhs: AffinePoint<C>) {
815        C::PointArithmetic::add_assign_mixed(self, &-rhs);
816    }
817}
818
819impl<C> SubAssign<&AffinePoint<C>> for ProjectivePoint<C>
820where
821    C: PrimeCurveParams,
822{
823    #[inline]
824    fn sub_assign(&mut self, rhs: &AffinePoint<C>) {
825        *self -= *rhs;
826    }
827}
828
829impl<C, S> Mul<S> for ProjectivePoint<C>
830where
831    Self: Double,
832    C: PrimeCurveParams,
833    S: Borrow<Scalar<C>>,
834{
835    type Output = Self;
836
837    #[inline]
838    fn mul(self, scalar: S) -> Self {
839        ProjectivePoint::mul(&self, scalar.borrow())
840    }
841}
842
843impl<C, S> Mul<S> for &ProjectivePoint<C>
844where
845    Self: Double,
846    C: PrimeCurveParams,
847    S: Borrow<Scalar<C>>,
848{
849    type Output = ProjectivePoint<C>;
850
851    #[inline]
852    fn mul(self, scalar: S) -> ProjectivePoint<C> {
853        ProjectivePoint::mul(self, scalar.borrow())
854    }
855}
856
857impl<C> Mul<&Scalar<C>> for &ProjectivePoint<C>
858where
859    C: PrimeCurveParams,
860    ProjectivePoint<C>: Double,
861{
862    type Output = ProjectivePoint<C>;
863
864    #[inline]
865    fn mul(self, scalar: &Scalar<C>) -> ProjectivePoint<C> {
866        ProjectivePoint::mul(self, scalar)
867    }
868}
869
870impl<C, S> MulVartime<S> for ProjectivePoint<C>
871where
872    Self: Double,
873    C: PrimeCurveParams,
874    S: Borrow<Scalar<C>>,
875{
876    #[inline]
877    fn mul_vartime(self, scalar: S) -> Self {
878        ProjectivePoint::mul_vartime(&self, scalar.borrow())
879    }
880}
881
882impl<C, S> MulVartime<S> for &ProjectivePoint<C>
883where
884    Self: Double,
885    C: PrimeCurveParams,
886    S: Borrow<Scalar<C>>,
887{
888    #[inline]
889    fn mul_vartime(self, scalar: S) -> ProjectivePoint<C> {
890        ProjectivePoint::mul_vartime(self, scalar.borrow())
891    }
892}
893
894impl<C> MulVartime<&Scalar<C>> for &ProjectivePoint<C>
895where
896    C: PrimeCurveParams,
897    ProjectivePoint<C>: Double,
898{
899    #[inline]
900    fn mul_vartime(self, scalar: &Scalar<C>) -> ProjectivePoint<C> {
901        ProjectivePoint::mul_vartime(self, scalar)
902    }
903}
904
905impl<C> MulByGeneratorVartime for ProjectivePoint<C>
906where
907    C: PrimeCurveParams,
908{
909    #[inline]
910    fn mul_by_generator_vartime(scalar: &Scalar<C>) -> Self {
911        C::Backend::mul_by_generator_vartime(scalar)
912    }
913
914    #[inline]
915    fn mul_by_generator_and_mul_add_vartime(
916        a: &Self::Scalar,
917        b_scalar: &Self::Scalar,
918        b_point: &Self,
919    ) -> Self {
920        C::Backend::mul_by_generator_and_mul_add_vartime(a, b_scalar, b_point)
921    }
922}
923
924impl<C, S> MulAssign<S> for ProjectivePoint<C>
925where
926    Self: Double,
927    C: PrimeCurveParams,
928    S: Borrow<Scalar<C>>,
929{
930    #[inline]
931    fn mul_assign(&mut self, scalar: S) {
932        *self = ProjectivePoint::mul(self, scalar.borrow());
933    }
934}
935
936impl<C> Neg for ProjectivePoint<C>
937where
938    C: PrimeCurveParams,
939{
940    type Output = ProjectivePoint<C>;
941
942    fn neg(self) -> ProjectivePoint<C> {
943        ProjectivePoint::neg(&self)
944    }
945}
946
947impl<C> Neg for &ProjectivePoint<C>
948where
949    C: PrimeCurveParams,
950{
951    type Output = ProjectivePoint<C>;
952
953    fn neg(self) -> ProjectivePoint<C> {
954        ProjectivePoint::neg(self)
955    }
956}
957
958//
959// serde support
960//
961
962#[cfg(feature = "serde")]
963impl<C> Serialize for ProjectivePoint<C>
964where
965    C: PrimeCurveParams,
966{
967    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
968    where
969        S: ser::Serializer,
970    {
971        self.to_affine().serialize(serializer)
972    }
973}
974
975#[cfg(feature = "serde")]
976impl<'de, C> Deserialize<'de> for ProjectivePoint<C>
977where
978    C: PrimeCurveParams,
979{
980    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
981    where
982        D: de::Deserializer<'de>,
983    {
984        AffinePoint::<C>::deserialize(deserializer).map(Self::from)
985    }
986}