diff --git a/src/util/address.rs b/src/util/address.rs index 1d2cee4..6a96fdc 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -16,8 +16,8 @@ //! Support for ordinary base58 Bitcoin addresses and private keys //! +use std::fmt::{self, Display, Formatter}; use std::str::FromStr; -use std::string::ToString; use bitcoin_bech32::{self, WitnessProgram, u5}; use secp256k1::key::PublicKey; @@ -203,8 +203,8 @@ impl Address { } } -impl ToString for Address { - fn to_string(&self) -> String { +impl Display for Address { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { match self.payload { // note: serialization for pay-to-pk is defined, but is irreversible Payload::Pubkey(ref pk) => { @@ -215,7 +215,7 @@ impl ToString for Address { Network::Testnet | Network::Regtest => 111, }; prefixed[1..].copy_from_slice(&hash[..]); - base58::check_encode_slice(&prefixed[..]) + base58::check_encode_slice_to_fmt(fmt, &prefixed[..]) }, Payload::PubkeyHash(ref hash) => { let mut prefixed = [0; 21]; @@ -224,7 +224,7 @@ impl ToString for Address { Network::Testnet | Network::Regtest => 111, }; prefixed[1..].copy_from_slice(&hash[..]); - base58::check_encode_slice(&prefixed[..]) + base58::check_encode_slice_to_fmt(fmt, &prefixed[..]) }, Payload::ScriptHash(ref hash) => { let mut prefixed = [0; 21]; @@ -233,10 +233,10 @@ impl ToString for Address { Network::Testnet | Network::Regtest => 196, }; prefixed[1..].copy_from_slice(&hash[..]); - base58::check_encode_slice(&prefixed[..]) + base58::check_encode_slice_to_fmt(fmt, &prefixed[..]) }, Payload::WitnessProgram(ref witprog) => { - witprog.to_address() + fmt.write_str(&witprog.to_address()) }, } } diff --git a/src/util/base58.rs b/src/util/base58.rs index a50be08..28384a0 100644 --- a/src/util/base58.rs +++ b/src/util/base58.rs @@ -14,7 +14,7 @@ //! Base58 encoder and decoder -use std::{error, fmt}; +use std::{error, fmt, str}; use byteorder::{ByteOrder, LittleEndian}; use util::hash::Sha256dHash; @@ -134,7 +134,7 @@ pub fn from_check(data: &str) -> Result, Error> { Ok(ret) } -fn encode_iter(data: I) -> String +fn encode_iter_utf8(data: I) -> Vec where I: Iterator + Clone, { @@ -173,9 +173,26 @@ where for ch in ret.iter_mut() { *ch = BASE58_CHARS[*ch as usize]; } + ret +} + +fn encode_iter(data: I) -> String +where + I: Iterator + Clone, +{ + let ret = encode_iter_utf8(data); String::from_utf8(ret).unwrap() } +/// Directly encode a slice as base58 into a `Formatter`. +fn encode_iter_to_fmt(fmt: &mut fmt::Formatter, data: I) -> fmt::Result +where + I: Iterator + Clone, +{ + let ret = encode_iter_utf8(data); + fmt.write_str(str::from_utf8(&ret).unwrap()) +} + /// Directly encode a slice as base58 pub fn encode_slice(data: &[u8]) -> String { encode_iter(data.iter().cloned()) @@ -192,6 +209,16 @@ pub fn check_encode_slice(data: &[u8]) -> String { ) } +/// Obtain a string with the base58check encoding of a slice +/// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) +pub fn check_encode_slice_to_fmt(fmt: &mut fmt::Formatter, data: &[u8]) -> fmt::Result { + let checksum = Sha256dHash::from_data(&data); + let iter = data.iter() + .cloned() + .chain(checksum[0..4].iter().cloned()); + encode_iter_to_fmt(fmt, iter) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/util/privkey.rs b/src/util/privkey.rs index 32ba097..57a7a81 100644 --- a/src/util/privkey.rs +++ b/src/util/privkey.rs @@ -15,6 +15,8 @@ //! //! A private key represents the secret data associated with its proposed use //! + +use std::fmt::{self, Display, Formatter}; use std::str::FromStr; use util::Error; use secp256k1::{self, Secp256k1}; @@ -92,20 +94,21 @@ impl Privkey { } } -impl ToString for Privkey { - fn to_string(&self) -> String { +impl Display for Privkey { + fn fmt(&self, fmt: &mut Formatter) -> 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[..]); - if self.compressed { + let privkey = if self.compressed { ret[33] = 1; base58::check_encode_slice(&ret[..]) } else { base58::check_encode_slice(&ret[..33]) - } + }; + fmt.write_str(&privkey) } }