tests for parsing and printing private

This commit is contained in:
debris 2016-08-18 13:43:53 +02:00
parent e39f37fac7
commit 355e042931
5 changed files with 98 additions and 5 deletions

View File

@ -8,7 +8,7 @@ use std::ops::Deref;
use base58::ToBase58; use base58::ToBase58;
use network::Network; use network::Network;
use hash::H160; use hash::H160;
use keys::{DisplayLayout, checksum}; use keys::{DisplayLayout, checksum, Error};
/// There are two address formats currently in use. /// There are two address formats currently in use.
/// https://bitcoin.org/en/developer-reference#address-conversion /// https://bitcoin.org/en/developer-reference#address-conversion
@ -62,6 +62,10 @@ impl DisplayLayout for Address {
result[21..25].copy_from_slice(&cs); result[21..25].copy_from_slice(&cs);
AddressDisplayLayout(result) AddressDisplayLayout(result)
} }
fn from_layout(_data: &[u8]) -> Result<Self, Error> where Self: Sized {
unimplemented!();
}
} }
impl fmt::Display for Address { impl fmt::Display for Address {

View File

@ -3,7 +3,6 @@ use crypto::dhash;
/// Data checksum /// Data checksum
pub fn checksum(data: &[u8]) -> [u8; 4] { pub fn checksum(data: &[u8]) -> [u8; 4] {
let mut result = [0u8; 4]; let mut result = [0u8; 4];
// TODO: check if this checksum is valid result.copy_from_slice(&dhash(data)[0..4]);
result.copy_from_slice(&dhash(data)[28..]);
result result
} }

View File

@ -1,7 +1,10 @@
use std::ops::Deref; use std::ops::Deref;
use keys::Error;
pub trait DisplayLayout { pub trait DisplayLayout {
type Target: Deref<Target = [u8]>; type Target: Deref<Target = [u8]>;
fn layout(&self) -> Self::Target; fn layout(&self) -> Self::Target;
fn from_layout(data: &[u8]) -> Result<Self, Error> where Self: Sized;
} }

View File

@ -7,6 +7,9 @@ pub enum Error {
InvalidSecret, InvalidSecret,
InvalidMessage, InvalidMessage,
InvalidSignature, InvalidSignature,
InvalidNetwork,
InvalidChecksum,
InvalidPrivate,
FailedKeyGeneration, FailedKeyGeneration,
} }
@ -17,6 +20,9 @@ impl fmt::Display for Error {
Error::InvalidSecret => "Invalid Secret", Error::InvalidSecret => "Invalid Secret",
Error::InvalidMessage => "Invalid Message", Error::InvalidMessage => "Invalid Message",
Error::InvalidSignature => "Invalid Signature", Error::InvalidSignature => "Invalid Signature",
Error::InvalidNetwork => "Invalid Network",
Error::InvalidChecksum => "Invalid Checksum",
Error::InvalidPrivate => "Invalid Private",
Error::FailedKeyGeneration => "Key generation failed", Error::FailedKeyGeneration => "Key generation failed",
}; };

View File

@ -1,7 +1,8 @@
use std::fmt; use std::fmt;
use base58::ToBase58; use std::str::FromStr;
use base58::{ToBase58, FromBase58};
use network::Network; use network::Network;
use keys::{Secret, DisplayLayout}; use keys::{Secret, DisplayLayout, checksum, Error};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Private { pub struct Private {
@ -28,8 +29,44 @@ impl DisplayLayout for Private {
if self.compressed { if self.compressed {
result.push(1); result.push(1);
} }
let cs = checksum(&result);
result.extend(&cs);
result result
} }
fn from_layout(data: &[u8]) -> Result<Self, Error> where Self: Sized {
let compressed = match data.len() {
37 => false,
38 => true,
_ => return Err(Error::InvalidPrivate),
};
if compressed && data[data.len() - 5] != 1 {
return Err(Error::InvalidPrivate);
}
let cs = checksum(&data[0..data.len() - 4]);
if cs != &data[data.len() - 4..] {
return Err(Error::InvalidChecksum);
}
let network = match data[0] {
128 => Network::Mainnet,
239 => Network::Testnet,
_ => return Err(Error::InvalidPrivate),
};
let mut secret = [0u8; 32];
secret.copy_from_slice(&data[1..33]);
let private = Private {
network: network,
secret: secret,
compressed: compressed,
};
Ok(private)
}
} }
impl fmt::Display for Private { impl fmt::Display for Private {
@ -37,3 +74,47 @@ impl fmt::Display for Private {
self.layout().to_base58().fmt(f) self.layout().to_base58().fmt(f)
} }
} }
impl FromStr for Private {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> where Self: Sized {
let hex = try!(s.from_base58().map_err(|_| Error::InvalidPrivate));
Private::from_layout(&hex)
}
}
impl From<&'static str> for Private {
fn from(s: &'static str) -> Self {
s.parse().unwrap()
}
}
#[cfg(test)]
mod tests {
use hash::h256_from_str;
use network::Network;
use super::Private;
#[test]
fn test_private_to_string() {
let private = Private {
network: Network::Mainnet,
secret: h256_from_str("063377054c25f98bc538ac8dd2cf9064dd5d253a725ece0628a34e2f84803bd5"),
compressed: false,
};
assert_eq!("5KSCKP8NUyBZPCCQusxRwgmz9sfvJQEgbGukmmHepWw5Bzp95mu".to_owned(), private.to_string());
}
#[test]
fn test_private_from_str() {
let private = Private {
network: Network::Mainnet,
secret: h256_from_str("063377054c25f98bc538ac8dd2cf9064dd5d253a725ece0628a34e2f84803bd5"),
compressed: false,
};
assert_eq!(private, "5KSCKP8NUyBZPCCQusxRwgmz9sfvJQEgbGukmmHepWw5Bzp95mu".into());
}
}