1#![allow(clippy::op_ref)]
4
5use crate::{PrimeCurveParams, ProjectivePoint};
6use core::borrow::Borrow;
7use elliptic_curve::{
8 Error, FieldBytes, Generate, PublicKey, Result, Scalar,
9 bigint::modular::Retrieve,
10 ctutils::{self, CtGt as _, CtSelect as _},
11 ff::{Field, PrimeField},
12 group::{CurveAffine, GroupEncoding},
13 ops::{Double, Mul, MulVartime, Neg},
14 point::{AffineCoordinates, DecompactPoint, DecompressPoint, NonIdentity},
15 rand_core::{TryCryptoRng, TryRng},
16 sec1::{self, CompressedPoint, FromSec1Point, Sec1Point, ToCompactSec1Point, ToSec1Point},
17 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
18 zeroize::DefaultIsZeroes,
19};
20
21#[cfg(feature = "serde")]
22use serdect::serde::{Deserialize, Serialize, de, ser};
23
24#[derive(Clone, Copy, Debug)]
26pub struct AffinePoint<C: PrimeCurveParams> {
27 pub(crate) x: C::FieldElement,
29
30 pub(crate) y: C::FieldElement,
32
33 pub(crate) infinity: u8,
38}
39
40impl<C> AffinePoint<C>
41where
42 C: PrimeCurveParams,
43{
44 pub const IDENTITY: Self = Self {
46 x: C::FieldElement::ZERO,
47 y: C::FieldElement::ZERO,
48 infinity: 1,
49 };
50
51 pub const GENERATOR: Self = Self {
53 x: C::GENERATOR.0,
54 y: C::GENERATOR.1,
55 infinity: 0,
56 };
57
58 pub fn is_identity(&self) -> Choice {
60 Choice::from(self.infinity)
61 }
62
63 fn to_compact(self) -> Self {
65 let neg_self = -self;
66 let gt = self.y.retrieve().ct_gt(&neg_self.y.retrieve());
67 let y = C::FieldElement::conditional_select(&self.y, &neg_self.y, gt.into());
68 Self {
69 x: self.x,
70 y,
71 infinity: self.infinity,
72 }
73 }
74
75 pub(crate) fn try_random<R: TryRng + ?Sized>(
79 rng: &mut R,
80 ) -> core::result::Result<Self, R::Error> {
81 let mut bytes = FieldBytes::<C>::default();
82 let mut sign = 0;
83
84 loop {
85 rng.try_fill_bytes(&mut bytes)?;
86 rng.try_fill_bytes(core::array::from_mut(&mut sign))?;
87 if let Some(point) = Self::decompress(&bytes, Choice::from(sign & 1)).into_option() {
88 return Ok(point);
89 }
90 }
91 }
92}
93
94impl<C> AffineCoordinates for AffinePoint<C>
95where
96 C: PrimeCurveParams,
97{
98 type FieldRepr = FieldBytes<C>;
99
100 fn from_coordinates(x: &Self::FieldRepr, y: &Self::FieldRepr) -> CtOption<Self> {
101 C::FieldElement::from_repr(*y).and_then(|y| {
102 C::FieldElement::from_repr(*x).and_then(|x| {
103 let lhs = y * &y;
104 let rhs = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B;
105 CtOption::new(Self { x, y, infinity: 0 }, lhs.ct_eq(&rhs))
106 })
107 })
108 }
109
110 fn x(&self) -> FieldBytes<C> {
111 self.x.to_repr()
112 }
113
114 fn y(&self) -> FieldBytes<C> {
115 self.y.to_repr()
116 }
117
118 fn x_is_odd(&self) -> Choice {
119 self.x.is_odd()
120 }
121
122 fn y_is_odd(&self) -> Choice {
123 self.y.is_odd()
124 }
125}
126
127impl<C> ConditionallySelectable for AffinePoint<C>
128where
129 C: PrimeCurveParams,
130{
131 #[inline(always)]
132 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
133 Self {
134 x: C::FieldElement::conditional_select(&a.x, &b.x, choice),
135 y: C::FieldElement::conditional_select(&a.y, &b.y, choice),
136 infinity: u8::conditional_select(&a.infinity, &b.infinity, choice),
137 }
138 }
139}
140
141impl<C> ConstantTimeEq for AffinePoint<C>
142where
143 C: PrimeCurveParams,
144{
145 fn ct_eq(&self, other: &Self) -> Choice {
146 self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity)
147 }
148}
149
150impl<C> ctutils::CtEq for AffinePoint<C>
151where
152 C: PrimeCurveParams,
153{
154 fn ct_eq(&self, other: &Self) -> ctutils::Choice {
155 ConstantTimeEq::ct_eq(self, other).into()
156 }
157}
158
159impl<C> ctutils::CtSelect for AffinePoint<C>
160where
161 C: PrimeCurveParams,
162{
163 fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self {
164 ConditionallySelectable::conditional_select(self, other, choice.into())
165 }
166}
167
168impl<C> Default for AffinePoint<C>
169where
170 C: PrimeCurveParams,
171{
172 fn default() -> Self {
173 Self::IDENTITY
174 }
175}
176
177impl<C> DefaultIsZeroes for AffinePoint<C> where C: PrimeCurveParams {}
178
179impl<C> DecompressPoint<C> for AffinePoint<C>
180where
181 C: PrimeCurveParams,
182{
183 fn decompress(x_bytes: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self> {
184 C::FieldElement::from_repr(*x_bytes).and_then(|x| {
185 let alpha = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B;
186 let beta = alpha.sqrt();
187
188 beta.map(|beta| {
189 let y = C::FieldElement::conditional_select(
190 &-beta,
191 &beta,
192 beta.is_odd().ct_eq(&y_is_odd),
193 );
194
195 Self { x, y, infinity: 0 }
196 })
197 })
198 }
199}
200
201impl<C> DecompactPoint<C> for AffinePoint<C>
202where
203 C: PrimeCurveParams,
204{
205 fn decompact(x_bytes: &FieldBytes<C>) -> CtOption<Self> {
206 Self::decompress(x_bytes, Choice::from(0)).map(AffinePoint::to_compact)
207 }
208}
209
210impl<C> Eq for AffinePoint<C> where C: PrimeCurveParams {}
211
212impl<C> FromSec1Point<C> for AffinePoint<C>
213where
214 C: PrimeCurveParams,
215{
216 fn from_sec1_point(encoded_point: &Sec1Point<C>) -> ctutils::CtOption<Self> {
223 match encoded_point.coordinates() {
224 sec1::Coordinates::Identity => ctutils::CtOption::some(Self::IDENTITY),
225 sec1::Coordinates::Compact { x } => Self::decompact(x).into(),
226 sec1::Coordinates::Compressed { x, y_is_odd } => {
227 Self::decompress(x, Choice::from(u8::from(y_is_odd))).into()
228 }
229 sec1::Coordinates::Uncompressed { x, y } => Self::from_coordinates(x, y).into(),
230 }
231 }
232}
233
234impl<C> From<NonIdentity<AffinePoint<C>>> for AffinePoint<C>
235where
236 C: PrimeCurveParams,
237{
238 fn from(affine: NonIdentity<AffinePoint<C>>) -> Self {
239 affine.to_point()
240 }
241}
242
243impl<C> From<ProjectivePoint<C>> for AffinePoint<C>
244where
245 C: PrimeCurveParams,
246{
247 fn from(p: ProjectivePoint<C>) -> AffinePoint<C> {
248 p.to_affine()
249 }
250}
251
252impl<C> From<&ProjectivePoint<C>> for AffinePoint<C>
253where
254 C: PrimeCurveParams,
255{
256 fn from(p: &ProjectivePoint<C>) -> AffinePoint<C> {
257 p.to_affine()
258 }
259}
260
261impl<C> From<PublicKey<C>> for AffinePoint<C>
262where
263 C: PrimeCurveParams,
264{
265 fn from(public_key: PublicKey<C>) -> AffinePoint<C> {
266 *public_key.as_affine()
267 }
268}
269
270impl<C> From<&PublicKey<C>> for AffinePoint<C>
271where
272 C: PrimeCurveParams,
273{
274 fn from(public_key: &PublicKey<C>) -> AffinePoint<C> {
275 AffinePoint::from(*public_key)
276 }
277}
278
279impl<C> From<AffinePoint<C>> for Sec1Point<C>
280where
281 C: PrimeCurveParams,
282{
283 fn from(affine: AffinePoint<C>) -> Sec1Point<C> {
284 affine.to_sec1_point(false)
285 }
286}
287
288impl<C> Generate for AffinePoint<C>
289where
290 C: PrimeCurveParams,
291{
292 fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
293 rng: &mut R,
294 ) -> core::result::Result<Self, R::Error> {
295 Self::try_random(rng)
296 }
297}
298
299impl<C> GroupEncoding for AffinePoint<C>
300where
301 C: PrimeCurveParams,
302{
303 type Repr = CompressedPoint<C>;
304
305 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
307 Sec1Point::<C>::from_bytes(bytes)
308 .map_or_else(
309 |_| {
310 let is_identity =
313 ctutils::CtEq::ct_eq(bytes.as_slice(), Self::Repr::default().as_slice());
314 ctutils::CtOption::new(Sec1Point::<C>::identity(), is_identity)
315 },
316 ctutils::CtOption::some,
317 )
318 .and_then(|point| Self::from_sec1_point(&point))
319 .into()
320 }
321
322 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
323 Self::from_bytes(bytes)
325 }
326
327 fn to_bytes(&self) -> Self::Repr {
328 let encoded = self.to_sec1_point(true);
329 let mut result = CompressedPoint::<C>::default();
330 result[..encoded.len()].copy_from_slice(encoded.as_bytes());
331 result
332 }
333}
334
335impl<C> PartialEq for AffinePoint<C>
336where
337 C: PrimeCurveParams,
338{
339 fn eq(&self, other: &Self) -> bool {
340 self.ct_eq(other).into()
341 }
342}
343
344impl<C> CurveAffine for AffinePoint<C>
345where
346 C: PrimeCurveParams,
347{
348 type Curve = ProjectivePoint<C>;
349 type Scalar = Scalar<C>;
350
351 fn identity() -> AffinePoint<C> {
352 Self::IDENTITY
353 }
354
355 fn generator() -> AffinePoint<C> {
356 Self::GENERATOR
357 }
358
359 fn is_identity(&self) -> Choice {
360 self.is_identity()
361 }
362
363 fn to_curve(&self) -> ProjectivePoint<C> {
364 ProjectivePoint::from(*self)
365 }
366}
367
368impl<C> ToCompactSec1Point<C> for AffinePoint<C>
369where
370 C: PrimeCurveParams,
371{
372 fn to_compact_encoded_point(&self) -> ctutils::CtOption<Sec1Point<C>> {
374 let point = self.to_compact();
375
376 let mut bytes = CompressedPoint::<C>::default();
377 bytes[0] = sec1::Tag::Compact.into();
378 bytes[1..].copy_from_slice(&point.x.to_repr());
379
380 let encoded = Sec1Point::<C>::from_bytes(bytes);
381 let is_some =
382 ctutils::CtEq::ct_eq(point.y.to_repr().as_slice(), self.y.to_repr().as_slice());
383 ctutils::CtOption::new(encoded.unwrap_or_default(), is_some)
384 }
385}
386
387impl<C> ToSec1Point<C> for AffinePoint<C>
388where
389 C: PrimeCurveParams,
390{
391 fn to_sec1_point(&self, compress: bool) -> Sec1Point<C> {
392 Sec1Point::<C>::ct_select(
393 &Sec1Point::<C>::from_affine_coordinates(
394 &self.x.to_repr(),
395 &self.y.to_repr(),
396 compress,
397 ),
398 &Sec1Point::<C>::identity(),
399 self.is_identity().into(),
400 )
401 }
402}
403
404impl<C> TryFrom<AffinePoint<C>> for NonIdentity<AffinePoint<C>>
406where
407 C: PrimeCurveParams,
408{
409 type Error = Error;
410
411 fn try_from(affine_point: AffinePoint<C>) -> Result<Self> {
412 NonIdentity::new(affine_point).into_option().ok_or(Error)
413 }
414}
415
416impl<C> TryFrom<Sec1Point<C>> for AffinePoint<C>
417where
418 C: PrimeCurveParams,
419{
420 type Error = Error;
421
422 fn try_from(point: Sec1Point<C>) -> Result<AffinePoint<C>> {
423 AffinePoint::try_from(&point)
424 }
425}
426
427impl<C> TryFrom<&Sec1Point<C>> for AffinePoint<C>
428where
429 C: PrimeCurveParams,
430{
431 type Error = Error;
432
433 fn try_from(point: &Sec1Point<C>) -> Result<AffinePoint<C>> {
434 Option::from(AffinePoint::<C>::from_sec1_point(point)).ok_or(Error)
435 }
436}
437
438impl<C> TryFrom<AffinePoint<C>> for PublicKey<C>
439where
440 C: PrimeCurveParams,
441{
442 type Error = Error;
443
444 fn try_from(affine_point: AffinePoint<C>) -> Result<PublicKey<C>> {
445 PublicKey::from_affine(affine_point)
446 }
447}
448
449impl<C> TryFrom<&AffinePoint<C>> for PublicKey<C>
450where
451 C: PrimeCurveParams,
452{
453 type Error = Error;
454
455 fn try_from(affine_point: &AffinePoint<C>) -> Result<PublicKey<C>> {
456 PublicKey::<C>::try_from(*affine_point)
457 }
458}
459
460impl<C, S> Mul<S> for AffinePoint<C>
465where
466 C: PrimeCurveParams,
467 S: Borrow<Scalar<C>>,
468 ProjectivePoint<C>: Double,
469{
470 type Output = ProjectivePoint<C>;
471
472 #[inline]
473 fn mul(self, scalar: S) -> ProjectivePoint<C> {
474 ProjectivePoint::<C>::from(self) * scalar
475 }
476}
477
478impl<C, S> Mul<S> for &AffinePoint<C>
479where
480 C: PrimeCurveParams,
481 S: Borrow<Scalar<C>>,
482 ProjectivePoint<C>: Double,
483{
484 type Output = ProjectivePoint<C>;
485
486 #[inline]
487 fn mul(self, scalar: S) -> ProjectivePoint<C> {
488 ProjectivePoint::<C>::from(self) * scalar
489 }
490}
491
492impl<C, S> MulVartime<S> for AffinePoint<C>
493where
494 C: PrimeCurveParams,
495 S: Borrow<Scalar<C>>,
496 ProjectivePoint<C>: Double,
497{
498 #[inline]
499 fn mul_vartime(self, scalar: S) -> ProjectivePoint<C> {
500 ProjectivePoint::<C>::from(self).mul_vartime(scalar)
501 }
502}
503
504impl<C, S> MulVartime<S> for &AffinePoint<C>
505where
506 C: PrimeCurveParams,
507 S: Borrow<Scalar<C>>,
508 ProjectivePoint<C>: Double,
509{
510 #[inline]
511 fn mul_vartime(self, scalar: S) -> ProjectivePoint<C> {
512 ProjectivePoint::<C>::from(self).mul_vartime(scalar)
513 }
514}
515
516impl<C> Neg for AffinePoint<C>
517where
518 C: PrimeCurveParams,
519{
520 type Output = Self;
521
522 #[inline]
523 fn neg(self) -> Self {
524 AffinePoint {
525 x: self.x,
526 y: -self.y,
527 infinity: self.infinity,
528 }
529 }
530}
531
532impl<C> Neg for &AffinePoint<C>
533where
534 C: PrimeCurveParams,
535{
536 type Output = AffinePoint<C>;
537
538 #[inline]
539 fn neg(self) -> AffinePoint<C> {
540 -(*self)
541 }
542}
543
544#[cfg(feature = "serde")]
549impl<C> Serialize for AffinePoint<C>
550where
551 C: PrimeCurveParams,
552{
553 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
554 where
555 S: ser::Serializer,
556 {
557 self.to_sec1_point(true).serialize(serializer)
558 }
559}
560
561#[cfg(feature = "serde")]
562impl<'de, C> Deserialize<'de> for AffinePoint<C>
563where
564 C: PrimeCurveParams,
565{
566 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
567 where
568 D: de::Deserializer<'de>,
569 {
570 Sec1Point::<C>::deserialize(deserializer)?
571 .try_into()
572 .map_err(de::Error::custom)
573 }
574}