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