![License](https://img.shields.io/crates/l/generic-ec.svg) [![Docs](https://docs.rs/generic-ec/badge.svg)](https://docs.rs/generic-ec) [![Crates io](https://img.shields.io/crates/v/generic-ec.svg)](https://crates.io/crates/generic-ec) [![Discord](https://img.shields.io/discord/905194001349627914?logo=discord&logoColor=ffffff&label=Discord)][in Discord] # General elliptic curve cryptography The library provides a set of simple abstractions boosting experience of doing elliptic curve arithmetic in Rust. Aim is to **stay simple**, **generic**, and **secure**. It's handy for developers who implement MPC, zero-knowledge protocols, or any other elliptic crypto algorithms. `generic-ec` is `no_std` and web assembly friendly. ## Overview Crate provides three primitives: a point on elliptic curve [`Point`](Point), an integer modulus group order [`Scalar`](Scalar), and a secret scalar carrying some sensitive value (e.g. secret key) [`SecretScalar`](SecretScalar). `E` stands for a choice of elliptic curve, it could be any [supported curve][supported curves], e.g. `Point` is an elliptic point on secp256k1 curve. ## Exposed API Limited API is exposed: elliptic point arithmetic (points addition, negation, multiplying at scalar), scalar arithmetic (addition, multiplication, inverse modulo prime group order), and encode/decode to bytes represenstation. Hash to curve, hash to scalar primitives, accessing affine coordinates of points are available for some curves through `FromHash` and other traits. ## Security & guarantees Library mitigates a bunch of attacks (such as small-group attack) by design by enforcing following checks: * Scalar `Scalar` must be an integer modulo curve prime order * Elliptic point `Point` must be on the curve \ I.e. elliptic point is guaranteed to satisfy equation of `E` * `Point` is torsion-free \ Elliptic points should be free of small-group component. This eliminates any kind of small-group attacks. Point or scalar not meeting above requirements cannot be constructed (in safe Rust), as these checks are always enforced. E.g. if you're deserializing a sequence of bytes that represents an invalid point, deserialization will result into error. ### `SecretScalar` Sometimes your scalar represents some sensitive value like secret key, and you want to keep it safer. `SecretScalar` is in-place replacement of `Scalar` that enforces additional security by storing the scalar value on the heap, and erasing it on drop. Its advantage is that it doesn't leave any trace in memory dump after it's dropped (which is not guaranteed by regular `Scalar`). But keep in mind that we can't control the OS which could potentially load RAM page containing sensitive value 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. We avoid writing unsafe or OS-specific code that could mitigate this problem. ### Points at infinity It should be noticed that point at infinity (or identity point) is a valid `Point`. You can construct it by calling `Point::::zero()`, e.g. `Point::::zero()` is a point at infinity for secp256k1 curve. If the protocol you're implementing requires points/scalars to be non-zero, you may need to enforce this check by calling `.is_zero()` method or by using [`NonZero`](NonZero) (`NonZero>` or `NonZero>`). Using `NonZero` gives some compile-time guarantees. For instance, multiplying non-zero point in the prime group at non-zero scalar mod group order is mathematically guaranteed to output non-zero point in that prime group. Thus, multiplying `NonZero>` at `NonZero>` returns `NonZero>`. ## Supported curves Crate provides support for following elliptic curves out of box: | Curve | Feature | Backend | |--------------|--------------------|-------------------| | secp256k1 | `curve-secp256k1` | [RustCrypto/k256] | | secp256r1 | `curve-secp256r1` | [RustCrypto/p256] | | stark-curve | `curve-stark` | [Dfns/stark] | | Ed25519 | `curve-ed25519` | [curve25519-dalek]| [RustCrypto/k256]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256 [RustCrypto/p256]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 [Dfns/stark]: https://github.com/LFDT-Lockness/stark-curve/ [curve25519-dalek]: https://docs.rs/curve25519-dalek/ In order to use one of the supported curves, you need to turn on corresponding feature. E.g. if you want to use secp256k1 curve, add this to Cargo.toml: ```toml [dependency] generic-ec = { version = "...", features = ["curve-secp256k1"] } ``` And now you can generate a point on that curve: ```rust use generic_ec::{Point, Scalar, curves::Secp256k1}; let random_point: Point = Point::generator() * Scalar::random(&mut rng); ``` ### Adding support for other curves Adding new curve is as easy as implementing [`Curve` trait](Curve)! If you're missing some curve support, or you're not fine with using existing implementation, you may define your implementation of `Curve` trait and enjoy using the same handy primitives `Point`, `Scalar`, and etc. ## Features * `curve-{name}` enables specified curve support. See list of [supported curves]. * `all-curves` enables all supported curves * `serde` enables points/scalar (de)serialization support. (enabled by default) * `std` enables support of standard library (enabled by default) ## Examples ### Random scalar / point generation ```rust use generic_ec::{Point, Scalar, curves::Secp256k1}; // Generates random non-zero scalar let random_scalar = Scalar::::random(&mut rng); // Produces a point that's result of generator multiplied at the random scalar let point = Point::generator() * &random_scalar; ``` ### Diffie-Hellman key exchange ```rust use generic_ec::{Point, SecretScalar, curves::Secp256k1}; let alice_sk = SecretScalar::::random(&mut rng); let alice_pk = Point::generator() * &alice_sk; let bob_sk = SecretScalar::::random(&mut rng); let bob_pk = Point::generator() * &bob_sk; let shared_secret_learned_by_alice = bob_pk * &alice_sk; let shared_secret_learned_by_bob = alice_pk * &bob_sk; assert_eq!(shared_secret_learned_by_alice, shared_secret_learned_by_bob); ``` ### Generic over choice of curve You can simply make your function generic over choice of curve: ```rust use generic_ec::{Point, Scalar, Curve}; use rand::RngCore; fn some_generic_computation(rng: &mut impl RngCore, point: Point) -> Point { let blinding = Point::::generator() * Scalar::random(rng); let e = &point + &blinding; // ... some computation } // You can run this function with any supported curve: use generic_ec::curves::{Secp256k1, Secp256r1}; let point1 = Point::::generator().to_point(); let _ = some_generic_computation(&mut rng, point1); let point2 = Point::::generator().to_point(); let _ = some_generic_computation(&mut rng, point2); // ... ``` [examples]: #examples [supported curves]: #supported-curves ## Join us in Discord! Feel free to reach out to us [in Discord]! [in Discord]: https://discordapp.com/channels/905194001349627914/1285268686147424388 ## License The crate is licensed under MIT or Apache-2.0 at your choice.