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