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<E>, an integer modulus group order
Scalar<E>, and a secret scalar carrying some sensitive value (e.g. secret key) SecretScalar<E>.
E stands for a choice of elliptic curve, it could be any supported curve, e.g. Point<Secp256k1>
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<E>must be an integer modulo curve prime order - Elliptic point
Point<E>must be on the curve
I.e. elliptic point is guaranteed to satisfy equation ofE Point<E>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<E>
Sometimes your scalar represents some sensitive value like secret key, and you want to keep it safer.
SecretScalar<E> is in-place replacement of Scalar<E> 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<E>).
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<E>. You can construct it by calling
Point::<E>::zero(), e.g. Point::<Secp256k1>::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<T> (NonZero<Point<E>> or NonZero<Scalar<E>>).
Using NonZero<T> 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<Point<E>> at NonZero<Scalar<E>> returns NonZero<Point<E>>.
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 |
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:
[]
= { = "...", = ["curve-secp256k1"] }
And now you can generate a point on that curve:
use ;
let random_point: = generator * random;
Adding support for other curves
Adding new curve is as easy as implementing Curve trait! 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<YOUR_EC>, Scalar<YOUR_EC>, and etc.
Features
curve-{name}enables specified curve support. See list of supported curves.all-curvesenables all supported curvesserdeenables points/scalar (de)serialization support. (enabled by default)stdenables support of standard library (enabled by default)wasmeanbles support forwasm32-unknown-unknowntarget
Examples
Random scalar / point generation
use ;
// Generates random non-zero scalar
let random_scalar = random;
// Produces a point that's result of generator multiplied at the random scalar
let point = generator * &random_scalar;
Diffie-Hellman key exchange
use ;
let alice_sk = random;
let alice_pk = generator * &alice_sk;
let bob_sk = random;
let bob_pk = 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!;
Generic over choice of curve
You can simply make your function generic over choice of curve:
use ;
use RngCore;
// You can run this function with any supported curve:
use ;
let point1 = generator.to_point;
let _ = some_generic_computation;
let point2 = generator.to_point;
let _ = some_generic_computation;
// ...
License
The crate is licensed under MIT or Apache-2.0 at your choice.