tests for parsing and printing private
This commit is contained in:
parent
e39f37fac7
commit
355e042931
|
@ -8,7 +8,7 @@ use std::ops::Deref;
|
|||
use base58::ToBase58;
|
||||
use network::Network;
|
||||
use hash::H160;
|
||||
use keys::{DisplayLayout, checksum};
|
||||
use keys::{DisplayLayout, checksum, Error};
|
||||
|
||||
/// There are two address formats currently in use.
|
||||
/// https://bitcoin.org/en/developer-reference#address-conversion
|
||||
|
@ -62,6 +62,10 @@ impl DisplayLayout for Address {
|
|||
result[21..25].copy_from_slice(&cs);
|
||||
AddressDisplayLayout(result)
|
||||
}
|
||||
|
||||
fn from_layout(_data: &[u8]) -> Result<Self, Error> where Self: Sized {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Address {
|
||||
|
|
|
@ -3,7 +3,6 @@ use crypto::dhash;
|
|||
/// Data checksum
|
||||
pub fn checksum(data: &[u8]) -> [u8; 4] {
|
||||
let mut result = [0u8; 4];
|
||||
// TODO: check if this checksum is valid
|
||||
result.copy_from_slice(&dhash(data)[28..]);
|
||||
result.copy_from_slice(&dhash(data)[0..4]);
|
||||
result
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use std::ops::Deref;
|
||||
use keys::Error;
|
||||
|
||||
pub trait DisplayLayout {
|
||||
type Target: Deref<Target = [u8]>;
|
||||
|
||||
fn layout(&self) -> Self::Target;
|
||||
|
||||
fn from_layout(data: &[u8]) -> Result<Self, Error> where Self: Sized;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ pub enum Error {
|
|||
InvalidSecret,
|
||||
InvalidMessage,
|
||||
InvalidSignature,
|
||||
InvalidNetwork,
|
||||
InvalidChecksum,
|
||||
InvalidPrivate,
|
||||
FailedKeyGeneration,
|
||||
}
|
||||
|
||||
|
@ -17,6 +20,9 @@ impl fmt::Display for Error {
|
|||
Error::InvalidSecret => "Invalid Secret",
|
||||
Error::InvalidMessage => "Invalid Message",
|
||||
Error::InvalidSignature => "Invalid Signature",
|
||||
Error::InvalidNetwork => "Invalid Network",
|
||||
Error::InvalidChecksum => "Invalid Checksum",
|
||||
Error::InvalidPrivate => "Invalid Private",
|
||||
Error::FailedKeyGeneration => "Key generation failed",
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::fmt;
|
||||
use base58::ToBase58;
|
||||
use std::str::FromStr;
|
||||
use base58::{ToBase58, FromBase58};
|
||||
use network::Network;
|
||||
use keys::{Secret, DisplayLayout};
|
||||
use keys::{Secret, DisplayLayout, checksum, Error};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Private {
|
||||
|
@ -28,8 +29,44 @@ impl DisplayLayout for Private {
|
|||
if self.compressed {
|
||||
result.push(1);
|
||||
}
|
||||
let cs = checksum(&result);
|
||||
result.extend(&cs);
|
||||
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 {
|
||||
|
@ -37,3 +74,47 @@ impl fmt::Display for Private {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue