generic_ec_core/lib.rs
1//! This crate contains core traits for [`generic-ec`](https://docs.rs/generic-ec) crate.
2//! You should only need these traits if you implement your own [`Curve`] instance.
3//! Otherwise, `generic-ec` API should suffice.
4
5#![no_std]
6#![cfg_attr(not(test), forbid(unused_crate_dependencies))]
7#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
8#![forbid(missing_docs)]
9
10use core::fmt::Debug;
11use core::hash::Hash;
12
13use generic_array::{ArrayLength, GenericArray};
14use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
15use zeroize::Zeroize;
16
17pub mod coords;
18
19/// Elliptic curve
20///
21/// This trait contains all the low-level curve implementation logic: scalar, point arithmetics,
22/// encoding and etc.
23pub trait Curve: Debug + Copy + Eq + Ord + Hash + Default + Sync + Send + 'static {
24 /// Curve name
25 const CURVE_NAME: &'static str;
26
27 /// Type that represents a curve point
28 type Point: Additive
29 + From<CurveGenerator>
30 + Zero
31 + Zeroize
32 + OnCurve
33 + SmallFactor
34 + Copy
35 + Eq
36 + ConstantTimeEq
37 + ConditionallySelectable
38 + Default
39 + CompressedEncoding<Bytes = Self::CompressedPointArray>
40 + UncompressedEncoding<Bytes = Self::UncompressedPointArray>
41 + Decode
42 + Unpin
43 + Sync
44 + Send;
45 /// Type that represents a curve scalar
46 type Scalar: Additive
47 + Multiplicative<Self::Scalar, Output = Self::Scalar>
48 + Multiplicative<CurveGenerator, Output = Self::Point>
49 + Multiplicative<Self::Point, Output = Self::Point>
50 + Invertible
51 + Zero
52 + One
53 + FromUniformBytes
54 + SamplableVartime
55 + Zeroize
56 + Copy
57 + Eq
58 + ConstantTimeEq
59 + ConditionallySelectable
60 + Default
61 + IntegerEncoding<Bytes = Self::ScalarArray>
62 + Unpin
63 + Sync
64 + Send;
65
66 /// Byte array that fits the whole bytes representation of compressed point
67 type CompressedPointArray: ByteArray;
68 /// Byte array that fits the whole bytes representation of uncompressed point
69 type UncompressedPointArray: ByteArray;
70 /// Byte array that fits the whole bytes representation of a scalar
71 type ScalarArray: ByteArray;
72 /// Byte array that fits the whole bytes representation of a coordinate
73 ///
74 /// If a curve doesn't expose point coordinates, it may be `[u8; 0]`
75 type CoordinateArray: ByteArray;
76}
77
78/// Type for which addition is defined
79pub trait Additive {
80 /// Computes `a + b`
81 fn add(a: &Self, b: &Self) -> Self;
82 /// Computes `a - b`
83 fn sub(a: &Self, b: &Self) -> Self;
84 /// Computes `-a`
85 fn negate(x: &Self) -> Self;
86
87 /// Takes `x`, returns `x + x`
88 ///
89 /// This can be more efficient than calling [`Self::add(x, x)`](Self::add)
90 fn double(x: &Self) -> Self
91 where
92 Self: Sized,
93 {
94 Self::add(x, x)
95 }
96}
97
98/// Type for which multiplication is defined
99pub trait Multiplicative<Rhs> {
100 /// Type of multiplication output
101 type Output;
102 /// Computes `a * b`
103 fn mul(a: &Self, b: &Rhs) -> Self::Output;
104}
105
106/// Type for which invert function is defined
107pub trait Invertible
108where
109 Self: Sized,
110{
111 /// Inverts $x$, returns $x^{-1}$ such that $x \cdot x^{-1} = 1$
112 fn invert(x: &Self) -> CtOption<Self>;
113}
114
115/// Type that has zero value (additive identity)
116pub trait Zero {
117 /// Constructs zero value of `Self`
118 fn zero() -> Self;
119 /// Checks (in constant-time) if `x` is zero
120 fn is_zero(x: &Self) -> Choice;
121}
122
123/// Type that has "one" value (multiplicative identity)
124pub trait One {
125 /// Constructs one value of `Self`
126 fn one() -> Self;
127 /// Checks (in constant-time) if `x` is one
128 fn is_one(x: &Self) -> Choice;
129}
130
131/// Uniform instance of the type can be derived from uniformly distributed byte array
132pub trait FromUniformBytes {
133 /// Byte array that can be converted into instance of `Self` via [`FromUniformBytes::from_uniform_bytes`]
134 type Bytes: ByteArray;
135
136 /// Maps uniformly distributed bytes array to uniformly distributed instance of `Self`.
137 ///
138 /// Instead of taking a source of randomness directly, this implementation takes a byte array, that was
139 /// populated from the source of randomness, and outputs a random element.
140 ///
141 /// ## Guarantees
142 /// When `bytes` are uniformly distributed, output distribution must be indistinguishable from uniform,
143 /// with bias respective to the security level of the curve, meaning that any instance of the type can
144 /// appear with equal probability.
145 ///
146 /// Implementation is reproducible: the same input `bytes` give the same output on all platforms.
147 ///
148 /// Implementation is constant-time: there's no branching on the input.
149 ///
150 /// ## Implementation details
151 /// This trait is required to be implemented for scalars. It's recommended to take approach described in
152 /// "5. Hashing to Finite Field" of [RFC9380]:
153 ///
154 /// 1. Take a uniform bytestring of `L` bytes, where
155 /// ```text
156 /// L = ceil((ceil(log2(q)) + k) / 8)
157 /// ```
158 ///
159 /// `q` is prime (sub)group order, and `k` is target security level in bits
160 /// 2. Interpret the bytestring as big-endian/little-endian encoding of the integer, and reduce it modulo `q`
161 ///
162 /// The output is then guaranteed to have a bias at most 2^-k.
163 ///
164 /// [RFC9380]: https://www.rfc-editor.org/rfc/rfc9380.html#name-hashing-to-a-finite-field
165 fn from_uniform_bytes(bytes: &Self::Bytes) -> Self;
166}
167
168/// Samples a uniform instance of the type from source of randomness
169pub trait SamplableVartime {
170 /// Samples a uniform instance of the type from source of randomness
171 ///
172 /// ## Guarantees
173 /// If output of provided PRNG is uniform, then the output of this function is uniformly
174 /// distributed (with bias respective to the security level of the curve), meaning that
175 /// any instance of the type can appear with equal probability.
176 ///
177 /// Implementation **is not** reproducible: it may lead to different results on different
178 /// platform and/or instances of the program even if the same `rng` is used with the same
179 /// seed.
180 ///
181 /// Implementation **is not** constant-time: it likely uses reject-sample strategy.
182 fn random_vartime(rng: &mut impl rand_core::RngCore) -> Self;
183}
184
185/// Checks whether the point is on curve
186pub trait OnCurve {
187 /// Checks whether the point is on curve
188 fn is_on_curve(&self) -> Choice;
189}
190
191/// Checks whether a point has small factor
192pub trait SmallFactor {
193 /// Checks whether a point has no small factor
194 fn is_torsion_free(&self) -> Choice;
195}
196
197/// Curve generator
198///
199/// Represents a curve generator. The curve point must implement `From<CurveGenerator>`.
200/// The curve scalar can be multiplied at `CurveGenerator`, implementation may be
201/// more efficient than a generic multiplication.
202pub struct CurveGenerator;
203
204/// Compressed encoding of the point
205pub trait CompressedEncoding
206where
207 Self: Sized,
208{
209 /// Byte array that fits the whole compressed point representation
210 type Bytes: ByteArray;
211
212 /// Encodes the point as bytes in compressed form
213 fn to_bytes_compressed(&self) -> Self::Bytes;
214}
215
216/// Uncompressed encoding of the point
217pub trait UncompressedEncoding
218where
219 Self: Sized,
220{
221 /// Byte array that fits the whole uncompressed point representation
222 type Bytes: ByteArray;
223
224 /// Encodes the point as bytes in uncompressed form
225 ///
226 /// Some curves may not have such thing as compressed and uncompressed forms.
227 /// For these curves, we `CompressedEncoding` and `UncompressedEncoding` should
228 /// return the same encoding.
229 fn to_bytes_uncompressed(&self) -> Self::Bytes;
230}
231
232/// Encodes an integer as bytes
233pub trait IntegerEncoding
234where
235 Self: Sized,
236{
237 /// Byte array that fits the whole encoded integer
238 type Bytes: ByteArray;
239
240 /// Encodes integer as bytes in big-endian byte order
241 fn to_be_bytes(&self) -> Self::Bytes;
242 /// Encodes integer as bytes in little-endian byte order
243 fn to_le_bytes(&self) -> Self::Bytes;
244
245 /// Decodes integer encoded as bytes in big-endian bytes order
246 ///
247 /// Returns `None` if the bytes don't correspond to a valid integer.
248 fn from_be_bytes_exact(bytes: &Self::Bytes) -> Option<Self>;
249 /// Decodes integer encoded as bytes in little-endian bytes order
250 ///
251 /// Returns `None` if the bytes don't correspond to a valid integer.
252 fn from_le_bytes_exact(bytes: &Self::Bytes) -> Option<Self>;
253
254 /// Interprets `bytes` as big-endian encoding of an integer. Returns integer mod curve (prime) order.
255 fn from_be_bytes_mod_order(bytes: &[u8]) -> Self;
256 /// Interprets `bytes` as little-endian encoding of an integer. Returns integer mod curve (prime) order.
257 fn from_le_bytes_mod_order(bytes: &[u8]) -> Self;
258}
259
260/// Decodes a point from its compressed or uncompressed representation
261pub trait Decode: Sized {
262 /// Decodes a point from its compressed or uncompressed representation
263 fn decode(bytes: &[u8]) -> Option<Self>;
264}
265
266/// Error type
267pub struct Error;
268
269/// Byte array
270pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + Clone + Send + Sync + 'static {
271 /// New byte array of zeroes
272 ///
273 /// Alternative to [`Default`] that is not implemented for generic `[T; N]`
274 /// (see [tracking issue](https://github.com/rust-lang/rust/issues/61415))
275 fn zeroes() -> Self;
276}
277
278impl<const N: usize> ByteArray for [u8; N] {
279 fn zeroes() -> Self {
280 [0; N]
281 }
282}
283
284impl<N: ArrayLength<u8>> ByteArray for GenericArray<u8, N> {
285 fn zeroes() -> Self {
286 GenericArray::default()
287 }
288}
289
290/// Reduces an integer represented as array of `N` bytes modulo curve (prime) order
291pub trait Reduce<const N: usize> {
292 /// Interprets `bytes` as big-endian encoding of an integer, returns this
293 /// integer modulo curve (prime) order
294 fn from_be_array_mod_order(bytes: &[u8; N]) -> Self;
295 /// Interprets `bytes` as little-endian encoding of an integer, returns this
296 /// integer modulo curve (prime) order
297 fn from_le_array_mod_order(bytes: &[u8; N]) -> Self;
298}
299
300/// Marker trait for curves whose underlying implementation doesn't allow
301/// representing invalid points.
302/// # Safety
303/// Safe to implement when the checks for valid points always return `true`.
304/// Those checks are:
305/// - [`OnCurve::is_on_curve`]
306/// - [`SmallFactor::is_torsion_free`]
307pub unsafe trait NoInvalidPoints {}