# Features
| Feature | Description | Dependencies | Enabled by Default |
|---------|-------------|--------------|:------------------:|
| `secp256k1` | Use [`libsecp256k1`](https://github.com/bitcoin-core/secp256k1) bindings for elliptic curve math. Include trait implementations for converting to and from types in [the `secp256k1` crate][secp256k1]. This feature supercedes the `k256` feature if that one is enabled. | [`secp256k1`] | ✅ |
| `k256` | Use [the `k256` crate][k256] for elliptic curve math. This enables a pure-rust build. Include trait implementations for types from `k256`. If the `secp256k1` feature is enabled, then `k256` will still be brought in and trait implementations will be included, but the actual curve math will be done by `libsecp256k1`. | [`k256`] | ❌ |
| `serde` | Implement serialization and deserialization for types in this crate. | [`serde`](https://docs.rs/serde) | ❌ |
| `rand` | Enable support for random scalar sampling with a CSPRNG, via [the `rand` crate](https://crates.io/crates/rand) | [`rand`] | ❌ |
| `secp256k1-invert` | `libsecp256k1` doesn't expose any functionality to invert scalars modulo the curve order (i.e. to compute t-1 for some scalar t, so that t(t-1) = 1 mod n). Inversion is useful for certain cryptographic operations, such as ECDSA signing, or OPRFs.
Enable this feature if you need to invert scalars but you only have the `secp256k1` feature enabled. This feature is only useful if the `secp256k1` feature is enabled but `k256` is not, as the [`k256`] crate provides scalar inversion methods. This feature pulls in [the `crypto-bigint` crate][crypto_bigint] to perform the inversion. | [`crypto_bigint`] | ❌ |
| `num-traits` | Enable support for numeric identity traits via [the `num-traits` crate](https://crates.io/crates/num-traits). | [`num_traits`] | ❌ |
| `cli-rng` | Enable RNG features needed to compile the `secp` CLI program. **Not for public use.** | [`rand`] | ❌ |
# Usage
The `secp` crate's primary export is four types which can be used to represent elliptic curve points (e.g. public keys) and scalars (e.g. private keys).
- [`Scalar`] for non-zero scalar values.
- [`Point`] for non-infinity curve points
- [`MaybeScalar`] for possibly-zero scalars.
- [`MaybePoint`] for possibly-infinity curve points.
Depending on which features of this crate are enabled, we implement various conversion traits between these types and higher-level types such as [`secp256k1::PublicKey`] or [`k256::SecretKey`].
```rust
# #[cfg(all(feature = "secp256k1", feature = "rand"))]
# {
let seckey = secp256k1::SecretKey::new(&mut rand::rngs::OsRng);
let scalar = secp::Scalar::from(seckey);
secp256k1::SecretKey::from(scalar);
secp256k1::Scalar::from(scalar);
let point: secp::Point = scalar.base_point_mul();
secp256k1::PublicKey::from(point);
# }
# #[cfg(feature = "k256")]
# {
let seckey = k256::SecretKey::random(&mut rand::rngs::OsRng);
let scalar = secp::Scalar::from(seckey);
k256::SecretKey::from(scalar);
k256::Scalar::from(scalar);
k256::NonZeroScalar::from(scalar);
k256::Scalar::from(secp::MaybeScalar::Valid(scalar));
assert!(k256::NonZeroScalar::try_from(secp::MaybeScalar::Valid(scalar)).is_ok());
assert!(k256::NonZeroScalar::try_from(secp::MaybeScalar::Zero).is_err());
let point: secp::Point = scalar.base_point_mul();
k256::PublicKey::from(point);
k256::AffinePoint::from(point);
# }
```
# Scalars
A [`Scalar`] can represent any integers in the range `[1, n)`, while a [`MaybeScalar`] represents any integer in the range `[0, n)`, where `n` is the secp256k1 elliptic curve order (the number of possible points on the curve). As [`Scalar`] is never zero it doesn't implement [`Default`]). [`MaybeScalar::Zero`] represents the integer zero.
```rust
# use secp::Scalar;
pub enum MaybeScalar {
Zero,
Valid(Scalar),
}
```
## Arithmetic
Addition, subtract, and multiplication operators are supported by default between the two scalar types. All operations are done in the finite field modulo `n`.
```rust
use secp::{MaybeScalar, Scalar};
assert_eq!(
(Scalar::one() + Scalar::two()) * Scalar::max(),
Scalar::max() - Scalar::two()
);
// Addition or subtraction of two non-zero [`Scalar`] instances will
// output a [`MaybeScalar`], since the sum of two non-zero numbers
// could be zero in a finite field.
assert_eq!(Scalar::one() + Scalar::one(), MaybeScalar::two());
// Arithmetic works across commutatively both scalar types.
assert_eq!(
MaybeScalar::from(20) * Scalar::two() - Scalar::try_from(10).unwrap(),
MaybeScalar::from(30)
);
// Zero acts like zero.
assert_eq!(MaybeScalar::Zero + Scalar::two(), MaybeScalar::two());
assert_eq!(MaybeScalar::Zero * Scalar::two(), MaybeScalar::Zero);
```
Division is supported via [modular multiplicative inversion](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse). Since libsecp256k1 does not support this out of the box, scalar inversion requires either the `k256` feature or the `secp256k1-invert` feature to be enabled.
```rust
# #[cfg(any(feature = "k256", feature = "secp256k1-invert"))]
# {
# use secp::Scalar;
let x = "0000000000000000000000000000000000000000000000000000000000000aae"
.parse::()
.unwrap();
assert_eq!(
x / Scalar::two(),
"0000000000000000000000000000000000000000000000000000000000000557"
.parse()
.unwrap()
);
// Since `0xAAF` is an odd number, this would be a fraction if we were
// operating in the real numbers. Since we're operating in a finite field,
// there does exist an integer solution to the equation `x * 2 = 0xAAF`
assert_eq!(
(x + Scalar::one()) / Scalar::two(),
"7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b25f8"
.parse()
.unwrap()
);
# }
```
Division by a `MaybeScalar` is not defined, since the divisor might be zero.
```compile_fail
# use secp::{MaybeScalar, Scalar};
Scalar::two() / MaybeScalar::two();
```
## Formatting
To reduce the risk of accidental exposure of private keys, signatures, or other secret scalar values, `Scalar` does not implement [`Display`][std::fmt::Display].
```compile_fail
println!("{}", Scalar::max());
```
Instead, `Scalar`s can be formatted as hex strings explicitly by using `{:x}` or `{:X}` format directives, via the [`LowerHex`][std::fmt::LowerHex] or [`UpperHex`][std::fmt::UpperHex] trait implementations on `Scalar`. Conversion to hex is done in constant-time, but we can't make any guarantees about side-channel leakage beyond that point.
```rust
# use secp::{MaybeScalar, Scalar};
let hex = "e2df7e885217c19c42a8159fd02633f0dc463fadfafc09a71af20bfa2b9036c6";
let scalar = hex.parse::().unwrap();
assert_eq!(format!("{:x}", scalar), hex);
assert_eq!(format!("{:X}", scalar), hex.to_uppercase());
assert_eq!(format!("{:x}", MaybeScalar::Valid(scalar)), hex);
assert_eq!(format!("{:X}", MaybeScalar::Valid(scalar)), hex.to_uppercase());
assert_eq!(
format!("{:x}", MaybeScalar::Zero),
"0000000000000000000000000000000000000000000000000000000000000000"
);
```
# Points
Valid elliptic curve points are represented by the [`Point`] type. There is a special curve point called _infinity,_ or the _identity point,_ or the _zero point,_ which we represent as [`MaybePoint::Infinity`].
```rust
# use secp::Point;
pub enum MaybePoint {
Infinity,
Valid(Point),
}
```
## Arithmetic
Points can be added and subtracted from one-another.
```rust
use secp::{MaybePoint, Point};
let P1 = "02b435092055e2dc9a1474dac777302c172dde0a40323f0879bff48d002575b685"
.parse::()
.unwrap();
let P2 = "0375663d8ea90563709204f1b1ff4822220cfb257ed5602609282314ba4e7d492c"
.parse::()
.unwrap();
let P3 = "02bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db"
.parse::()
.unwrap();
// Similar to `Scalar`, adding and subtracting non-infinity points
// results in a `MaybePoint`, because point addition is cyclic just
// like scalar addition.
assert_eq!(P1 + P2, MaybePoint::Valid(P3));
assert_eq!(P3 - P2, MaybePoint::Valid(P1));
// Iterators of points can be summed like any other number-like type.
// Prefer this over manually implementing a summation reducer, as
// we offload most of the work to libsecp256k1.
assert_eq!(
[P1, P2].into_iter().sum::(),
MaybePoint::Valid(P3)
);
```
And of course, the most important operation in elliptic curve cryptography, **scalar-point multiplication** is also supported.
```rust
use secp::{MaybePoint, Point, Scalar};
let P = "02b435092055e2dc9a1474dac777302c172dde0a40323f0879bff48d002575b685"
.parse::()
.unwrap();
let d = Scalar::try_from(3).unwrap();
// Multiplying by one is a no-op.
assert_eq!(P * Scalar::one(), P);
// Multiplying by a non-zero scalar guarantees a non-zero
// point is the output.
assert_eq!(
P * d,
(P + P + P).unwrap()
);
// Multiplying by the secp256k1 base point `G` is easy.
assert_eq!(
d.base_point_mul(),
d * Point::generator()
);
// We provide a static shortcut to the generator point `G`
// which works with arithemtic operators.
use secp::G;
assert_eq!(
G * d,
(G + G + G).unwrap()
);
assert_eq!(G - G, MaybePoint::Infinity);
// Point-scalar division works if scalar inversion is enabled
// by the feature set.
# #[cfg(any(feature = "k256", feature = "secp256k1-invert"))]
assert_eq!(d * G / d, (*G));
```
## Formatting
Like the scalars, [`Point`] and [`MaybePoint`] can be formatted compressed form as hex strings explicitly using `{:x}` and `{:X}` directives. They also implement [`Display`][std::fmt::Display]. The default displayable string value of [`Point`] and [`MaybePoint`] is the compressed lower-case hex encoding. Uncompressed keys can be formatted by adding the `+` flag to the directive, i.e. by formatting as `{:+}` or `{:+x}`.
```rust
# use secp::{MaybePoint, Point};
// Compressed
let point_hex = "02bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db";
let point: Point = point_hex.parse().unwrap();
assert_eq!(point.to_string(), point_hex);
assert_eq!(format!("{}", point), point_hex);
assert_eq!(format!("{:x}", point), point_hex);
assert_eq!(format!("{:X}", point), point_hex.to_uppercase());
assert_eq!(format!("{:x}", MaybePoint::Valid(point)), point_hex);
assert_eq!(format!("{:X}", MaybePoint::Valid(point)), point_hex.to_uppercase());
assert_eq!(
format!("{:x}", MaybePoint::Infinity),
"000000000000000000000000000000000000000000000000000000000000000000"
);
// Uncompressed
let point_hex_uncompressed =
"04bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db\
6c11d8da7d251e5756c297147a40767bd21d3cd18a830bf79dd4d17ba26fc546";
let point: Point = point_hex_uncompressed.parse().unwrap();
assert_eq!(format!("{:+}", point), point_hex_uncompressed);
assert_eq!(format!("{:+x}", point), point_hex_uncompressed);
assert_eq!(format!("{:+X}", point), point_hex_uncompressed.to_uppercase());
assert_eq!(format!("{:+x}", MaybePoint::Valid(point)), point_hex_uncompressed);
assert_eq!(format!("{:+X}", MaybePoint::Valid(point)), point_hex_uncompressed.to_uppercase());
assert_eq!(
format!("{:+x}", MaybePoint::Infinity),
"000000000000000000000000000000000000000000000000000000000000000000\
0000000000000000000000000000000000000000000000000000000000000000"
);
```