summaryrefslogtreecommitdiffstats
path: root/vendor/primeorder/src/affine.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/primeorder/src/affine.rs')
-rw-r--r--vendor/primeorder/src/affine.rs485
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)
+ }
+}