// Rust Bitcoin Library // Written in 2014 by // Andrew Poelstra // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to // the public domain worldwide. This software is distributed without // any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. // If not, see . // //! ECDSA Bitcoin keys. //! //! This module provides ECDSA keys used in Bitcoin that can be roundtrip //! (de)serialized. //! use prelude::*; use core::{ops, str::FromStr}; use core::fmt::{self, Write as _fmtWrite}; use io; use secp256k1::{self, Secp256k1}; use network::constants::Network; use hashes::{Hash, hash160, hex}; use hashes::hex::FromHex; use hash_types::{PubkeyHash, WPubkeyHash}; use util::base58; use util::key::Error; use blockdata::transaction::{EcdsaSigHashType, NonStandardSigHashType}; /// A Bitcoin ECDSA public key #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PublicKey { /// Whether this public key should be serialized as compressed pub compressed: bool, /// The actual ECDSA key pub key: secp256k1::PublicKey, } impl PublicKey { /// Constructs compressed ECDSA public key from the provided generic Secp256k1 public key pub fn new(key: secp256k1::PublicKey) -> PublicKey { PublicKey { compressed: true, key, } } /// Constructs uncompressed (legacy) ECDSA public key from the provided generic Secp256k1 /// public key pub fn new_uncompressed(key: secp256k1::PublicKey) -> PublicKey { PublicKey { compressed: false, key, } } /// Returns bitcoin 160-bit hash of the public key pub fn pubkey_hash(&self) -> PubkeyHash { if self.compressed { PubkeyHash::hash(&self.key.serialize()) } else { PubkeyHash::hash(&self.key.serialize_uncompressed()) } } /// Returns bitcoin 160-bit hash of the public key for witness program pub fn wpubkey_hash(&self) -> Option { if self.compressed { Some(WPubkeyHash::from_inner( hash160::Hash::hash(&self.key.serialize()).into_inner() )) } else { // We can't create witness pubkey hashes for an uncompressed // public keys None } } /// Write the public key into a writer pub fn write_into(&self, mut writer: W) -> Result<(), io::Error> { if self.compressed { writer.write_all(&self.key.serialize()) } else { writer.write_all(&self.key.serialize_uncompressed()) } } /// Read the public key from a reader /// /// This internally reads the first byte before reading the rest, so /// use of a `BufReader` is recommended. pub fn read_from(mut reader: R) -> Result { let mut bytes = [0; 65]; reader.read_exact(&mut bytes[0..1])?; let bytes = if bytes[0] < 4 { &mut bytes[..33] } else { &mut bytes[..65] }; reader.read_exact(&mut bytes[1..])?; Self::from_slice(bytes).map_err(|e|{ // Need a static string for core2 #[cfg(feature = "std")] let reason = e; #[cfg(not(feature = "std"))] let reason = match e { Error::Base58(_) => "base58 error", Error::Secp256k1(_) => "secp256k1 error", }; io::Error::new(io::ErrorKind::InvalidData, reason) }) } /// Serialize the public key to bytes pub fn to_bytes(&self) -> Vec { let mut buf = Vec::new(); self.write_into(&mut buf).expect("vecs don't error"); buf } /// Deserialize a public key from a slice pub fn from_slice(data: &[u8]) -> Result { let compressed: bool = match data.len() { 33 => true, 65 => false, len => { return Err(base58::Error::InvalidLength(len).into()); }, }; Ok(PublicKey { compressed, key: secp256k1::PublicKey::from_slice(data)?, }) } /// Computes the public key as supposed to be used with this secret pub fn from_private_key(secp: &Secp256k1, sk: &PrivateKey) -> PublicKey { sk.public_key(secp) } } impl fmt::Display for PublicKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.compressed { for ch in &self.key.serialize()[..] { write!(f, "{:02x}", ch)?; } } else { for ch in &self.key.serialize_uncompressed()[..] { write!(f, "{:02x}", ch)?; } } Ok(()) } } impl FromStr for PublicKey { type Err = Error; fn from_str(s: &str) -> Result { let key = secp256k1::PublicKey::from_str(s)?; Ok(PublicKey { key, compressed: s.len() == 66 }) } } /// A Bitcoin ECDSA private key #[derive(Copy, Clone, PartialEq, Eq)] pub struct PrivateKey { /// Whether this private key should be serialized as compressed pub compressed: bool, /// The network on which this key should be used pub network: Network, /// The actual ECDSA key pub key: secp256k1::SecretKey, } impl PrivateKey { /// Constructs compressed ECDSA private key from the provided generic Secp256k1 private key /// and the specified network pub fn new(key: secp256k1::SecretKey, network: Network) -> PrivateKey { PrivateKey { compressed: true, network, key, } } /// Constructs uncompressed (legacy) ECDSA private key from the provided generic Secp256k1 /// private key and the specified network pub fn new_uncompressed(key: secp256k1::SecretKey, network: Network) -> PrivateKey { PrivateKey { compressed: false, network, key, } } /// Creates a public key from this private key pub fn public_key(&self, secp: &Secp256k1) -> PublicKey { PublicKey { compressed: self.compressed, key: secp256k1::PublicKey::from_secret_key(secp, &self.key) } } /// Serialize the private key to bytes pub fn to_bytes(&self) -> Vec { self.key[..].to_vec() } /// Deserialize a private key from a slice pub fn from_slice(data: &[u8], network: Network) -> Result { Ok(PrivateKey::new( secp256k1::SecretKey::from_slice(data)?, network, )) } /// Format the private key to WIF format. pub fn fmt_wif(&self, fmt: &mut dyn fmt::Write) -> fmt::Result { let mut ret = [0; 34]; ret[0] = match self.network { Network::Bitcoin => 128, Network::Testnet | Network::Signet | Network::Regtest => 239, }; ret[1..33].copy_from_slice(&self.key[..]); let privkey = if self.compressed { ret[33] = 1; base58::check_encode_slice(&ret[..]) } else { base58::check_encode_slice(&ret[..33]) }; fmt.write_str(&privkey) } /// Get WIF encoding of this private key. pub fn to_wif(&self) -> String { let mut buf = String::new(); buf.write_fmt(format_args!("{}", self)).unwrap(); buf.shrink_to_fit(); buf } /// Parse WIF encoded private key. pub fn from_wif(wif: &str) -> Result { let data = base58::from_check(wif)?; let compressed = match data.len() { 33 => false, 34 => true, _ => { return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); } }; let network = match data[0] { 128 => Network::Bitcoin, 239 => Network::Testnet, x => { return Err(Error::Base58(base58::Error::InvalidAddressVersion(x))); } }; Ok(PrivateKey { compressed, network, key: secp256k1::SecretKey::from_slice(&data[1..33])?, }) } } impl fmt::Display for PrivateKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_wif(f) } } impl fmt::Debug for PrivateKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[private key data]") } } impl FromStr for PrivateKey { type Err = Error; fn from_str(s: &str) -> Result { PrivateKey::from_wif(s) } } impl ops::Index for PrivateKey { type Output = [u8]; fn index(&self, _: ops::RangeFull) -> &[u8] { &self.key[..] } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl ::serde::Serialize for PrivateKey { fn serialize(&self, s: S) -> Result { s.collect_str(self) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> ::serde::Deserialize<'de> for PrivateKey { fn deserialize>(d: D) -> Result { struct WifVisitor; impl<'de> ::serde::de::Visitor<'de> for WifVisitor { type Value = PrivateKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { formatter.write_str("an ASCII WIF string") } fn visit_bytes(self, v: &[u8]) -> Result where E: ::serde::de::Error, { if let Ok(s) = ::core::str::from_utf8(v) { PrivateKey::from_str(s).map_err(E::custom) } else { Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) } } fn visit_str(self, v: &str) -> Result where E: ::serde::de::Error, { PrivateKey::from_str(v).map_err(E::custom) } } d.deserialize_str(WifVisitor) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl ::serde::Serialize for PublicKey { fn serialize(&self, s: S) -> Result { if s.is_human_readable() { s.collect_str(self) } else { if self.compressed { s.serialize_bytes(&self.key.serialize()[..]) } else { s.serialize_bytes(&self.key.serialize_uncompressed()[..]) } } } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> ::serde::Deserialize<'de> for PublicKey { fn deserialize>(d: D) -> Result { if d.is_human_readable() { struct HexVisitor; impl<'de> ::serde::de::Visitor<'de> for HexVisitor { type Value = PublicKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { formatter.write_str("an ASCII hex string") } fn visit_bytes(self, v: &[u8]) -> Result where E: ::serde::de::Error, { if let Ok(hex) = ::core::str::from_utf8(v) { PublicKey::from_str(hex).map_err(E::custom) } else { Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) } } fn visit_str(self, v: &str) -> Result where E: ::serde::de::Error, { PublicKey::from_str(v).map_err(E::custom) } } d.deserialize_str(HexVisitor) } else { struct BytesVisitor; impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { type Value = PublicKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { formatter.write_str("a bytestring") } fn visit_bytes(self, v: &[u8]) -> Result where E: ::serde::de::Error, { PublicKey::from_slice(v).map_err(E::custom) } } d.deserialize_bytes(BytesVisitor) } } } /// An ECDSA signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct EcdsaSig { /// The underlying ECDSA Signature pub sig: secp256k1::ecdsa::Signature, /// The corresponding hash type pub hash_ty: EcdsaSigHashType, } impl EcdsaSig { /// Constructs ECDSA bitcoin signature for [`EcdsaSigHashType::All`] pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> EcdsaSig { EcdsaSig { sig, hash_ty: EcdsaSigHashType::All } } /// Deserialize from slice pub fn from_slice(sl: &[u8]) -> Result { let (hash_ty, sig) = sl.split_last() .ok_or(EcdsaSigError::EmptySignature)?; let hash_ty = EcdsaSigHashType::from_u32_standard(*hash_ty as u32) .map_err(|_| EcdsaSigError::NonStandardSigHashType(*hash_ty as u32))?; let sig = secp256k1::ecdsa::Signature::from_der(sig) .map_err(EcdsaSigError::Secp256k1)?; Ok(EcdsaSig { sig, hash_ty }) } /// Serialize EcdsaSig pub fn to_vec(&self) -> Vec { // TODO: add support to serialize to a writer to SerializedSig let mut ser_sig = self.sig.serialize_der().to_vec(); ser_sig.push(self.hash_ty.as_u32() as u8); ser_sig } } impl fmt::Display for EcdsaSig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex::format_hex(&self.sig.serialize_der(), f)?; hex::format_hex(&[self.hash_ty as u8], f) } } impl FromStr for EcdsaSig { type Err = EcdsaSigError; fn from_str(s: &str) -> Result { let bytes = Vec::from_hex(s)?; let (sighash_byte, signature) = bytes.split_last() .ok_or(EcdsaSigError::EmptySignature)?; Ok(EcdsaSig { sig: secp256k1::ecdsa::Signature::from_der(signature)?, hash_ty: EcdsaSigHashType::from_u32_standard(*sighash_byte as u32)? }) } } /// A key-related error. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum EcdsaSigError { /// Hex encoding error HexEncoding(hex::Error), /// Base58 encoding error NonStandardSigHashType(u32), /// Empty Signature EmptySignature, /// secp256k1-related error Secp256k1(secp256k1::Error), } impl fmt::Display for EcdsaSigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { EcdsaSigError::NonStandardSigHashType(hash_ty) => write!(f, "Non standard signature hash type {}", hash_ty), EcdsaSigError::Secp256k1(ref e) => write!(f, "Invalid Ecdsa signature: {}", e), EcdsaSigError::EmptySignature => write!(f, "Empty ECDSA signature"), EcdsaSigError::HexEncoding(e) => write!(f, "EcdsaSig hex encoding error: {}", e) } } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl ::std::error::Error for EcdsaSigError {} impl From for EcdsaSigError { fn from(e: secp256k1::Error) -> EcdsaSigError { EcdsaSigError::Secp256k1(e) } } impl From for EcdsaSigError { fn from(err: NonStandardSigHashType) -> Self { EcdsaSigError::NonStandardSigHashType(err.0) } } impl From for EcdsaSigError { fn from(err: hex::Error) -> Self { EcdsaSigError::HexEncoding(err) } } #[cfg(test)] mod tests { use io; use super::{PrivateKey, PublicKey}; use secp256k1::Secp256k1; use std::str::FromStr; use hashes::hex::ToHex; use network::constants::Network::Testnet; use network::constants::Network::Bitcoin; use util::address::Address; #[test] fn test_key_derivation() { // testnet compressed let sk = PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap(); assert_eq!(sk.network, Testnet); assert_eq!(sk.compressed, true); assert_eq!(&sk.to_wif(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"); let secp = Secp256k1::new(); let pk = Address::p2pkh(&sk.public_key(&secp), sk.network); assert_eq!(&pk.to_string(), "mqwpxxvfv3QbM8PU8uBx2jaNt9btQqvQNx"); // test string conversion assert_eq!(&sk.to_string(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"); let sk_str = PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap(); assert_eq!(&sk.to_wif(), &sk_str.to_wif()); // mainnet uncompressed let sk = PrivateKey::from_wif("5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3").unwrap(); assert_eq!(sk.network, Bitcoin); assert_eq!(sk.compressed, false); assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3"); let secp = Secp256k1::new(); let mut pk = sk.public_key(&secp); assert_eq!(pk.compressed, false); assert_eq!(&pk.to_string(), "042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"); assert_eq!(pk, PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap()); let addr = Address::p2pkh(&pk, sk.network); assert_eq!(&addr.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8"); pk.compressed = true; assert_eq!(&pk.to_string(), "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"); assert_eq!(pk, PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap()); } #[test] fn test_pubkey_hash() { let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap(); let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap(); assert_eq!(pk.pubkey_hash().to_hex(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4"); assert_eq!(upk.pubkey_hash().to_hex(), "ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a"); } #[test] fn test_wpubkey_hash() { let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap(); let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap(); assert_eq!(pk.wpubkey_hash().unwrap().to_hex(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4"); assert_eq!(upk.wpubkey_hash(), None); } #[cfg(feature = "serde")] #[test] fn test_key_serde() { use serde_test::{Configure, Token, assert_tokens}; static KEY_WIF: &'static str = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"; static PK_STR: &'static str = "039b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef"; static PK_STR_U: &'static str = "\ 04\ 9b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef\ 87288ed73ce47fc4f5c79d19ebfa57da7cff3aff6e819e4ee971d86b5e61875d\ "; static PK_BYTES: [u8; 33] = [ 0x03, 0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec, 0x93, 0x82, 0x6d, 0xc6, 0x1c, 0x19, 0xf4, 0x7c, 0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e, 0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef, ]; static PK_BYTES_U: [u8; 65] = [ 0x04, 0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec, 0x93, 0x82, 0x6d, 0xc6, 0x1c, 0x19, 0xf4, 0x7c, 0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e, 0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef, 0x87, 0x28, 0x8e, 0xd7, 0x3c, 0xe4, 0x7f, 0xc4, 0xf5, 0xc7, 0x9d, 0x19, 0xeb, 0xfa, 0x57, 0xda, 0x7c, 0xff, 0x3a, 0xff, 0x6e, 0x81, 0x9e, 0x4e, 0xe9, 0x71, 0xd8, 0x6b, 0x5e, 0x61, 0x87, 0x5d, ]; let s = Secp256k1::new(); let sk = PrivateKey::from_str(&KEY_WIF).unwrap(); let pk = PublicKey::from_private_key(&s, &sk); let pk_u = PublicKey { key: pk.key, compressed: false, }; assert_tokens(&sk, &[Token::BorrowedStr(KEY_WIF)]); assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]); assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); assert_tokens(&pk_u.compact(), &[Token::BorrowedBytes(&PK_BYTES_U[..])]); assert_tokens(&pk_u.readable(), &[Token::BorrowedStr(PK_STR_U)]); } fn random_key(mut seed: u8) -> PublicKey { loop { let mut data = [0; 65]; for byte in &mut data[..] { *byte = seed; // totally a rng seed = seed.wrapping_mul(41).wrapping_add(43); } if data[0] % 2 == 0 { data[0] = 4; if let Ok(key) = PublicKey::from_slice(&data[..]) { return key; } } else { data[0] = 2 + (data[0] >> 7); if let Ok(key) = PublicKey::from_slice(&data[..33]) { return key; } } } } #[test] fn pubkey_read_write() { const N_KEYS: usize = 20; let keys: Vec<_> = (0..N_KEYS).map(|i| random_key(i as u8)).collect(); let mut v = vec![]; for k in &keys { k.write_into(&mut v).expect("writing into vec"); } let mut dec_keys = vec![]; let mut cursor = io::Cursor::new(&v); for _ in 0..N_KEYS { dec_keys.push(PublicKey::read_from(&mut cursor).expect("reading from vec")); } assert_eq!(keys, dec_keys); // sanity checks assert!(PublicKey::read_from(&mut cursor).is_err()); assert!(PublicKey::read_from(io::Cursor::new(&[])).is_err()); assert!(PublicKey::read_from(io::Cursor::new(&[0; 33][..])).is_err()); assert!(PublicKey::read_from(io::Cursor::new(&[2; 32][..])).is_err()); assert!(PublicKey::read_from(io::Cursor::new(&[0; 65][..])).is_err()); assert!(PublicKey::read_from(io::Cursor::new(&[4; 64][..])).is_err()); } }