diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/primeorder/src/affine.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/primeorder/src/affine.rs')
-rw-r--r-- | vendor/primeorder/src/affine.rs | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/vendor/primeorder/src/affine.rs b/vendor/primeorder/src/affine.rs new file mode 100644 index 000000000..e7f2feccd --- /dev/null +++ b/vendor/primeorder/src/affine.rs @@ -0,0 +1,485 @@ +//! Affine curve points. + +#![allow(clippy::op_ref)] + +use crate::{PrimeCurveParams, ProjectivePoint}; +use core::{ + borrow::Borrow, + ops::{Mul, Neg}, +}; +use elliptic_curve::{ + ff::{Field, PrimeField}, + generic_array::ArrayLength, + group::{prime::PrimeCurveAffine, GroupEncoding}, + point::{AffineCoordinates, DecompactPoint, DecompressPoint, Double}, + sec1::{ + self, CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToCompactEncodedPoint, + ToEncodedPoint, UncompressedPointSize, + }, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, + zeroize::DefaultIsZeroes, + Error, FieldBytes, FieldBytesEncoding, FieldBytesSize, PublicKey, Result, Scalar, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Point on a Weierstrass curve in affine coordinates. +#[derive(Clone, Copy, Debug)] +pub struct AffinePoint<C: PrimeCurveParams> { + /// x-coordinate + pub(crate) x: C::FieldElement, + + /// y-coordinate + pub(crate) y: C::FieldElement, + + /// Is this point the point at infinity? 0 = no, 1 = yes + /// + /// This is a proxy for [`Choice`], but uses `u8` instead to permit `const` + /// constructors for `IDENTITY` and `GENERATOR`. + pub(crate) infinity: u8, +} + +impl<C> AffinePoint<C> +where + C: PrimeCurveParams, +{ + /// Additive identity of the group a.k.a. the point at infinity. + pub const IDENTITY: Self = Self { + x: C::FieldElement::ZERO, + y: C::FieldElement::ZERO, + infinity: 1, + }; + + /// Base point of the curve. + pub const GENERATOR: Self = Self { + x: C::GENERATOR.0, + y: C::GENERATOR.1, + infinity: 0, + }; + + /// Is this point the point at infinity? + pub fn is_identity(&self) -> Choice { + Choice::from(self.infinity) + } + + /// Conditionally negate [`AffinePoint`] for use with point compaction. + fn to_compact(self) -> Self { + let neg_self = -self; + let choice = C::Uint::decode_field_bytes(&self.y.to_repr()) + .ct_gt(&C::Uint::decode_field_bytes(&neg_self.y.to_repr())); + + Self { + x: self.x, + y: C::FieldElement::conditional_select(&self.y, &neg_self.y, choice), + infinity: self.infinity, + } + } +} + +impl<C> AffineCoordinates for AffinePoint<C> +where + C: PrimeCurveParams, +{ + type FieldRepr = FieldBytes<C>; + + fn x(&self) -> FieldBytes<C> { + self.x.to_repr() + } + + fn y_is_odd(&self) -> Choice { + self.y.is_odd() + } +} + +impl<C> ConditionallySelectable for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + x: C::FieldElement::conditional_select(&a.x, &b.x, choice), + y: C::FieldElement::conditional_select(&a.y, &b.y, choice), + infinity: u8::conditional_select(&a.infinity, &b.infinity, choice), + } + } +} + +impl<C> ConstantTimeEq for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity) + } +} + +impl<C> Default for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn default() -> Self { + Self::IDENTITY + } +} + +impl<C> DefaultIsZeroes for AffinePoint<C> where C: PrimeCurveParams {} + +impl<C> DecompressPoint<C> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, +{ + fn decompress(x_bytes: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self> { + C::FieldElement::from_repr(*x_bytes).and_then(|x| { + let alpha = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B; + let beta = alpha.sqrt(); + + beta.map(|beta| { + let y = C::FieldElement::conditional_select( + &-beta, + &beta, + beta.is_odd().ct_eq(&y_is_odd), + ); + + Self { x, y, infinity: 0 } + }) + }) + } +} + +impl<C> DecompactPoint<C> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, +{ + fn decompact(x_bytes: &FieldBytes<C>) -> CtOption<Self> { + Self::decompress(x_bytes, Choice::from(0)).map(|point| point.to_compact()) + } +} + +impl<C> Eq for AffinePoint<C> where C: PrimeCurveParams {} + +impl<C> FromEncodedPoint<C> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, +{ + /// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded + /// [`AffinePoint`]. + /// + /// # Returns + /// + /// `None` value if `encoded_point` is not on the secp384r1 curve. + fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> { + match encoded_point.coordinates() { + sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()), + sec1::Coordinates::Compact { x } => Self::decompact(x), + sec1::Coordinates::Compressed { x, y_is_odd } => { + Self::decompress(x, Choice::from(y_is_odd as u8)) + } + sec1::Coordinates::Uncompressed { x, y } => { + C::FieldElement::from_repr(*y).and_then(|y| { + Self::decompress(x, y.is_odd()) + .and_then(|point| CtOption::new(point, point.y.ct_eq(&y))) + }) + } + } + } +} + +impl<C> From<ProjectivePoint<C>> for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn from(p: ProjectivePoint<C>) -> AffinePoint<C> { + p.to_affine() + } +} + +impl<C> From<&ProjectivePoint<C>> for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn from(p: &ProjectivePoint<C>) -> AffinePoint<C> { + p.to_affine() + } +} + +impl<C> From<PublicKey<C>> for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn from(public_key: PublicKey<C>) -> AffinePoint<C> { + *public_key.as_affine() + } +} + +impl<C> From<&PublicKey<C>> for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn from(public_key: &PublicKey<C>) -> AffinePoint<C> { + AffinePoint::from(*public_key) + } +} + +impl<C> From<AffinePoint<C>> for EncodedPoint<C> +where + C: PrimeCurveParams, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + fn from(affine: AffinePoint<C>) -> EncodedPoint<C> { + affine.to_encoded_point(false) + } +} + +impl<C> GroupEncoding for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + type Repr = CompressedPoint<C>; + + /// NOTE: not constant-time with respect to identity point + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + EncodedPoint::<C>::from_bytes(bytes) + .map(|point| CtOption::new(point, Choice::from(1))) + .unwrap_or_else(|_| { + // SEC1 identity encoding is technically 1-byte 0x00, but the + // `GroupEncoding` API requires a fixed-width `Repr` + let is_identity = bytes.ct_eq(&Self::Repr::default()); + CtOption::new(EncodedPoint::<C>::identity(), is_identity) + }) + .and_then(|point| Self::from_encoded_point(&point)) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + // No unchecked conversion possible for compressed points + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + let encoded = self.to_encoded_point(true); + let mut result = CompressedPoint::<C>::default(); + result[..encoded.len()].copy_from_slice(encoded.as_bytes()); + result + } +} + +impl<C> PartialEq for AffinePoint<C> +where + C: PrimeCurveParams, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl<C> PrimeCurveAffine for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + ProjectivePoint<C>: Double, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + type Curve = ProjectivePoint<C>; + type Scalar = Scalar<C>; + + fn identity() -> AffinePoint<C> { + Self::IDENTITY + } + + fn generator() -> AffinePoint<C> { + Self::GENERATOR + } + + fn is_identity(&self) -> Choice { + self.is_identity() + } + + fn to_curve(&self) -> ProjectivePoint<C> { + ProjectivePoint::from(*self) + } +} + +impl<C> ToCompactEncodedPoint<C> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + /// Serialize this value as a SEC1 compact [`EncodedPoint`] + fn to_compact_encoded_point(&self) -> CtOption<EncodedPoint<C>> { + let point = self.to_compact(); + + let mut bytes = CompressedPoint::<C>::default(); + bytes[0] = sec1::Tag::Compact.into(); + bytes[1..].copy_from_slice(&point.x.to_repr()); + + let encoded = EncodedPoint::<C>::from_bytes(bytes); + let is_some = point.y.ct_eq(&self.y); + CtOption::new(encoded.unwrap_or_default(), is_some) + } +} + +impl<C> ToEncodedPoint<C> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> { + EncodedPoint::<C>::conditional_select( + &EncodedPoint::<C>::from_affine_coordinates( + &self.x.to_repr(), + &self.y.to_repr(), + compress, + ), + &EncodedPoint::<C>::identity(), + self.is_identity(), + ) + } +} + +impl<C> TryFrom<EncodedPoint<C>> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, +{ + type Error = Error; + + fn try_from(point: EncodedPoint<C>) -> Result<AffinePoint<C>> { + AffinePoint::try_from(&point) + } +} + +impl<C> TryFrom<&EncodedPoint<C>> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, +{ + type Error = Error; + + fn try_from(point: &EncodedPoint<C>) -> Result<AffinePoint<C>> { + Option::from(AffinePoint::<C>::from_encoded_point(point)).ok_or(Error) + } +} + +impl<C> TryFrom<AffinePoint<C>> for PublicKey<C> +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(affine_point: AffinePoint<C>) -> Result<PublicKey<C>> { + PublicKey::from_affine(affine_point) + } +} + +impl<C> TryFrom<&AffinePoint<C>> for PublicKey<C> +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(affine_point: &AffinePoint<C>) -> Result<PublicKey<C>> { + PublicKey::<C>::try_from(*affine_point) + } +} + +// +// Arithmetic trait impls +// + +impl<C, S> Mul<S> for AffinePoint<C> +where + C: PrimeCurveParams, + S: Borrow<Scalar<C>>, + ProjectivePoint<C>: Double, +{ + type Output = ProjectivePoint<C>; + + fn mul(self, scalar: S) -> ProjectivePoint<C> { + ProjectivePoint::<C>::from(self) * scalar + } +} + +impl<C> Neg for AffinePoint<C> +where + C: PrimeCurveParams, +{ + type Output = Self; + + fn neg(self) -> Self { + AffinePoint { + x: self.x, + y: -self.y, + infinity: self.infinity, + } + } +} + +impl<C> Neg for &AffinePoint<C> +where + C: PrimeCurveParams, +{ + type Output = AffinePoint<C>; + + fn neg(self) -> AffinePoint<C> { + -(*self) + } +} + +// +// serde support +// + +#[cfg(feature = "serde")] +impl<C> Serialize for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, + <UncompressedPointSize<C> as ArrayLength<u8>>::ArrayType: Copy, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + self.to_encoded_point(true).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for AffinePoint<C> +where + C: PrimeCurveParams, + FieldBytes<C>: Copy, + FieldBytesSize<C>: ModulusSize, + CompressedPoint<C>: Copy, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + EncodedPoint::<C>::deserialize(deserializer)? + .try_into() + .map_err(de::Error::custom) + } +} |