Skip to main content

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