1#![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#[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 pub const IDENTITY: Self = Self {
49 x: C::FieldElement::ZERO,
50 y: C::FieldElement::ONE,
51 z: C::FieldElement::ZERO,
52 };
53
54 pub const GENERATOR: Self = Self {
56 x: C::GENERATOR.0,
57 y: C::GENERATOR.1,
58 z: C::FieldElement::ONE,
59 };
60
61 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 pub fn neg(&self) -> Self {
78 Self {
79 x: self.x,
80 y: -self.y,
81 z: self.z,
82 }
83 }
84
85 pub fn add(&self, other: &Self) -> Self {
87 C::PointArithmetic::add(self, other)
88 }
89
90 fn add_mixed(&self, other: &AffinePoint<C>) -> Self {
92 C::PointArithmetic::add_mixed(self, other)
93 }
94
95 pub fn sub(&self, other: &Self) -> Self {
97 self.add(&other.neg())
98 }
99
100 fn sub_mixed(&self, other: &AffinePoint<C>) -> Self {
102 self.add_mixed(&other.neg())
103 }
104
105 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 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 }
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
381fn 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 zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&C::FieldElement::ZERO));
399 }
400
401 let zs_inverses = <C::FieldElement as BatchInvert<Z>>::batch_invert(zs).unwrap();
403
404 for i in 0..out.len() {
405 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 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
499impl<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}