Expand description
Elliptic Curve Digital Signature Algorithm (ECDSA).
This module contains support for computing and verifying ECDSA signatures. To use it, you will need to enable one of the two following Cargo features:
ecdsa-core
: provides only theSignature
type (which represents an ECDSA/secp256k1 signature). Does not require thearithmetic
feature. This is useful for 3rd-party crates which wish to use theSignature
type for interoperability purposes (particularly in conjunction with thesignature::Signer
trait). Example use cases for this include other software implementations of ECDSA/secp256k1 and wrappers for cloud KMS services or hardware devices (HSM or crypto hardware wallet).ecdsa
: providesecdsa-core
features plus theSigningKey
andVerifyingKey
types which natively implement ECDSA/secp256k1 signing and verification.
Most users of this library who want to sign/verify signatures will want to
enable the ecdsa
and sha256
Cargo features.
§Signing and Verifying Signatures
This example requires the ecdsa
and sha256
Cargo features are enabled:
use k256::{
ecdsa::{SigningKey, Signature, signature::Signer},
SecretKey,
};
use rand_core::OsRng; // requires 'getrandom' feature
// Signing
let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
// Note: The signature type must be annotated or otherwise inferable as
// `Signer` has many impls of the `Signer` trait (for both regular and
// recoverable signature types).
let signature: Signature = signing_key.sign(message);
// Verification
use k256::{EncodedPoint, ecdsa::{VerifyingKey, signature::Verifier}};
let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()`
assert!(verifying_key.verify(message, &signature).is_ok());
§Recovering VerifyingKey
from Signature
ECDSA makes it possible to recover the public key used to verify a signature with the assistance of 2-bits of additional information.
This is helpful when there is already a trust relationship for a particular key, and it’s desirable to omit the full public key used to sign a particular message.
One common application of signature recovery with secp256k1 is Ethereum.
§Upgrading recoverable signature code from earlier versions of k256
The v0.12 release of k256
contains a brand new recoverable signature API
from previous releases. Functionality has been upstreamed from k256
to a
generic implementation in the ecdsa
crate.
If you previously used k256::ecdsa::recoverable::Signature
, the old
functionality now uses a “detached” Signature
and RecoveryId
.
Here is where the various functionality went:
- Signing now requires the use of the
hazmat::SignPrimitive
trait (see examples immediately below). - Signature recovery is now implemented as methods of the
VerifyingKey
type (i.e.::recover_from_*
). - Trial recovery is now defined on the
RecoveryId
type (i.e.::trial_recovery_from_*
).
§Computing a signature with a RecoveryId
.
This example shows how to compute a signature and its associated
RecoveryId
in a manner which is byte-for-byte compatible with
Ethereum libraries, leveraging the SigningKey::sign_digest_recoverable
API:
use hex_literal::hex;
use k256::ecdsa::{hazmat::SignPrimitive, RecoveryId, Signature, SigningKey};
use sha2::Sha256;
use sha3::{Keccak256, Digest};
let signing_key = SigningKey::from_bytes(&hex!(
"4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
).into())?;
let msg = hex!("e9808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca0080018080");
let digest = Keccak256::new_with_prefix(msg);
let (signature, recid) = signing_key.sign_digest_recoverable(digest)?;
assert_eq!(
signature.to_bytes().as_slice(),
&hex!("c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68")
);
assert_eq!(recid, RecoveryId::try_from(0u8).unwrap());
§Recovering a VerifyingKey
from a signature
use hex_literal::hex;
use k256::ecdsa::{RecoveryId, Signature, VerifyingKey};
use sha3::{Keccak256, Digest};
use elliptic_curve::sec1::ToEncodedPoint;
let msg = b"example message";
let signature = Signature::try_from(hex!(
"46c05b6368a44b8810d79859441d819b8e7cdc8bfd371e35c53196f4bcacdb51
35c7facce2a97b95eacba8a586d87b7958aaf8368ab29cee481f76e871dbd9cb"
).as_slice())?;
let recid = RecoveryId::try_from(1u8)?;
let recovered_key = VerifyingKey::recover_from_digest(
Keccak256::new_with_prefix(msg),
&signature,
recid
)?;
let expected_key = VerifyingKey::from_sec1_bytes(
&hex!("0200866db99873b09fc2fb1e3ba549b156e96d1a567e3284f5f0e859a83320cb8b")
)?;
assert_eq!(recovered_key, expected_key);
Re-exports§
pub use ecdsa_core::signature;
Modules§
- Low-level ECDSA primitives.
Structs§
- Signature errors.
- Recovery IDs, a.k.a. “recid”.
Type Aliases§
- ECDSA/secp256k1 signature (ASN.1 DER encoded)
- ECDSA/secp256k1 signature (fixed-size)
- ECDSA/secp256k1 signing key
- ECDSA/secp256k1 verification key (i.e. public key)