generic_ec_curves/rust_crypto/
mod.rs

1//! Adapter for curves implemented on top of [`elliptic_curve`] package
2//!
3//! This module provide generic wrappers that can port any curve implemented on top of
4//! [`elliptic_curve`] package to `generic-ec`.
5
6use core::fmt;
7use core::hash::{self, Hash};
8use core::marker::PhantomData;
9use core::ops::Mul;
10
11use elliptic_curve::group::cofactor::CofactorGroup;
12use elliptic_curve::hash2curve::ExpandMsgXmd;
13use elliptic_curve::ops::Reduce;
14use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
15use elliptic_curve::{CurveArithmetic, FieldBytesSize, ScalarPrimitive};
16use generic_ec_core::{
17    CompressedEncoding, Curve, IntegerEncoding, NoInvalidPoints, UncompressedEncoding,
18};
19use subtle::{ConditionallySelectable, ConstantTimeEq};
20use zeroize::{DefaultIsZeroes, Zeroize};
21
22#[cfg(any(feature = "secp256k1", feature = "secp256r1", feature = "stark"))]
23use sha2::Sha256;
24
25pub use self::{curve_name::CurveName, point::RustCryptoPoint, scalar::RustCryptoScalar};
26
27mod affine_coords;
28mod curve_name;
29mod hash_to_curve;
30mod point;
31mod scalar;
32
33/// Curve ported from [`elliptic_curve`] crate
34pub struct RustCryptoCurve<C, X> {
35    _ph: PhantomData<fn() -> (C, X)>,
36}
37
38impl<C, X> RustCryptoCurve<C, X>
39where
40    C: CurveArithmetic,
41{
42    /// Constructs a point on the curve
43    pub fn point(point: C::ProjectivePoint) -> RustCryptoPoint<C> {
44        RustCryptoPoint(point)
45    }
46}
47
48impl<C, X> RustCryptoCurve<C, X>
49where
50    C: CurveArithmetic,
51{
52    /// Constructs a scalar
53    pub fn scalar(scalar: C::Scalar) -> RustCryptoScalar<C> {
54        RustCryptoScalar(scalar)
55    }
56}
57
58/// secp256k1 curve
59///
60/// Based on [k256] crate
61#[cfg(feature = "secp256k1")]
62pub type Secp256k1 = RustCryptoCurve<k256::Secp256k1, ExpandMsgXmd<Sha256>>;
63/// secp256r1 curve
64///
65/// Based on [p256] crate
66#[cfg(feature = "secp256r1")]
67pub type Secp256r1 = RustCryptoCurve<p256::NistP256, ExpandMsgXmd<Sha256>>;
68
69/// Stark curve
70///
71/// Based on [stark_curve] crate
72#[cfg(feature = "stark")]
73pub type Stark = RustCryptoCurve<stark_curve::StarkCurve, ExpandMsgXmd<Sha256>>;
74
75impl<C, X> Curve for RustCryptoCurve<C, X>
76where
77    C: CurveName + CurveArithmetic,
78    C::ProjectivePoint: From<C::AffinePoint>
79        + CofactorGroup
80        + Copy
81        + Eq
82        + Default
83        + ConstantTimeEq
84        + ConditionallySelectable
85        + Zeroize
86        + Unpin,
87    C::AffinePoint: From<C::ProjectivePoint> + ToEncodedPoint<C> + FromEncodedPoint<C>,
88    for<'a> &'a C::ProjectivePoint: Mul<&'a C::Scalar, Output = C::ProjectivePoint>,
89    C::Scalar:
90        Reduce<C::Uint> + Eq + ConstantTimeEq + ConditionallySelectable + DefaultIsZeroes + Unpin,
91    RustCryptoScalar<C>: scalar::BytesModOrder,
92    for<'a> ScalarPrimitive<C>: From<&'a C::Scalar>,
93    FieldBytesSize<C>: ModulusSize,
94    X: 'static,
95{
96    const CURVE_NAME: &'static str = C::CURVE_NAME;
97
98    type Point = RustCryptoPoint<C>;
99    type Scalar = RustCryptoScalar<C>;
100
101    type CompressedPointArray = <Self::Point as CompressedEncoding>::Bytes;
102    type UncompressedPointArray = <Self::Point as UncompressedEncoding>::Bytes;
103
104    type ScalarArray = <Self::Scalar as IntegerEncoding>::Bytes;
105
106    type CoordinateArray = elliptic_curve::FieldBytes<C>;
107}
108
109impl<C: CurveName, X> fmt::Debug for RustCryptoCurve<C, X> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        f.debug_struct("RustCryptoCurve")
112            .field("curve", &C::CURVE_NAME)
113            .finish()
114    }
115}
116
117impl<C, X> Clone for RustCryptoCurve<C, X> {
118    fn clone(&self) -> Self {
119        *self
120    }
121}
122
123impl<C, X> Copy for RustCryptoCurve<C, X> {}
124
125impl<C, X> PartialEq for RustCryptoCurve<C, X> {
126    fn eq(&self, _other: &Self) -> bool {
127        true
128    }
129}
130
131impl<C, X> Eq for RustCryptoCurve<C, X> {}
132
133impl<C, X> PartialOrd for RustCryptoCurve<C, X> {
134    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
135        Some(self.cmp(other))
136    }
137}
138
139impl<C, X> Ord for RustCryptoCurve<C, X> {
140    fn cmp(&self, _other: &Self) -> core::cmp::Ordering {
141        core::cmp::Ordering::Equal
142    }
143}
144
145impl<C, X> Hash for RustCryptoCurve<C, X>
146where
147    C: CurveName,
148{
149    fn hash<H: hash::Hasher>(&self, state: &mut H) {
150        state.write(C::CURVE_NAME.as_bytes())
151    }
152}
153
154impl<C, X> Default for RustCryptoCurve<C, X> {
155    fn default() -> Self {
156        Self { _ph: PhantomData }
157    }
158}
159
160/// Safe because:
161/// - RustCrypto curves are always on curve:
162///   generic-ec-curves/src/rust_crypto/point.rs:60
163/// - k256 is prime order and so is always torsion-free:
164///   <https://github.com/RustCrypto/elliptic-curves/blob/f06ae5b93f83c571ed7ef7031b99e24759b90f9e/k256/src/arithmetic/hash2curve.rs#L259-L273>
165#[cfg(feature = "secp256k1")]
166unsafe impl NoInvalidPoints for Secp256k1 {}
167/// Safe because:
168/// - RustCrypto curves are always on curve:
169///   generic-ec-curves/src/rust_crypto/point.rs:60
170/// - p256 is prime order and so is always torsion-free. This check isn't even
171///   implemented in code.
172#[cfg(feature = "secp256r1")]
173unsafe impl NoInvalidPoints for Secp256r1 {}
174/// Safe because:
175/// - RustCrypto curves are always on curve:
176///   generic-ec-curves/src/rust_crypto/point.rs:60
177/// - stark is prime order and so is always torsion-free:
178///   <https://github.com/RustCrypto/elliptic-curves/blob/7a71e403e49fbe92d6b2ae8fe3eabbfdef124975/primeorder/src/projective.rs#L172-L174>
179#[cfg(feature = "stark")]
180unsafe impl NoInvalidPoints for Stark {}
181
182#[cfg(test)]
183mod tests {
184    use generic_ec_core::{
185        coords::{HasAffineX, HasAffineXAndParity, HasAffineXY},
186        Curve,
187    };
188
189    use super::{Secp256k1, Secp256r1, Stark};
190
191    /// Asserts that `E` implements `Curve`
192    fn _impls_curve<E: Curve>() {}
193    fn _exposes_affine_coords<E: HasAffineX + HasAffineXAndParity + HasAffineXY>() {}
194
195    fn _curves_impl_trait() {
196        _impls_curve::<Secp256k1>();
197        _impls_curve::<Secp256r1>();
198        _impls_curve::<Stark>();
199
200        _exposes_affine_coords::<Secp256k1>();
201        _exposes_affine_coords::<Secp256r1>();
202        _exposes_affine_coords::<Stark>();
203    }
204}