/rust/registry/src/index.crates.io-1949cf8c6b5b557f/primeorder-0.13.6/src/affine.rs
Line | Count | Source |
1 | | //! Affine curve points. |
2 | | |
3 | | #![allow(clippy::op_ref)] |
4 | | |
5 | | use crate::{PrimeCurveParams, ProjectivePoint}; |
6 | | use core::{ |
7 | | borrow::Borrow, |
8 | | ops::{Mul, Neg}, |
9 | | }; |
10 | | use elliptic_curve::{ |
11 | | ff::{Field, PrimeField}, |
12 | | generic_array::ArrayLength, |
13 | | group::{prime::PrimeCurveAffine, GroupEncoding}, |
14 | | point::{AffineCoordinates, DecompactPoint, DecompressPoint, Double}, |
15 | | sec1::{ |
16 | | self, CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToCompactEncodedPoint, |
17 | | ToEncodedPoint, UncompressedPointSize, |
18 | | }, |
19 | | subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, |
20 | | zeroize::DefaultIsZeroes, |
21 | | Error, FieldBytes, FieldBytesEncoding, FieldBytesSize, PublicKey, Result, Scalar, |
22 | | }; |
23 | | |
24 | | #[cfg(feature = "serde")] |
25 | | use serdect::serde::{de, ser, Deserialize, Serialize}; |
26 | | |
27 | | /// Point on a Weierstrass curve in affine coordinates. |
28 | | #[derive(Clone, Copy, Debug)] |
29 | | pub struct AffinePoint<C: PrimeCurveParams> { |
30 | | /// x-coordinate |
31 | | pub(crate) x: C::FieldElement, |
32 | | |
33 | | /// y-coordinate |
34 | | pub(crate) y: C::FieldElement, |
35 | | |
36 | | /// Is this point the point at infinity? 0 = no, 1 = yes |
37 | | /// |
38 | | /// This is a proxy for [`Choice`], but uses `u8` instead to permit `const` |
39 | | /// constructors for `IDENTITY` and `GENERATOR`. |
40 | | pub(crate) infinity: u8, |
41 | | } |
42 | | |
43 | | impl<C> AffinePoint<C> |
44 | | where |
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::ZERO, |
51 | | infinity: 1, |
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 | | infinity: 0, |
59 | | }; |
60 | | |
61 | | /// Is this point the point at infinity? |
62 | 4.37k | pub fn is_identity(&self) -> Choice { |
63 | 4.37k | Choice::from(self.infinity) |
64 | 4.37k | } |
65 | | |
66 | | /// Conditionally negate [`AffinePoint`] for use with point compaction. |
67 | 0 | fn to_compact(self) -> Self { |
68 | 0 | let neg_self = -self; |
69 | 0 | let choice = C::Uint::decode_field_bytes(&self.y.to_repr()) |
70 | 0 | .ct_gt(&C::Uint::decode_field_bytes(&neg_self.y.to_repr())); |
71 | | |
72 | 0 | Self { |
73 | 0 | x: self.x, |
74 | 0 | y: C::FieldElement::conditional_select(&self.y, &neg_self.y, choice), |
75 | 0 | infinity: self.infinity, |
76 | 0 | } |
77 | 0 | } |
78 | | } |
79 | | |
80 | | impl<C> AffineCoordinates for AffinePoint<C> |
81 | | where |
82 | | C: PrimeCurveParams, |
83 | | { |
84 | | type FieldRepr = FieldBytes<C>; |
85 | | |
86 | 5.79k | fn x(&self) -> FieldBytes<C> { |
87 | 5.79k | self.x.to_repr() |
88 | 5.79k | } |
89 | | |
90 | 2.89k | fn y_is_odd(&self) -> Choice { |
91 | 2.89k | self.y.is_odd() |
92 | 2.89k | } |
93 | | } |
94 | | |
95 | | impl<C> ConditionallySelectable for AffinePoint<C> |
96 | | where |
97 | | C: PrimeCurveParams, |
98 | | { |
99 | | #[inline(always)] |
100 | 7.69k | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { |
101 | 7.69k | Self { |
102 | 7.69k | x: C::FieldElement::conditional_select(&a.x, &b.x, choice), |
103 | 7.69k | y: C::FieldElement::conditional_select(&a.y, &b.y, choice), |
104 | 7.69k | infinity: u8::conditional_select(&a.infinity, &b.infinity, choice), |
105 | 7.69k | } |
106 | 7.69k | } |
107 | | } |
108 | | |
109 | | impl<C> ConstantTimeEq for AffinePoint<C> |
110 | | where |
111 | | C: PrimeCurveParams, |
112 | | { |
113 | | fn ct_eq(&self, other: &Self) -> Choice { |
114 | | self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity) |
115 | | } |
116 | | } |
117 | | |
118 | | impl<C> Default for AffinePoint<C> |
119 | | where |
120 | | C: PrimeCurveParams, |
121 | | { |
122 | 74 | fn default() -> Self { |
123 | 74 | Self::IDENTITY |
124 | 74 | } |
125 | | } |
126 | | |
127 | | impl<C> DefaultIsZeroes for AffinePoint<C> where C: PrimeCurveParams {} |
128 | | |
129 | | impl<C> DecompressPoint<C> for AffinePoint<C> |
130 | | where |
131 | | C: PrimeCurveParams, |
132 | | FieldBytes<C>: Copy, |
133 | | { |
134 | 0 | fn decompress(x_bytes: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self> { |
135 | 0 | C::FieldElement::from_repr(*x_bytes).and_then(|x| { |
136 | 0 | let alpha = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B; |
137 | 0 | let beta = alpha.sqrt(); |
138 | | |
139 | 0 | beta.map(|beta| { |
140 | 0 | let y = C::FieldElement::conditional_select( |
141 | 0 | &-beta, |
142 | 0 | &beta, |
143 | 0 | beta.is_odd().ct_eq(&y_is_odd), |
144 | | ); |
145 | | |
146 | 0 | Self { x, y, infinity: 0 } |
147 | 0 | }) |
148 | 0 | }) |
149 | 0 | } |
150 | | } |
151 | | |
152 | | impl<C> DecompactPoint<C> for AffinePoint<C> |
153 | | where |
154 | | C: PrimeCurveParams, |
155 | | FieldBytes<C>: Copy, |
156 | | { |
157 | 0 | fn decompact(x_bytes: &FieldBytes<C>) -> CtOption<Self> { |
158 | 0 | Self::decompress(x_bytes, Choice::from(0)).map(|point| point.to_compact()) |
159 | 0 | } |
160 | | } |
161 | | |
162 | | impl<C> Eq for AffinePoint<C> where C: PrimeCurveParams {} |
163 | | |
164 | | impl<C> FromEncodedPoint<C> for AffinePoint<C> |
165 | | where |
166 | | C: PrimeCurveParams, |
167 | | FieldBytes<C>: Copy, |
168 | | FieldBytesSize<C>: ModulusSize, |
169 | | CompressedPoint<C>: Copy, |
170 | | { |
171 | | /// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded |
172 | | /// [`AffinePoint`]. |
173 | | /// |
174 | | /// # Returns |
175 | | /// |
176 | | /// `None` value if `encoded_point` is not on the secp384r1 curve. |
177 | 74 | fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> { |
178 | 74 | match encoded_point.coordinates() { |
179 | 0 | sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()), |
180 | 0 | sec1::Coordinates::Compact { x } => Self::decompact(x), |
181 | 0 | sec1::Coordinates::Compressed { x, y_is_odd } => { |
182 | 0 | Self::decompress(x, Choice::from(y_is_odd as u8)) |
183 | | } |
184 | 74 | sec1::Coordinates::Uncompressed { x, y } => { |
185 | 74 | C::FieldElement::from_repr(*y).and_then(|y| { |
186 | 74 | C::FieldElement::from_repr(*x).and_then(|x| { |
187 | 74 | let lhs = y * &y; |
188 | 74 | let rhs = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B; |
189 | 74 | CtOption::new(Self { x, y, infinity: 0 }, lhs.ct_eq(&rhs)) |
190 | 74 | }) |
191 | 74 | }) |
192 | | } |
193 | | } |
194 | 74 | } |
195 | | } |
196 | | |
197 | | impl<C> From<ProjectivePoint<C>> for AffinePoint<C> |
198 | | where |
199 | | C: PrimeCurveParams, |
200 | | { |
201 | | fn from(p: ProjectivePoint<C>) -> AffinePoint<C> { |
202 | | p.to_affine() |
203 | | } |
204 | | } |
205 | | |
206 | | impl<C> From<&ProjectivePoint<C>> for AffinePoint<C> |
207 | | where |
208 | | C: PrimeCurveParams, |
209 | | { |
210 | | fn from(p: &ProjectivePoint<C>) -> AffinePoint<C> { |
211 | | p.to_affine() |
212 | | } |
213 | | } |
214 | | |
215 | | impl<C> From<PublicKey<C>> for AffinePoint<C> |
216 | | where |
217 | | C: PrimeCurveParams, |
218 | | { |
219 | | fn from(public_key: PublicKey<C>) -> AffinePoint<C> { |
220 | | *public_key.as_affine() |
221 | | } |
222 | | } |
223 | | |
224 | | impl<C> From<&PublicKey<C>> for AffinePoint<C> |
225 | | where |
226 | | C: PrimeCurveParams, |
227 | | { |
228 | | fn from(public_key: &PublicKey<C>) -> AffinePoint<C> { |
229 | | AffinePoint::from(*public_key) |
230 | | } |
231 | | } |
232 | | |
233 | | impl<C> From<AffinePoint<C>> for EncodedPoint<C> |
234 | | where |
235 | | C: PrimeCurveParams, |
236 | | FieldBytesSize<C>: ModulusSize, |
237 | | CompressedPoint<C>: Copy, |
238 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
239 | | { |
240 | | fn from(affine: AffinePoint<C>) -> EncodedPoint<C> { |
241 | | affine.to_encoded_point(false) |
242 | | } |
243 | | } |
244 | | |
245 | | impl<C> GroupEncoding for AffinePoint<C> |
246 | | where |
247 | | C: PrimeCurveParams, |
248 | | FieldBytes<C>: Copy, |
249 | | FieldBytesSize<C>: ModulusSize, |
250 | | CompressedPoint<C>: Copy, |
251 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
252 | | { |
253 | | type Repr = CompressedPoint<C>; |
254 | | |
255 | | /// NOTE: not constant-time with respect to identity point |
256 | | fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { |
257 | | EncodedPoint::<C>::from_bytes(bytes) |
258 | | .map(|point| CtOption::new(point, Choice::from(1))) |
259 | | .unwrap_or_else(|_| { |
260 | | // SEC1 identity encoding is technically 1-byte 0x00, but the |
261 | | // `GroupEncoding` API requires a fixed-width `Repr` |
262 | | let is_identity = bytes.ct_eq(&Self::Repr::default()); |
263 | | CtOption::new(EncodedPoint::<C>::identity(), is_identity) |
264 | | }) |
265 | | .and_then(|point| Self::from_encoded_point(&point)) |
266 | | } |
267 | | |
268 | | fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { |
269 | | // No unchecked conversion possible for compressed points |
270 | | Self::from_bytes(bytes) |
271 | | } |
272 | | |
273 | | fn to_bytes(&self) -> Self::Repr { |
274 | | let encoded = self.to_encoded_point(true); |
275 | | let mut result = CompressedPoint::<C>::default(); |
276 | | result[..encoded.len()].copy_from_slice(encoded.as_bytes()); |
277 | | result |
278 | | } |
279 | | } |
280 | | |
281 | | impl<C> PartialEq for AffinePoint<C> |
282 | | where |
283 | | C: PrimeCurveParams, |
284 | | { |
285 | | fn eq(&self, other: &Self) -> bool { |
286 | | self.ct_eq(other).into() |
287 | | } |
288 | | } |
289 | | |
290 | | impl<C> PrimeCurveAffine for AffinePoint<C> |
291 | | where |
292 | | C: PrimeCurveParams, |
293 | | FieldBytes<C>: Copy, |
294 | | FieldBytesSize<C>: ModulusSize, |
295 | | ProjectivePoint<C>: Double, |
296 | | CompressedPoint<C>: Copy, |
297 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
298 | | { |
299 | | type Curve = ProjectivePoint<C>; |
300 | | type Scalar = Scalar<C>; |
301 | | |
302 | | fn identity() -> AffinePoint<C> { |
303 | | Self::IDENTITY |
304 | | } |
305 | | |
306 | | fn generator() -> AffinePoint<C> { |
307 | | Self::GENERATOR |
308 | | } |
309 | | |
310 | | fn is_identity(&self) -> Choice { |
311 | | self.is_identity() |
312 | | } |
313 | | |
314 | | fn to_curve(&self) -> ProjectivePoint<C> { |
315 | | ProjectivePoint::from(*self) |
316 | | } |
317 | | } |
318 | | |
319 | | impl<C> ToCompactEncodedPoint<C> for AffinePoint<C> |
320 | | where |
321 | | C: PrimeCurveParams, |
322 | | FieldBytesSize<C>: ModulusSize, |
323 | | CompressedPoint<C>: Copy, |
324 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
325 | | { |
326 | | /// Serialize this value as a SEC1 compact [`EncodedPoint`] |
327 | | fn to_compact_encoded_point(&self) -> CtOption<EncodedPoint<C>> { |
328 | | let point = self.to_compact(); |
329 | | |
330 | | let mut bytes = CompressedPoint::<C>::default(); |
331 | | bytes[0] = sec1::Tag::Compact.into(); |
332 | | bytes[1..].copy_from_slice(&point.x.to_repr()); |
333 | | |
334 | | let encoded = EncodedPoint::<C>::from_bytes(bytes); |
335 | | let is_some = point.y.ct_eq(&self.y); |
336 | | CtOption::new(encoded.unwrap_or_default(), is_some) |
337 | | } |
338 | | } |
339 | | |
340 | | impl<C> ToEncodedPoint<C> for AffinePoint<C> |
341 | | where |
342 | | C: PrimeCurveParams, |
343 | | FieldBytesSize<C>: ModulusSize, |
344 | | CompressedPoint<C>: Copy, |
345 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
346 | | { |
347 | 4.37k | fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> { |
348 | 4.37k | EncodedPoint::<C>::conditional_select( |
349 | 4.37k | &EncodedPoint::<C>::from_affine_coordinates( |
350 | 4.37k | &self.x.to_repr(), |
351 | 4.37k | &self.y.to_repr(), |
352 | 4.37k | compress, |
353 | 4.37k | ), |
354 | 4.37k | &EncodedPoint::<C>::identity(), |
355 | 4.37k | self.is_identity(), |
356 | | ) |
357 | 4.37k | } |
358 | | } |
359 | | |
360 | | impl<C> TryFrom<EncodedPoint<C>> for AffinePoint<C> |
361 | | where |
362 | | C: PrimeCurveParams, |
363 | | FieldBytes<C>: Copy, |
364 | | FieldBytesSize<C>: ModulusSize, |
365 | | CompressedPoint<C>: Copy, |
366 | | { |
367 | | type Error = Error; |
368 | | |
369 | | fn try_from(point: EncodedPoint<C>) -> Result<AffinePoint<C>> { |
370 | | AffinePoint::try_from(&point) |
371 | | } |
372 | | } |
373 | | |
374 | | impl<C> TryFrom<&EncodedPoint<C>> for AffinePoint<C> |
375 | | where |
376 | | C: PrimeCurveParams, |
377 | | FieldBytes<C>: Copy, |
378 | | FieldBytesSize<C>: ModulusSize, |
379 | | CompressedPoint<C>: Copy, |
380 | | { |
381 | | type Error = Error; |
382 | | |
383 | | fn try_from(point: &EncodedPoint<C>) -> Result<AffinePoint<C>> { |
384 | | Option::from(AffinePoint::<C>::from_encoded_point(point)).ok_or(Error) |
385 | | } |
386 | | } |
387 | | |
388 | | impl<C> TryFrom<AffinePoint<C>> for PublicKey<C> |
389 | | where |
390 | | C: PrimeCurveParams, |
391 | | { |
392 | | type Error = Error; |
393 | | |
394 | | fn try_from(affine_point: AffinePoint<C>) -> Result<PublicKey<C>> { |
395 | | PublicKey::from_affine(affine_point) |
396 | | } |
397 | | } |
398 | | |
399 | | impl<C> TryFrom<&AffinePoint<C>> for PublicKey<C> |
400 | | where |
401 | | C: PrimeCurveParams, |
402 | | { |
403 | | type Error = Error; |
404 | | |
405 | | fn try_from(affine_point: &AffinePoint<C>) -> Result<PublicKey<C>> { |
406 | | PublicKey::<C>::try_from(*affine_point) |
407 | | } |
408 | | } |
409 | | |
410 | | // |
411 | | // Arithmetic trait impls |
412 | | // |
413 | | |
414 | | impl<C, S> Mul<S> for AffinePoint<C> |
415 | | where |
416 | | C: PrimeCurveParams, |
417 | | S: Borrow<Scalar<C>>, |
418 | | ProjectivePoint<C>: Double, |
419 | | { |
420 | | type Output = ProjectivePoint<C>; |
421 | | |
422 | | fn mul(self, scalar: S) -> ProjectivePoint<C> { |
423 | | ProjectivePoint::<C>::from(self) * scalar |
424 | | } |
425 | | } |
426 | | |
427 | | impl<C> Neg for AffinePoint<C> |
428 | | where |
429 | | C: PrimeCurveParams, |
430 | | { |
431 | | type Output = Self; |
432 | | |
433 | 0 | fn neg(self) -> Self { |
434 | 0 | AffinePoint { |
435 | 0 | x: self.x, |
436 | 0 | y: -self.y, |
437 | 0 | infinity: self.infinity, |
438 | 0 | } |
439 | 0 | } |
440 | | } |
441 | | |
442 | | impl<C> Neg for &AffinePoint<C> |
443 | | where |
444 | | C: PrimeCurveParams, |
445 | | { |
446 | | type Output = AffinePoint<C>; |
447 | | |
448 | | fn neg(self) -> AffinePoint<C> { |
449 | | -(*self) |
450 | | } |
451 | | } |
452 | | |
453 | | // |
454 | | // serde support |
455 | | // |
456 | | |
457 | | #[cfg(feature = "serde")] |
458 | | impl<C> Serialize for AffinePoint<C> |
459 | | where |
460 | | C: PrimeCurveParams, |
461 | | FieldBytesSize<C>: ModulusSize, |
462 | | CompressedPoint<C>: Copy, |
463 | | <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, |
464 | | { |
465 | | fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> |
466 | | where |
467 | | S: ser::Serializer, |
468 | | { |
469 | | self.to_encoded_point(true).serialize(serializer) |
470 | | } |
471 | | } |
472 | | |
473 | | #[cfg(feature = "serde")] |
474 | | impl<'de, C> Deserialize<'de> for AffinePoint<C> |
475 | | where |
476 | | C: PrimeCurveParams, |
477 | | FieldBytes<C>: Copy, |
478 | | FieldBytesSize<C>: ModulusSize, |
479 | | CompressedPoint<C>: Copy, |
480 | | { |
481 | | fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> |
482 | | where |
483 | | D: de::Deserializer<'de>, |
484 | | { |
485 | | EncodedPoint::<C>::deserialize(deserializer)? |
486 | | .try_into() |
487 | | .map_err(de::Error::custom) |
488 | | } |
489 | | } |