generic_ec/lib.rs
1//! 
2//! [](https://docs.rs/generic-ec)
3//! [](https://crates.io/crates/generic-ec)
4//! [][in Discord]
5//! [](https://scorecard.dev/viewer/?uri=github.com/LFDT-Lockness/generic-ec)
6//!
7//! # General elliptic curve cryptography
8//!
9//! The library provides a set of simple abstractions boosting experience of doing elliptic curve arithmetic
10//! in Rust. Aim is to **stay simple**, **generic**, and **secure**. It's handy for developers who implement MPC,
11//! zero-knowledge protocols, or any other elliptic crypto algorithms.
12//!
13//! `generic-ec` is `no_std` and web assembly friendly.
14//!
15//! ## Overview
16//!
17//! Crate provides three primitives: a point on elliptic curve [`Point<E>`](Point), an integer modulus group order
18//! [`Scalar<E>`](Scalar), and a secret scalar carrying some sensitive value (e.g. secret key) [`SecretScalar<E>`](SecretScalar).
19//! `E` stands for a choice of elliptic curve, it could be any [supported curve][supported curves], e.g. `Point<Secp256k1>`
20//! is an elliptic point on secp256k1 curve.
21//!
22//! ## Exposed API
23//!
24//! Limited API is exposed: elliptic point arithmetic (points addition, negation, multiplying at scalar), scalar
25//! arithmetic (addition, multiplication, inverse modulo prime group order), and encode/decode to bytes representation.
26//!
27//! Hash to curve, hash to scalar primitives, accessing affine coordinates of points are available for some curves through
28//! `FromHash` and other traits.
29//!
30//! ## Security & guarantees
31//!
32//! Library mitigates a bunch of attacks (such as small-group attack) by design by enforcing following checks:
33//! * Scalar `Scalar<E>` must be an integer modulo curve prime order
34//! * Elliptic point `Point<E>` must be on the curve \
35//! I.e. elliptic point is guaranteed to satisfy equation of `E`
36//! * `Point<E>` is torsion-free \
37//! Elliptic points should be free of small-group component. This eliminates any kind of small-group attacks.
38//!
39//! Point or scalar not meeting above requirements cannot be constructed (in safe Rust), as these checks are
40//! always enforced. E.g. if you're deserializing a sequence of bytes that represents an invalid point,
41//! deserialization will result into error.
42//!
43//! ### `SecretScalar<E>` and `SecretPoint<E>`
44//!
45//! Sometimes your scalar represents some sensitive value like secret key, and you want to keep it safer.
46//! `SecretScalar<E>` is in-place replacement of `Scalar<E>` that enforces additional security by storing
47//! the scalar value on the heap, and erasing it on drop. Its advantage is that it doesn't leave any trace
48//! in memory dump after it's dropped (which is not guaranteed by regular `Scalar<E>`). `SecretPoint<E>`
49//! is a similar structure, except it acts as a replacement for `Point<E>`.
50//!
51//! But keep in mind that we can't control the OS which could potentially load RAM page containing sensitive value
52//! to the swap disk (i.e. on your HDD/SSD) if you're running low on memory. Or it could do any other fancy stuff.
53//! We avoid writing unsafe or OS-specific code that could mitigate this problem.
54//!
55//! ### Points at infinity
56//!
57//! It should be noticed that point at infinity (or identity point) is a valid `Point<E>`. You can construct it by calling
58//! `Point::<E>::zero()`, e.g. `Point::<Secp256k1>::zero()` is a point at infinity for secp256k1 curve.
59//!
60//! If the protocol you're implementing requires points/scalars to be non-zero, you may need to enforce this check by calling
61//! `.is_zero()` method or by using [`NonZero<T>`](NonZero) (`NonZero<Point<E>>` or `NonZero<Scalar<E>>`).
62//!
63//! Using `NonZero<T>` gives some compile-time guarantees. For instance, multiplying non-zero point in the prime group at
64//! non-zero scalar mod group order is mathematically guaranteed to output non-zero point in that prime group. Thus,
65//! multiplying `NonZero<Point<E>>` at `NonZero<Scalar<E>>` returns `NonZero<Point<E>>`.
66//!
67//!
68//! ## Supported curves
69//!
70//! Crate provides support for following elliptic curves out of box:
71//!
72//! | Curve | Feature | Backend |
73//! |--------------|--------------------|-------------------|
74//! | secp256k1 | `curve-secp256k1` | [RustCrypto/k256] |
75//! | secp256r1 | `curve-secp256r1` | [RustCrypto/p256] |
76//! | secp384r1 | `curve-secp384r1` | [RustCrypto/p384] |
77//! | stark-curve | `curve-stark` | [Dfns/stark] |
78//! | Ed25519 | `curve-ed25519` | [curve25519-dalek]|
79//!
80//! [RustCrypto/k256]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256
81//! [RustCrypto/p256]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256
82//! [RustCrypto/p384]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384
83//! [Dfns/stark]: https://github.com/LFDT-Lockness/stark-curve/
84//! [curve25519-dalek]: https://docs.rs/curve25519-dalek/
85//!
86//! In order to use one of the supported curves, you need to turn on corresponding feature. E.g. if you want
87//! to use secp256k1 curve, add this to Cargo.toml:
88//!
89//! ```toml
90//! [dependency]
91//! generic-ec = { version = "...", features = ["curve-secp256k1"] }
92//! ```
93//!
94//! And now you can generate a point on that curve:
95//!
96//! ```rust
97//! use generic_ec::{Point, Scalar, curves::Secp256k1};
98//! # let mut rng = rand::rngs::OsRng;
99//!
100//! let random_point: Point<Secp256k1> = Point::generator() * Scalar::random(&mut rng);
101//! ```
102//!
103//! ### Adding support for other curves
104//!
105//! Adding new curve is as easy as implementing [`Curve` trait](Curve)! If you're missing some curve support,
106//! or you're not fine with using existing implementation, you may define your implementation of `Curve` trait
107//! and enjoy using the same handy primitives `Point<YOUR_EC>`, `Scalar<YOUR_EC>`, and etc.
108//!
109//! ## Features
110//!
111//! * `curve-{name}` enables specified curve support. See list of [supported curves].
112//! * `all-curves` enables all supported curves
113//! * `serde` enables points/scalar (de)serialization support. (enabled by default)
114//! * `std` enables support of standard library (enabled by default)
115//!
116//! ## Examples
117//!
118//! ### Random scalar / point generation
119//!
120//! ```rust
121//! use generic_ec::{Point, Scalar, curves::Secp256k1};
122//! # let mut rng = rand::rngs::OsRng;
123//!
124//! // Generates random non-zero scalar
125//! let random_scalar = Scalar::<Secp256k1>::random(&mut rng);
126//! // Produces a point that's result of generator multiplied at the random scalar
127//! let point = Point::generator() * &random_scalar;
128//! ```
129//!
130//! ### Diffie-Hellman key exchange
131//!
132//! ```rust
133//! use generic_ec::{Point, SecretScalar, curves::Secp256k1};
134//! # let mut rng = rand::rngs::OsRng;
135//!
136//! let alice_sk = SecretScalar::<Secp256k1>::random(&mut rng);
137//! let alice_pk = Point::generator() * &alice_sk;
138//!
139//! let bob_sk = SecretScalar::<Secp256k1>::random(&mut rng);
140//! let bob_pk = Point::generator() * &bob_sk;
141//!
142//! let shared_secret_learned_by_alice = bob_pk * &alice_sk;
143//! let shared_secret_learned_by_bob = alice_pk * &bob_sk;
144//! assert_eq!(shared_secret_learned_by_alice, shared_secret_learned_by_bob);
145//! ```
146//!
147//! ### Generic over choice of curve
148//!
149//! You can simply make your function generic over choice of curve:
150//!
151//! ```rust
152//! use generic_ec::{Point, Scalar, Curve};
153//! use rand::RngCore;
154//!
155//! fn some_generic_computation<E: Curve>(rng: &mut impl RngCore, point: Point<E>) -> Point<E> {
156//! let blinding = Point::<E>::generator() * Scalar::random(rng);
157//! let e = &point + &blinding;
158//! // ... some computation
159//! # e
160//! }
161//!
162//! // You can run this function with any supported curve:
163//! use generic_ec::curves::{Secp256k1, Secp256r1};
164//! # let mut rng = rand::rngs::OsRng;
165//!
166//! let point1 = Point::<Secp256k1>::generator().to_point();
167//! let _ = some_generic_computation(&mut rng, point1);
168//!
169//! let point2 = Point::<Secp256r1>::generator().to_point();
170//! let _ = some_generic_computation(&mut rng, point2);
171//!
172//! // ...
173//! ```
174//!
175//! [examples]: #examples
176//! [supported curves]: #supported-curves
177//!
178//! ## Join us in Discord!
179//! Feel free to reach out to us [in Discord]!
180//!
181//! [in Discord]: https://discord.com/invite/hyperledger
182//!
183//! ## License
184//!
185//! The crate is licensed under MIT or Apache-2.0 at your choice.
186
187#![forbid(missing_docs)]
188#![cfg_attr(not(test), forbid(unused_crate_dependencies))]
189#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
190#![no_std]
191#![cfg_attr(docsrs, feature(doc_cfg))]
192
193#[cfg(feature = "std")]
194extern crate std;
195
196#[cfg(feature = "alloc")]
197extern crate alloc;
198
199pub use generic_ec_core as core;
200
201mod arithmetic;
202pub mod as_raw;
203pub mod coords;
204mod encoded;
205pub mod errors;
206mod generator;
207pub mod multiscalar;
208mod non_zero;
209mod point;
210mod scalar;
211mod secret;
212mod secret_point;
213mod secret_scalar;
214
215mod _unused_deps {
216 // This dependency is not used directly without `alloc` feature. Note that
217 // even if `alloc` feature is off, this crate is still present in the
218 // dependency tree as `curve-ed25519` feature is enabled, it's just not
219 // used directly
220 #[cfg(all(feature = "curve-ed25519", not(feature = "alloc")))]
221 use curve25519 as _;
222}
223
224/// Common traits for points and scalars
225pub mod traits {
226 #[doc(inline)]
227 pub use crate::core::{NoInvalidPoints, One, Reduce, Zero};
228
229 /// Trait that allows you to check whether value is zero
230 pub trait IsZero {
231 /// Checks whether `self` is zero
232 fn is_zero(&self) -> bool;
233 }
234
235 /// Uniformly samples an instance of `Self` from source of randomness
236 ///
237 /// This trait is implemented for scalars in all their variations: `Scalar<E>`,
238 /// `SecretScalar<E>`, `NonZero<Scalar<E>>`, etc.
239 ///
240 /// Under the hood, it uses `NonZero::<Scalar<E>>::{random, random_vartime}`
241 /// methods.
242 pub trait Samplable {
243 /// Uniformly samples an instance of `Self` from source of randomness
244 /// using constant-time method
245 ///
246 /// Under the hood, it uses [`NonZero::<Scalar<E>>::random()`](
247 /// crate::NonZero::<Scalar<E>>::random()) method,
248 /// therefore it shares the same guarantees and performance drawbacks.
249 /// Refer to its documentation to learn more.
250 fn random<R: rand_core::RngCore>(rng: &mut R) -> Self;
251
252 /// Uniformly samples an instance of `Self` from source of randomness
253 /// using vartime method
254 ///
255 /// Under the hood, it uses [`NonZero::<Scalar<E>>::random_vartime()`](
256 /// crate::NonZero::<Scalar<E>>::random_vartime()) method,
257 /// therefore it shares the same guarantees and performance drawbacks.
258 /// Refer to its documentation to learn more.
259 fn random_vartime<R: rand_core::RngCore>(rng: &mut R) -> Self;
260 }
261}
262
263pub mod serde;
264
265pub use self::{
266 core::Curve,
267 encoded::{EncodedPoint, EncodedScalar, EncodedSecretPoint, EncodedSecretScalar},
268 generator::Generator,
269 non_zero::definition::NonZero,
270 point::definition::Point,
271 scalar::{Radix16Iter, Scalar},
272 secret_point::SecretPoint,
273 secret_scalar::SecretScalar,
274};
275
276/// Curves supported out of the box
277pub mod curves {
278 #[cfg(feature = "curve-ed25519")]
279 #[cfg_attr(docsrs, doc(cfg(feature = "curve-ed25519")))]
280 pub use generic_ec_curves::Ed25519;
281 #[cfg(feature = "curve-secp256k1")]
282 #[cfg_attr(docsrs, doc(cfg(feature = "curve-secp256k1")))]
283 pub use generic_ec_curves::Secp256k1;
284 #[cfg(feature = "curve-secp256r1")]
285 #[cfg_attr(docsrs, doc(cfg(feature = "curve-secp256r1")))]
286 pub use generic_ec_curves::Secp256r1;
287 #[cfg(feature = "curve-secp384r1")]
288 #[cfg_attr(docsrs, doc(cfg(feature = "curve-secp384r1")))]
289 pub use generic_ec_curves::Secp384r1;
290 #[cfg(feature = "curve-stark")]
291 #[cfg_attr(docsrs, doc(cfg(feature = "curve-stark")))]
292 pub use generic_ec_curves::Stark;
293
294 macro_rules! create_aliases {
295 ($(#[$attr:meta] $mod:ident: $curve:ident),+$(,)?) => {$(
296 /// Aliases for [`
297 #[doc = stringify!($curve)]
298 /// `] curve
299 ///
300 /// This module provides type aliases to [`Point`](crate::Point), [`Scalar`](crate::Scalar), and other types
301 /// instantiated with [`
302 #[doc = stringify!($curve)]
303 /// `]. It might be convenient to use this module when you don't need your code to be generic over choice
304 /// of curve.
305 ///
306 /// ## Example
307 /// The code below only works with [`
308 #[doc = stringify!($curve)]
309 /// `] curve. By using type aliases from
310 #[doc = concat!("[`generic_ec::curves::", stringify!($mod), "`](", stringify!($mod), ")")]
311 /// , we never need to deal with generic parameters.
312 ///
313 /// ```rust
314 #[doc = concat!("use generic_ec::curves::", stringify!($mod), "::{Point, SecretScalar};")]
315 ///
316 /// let mut rng = rand::rngs::OsRng;
317 /// let secret_key = SecretScalar::random(&mut rng);
318 /// let public_key = Point::generator() * &secret_key;
319 /// // ...
320 /// ```
321 #[$attr]
322 pub mod $mod {
323 /// Alias for
324 #[doc = concat!("[", stringify!($curve), "](super::", stringify!($curve), ")")]
325 /// curve
326 pub type E = super::$curve;
327 /// Point on [`
328 #[doc = stringify!($curve)]
329 /// `](E) curve
330 pub type Point = crate::Point<super::$curve>;
331 /// Secret point on [`
332 #[doc = stringify!($curve)]
333 /// `](E) curve
334 pub type SecretPoint = crate::SecretPoint<super::$curve>;
335 /// Scalar in [`
336 #[doc = stringify!($curve)]
337 /// `](E) curve large prime subgroup
338 pub type Scalar = crate::Scalar<super::$curve>;
339 /// Secret scalar in [`
340 #[doc = stringify!($curve)]
341 /// `](E) curve large prime subgroup
342 pub type SecretScalar = crate::SecretScalar<super::$curve>;
343 /// Point on [`
344 #[doc = stringify!($curve)]
345 /// `](E) curve encoded as bytes
346 pub type EncodedPoint = crate::EncodedPoint<super::$curve>;
347 /// Scalar in [`
348 #[doc = stringify!($curve)]
349 /// `](E) curve large prime subgroup encoded as bytes
350 pub type EncodedScalar = crate::EncodedScalar<super::$curve>;
351 /// Iterator over scalar coefficients in radix 16 representation of [`
352 #[doc = stringify!($curve)]
353 /// `](E) curve
354 pub type Radix16Iter = crate::Radix16Iter<super::$curve>;
355 /// Generator of [`
356 #[doc = stringify!($curve)]
357 /// `](E) curve
358 pub type Generator = crate::Generator<super::$curve>;
359 }
360 )+};
361 }
362
363 create_aliases! {
364 #[cfg(feature = "curve-secp256k1")]
365 secp256k1: Secp256k1,
366 #[cfg(feature = "curve-secp256r1")]
367 secp256r1: Secp256r1,
368 #[cfg(feature = "curve-secp384r1")]
369 secp384r1: Secp384r1,
370 #[cfg(feature = "curve-stark")]
371 stark: Stark,
372 #[cfg(feature = "curve-ed25519")]
373 ed25519: Ed25519,
374 }
375}