primeorder/
projective.rs

1//! Projective curve points.
2
3#![allow(clippy::needless_range_loop, clippy::op_ref)]
4
5use crate::{point_arithmetic::PointArithmetic, AffinePoint, Field, PrimeCurveParams};
6use core::{
7    borrow::Borrow,
8    iter::Sum,
9    ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
10};
11use elliptic_curve::{
12    bigint::{ArrayEncoding, Integer},
13    generic_array::ArrayLength,
14    group::{
15        self,
16        cofactor::CofactorGroup,
17        prime::{PrimeCurve, PrimeGroup},
18        Group, GroupEncoding,
19    },
20    ops::{BatchInvert, Invert, LinearCombination, MulByGenerator},
21    point::Double,
22    rand_core::RngCore,
23    sec1::{
24        CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint,
25        UncompressedPointSize,
26    },
27    subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
28    zeroize::DefaultIsZeroes,
29    BatchNormalize, Error, FieldBytes, FieldBytesSize, PublicKey, Result, Scalar,
30};
31
32#[cfg(feature = "alloc")]
33use alloc::vec::Vec;
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    pub fn add(&self, other: &Self) -> Self {
87        C::PointArithmetic::add(self, other)
88    }
89
90    /// Returns `self + other`.
91    fn add_mixed(&self, other: &AffinePoint<C>) -> Self {
92        C::PointArithmetic::add_mixed(self, other)
93    }
94
95    /// Returns `self - other`.
96    pub fn sub(&self, other: &Self) -> Self {
97        self.add(&other.neg())
98    }
99
100    /// Returns `self - other`.
101    fn sub_mixed(&self, other: &AffinePoint<C>) -> Self {
102        self.add_mixed(&other.neg())
103    }
104
105    /// Returns `[k] self`.
106    fn mul(&self, k: &Scalar<C>) -> Self
107    where
108        Self: Double,
109    {
110        let k = Into::<C::Uint>::into(*k).to_le_byte_array();
111
112        let mut pc = [Self::default(); 16];
113        pc[0] = Self::IDENTITY;
114        pc[1] = *self;
115
116        for i in 2..16 {
117            pc[i] = if i % 2 == 0 {
118                Double::double(&pc[i / 2])
119            } else {
120                pc[i - 1].add(self)
121            };
122        }
123
124        let mut q = Self::IDENTITY;
125        let mut pos = C::Uint::BITS - 4;
126
127        loop {
128            let slot = (k[pos >> 3] >> (pos & 7)) & 0xf;
129
130            let mut t = ProjectivePoint::IDENTITY;
131
132            for i in 1..16 {
133                t.conditional_assign(
134                    &pc[i],
135                    Choice::from(((slot as usize ^ i).wrapping_sub(1) >> 8) as u8 & 1),
136                );
137            }
138
139            q = q.add(&t);
140
141            if pos == 0 {
142                break;
143            }
144
145            q = Double::double(&Double::double(&Double::double(&Double::double(&q))));
146            pos -= 4;
147        }
148
149        q
150    }
151}
152
153impl<C> CofactorGroup for ProjectivePoint<C>
154where
155    Self: Double,
156    C: PrimeCurveParams,
157    FieldBytes<C>: Copy,
158    FieldBytesSize<C>: ModulusSize,
159    CompressedPoint<C>: Copy,
160    <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
161{
162    type Subgroup = Self;
163
164    fn clear_cofactor(&self) -> Self::Subgroup {
165        *self
166    }
167
168    fn into_subgroup(self) -> CtOption<Self> {
169        CtOption::new(self, 1.into())
170    }
171
172    fn is_torsion_free(&self) -> Choice {
173        1.into()
174    }
175}
176
177impl<C> ConditionallySelectable for ProjectivePoint<C>
178where
179    C: PrimeCurveParams,
180{
181    #[inline(always)]
182    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
183        Self {
184            x: C::FieldElement::conditional_select(&a.x, &b.x, choice),
185            y: C::FieldElement::conditional_select(&a.y, &b.y, choice),
186            z: C::FieldElement::conditional_select(&a.z, &b.z, choice),
187        }
188    }
189}
190
191impl<C> ConstantTimeEq for ProjectivePoint<C>
192where
193    C: PrimeCurveParams,
194{
195    fn ct_eq(&self, other: &Self) -> Choice {
196        self.to_affine().ct_eq(&other.to_affine())
197    }
198}
199
200impl<C> Default for ProjectivePoint<C>
201where
202    C: PrimeCurveParams,
203{
204    fn default() -> Self {
205        Self::IDENTITY
206    }
207}
208
209impl<C> DefaultIsZeroes for ProjectivePoint<C> where C: PrimeCurveParams {}
210
211impl<C: PrimeCurveParams> Double for ProjectivePoint<C> {
212    fn double(&self) -> Self {
213        C::PointArithmetic::double(self)
214    }
215}
216
217impl<C> Eq for ProjectivePoint<C> where C: PrimeCurveParams {}
218
219impl<C> From<AffinePoint<C>> for ProjectivePoint<C>
220where
221    C: PrimeCurveParams,
222{
223    fn from(p: AffinePoint<C>) -> Self {
224        let projective = ProjectivePoint {
225            x: p.x,
226            y: p.y,
227            z: C::FieldElement::ONE,
228        };
229        Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity())
230    }
231}
232
233impl<C> From<&AffinePoint<C>> for ProjectivePoint<C>
234where
235    C: PrimeCurveParams,
236{
237    fn from(p: &AffinePoint<C>) -> Self {
238        Self::from(*p)
239    }
240}
241
242impl<C> From<PublicKey<C>> for ProjectivePoint<C>
243where
244    C: PrimeCurveParams,
245{
246    fn from(public_key: PublicKey<C>) -> ProjectivePoint<C> {
247        AffinePoint::from(public_key).into()
248    }
249}
250
251impl<C> From<&PublicKey<C>> for ProjectivePoint<C>
252where
253    C: PrimeCurveParams,
254{
255    fn from(public_key: &PublicKey<C>) -> ProjectivePoint<C> {
256        AffinePoint::<C>::from(public_key).into()
257    }
258}
259
260impl<C> FromEncodedPoint<C> for ProjectivePoint<C>
261where
262    C: PrimeCurveParams,
263    FieldBytes<C>: Copy,
264    FieldBytesSize<C>: ModulusSize,
265    CompressedPoint<C>: Copy,
266{
267    fn from_encoded_point(p: &EncodedPoint<C>) -> CtOption<Self> {
268        AffinePoint::<C>::from_encoded_point(p).map(Self::from)
269    }
270}
271
272impl<C> Group for ProjectivePoint<C>
273where
274    Self: Double,
275    C: PrimeCurveParams,
276{
277    type Scalar = Scalar<C>;
278
279    fn random(mut rng: impl RngCore) -> Self {
280        Self::GENERATOR * <Scalar<C> as Field>::random(&mut rng)
281    }
282
283    fn identity() -> Self {
284        Self::IDENTITY
285    }
286
287    fn generator() -> Self {
288        Self::GENERATOR
289    }
290
291    fn is_identity(&self) -> Choice {
292        self.ct_eq(&Self::IDENTITY)
293    }
294
295    #[must_use]
296    fn double(&self) -> Self {
297        Double::double(self)
298    }
299}
300
301impl<C> GroupEncoding for ProjectivePoint<C>
302where
303    C: PrimeCurveParams,
304    FieldBytes<C>: Copy,
305    FieldBytesSize<C>: ModulusSize,
306    CompressedPoint<C>: Copy,
307    <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
308{
309    type Repr = CompressedPoint<C>;
310
311    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
312        <AffinePoint<C> as GroupEncoding>::from_bytes(bytes).map(Into::into)
313    }
314
315    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
316        // No unchecked conversion possible for compressed points
317        Self::from_bytes(bytes)
318    }
319
320    fn to_bytes(&self) -> Self::Repr {
321        self.to_affine().to_bytes()
322    }
323}
324
325impl<C> group::Curve for ProjectivePoint<C>
326where
327    Self: Double,
328    C: PrimeCurveParams,
329{
330    type AffineRepr = AffinePoint<C>;
331
332    fn to_affine(&self) -> AffinePoint<C> {
333        ProjectivePoint::to_affine(self)
334    }
335
336    // TODO(tarcieri): re-enable when we can add `Invert` bounds on `FieldElement`
337    // #[cfg(feature = "alloc")]
338    // #[inline]
339    // fn batch_normalize(projective: &[Self], affine: &mut [Self::AffineRepr]) {
340    //     assert_eq!(projective.len(), affine.len());
341    //     let mut zs = vec![C::FieldElement::ONE; projective.len()];
342    //     batch_normalize_generic(projective, zs.as_mut_slice(), affine);
343    // }
344}
345
346impl<const N: usize, C> BatchNormalize<[ProjectivePoint<C>; N]> for ProjectivePoint<C>
347where
348    Self: Double,
349    C: PrimeCurveParams,
350    C::FieldElement: Invert<Output = CtOption<C::FieldElement>>,
351{
352    type Output = [Self::AffineRepr; N];
353
354    #[inline]
355    fn batch_normalize(points: &[Self; N]) -> [Self::AffineRepr; N] {
356        let mut zs = [C::FieldElement::ONE; N];
357        let mut affine_points = [C::AffinePoint::IDENTITY; N];
358        batch_normalize_generic(points, &mut zs, &mut affine_points);
359        affine_points
360    }
361}
362
363#[cfg(feature = "alloc")]
364impl<C> BatchNormalize<[ProjectivePoint<C>]> for ProjectivePoint<C>
365where
366    Self: Double,
367    C: PrimeCurveParams,
368    C::FieldElement: Invert<Output = CtOption<C::FieldElement>>,
369{
370    type Output = Vec<Self::AffineRepr>;
371
372    #[inline]
373    fn batch_normalize(points: &[Self]) -> Vec<Self::AffineRepr> {
374        let mut zs = vec![C::FieldElement::ONE; points.len()];
375        let mut affine_points = vec![AffinePoint::IDENTITY; points.len()];
376        batch_normalize_generic(points, zs.as_mut_slice(), &mut affine_points);
377        affine_points
378    }
379}
380
381/// Generic implementation of batch normalization.
382fn batch_normalize_generic<C, P, Z, O>(points: &P, zs: &mut Z, out: &mut O)
383where
384    C: PrimeCurveParams,
385    C::FieldElement: BatchInvert<Z>,
386    C::ProjectivePoint: Double,
387    P: AsRef<[ProjectivePoint<C>]> + ?Sized,
388    Z: AsMut<[C::FieldElement]> + ?Sized,
389    O: AsMut<[AffinePoint<C>]> + ?Sized,
390{
391    let points = points.as_ref();
392    let out = out.as_mut();
393
394    for i in 0..points.len() {
395        // Even a single zero value will fail inversion for the entire batch.
396        // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds
397        // and treat that case specially later-on.
398        zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&C::FieldElement::ZERO));
399    }
400
401    // This is safe to unwrap since we assured that all elements are non-zero
402    let zs_inverses = <C::FieldElement as BatchInvert<Z>>::batch_invert(zs).unwrap();
403
404    for i in 0..out.len() {
405        // If the `z` coordinate is non-zero, we can use it to invert;
406        // otherwise it defaults to the `IDENTITY` value.
407        out[i] = C::AffinePoint::conditional_select(
408            &points[i].to_affine_internal(zs_inverses.as_ref()[i]),
409            &C::AffinePoint::IDENTITY,
410            points[i].z.ct_eq(&C::FieldElement::ZERO),
411        );
412    }
413}
414
415impl<C> LinearCombination for ProjectivePoint<C>
416where
417    Self: Double,
418    C: PrimeCurveParams,
419{
420}
421
422impl<C> MulByGenerator for ProjectivePoint<C>
423where
424    Self: Double,
425    C: PrimeCurveParams,
426{
427    fn mul_by_generator(scalar: &Self::Scalar) -> Self {
428        // TODO(tarcieri): precomputed basepoint tables
429        Self::generator() * scalar
430    }
431}
432
433impl<C> PrimeGroup for ProjectivePoint<C>
434where
435    Self: Double,
436    C: PrimeCurveParams,
437    FieldBytes<C>: Copy,
438    FieldBytesSize<C>: ModulusSize,
439    CompressedPoint<C>: Copy,
440    <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
441{
442}
443
444impl<C> PrimeCurve for ProjectivePoint<C>
445where
446    Self: Double,
447    C: PrimeCurveParams,
448    FieldBytes<C>: Copy,
449    FieldBytesSize<C>: ModulusSize,
450    CompressedPoint<C>: Copy,
451    <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
452{
453    type Affine = AffinePoint<C>;
454}
455
456impl<C> PartialEq for ProjectivePoint<C>
457where
458    C: PrimeCurveParams,
459{
460    fn eq(&self, other: &Self) -> bool {
461        self.ct_eq(other).into()
462    }
463}
464
465impl<C> ToEncodedPoint<C> for ProjectivePoint<C>
466where
467    C: PrimeCurveParams,
468    FieldBytesSize<C>: ModulusSize,
469    CompressedPoint<C>: Copy,
470    <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy,
471{
472    fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
473        self.to_affine().to_encoded_point(compress)
474    }
475}
476
477impl<C> TryFrom<ProjectivePoint<C>> for PublicKey<C>
478where
479    C: PrimeCurveParams,
480{
481    type Error = Error;
482
483    fn try_from(point: ProjectivePoint<C>) -> Result<PublicKey<C>> {
484        AffinePoint::<C>::from(point).try_into()
485    }
486}
487
488impl<C> TryFrom<&ProjectivePoint<C>> for PublicKey<C>
489where
490    C: PrimeCurveParams,
491{
492    type Error = Error;
493
494    fn try_from(point: &ProjectivePoint<C>) -> Result<PublicKey<C>> {
495        AffinePoint::<C>::from(point).try_into()
496    }
497}
498
499//
500// Arithmetic trait impls
501//
502
503impl<C> Add<ProjectivePoint<C>> for ProjectivePoint<C>
504where
505    C: PrimeCurveParams,
506{
507    type Output = ProjectivePoint<C>;
508
509    fn add(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
510        ProjectivePoint::add(&self, &other)
511    }
512}
513
514impl<C> Add<&ProjectivePoint<C>> for &ProjectivePoint<C>
515where
516    C: PrimeCurveParams,
517{
518    type Output = ProjectivePoint<C>;
519
520    fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
521        ProjectivePoint::add(self, other)
522    }
523}
524
525impl<C> Add<&ProjectivePoint<C>> for ProjectivePoint<C>
526where
527    C: PrimeCurveParams,
528{
529    type Output = ProjectivePoint<C>;
530
531    fn add(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
532        ProjectivePoint::add(&self, other)
533    }
534}
535
536impl<C> AddAssign<ProjectivePoint<C>> for ProjectivePoint<C>
537where
538    C: PrimeCurveParams,
539{
540    fn add_assign(&mut self, rhs: ProjectivePoint<C>) {
541        *self = ProjectivePoint::add(self, &rhs);
542    }
543}
544
545impl<C> AddAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
546where
547    C: PrimeCurveParams,
548{
549    fn add_assign(&mut self, rhs: &ProjectivePoint<C>) {
550        *self = ProjectivePoint::add(self, rhs);
551    }
552}
553
554impl<C> Add<AffinePoint<C>> for ProjectivePoint<C>
555where
556    C: PrimeCurveParams,
557{
558    type Output = ProjectivePoint<C>;
559
560    fn add(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
561        ProjectivePoint::add_mixed(&self, &other)
562    }
563}
564
565impl<C> Add<&AffinePoint<C>> for &ProjectivePoint<C>
566where
567    C: PrimeCurveParams,
568{
569    type Output = ProjectivePoint<C>;
570
571    fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
572        ProjectivePoint::add_mixed(self, other)
573    }
574}
575
576impl<C> Add<&AffinePoint<C>> for ProjectivePoint<C>
577where
578    C: PrimeCurveParams,
579{
580    type Output = ProjectivePoint<C>;
581
582    fn add(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
583        ProjectivePoint::add_mixed(&self, other)
584    }
585}
586
587impl<C> AddAssign<AffinePoint<C>> for ProjectivePoint<C>
588where
589    C: PrimeCurveParams,
590{
591    fn add_assign(&mut self, rhs: AffinePoint<C>) {
592        *self = ProjectivePoint::add_mixed(self, &rhs);
593    }
594}
595
596impl<C> AddAssign<&AffinePoint<C>> for ProjectivePoint<C>
597where
598    C: PrimeCurveParams,
599{
600    fn add_assign(&mut self, rhs: &AffinePoint<C>) {
601        *self = ProjectivePoint::add_mixed(self, rhs);
602    }
603}
604
605impl<C> Sum for ProjectivePoint<C>
606where
607    C: PrimeCurveParams,
608{
609    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
610        iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b)
611    }
612}
613
614impl<'a, C> Sum<&'a ProjectivePoint<C>> for ProjectivePoint<C>
615where
616    C: PrimeCurveParams,
617{
618    fn sum<I: Iterator<Item = &'a ProjectivePoint<C>>>(iter: I) -> Self {
619        iter.cloned().sum()
620    }
621}
622
623impl<C> Sub<ProjectivePoint<C>> for ProjectivePoint<C>
624where
625    C: PrimeCurveParams,
626{
627    type Output = ProjectivePoint<C>;
628
629    fn sub(self, other: ProjectivePoint<C>) -> ProjectivePoint<C> {
630        ProjectivePoint::sub(&self, &other)
631    }
632}
633
634impl<C> Sub<&ProjectivePoint<C>> for &ProjectivePoint<C>
635where
636    C: PrimeCurveParams,
637{
638    type Output = ProjectivePoint<C>;
639
640    fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
641        ProjectivePoint::sub(self, other)
642    }
643}
644
645impl<C> Sub<&ProjectivePoint<C>> for ProjectivePoint<C>
646where
647    C: PrimeCurveParams,
648{
649    type Output = ProjectivePoint<C>;
650
651    fn sub(self, other: &ProjectivePoint<C>) -> ProjectivePoint<C> {
652        ProjectivePoint::sub(&self, other)
653    }
654}
655
656impl<C> SubAssign<ProjectivePoint<C>> for ProjectivePoint<C>
657where
658    C: PrimeCurveParams,
659{
660    fn sub_assign(&mut self, rhs: ProjectivePoint<C>) {
661        *self = ProjectivePoint::sub(self, &rhs);
662    }
663}
664
665impl<C> SubAssign<&ProjectivePoint<C>> for ProjectivePoint<C>
666where
667    C: PrimeCurveParams,
668{
669    fn sub_assign(&mut self, rhs: &ProjectivePoint<C>) {
670        *self = ProjectivePoint::sub(self, rhs);
671    }
672}
673
674impl<C> Sub<AffinePoint<C>> for ProjectivePoint<C>
675where
676    C: PrimeCurveParams,
677{
678    type Output = ProjectivePoint<C>;
679
680    fn sub(self, other: AffinePoint<C>) -> ProjectivePoint<C> {
681        ProjectivePoint::sub_mixed(&self, &other)
682    }
683}
684
685impl<C> Sub<&AffinePoint<C>> for &ProjectivePoint<C>
686where
687    C: PrimeCurveParams,
688{
689    type Output = ProjectivePoint<C>;
690
691    fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
692        ProjectivePoint::sub_mixed(self, other)
693    }
694}
695
696impl<C> Sub<&AffinePoint<C>> for ProjectivePoint<C>
697where
698    C: PrimeCurveParams,
699{
700    type Output = ProjectivePoint<C>;
701
702    fn sub(self, other: &AffinePoint<C>) -> ProjectivePoint<C> {
703        ProjectivePoint::sub_mixed(&self, other)
704    }
705}
706
707impl<C> SubAssign<AffinePoint<C>> for ProjectivePoint<C>
708where
709    C: PrimeCurveParams,
710{
711    fn sub_assign(&mut self, rhs: AffinePoint<C>) {
712        *self = ProjectivePoint::sub_mixed(self, &rhs);
713    }
714}
715
716impl<C> SubAssign<&AffinePoint<C>> for ProjectivePoint<C>
717where
718    C: PrimeCurveParams,
719{
720    fn sub_assign(&mut self, rhs: &AffinePoint<C>) {
721        *self = ProjectivePoint::sub_mixed(self, rhs);
722    }
723}
724
725impl<C, S> Mul<S> for ProjectivePoint<C>
726where
727    Self: Double,
728    C: PrimeCurveParams,
729    S: Borrow<Scalar<C>>,
730{
731    type Output = Self;
732
733    fn mul(self, scalar: S) -> Self {
734        ProjectivePoint::mul(&self, scalar.borrow())
735    }
736}
737
738impl<C> Mul<&Scalar<C>> for &ProjectivePoint<C>
739where
740    C: PrimeCurveParams,
741    ProjectivePoint<C>: Double,
742{
743    type Output = ProjectivePoint<C>;
744
745    fn mul(self, scalar: &Scalar<C>) -> ProjectivePoint<C> {
746        ProjectivePoint::mul(self, scalar)
747    }
748}
749
750impl<C, S> MulAssign<S> for ProjectivePoint<C>
751where
752    Self: Double,
753    C: PrimeCurveParams,
754    S: Borrow<Scalar<C>>,
755{
756    fn mul_assign(&mut self, scalar: S) {
757        *self = ProjectivePoint::mul(self, scalar.borrow());
758    }
759}
760
761impl<C> Neg for ProjectivePoint<C>
762where
763    C: PrimeCurveParams,
764{
765    type Output = ProjectivePoint<C>;
766
767    fn neg(self) -> ProjectivePoint<C> {
768        ProjectivePoint::neg(&self)
769    }
770}
771
772impl<'a, C> Neg for &'a ProjectivePoint<C>
773where
774    C: PrimeCurveParams,
775{
776    type Output = ProjectivePoint<C>;
777
778    fn neg(self) -> ProjectivePoint<C> {
779        ProjectivePoint::neg(self)
780    }
781}