Skip to main content

Curve

Trait Curve 

Source
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

MethodInputH needed?
keygenno
ecdhpeer SEC1 pkno
sign_rfc6979digestyes (HMAC inside RFC 6979)
sign_randomdigestno
verifydigestno
sign_rfc6979_msgmessageyes (hash + HMAC)
sign_random_msgmessageyes (hash)
verify_msgmessageyes (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§

Source

fn keygen(rng: &mut dyn CryptoRng) -> (PublicKey, SecretKey)

Generate a key pair on this curve.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

fn verify(pk: &PublicKey, digest: &[u8], sig: &Signature) -> bool

Verify a signature against a precomputed digest.

Provided Methods§

Source

fn sign_rfc6979_msg<H: Hasher>(sk: &SecretKey, msg: &[u8]) -> Signature

Convenience: hash msg with H, then call Self::sign_rfc6979.

Source

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.

Source

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.

Implementors§