The RustCrypto project splits ECDSA into a generic ecdsa crate and a crate per curve — p256, p384, p521, k256 for secp256k1 and the Brainpool crates — all implementing the signature traits (Signer, Verifier, PrehashSigner). They are pure Rust with no C dependencies, which makes them the usual choice for WebAssembly and embedded targets. The check used ecdsa 0.17.0 with p256, p384 and k256 0.14.0.
Signing is deterministic: the P-256 signature over the RFC 6979 test message reproduced the RFC's vector byte for byte. The Signature type is the 64-byte raw r‖s form; DER is an explicit to_der() and from_der(), and parsing the wrong form returns an error before any verification happens. The Signer trait hashes the message with the curve's default hash (SHA-256 for P-256); PrehashSigner::sign_prehash takes a digest and gave the identical signature for SHA-256 of the message.
Low-S handling differs by curve, which is the trap when one code base handles both. The NIST curve crates keep s as computed — 29 of 64 P-256 signatures were high-S — and their verifiers accept both halves. k256 normalizes s when signing and its verifier rejected the mirrored high-S form of a valid signature, matching Bitcoin's rules. A secp256k1 signature produced by OpenSSL, Java or a cloud KMS therefore fails in k256 about half the time; call normalize_s() on it first, as the sample shows for P-256.
Keys load from SPKI and PKCS#8 (PEM and DER, with the pem and pkcs8 features), SEC1 points in either form, SEC1 private keys and raw scalars. Ed25519 lives in the separate ed25519-dalek crate, and there are no post-quantum algorithms here; for FIPS-validated or post-quantum primitives in Rust see aws-lc-rs.
Because signing is deterministic, a changed signature in a test is a real regression signal here. Compare against other libraries with test vectors and the DER ⇄ raw converter.