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(|point| point.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(y_is_odd as u8)).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(ctutils::CtOption::some)
309 .unwrap_or_else(|_| {
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 .and_then(|point| Self::from_sec1_point(&point))
317 .into()
318 }
319
320 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
321 Self::from_bytes(bytes)
323 }
324
325 fn to_bytes(&self) -> Self::Repr {
326 let encoded = self.to_sec1_point(true);
327 let mut result = CompressedPoint::<C>::default();
328 result[..encoded.len()].copy_from_slice(encoded.as_bytes());
329 result
330 }
331}
332
333impl<C> PartialEq for AffinePoint<C>
334where
335 C: PrimeCurveParams,
336{
337 fn eq(&self, other: &Self) -> bool {
338 self.ct_eq(other).into()
339 }
340}
341
342impl<C> CurveAffine for AffinePoint<C>
343where
344 C: PrimeCurveParams,
345{
346 type Curve = ProjectivePoint<C>;
347 type Scalar = Scalar<C>;
348
349 fn identity() -> AffinePoint<C> {
350 Self::IDENTITY
351 }
352
353 fn generator() -> AffinePoint<C> {
354 Self::GENERATOR
355 }
356
357 fn is_identity(&self) -> Choice {
358 self.is_identity()
359 }
360
361 fn to_curve(&self) -> ProjectivePoint<C> {
362 ProjectivePoint::from(*self)
363 }
364}
365
366impl<C> ToCompactSec1Point<C> for AffinePoint<C>
367where
368 C: PrimeCurveParams,
369{
370 fn to_compact_encoded_point(&self) -> ctutils::CtOption<Sec1Point<C>> {
372 let point = self.to_compact();
373
374 let mut bytes = CompressedPoint::<C>::default();
375 bytes[0] = sec1::Tag::Compact.into();
376 bytes[1..].copy_from_slice(&point.x.to_repr());
377
378 let encoded = Sec1Point::<C>::from_bytes(bytes);
379 let is_some =
380 ctutils::CtEq::ct_eq(point.y.to_repr().as_slice(), self.y.to_repr().as_slice());
381 ctutils::CtOption::new(encoded.unwrap_or_default(), is_some)
382 }
383}
384
385impl<C> ToSec1Point<C> for AffinePoint<C>
386where
387 C: PrimeCurveParams,
388{
389 fn to_sec1_point(&self, compress: bool) -> Sec1Point<C> {
390 Sec1Point::<C>::ct_select(
391 &Sec1Point::<C>::from_affine_coordinates(
392 &self.x.to_repr(),
393 &self.y.to_repr(),
394 compress,
395 ),
396 &Sec1Point::<C>::identity(),
397 self.is_identity().into(),
398 )
399 }
400}
401
402impl<C> TryFrom<AffinePoint<C>> for NonIdentity<AffinePoint<C>>
404where
405 C: PrimeCurveParams,
406{
407 type Error = Error;
408
409 fn try_from(affine_point: AffinePoint<C>) -> Result<Self> {
410 NonIdentity::new(affine_point).into_option().ok_or(Error)
411 }
412}
413
414impl<C> TryFrom<Sec1Point<C>> for AffinePoint<C>
415where
416 C: PrimeCurveParams,
417{
418 type Error = Error;
419
420 fn try_from(point: Sec1Point<C>) -> Result<AffinePoint<C>> {
421 AffinePoint::try_from(&point)
422 }
423}
424
425impl<C> TryFrom<&Sec1Point<C>> for AffinePoint<C>
426where
427 C: PrimeCurveParams,
428{
429 type Error = Error;
430
431 fn try_from(point: &Sec1Point<C>) -> Result<AffinePoint<C>> {
432 Option::from(AffinePoint::<C>::from_sec1_point(point)).ok_or(Error)
433 }
434}
435
436impl<C> TryFrom<AffinePoint<C>> for PublicKey<C>
437where
438 C: PrimeCurveParams,
439{
440 type Error = Error;
441
442 fn try_from(affine_point: AffinePoint<C>) -> Result<PublicKey<C>> {
443 PublicKey::from_affine(affine_point)
444 }
445}
446
447impl<C> TryFrom<&AffinePoint<C>> for PublicKey<C>
448where
449 C: PrimeCurveParams,
450{
451 type Error = Error;
452
453 fn try_from(affine_point: &AffinePoint<C>) -> Result<PublicKey<C>> {
454 PublicKey::<C>::try_from(*affine_point)
455 }
456}
457
458impl<C, S> Mul<S> for AffinePoint<C>
463where
464 C: PrimeCurveParams,
465 S: Borrow<Scalar<C>>,
466 ProjectivePoint<C>: Double,
467{
468 type Output = ProjectivePoint<C>;
469
470 #[inline]
471 fn mul(self, scalar: S) -> ProjectivePoint<C> {
472 ProjectivePoint::<C>::from(self) * scalar
473 }
474}
475
476impl<C, S> Mul<S> for &AffinePoint<C>
477where
478 C: PrimeCurveParams,
479 S: Borrow<Scalar<C>>,
480 ProjectivePoint<C>: Double,
481{
482 type Output = ProjectivePoint<C>;
483
484 #[inline]
485 fn mul(self, scalar: S) -> ProjectivePoint<C> {
486 ProjectivePoint::<C>::from(self) * scalar
487 }
488}
489
490impl<C, S> MulVartime<S> for AffinePoint<C>
491where
492 C: PrimeCurveParams,
493 S: Borrow<Scalar<C>>,
494 ProjectivePoint<C>: Double,
495{
496 #[inline]
497 fn mul_vartime(self, scalar: S) -> ProjectivePoint<C> {
498 ProjectivePoint::<C>::from(self).mul_vartime(scalar)
499 }
500}
501
502impl<C, S> MulVartime<S> for &AffinePoint<C>
503where
504 C: PrimeCurveParams,
505 S: Borrow<Scalar<C>>,
506 ProjectivePoint<C>: Double,
507{
508 #[inline]
509 fn mul_vartime(self, scalar: S) -> ProjectivePoint<C> {
510 ProjectivePoint::<C>::from(self).mul_vartime(scalar)
511 }
512}
513
514impl<C> Neg for AffinePoint<C>
515where
516 C: PrimeCurveParams,
517{
518 type Output = Self;
519
520 #[inline]
521 fn neg(self) -> Self {
522 AffinePoint {
523 x: self.x,
524 y: -self.y,
525 infinity: self.infinity,
526 }
527 }
528}
529
530impl<C> Neg for &AffinePoint<C>
531where
532 C: PrimeCurveParams,
533{
534 type Output = AffinePoint<C>;
535
536 #[inline]
537 fn neg(self) -> AffinePoint<C> {
538 -(*self)
539 }
540}
541
542#[cfg(feature = "serde")]
547impl<C> Serialize for AffinePoint<C>
548where
549 C: PrimeCurveParams,
550{
551 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
552 where
553 S: ser::Serializer,
554 {
555 self.to_sec1_point(true).serialize(serializer)
556 }
557}
558
559#[cfg(feature = "serde")]
560impl<'de, C> Deserialize<'de> for AffinePoint<C>
561where
562 C: PrimeCurveParams,
563{
564 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
565 where
566 D: de::Deserializer<'de>,
567 {
568 Sec1Point::<C>::deserialize(deserializer)?
569 .try_into()
570 .map_err(de::Error::custom)
571 }
572}