mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Fix handling of prime/composite-order curves within short-weierstrass
This commit is contained in:
@@ -67,6 +67,10 @@ impl ShortWeierstrass for Embedwards25519 {
|
|||||||
|
|
||||||
(repr, odd_y)
|
(repr, odd_y)
|
||||||
}
|
}
|
||||||
|
// No points have a torsion element as this a prime-order curve
|
||||||
|
fn has_torsion_element(_point: Projective<Self>) -> Choice {
|
||||||
|
0.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Point = Projective<Embedwards25519>;
|
pub type Point = Projective<Embedwards25519>;
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ impl<C: ShortWeierstrass> Affine<C> {
|
|||||||
/// Create an affine point from `x, y` coordinates, without performing any checks.
|
/// Create an affine point from `x, y` coordinates, without performing any checks.
|
||||||
///
|
///
|
||||||
/// This should NOT be used. It is solely intended for trusted data at compile-time. It MUST NOT
|
/// This should NOT be used. It is solely intended for trusted data at compile-time. It MUST NOT
|
||||||
/// be used with any untrusted/unvalidated data. Providing any off-curve point may produce
|
/// be used with any untrusted/unvalidated data. Providing any point not within the largest
|
||||||
/// completely undefined behavior.
|
/// prime-order subgroup has completely undefined behavior.
|
||||||
pub const fn from_xy_unchecked(x: C::FieldElement, y: C::FieldElement) -> Self {
|
pub const fn from_xy_unchecked(x: C::FieldElement, y: C::FieldElement) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ mod projective;
|
|||||||
pub use projective::Projective;
|
pub use projective::Projective;
|
||||||
|
|
||||||
/// An elliptic curve represented in short Weierstrass form, with equation `y^2 = x^3 + A x + B`.
|
/// An elliptic curve represented in short Weierstrass form, with equation `y^2 = x^3 + A x + B`.
|
||||||
///
|
|
||||||
/// This elliptic curve is expected to be of prime order. If a generator of the elliptic curve has
|
|
||||||
/// a composite order, the elliptic curve is defined solely as its largest odd-prime-order
|
|
||||||
/// subgroup, further considered the entire group/elliptic curve.
|
|
||||||
pub trait ShortWeierstrass: 'static + Sized + Debug {
|
pub trait ShortWeierstrass: 'static + Sized + Debug {
|
||||||
/// The field the elliptic curve is defined over.
|
/// The field the elliptic curve is defined over.
|
||||||
type FieldElement: Zeroize + PrimeField;
|
type FieldElement: Zeroize + PrimeField;
|
||||||
@@ -26,9 +22,9 @@ pub trait ShortWeierstrass: 'static + Sized + Debug {
|
|||||||
const A: Self::FieldElement;
|
const A: Self::FieldElement;
|
||||||
/// The constant `B` from the curve equation.
|
/// The constant `B` from the curve equation.
|
||||||
const B: Self::FieldElement;
|
const B: Self::FieldElement;
|
||||||
/// A generator of this elliptic curve.
|
/// A generator of this elliptic curve's largest prime-order subgroup.
|
||||||
const GENERATOR: Affine<Self>;
|
const GENERATOR: Affine<Self>;
|
||||||
/// The scalar type.
|
/// The scalar type for the elliptic curve's largest prime-order subgroup.
|
||||||
///
|
///
|
||||||
/// This may be omitted by specifying `()`.
|
/// This may be omitted by specifying `()`.
|
||||||
type Scalar;
|
type Scalar;
|
||||||
@@ -45,4 +41,9 @@ pub trait ShortWeierstrass: 'static + Sized + Debug {
|
|||||||
///
|
///
|
||||||
/// This is expected to return the `x` coordinate and if the `y` coordinate is odd.
|
/// This is expected to return the `x` coordinate and if the `y` coordinate is odd.
|
||||||
fn decode_compressed(bytes: &Self::Repr) -> (<Self::FieldElement as PrimeField>::Repr, Choice);
|
fn decode_compressed(bytes: &Self::Repr) -> (<Self::FieldElement as PrimeField>::Repr, Choice);
|
||||||
|
|
||||||
|
/// If the point is outside the largest prime-order subgroup and isn't the identity point.
|
||||||
|
///
|
||||||
|
/// This may immediately return `Choice::new(0)` for curves of prime order.
|
||||||
|
fn has_torsion_element(point: Projective<Self>) -> Choice;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,12 +308,20 @@ impl<C: ShortWeierstrass> GroupEncoding for Projective<C> {
|
|||||||
|
|
||||||
let (x, odd_y) = C::decode_compressed(bytes);
|
let (x, odd_y) = C::decode_compressed(bytes);
|
||||||
|
|
||||||
// Parse x, recover y, return the result
|
let result = C::FieldElement::from_repr(x).and_then(|x| {
|
||||||
C::FieldElement::from_repr(x).and_then(|x| {
|
// Parse x and recover y
|
||||||
let non_identity_on_curve_point = Affine::decompress(x, odd_y).map(Projective::from);
|
let non_identity_on_curve_point = Affine::decompress(x, odd_y).map(Projective::from);
|
||||||
|
// Set the identity, if the identity
|
||||||
let identity = CtOption::new(Projective::IDENTITY, identity);
|
let identity = CtOption::new(Projective::IDENTITY, identity);
|
||||||
non_identity_on_curve_point.or_else(|| identity)
|
non_identity_on_curve_point.or_else(|| identity)
|
||||||
})
|
});
|
||||||
|
|
||||||
|
let mut result_is_valid = result.is_some();
|
||||||
|
let result = result.unwrap_or(Projective::IDENTITY);
|
||||||
|
// Constrain points to the prime-order subgroup
|
||||||
|
result_is_valid &= !C::has_torsion_element(result);
|
||||||
|
|
||||||
|
CtOption::new(result, result_is_valid)
|
||||||
}
|
}
|
||||||
fn from_bytes_unchecked(bytes: &C::Repr) -> CtOption<Self> {
|
fn from_bytes_unchecked(bytes: &C::Repr) -> CtOption<Self> {
|
||||||
Self::from_bytes(bytes)
|
Self::from_bytes(bytes)
|
||||||
@@ -341,6 +349,7 @@ impl<C: ShortWeierstrass> GroupEncoding for Projective<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// We implement `PrimeGroup` due to constraining to a prime-order subgroup
|
||||||
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> PrimeGroup for Projective<C> {}
|
impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> PrimeGroup for Projective<C> {}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
|||||||
Reference in New Issue
Block a user