support for compressed publics

This commit is contained in:
debris 2016-08-20 18:06:04 +02:00
parent aff17ede5c
commit c86ec93b60
5 changed files with 91 additions and 12 deletions

View File

@ -2,6 +2,7 @@ use hex::{ToHex, FromHex};
pub type H160 = [u8; 20];
pub type H256 = [u8; 32];
pub type H264 = [u8; 33];
pub type H512 = [u8; 64];
pub type H520 = [u8; 65];

View File

@ -16,10 +16,17 @@ pub struct KeyPair {
public: Public,
}
impl fmt::Debug for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(self.private.fmt(f));
writeln!(f, "public: {:?}", self.public)
}
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "private: {}", self.private.to_string()));
writeln!(f, "public: {}", self.public.to_hex())
try!(writeln!(f, "private: {}", self.private));
writeln!(f, "public: {}", self.public)
}
}
@ -29,10 +36,17 @@ impl KeyPair {
let s: key::SecretKey = try!(key::SecretKey::from_slice(context, &private.secret));
let pub_key = try!(key::PublicKey::from_secret_key(context, &s));
// TODO: take into account private field `compressed`
let serialized = pub_key.serialize_vec(context, false);
let serialized = pub_key.serialize_vec(context, private.compressed);
let mut public = [0u8; 65];
public.copy_from_slice(&serialized[0..65]);
let public = if private.compressed {
let mut public = [0u8; 33];
public.copy_from_slice(&serialized[0..33]);
Public::Compressed(public)
} else {
let mut public = [0u8; 65];
public.copy_from_slice(&serialized[0..65]);
Public::Normal(public)
};
let keypair = KeyPair {
private: private,
@ -56,7 +70,7 @@ impl KeyPair {
secret: secret,
compressed: false,
},
public: public,
public: Public::Normal(public),
}
}
@ -85,11 +99,30 @@ impl KeyPair {
mod tests {
use super::KeyPair;
/// Tests from:
/// https://github.com/bitcoin/bitcoin/blob/a6a860796a44a2805a58391a009ba22752f64e32/src/test/key_tests.cpp
const SECRET_0: &'static str = "5KSCKP8NUyBZPCCQusxRwgmz9sfvJQEgbGukmmHepWw5Bzp95mu";
const SECRET_1: &'static str = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
const SECRET_2: &'static str = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
const SECRET_3: &'static str = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
const SECRET_4: &'static str = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
const ADDRESS_0: &'static str = "16meyfSoQV6twkAAxPe51RtMVz7PGRmWna";
const ADDRESS_1: &'static str = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
const ADDRESS_2: &'static str = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
const ADDRESS_3: &'static str = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
const ADDRESS_4: &'static str = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
fn check_addresses(secret: &'static str, address: &'static str) -> bool {
let kp = KeyPair::from_private(secret.into()).unwrap();
kp.address() == address.into()
}
#[test]
fn test_generating_address() {
// secret: 5KSCKP8NUyBZPCCQusxRwgmz9sfvJQEgbGukmmHepWw5Bzp95mu
// address: 16meyfSoQV6twkAAxPe51RtMVz7PGRmWna
let kp = KeyPair::from_private("5KSCKP8NUyBZPCCQusxRwgmz9sfvJQEgbGukmmHepWw5Bzp95mu".into()).unwrap();
assert_eq!(kp.address(), "16meyfSoQV6twkAAxPe51RtMVz7PGRmWna".into());
assert!(check_addresses(SECRET_0, ADDRESS_0));
assert!(check_addresses(SECRET_1, ADDRESS_1));
assert!(check_addresses(SECRET_2, ADDRESS_2));
assert!(check_addresses(SECRET_3, ADDRESS_3));
assert!(check_addresses(SECRET_4, ADDRESS_4));
}
}

View File

@ -13,6 +13,7 @@ pub mod generator;
pub mod keypair;
mod error;
mod private;
mod public;
pub use self::address::{Type, Address};
pub use self::checksum::checksum;
@ -20,11 +21,11 @@ pub use self::display::DisplayLayout;
pub use self::keypair::KeyPair;
pub use self::error::Error;
pub use self::private::Private;
pub use self::public::Public;
use hash::{H160, H256, H520};
pub type AddressHash = H160;
pub type Secret = H256;
pub type Public = H520;
use secp256k1;
lazy_static! {

View File

@ -1,10 +1,11 @@
use std::fmt;
use std::str::FromStr;
use hex::ToHex;
use base58::{ToBase58, FromBase58};
use network::Network;
use keys::{Secret, DisplayLayout, checksum, Error};
#[derive(Debug, PartialEq)]
#[derive(PartialEq)]
pub struct Private {
/// The network on which this key should be used.
pub network: Network,
@ -69,6 +70,14 @@ impl DisplayLayout for Private {
}
}
impl fmt::Debug for Private {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "network: {:?}", self.network));
try!(writeln!(f, "secret: {}", self.secret.to_hex()));
writeln!(f, "compressed: {}", self.compressed)
}
}
impl fmt::Display for Private {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.layout().to_base58().fmt(f)

35
src/keys/public.rs Normal file
View File

@ -0,0 +1,35 @@
use std::fmt;
use std::ops::Deref;
use hex::ToHex;
use hash::{H264, H520};
pub enum Public {
Normal(H520),
Compressed(H264),
}
impl Deref for Public {
type Target = [u8];
fn deref(&self) -> &Self::Target {
match *self {
Public::Normal(ref hash) => hash,
Public::Compressed(ref hash) => hash,
}
}
}
impl fmt::Debug for Public {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Public::Normal(ref hash) => writeln!(f, "normal: {}", hash.to_hex()),
Public::Compressed(ref hash) => writeln!(f, "normal: {}", hash.to_hex()),
}
}
}
impl fmt::Display for Public {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_hex().fmt(f)
}
}