// 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 . // //! Bitcoin Keys //! //! Keys used in Bitcoin that can be roundtrip (de)serialized. //! use std::fmt::{self, Write}; use std::{io, ops, error}; use std::str::FromStr; use secp256k1::{self, Secp256k1}; use network::constants::Network; use hashes::{Hash, hash160}; use hash_types::{PubkeyHash, WPubkeyHash}; use util::base58; /// A key-related error. #[derive(Debug)] pub enum Error { /// Base58 encoding error Base58(base58::Error), /// secp256k1-related error Secp256k1(secp256k1::Error), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Base58(ref e) => write!(f, "base58 error: {}", e), Error::Secp256k1(ref e) => write!(f, "secp256k1 error: {}", e), } } } impl error::Error for Error { fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::Base58(ref e) => Some(e), Error::Secp256k1(ref e) => Some(e), } } } #[doc(hidden)] impl From for Error { fn from(e: base58::Error) -> Error { Error::Base58(e) } } #[doc(hidden)] impl From for Error { fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) } } /// 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 { /// 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) { let _: io::Result<()> = if self.compressed { writer.write_all(&self.key.serialize()) } else { writer.write_all(&self.key.serialize_uncompressed()) }; } /// Serialize the public key to bytes pub fn to_bytes(&self) -> Vec { let mut buf = Vec::new(); self.write_into(&mut buf); 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: 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: key, compressed: s.len() == 66 }) } } #[derive(Copy, Clone, PartialEq, Eq)] /// A Bitcoin ECDSA private key 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 { /// 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() } /// 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::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::InvalidVersion(vec![x]))); } }; Ok(PrivateKey { compressed: compressed, network: 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")] impl ::serde::Serialize for PrivateKey { fn serialize(&self, s: S) -> Result { s.collect_str(self) } } #[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 ::std::fmt::Formatter) -> ::std::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) = ::std::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")] 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")] 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 ::std::fmt::Formatter) -> ::std::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) = ::std::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 ::std::fmt::Formatter) -> ::std::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) } } } #[cfg(test)] mod tests { 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)]); } }