Merge pull request #141 from jeandudey/2018-08-display

Implement `Display` instead of `ToString` for `Address` and `PrivKey`.
This commit is contained in:
Andrew Poelstra 2018-08-21 16:41:58 +00:00 committed by GitHub
commit d16fdd63d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 13 deletions

View File

@ -16,8 +16,8 @@
//! Support for ordinary base58 Bitcoin addresses and private keys //! Support for ordinary base58 Bitcoin addresses and private keys
//! //!
use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
use std::string::ToString;
use bitcoin_bech32::{self, WitnessProgram, u5}; use bitcoin_bech32::{self, WitnessProgram, u5};
use secp256k1::key::PublicKey; use secp256k1::key::PublicKey;
@ -203,8 +203,8 @@ impl Address {
} }
} }
impl ToString for Address { impl Display for Address {
fn to_string(&self) -> String { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
match self.payload { match self.payload {
// note: serialization for pay-to-pk is defined, but is irreversible // note: serialization for pay-to-pk is defined, but is irreversible
Payload::Pubkey(ref pk) => { Payload::Pubkey(ref pk) => {
@ -215,7 +215,7 @@ impl ToString for Address {
Network::Testnet | Network::Regtest => 111, Network::Testnet | Network::Regtest => 111,
}; };
prefixed[1..].copy_from_slice(&hash[..]); prefixed[1..].copy_from_slice(&hash[..]);
base58::check_encode_slice(&prefixed[..]) base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
}, },
Payload::PubkeyHash(ref hash) => { Payload::PubkeyHash(ref hash) => {
let mut prefixed = [0; 21]; let mut prefixed = [0; 21];
@ -224,7 +224,7 @@ impl ToString for Address {
Network::Testnet | Network::Regtest => 111, Network::Testnet | Network::Regtest => 111,
}; };
prefixed[1..].copy_from_slice(&hash[..]); prefixed[1..].copy_from_slice(&hash[..]);
base58::check_encode_slice(&prefixed[..]) base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
}, },
Payload::ScriptHash(ref hash) => { Payload::ScriptHash(ref hash) => {
let mut prefixed = [0; 21]; let mut prefixed = [0; 21];
@ -233,10 +233,10 @@ impl ToString for Address {
Network::Testnet | Network::Regtest => 196, Network::Testnet | Network::Regtest => 196,
}; };
prefixed[1..].copy_from_slice(&hash[..]); prefixed[1..].copy_from_slice(&hash[..]);
base58::check_encode_slice(&prefixed[..]) base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
}, },
Payload::WitnessProgram(ref witprog) => { Payload::WitnessProgram(ref witprog) => {
witprog.to_address() fmt.write_str(&witprog.to_address())
}, },
} }
} }

View File

@ -14,7 +14,7 @@
//! Base58 encoder and decoder //! Base58 encoder and decoder
use std::{error, fmt}; use std::{error, fmt, str};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
@ -134,7 +134,7 @@ pub fn from_check(data: &str) -> Result<Vec<u8>, Error> {
Ok(ret) Ok(ret)
} }
fn encode_iter<I>(data: I) -> String fn encode_iter_utf8<I>(data: I) -> Vec<u8>
where where
I: Iterator<Item = u8> + Clone, I: Iterator<Item = u8> + Clone,
{ {
@ -173,9 +173,26 @@ where
for ch in ret.iter_mut() { for ch in ret.iter_mut() {
*ch = BASE58_CHARS[*ch as usize]; *ch = BASE58_CHARS[*ch as usize];
} }
ret
}
fn encode_iter<I>(data: I) -> String
where
I: Iterator<Item = u8> + Clone,
{
let ret = encode_iter_utf8(data);
String::from_utf8(ret).unwrap() String::from_utf8(ret).unwrap()
} }
/// Directly encode a slice as base58 into a `Formatter`.
fn encode_iter_to_fmt<I>(fmt: &mut fmt::Formatter, data: I) -> fmt::Result
where
I: Iterator<Item = u8> + Clone,
{
let ret = encode_iter_utf8(data);
fmt.write_str(str::from_utf8(&ret).unwrap())
}
/// Directly encode a slice as base58 /// Directly encode a slice as base58
pub fn encode_slice(data: &[u8]) -> String { pub fn encode_slice(data: &[u8]) -> String {
encode_iter(data.iter().cloned()) 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -15,6 +15,8 @@
//! //!
//! A private key represents the secret data associated with its proposed use //! A private key represents the secret data associated with its proposed use
//! //!
use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
use util::Error; use util::Error;
use secp256k1::{self, Secp256k1}; use secp256k1::{self, Secp256k1};
@ -92,20 +94,21 @@ impl Privkey {
} }
} }
impl ToString for Privkey { impl Display for Privkey {
fn to_string(&self) -> String { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
let mut ret = [0; 34]; let mut ret = [0; 34];
ret[0] = match self.network { ret[0] = match self.network {
Network::Bitcoin => 128, Network::Bitcoin => 128,
Network::Testnet | Network::Regtest => 239, Network::Testnet | Network::Regtest => 239,
}; };
ret[1..33].copy_from_slice(&self.key[..]); ret[1..33].copy_from_slice(&self.key[..]);
if self.compressed { let privkey = if self.compressed {
ret[33] = 1; ret[33] = 1;
base58::check_encode_slice(&ret[..]) base58::check_encode_slice(&ret[..])
} else { } else {
base58::check_encode_slice(&ret[..33]) base58::check_encode_slice(&ret[..33])
} };
fmt.write_str(&privkey)
} }
} }