Module coins_bip32::ecdsa

source ·
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 the Signature type (which represents an ECDSA/secp256k1 signature). Does not require the arithmetic feature. This is useful for 3rd-party crates which wish to use the Signature type for interoperability purposes (particularly in conjunction with the signature::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: provides ecdsa-core features plus the SigningKey and VerifyingKey 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);

Modules§

Structs§

Type Aliases§