pub trait Curve: Sized {
// Required methods
fn keygen(rng: &mut dyn CryptoRng) -> (PublicKey, SecretKey);
fn compress_pubkey(pk: &PublicKey) -> Option<Vec<u8>>;
fn decompress_pubkey(compressed: &[u8]) -> Option<PublicKey>;
fn ecdh(sk: &SecretKey, peer_pk: &PublicKey) -> Option<Vec<u8>>;
fn sign_rfc6979<H: Hasher>(sk: &SecretKey, digest: &[u8]) -> Signature;
fn sign_random(
sk: &SecretKey,
digest: &[u8],
rng: &mut dyn CryptoRng,
) -> Signature;
fn verify(pk: &PublicKey, digest: &[u8], sig: &Signature) -> bool;
// Provided methods
fn sign_rfc6979_msg<H: Hasher>(sk: &SecretKey, msg: &[u8]) -> Signature { ... }
fn sign_random_msg<H: Hasher>(
sk: &SecretKey,
msg: &[u8],
rng: &mut dyn CryptoRng,
) -> Signature { ... }
fn verify_msg<H: Hasher>(
pk: &PublicKey,
msg: &[u8],
sig: &Signature,
) -> bool { ... }
}Expand description
Operations on a short Weierstrass curve: keygen, ECDSA sign / verify, and ECDH key agreement.
Implementations are unit structs (P256, P384, P521,
Secp256k1, BrainpoolP256r1, BrainpoolP384r1,
BrainpoolP512r1) and the methods are called as e.g.
P256::sign_rfc6979::<Sha256>(&sk, &digest) or
P256::ecdh(&sk, &peer_pk).
§Method overview
| Method | Input | H needed? |
|---|---|---|
keygen | – | no |
ecdh | peer SEC1 pk | no |
sign_rfc6979 | digest | yes (HMAC inside RFC 6979) |
sign_random | digest | no |
verify | digest | no |
sign_rfc6979_msg | message | yes (hash + HMAC) |
sign_random_msg | message | yes (hash) |
verify_msg | message | yes (hash) |
Key pairs returned by keygen are interchangeable
across ECDSA and ECDH on the same curve – a SecretKey is just a
scalar, a PublicKey is just a point. There is no “ECDH-only” or
“ECDSA-only” key type.
§Hash choice (ECDSA)
Any Hasher implementation may be paired with any curve.
The standard pairings (P-256+SHA-256, P-384+SHA-384, brainpoolP512r1
+SHA-512, etc.) are common, but not mandated by this crate. If you
need P-256 + SHA-512 for an exotic protocol, that works too – the
bits2int step will truncate the digest to the curve’s qlen as
specified in RFC 6979 §2.3.2.
Per FIPS 186-5 §6.4.2, the hash output should provide at least the security level of the curve (e.g. don’t pair P-384 with SHA-1). The crate does not enforce this; document and test your protocol’s choice.
Required Methods§
Sourcefn keygen(rng: &mut dyn CryptoRng) -> (PublicKey, SecretKey)
fn keygen(rng: &mut dyn CryptoRng) -> (PublicKey, SecretKey)
Generate a key pair on this curve.
Sourcefn compress_pubkey(pk: &PublicKey) -> Option<Vec<u8>>
fn compress_pubkey(pk: &PublicKey) -> Option<Vec<u8>>
Compress a public key from SEC1 uncompressed (0x04 || X || Y)
to SEC1 compressed (0x02/0x03 || X). If the input is already
compressed, returns a validated clone. Returns None for
malformed or off-curve input.
Sourcefn decompress_pubkey(compressed: &[u8]) -> Option<PublicKey>
fn decompress_pubkey(compressed: &[u8]) -> Option<PublicKey>
Decompress a SEC1 compressed public key (0x02/0x03 || X) to
uncompressed form (0x04 || X || Y), recovering Y via the
field square-root. If the input is already uncompressed, acts
as a validate-and-clone. Returns None if the input is
malformed, if X is not a valid x-coordinate on the curve, or
if the decompressed point fails the on-curve check.
Sourcefn ecdh(sk: &SecretKey, peer_pk: &PublicKey) -> Option<Vec<u8>>
fn ecdh(sk: &SecretKey, peer_pk: &PublicKey) -> Option<Vec<u8>>
ECDH key agreement: derive the shared secret from our secret key and the peer’s SEC1 uncompressed public key.
Returns the raw X coordinate of sk * peer_pk as LIMBS * 8
big-endian bytes (matches NIST SP 800-56A §5.7.1.2 “ECC CDH
Primitive” and TLS / IKE conventions).
Returns None if any of the following holds:
- peer’s pk has the wrong SEC1 length / tag
- peer’s pk is not on the curve (defends against invalid-curve
attacks; see
super::curve::is_on_curve) - our secret scalar is not in
[1, n-1] - the resulting shared point is the point at infinity
Higher-level KDFs (HKDF, X9.63 KDF, …) are out of scope for this layer – callers feed the raw X bytes into their KDF of choice.
Sourcefn sign_rfc6979<H: Hasher>(sk: &SecretKey, digest: &[u8]) -> Signature
fn sign_rfc6979<H: Hasher>(sk: &SecretKey, digest: &[u8]) -> Signature
Sign a precomputed digest with the deterministic RFC 6979 nonce.
H is the hash that produced digest; it is required because RFC
6979 derives the nonce via HMAC-H internally. Two calls with the
same (sk, digest, H) produce byte-identical signatures.
Sourcefn sign_random(
sk: &SecretKey,
digest: &[u8],
rng: &mut dyn CryptoRng,
) -> Signature
fn sign_random( sk: &SecretKey, digest: &[u8], rng: &mut dyn CryptoRng, ) -> Signature
Sign a precomputed digest with a uniformly random nonce drawn from
rng. The hash function is irrelevant – only the digest bytes are
consumed (via bits2int). Each call must consume fresh entropy;
reusing k across two signatures with the same key recovers the
secret key.
Provided Methods§
Sourcefn sign_rfc6979_msg<H: Hasher>(sk: &SecretKey, msg: &[u8]) -> Signature
fn sign_rfc6979_msg<H: Hasher>(sk: &SecretKey, msg: &[u8]) -> Signature
Convenience: hash msg with H, then call Self::sign_rfc6979.
Sourcefn sign_random_msg<H: Hasher>(
sk: &SecretKey,
msg: &[u8],
rng: &mut dyn CryptoRng,
) -> Signature
fn sign_random_msg<H: Hasher>( sk: &SecretKey, msg: &[u8], rng: &mut dyn CryptoRng, ) -> Signature
Convenience: hash msg with H, then call Self::sign_random.
Sourcefn verify_msg<H: Hasher>(pk: &PublicKey, msg: &[u8], sig: &Signature) -> bool
fn verify_msg<H: Hasher>(pk: &PublicKey, msg: &[u8], sig: &Signature) -> bool
Convenience: hash msg with H, then call Self::verify.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.