From 238afb59a9ec318d8a601129bff894e41a457f82 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 21 Aug 2016 14:58:35 +0200 Subject: [PATCH] signature tests and tweaks --- src/keys/keypair.rs | 42 +++++++++++---- src/keys/mod.rs | 2 +- src/keys/private.rs | 8 +-- src/keys/signature.rs | 123 ++++++++++++++++++++++++++++-------------- 4 files changed, 120 insertions(+), 55 deletions(-) diff --git a/src/keys/keypair.rs b/src/keys/keypair.rs index 3a53c36c..953292e3 100644 --- a/src/keys/keypair.rs +++ b/src/keys/keypair.rs @@ -94,8 +94,7 @@ impl KeyPair { #[cfg(test)] mod tests { - use keys::Message; - use crypto::hash; + use crypto::dhash; use super::KeyPair; /// Tests from: @@ -111,6 +110,11 @@ mod tests { const ADDRESS_1C: &'static str = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"; const ADDRESS_2C: &'static str = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"; const SIGN_1: &'static str = "304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"; + const SIGN_2: &'static str = "3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"; + const SIGN_COMPACT_1: &'static str = "1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"; + const SIGN_COMPACT_1C: &'static str = "205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"; + const SIGN_COMPACT_2: &'static str = "1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"; + const SIGN_COMPACT_2C: &'static str = "2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"; fn check_addresses(secret: &'static str, address: &'static str) -> bool { let kp = KeyPair::from_private(secret.into()).unwrap(); @@ -122,6 +126,18 @@ mod tests { kp.private().compressed == compressed } + fn check_sign(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool { + let message = dhash(raw_message); + let kp = KeyPair::from_private(secret.into()).unwrap(); + kp.private().sign(&message).unwrap() == signature.into() + } + + fn check_sign_compact(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool { + let message = dhash(raw_message); + let kp = KeyPair::from_private(secret.into()).unwrap(); + kp.private().sign_compact(&message).unwrap() == signature.into() + } + #[test] fn test_keypair_address() { assert!(check_addresses(SECRET_0, ADDRESS_0)); @@ -140,15 +156,21 @@ mod tests { assert!(check_compressed(SECRET_2C, true)); } - // TODO: fix #[test] - #[ignore] fn test_sign() { - use hex::ToHex; - let message = hash(b"Very deterministic message"); - println!("message: {}", message.to_hex()); - let kp = KeyPair::from_private(SECRET_1.into()).unwrap(); - let signature = kp.private().sign(&message).unwrap(); - assert_eq!(signature, SIGN_1.into()); + let message = b"Very deterministic message"; + assert!(check_sign(SECRET_1, message, SIGN_1)); + assert!(check_sign(SECRET_1C, message, SIGN_1)); + assert!(check_sign(SECRET_2, message, SIGN_2)); + assert!(check_sign(SECRET_2C, message, SIGN_2)); + } + + #[test] + fn test_sign_compact() { + let message = b"Very deterministic message"; + assert!(check_sign_compact(SECRET_1, message, SIGN_COMPACT_1)); + assert!(check_sign_compact(SECRET_1C, message, SIGN_COMPACT_1C)); + assert!(check_sign_compact(SECRET_2, message, SIGN_COMPACT_2)); + assert!(check_sign_compact(SECRET_2C, message, SIGN_COMPACT_2C)); } } diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 88832acc..54ecb6e2 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -23,7 +23,7 @@ pub use self::keypair::KeyPair; pub use self::error::Error; pub use self::private::Private; pub use self::public::Public; -pub use self::signature::Signature; +pub use self::signature::{Signature, CompactSignature}; use hash::{H160, H256}; pub type AddressHash = H160; diff --git a/src/keys/private.rs b/src/keys/private.rs index a9334b41..3cb0cba3 100644 --- a/src/keys/private.rs +++ b/src/keys/private.rs @@ -5,7 +5,7 @@ use secp256k1::Message as SecpMessage; use hex::ToHex; use base58::{ToBase58, FromBase58}; use network::Network; -use keys::{Secret, DisplayLayout, checksum, Error, Message, Signature, SECP256K1}; +use keys::{Secret, DisplayLayout, checksum, Error, Message, Signature, CompactSignature, SECP256K1}; #[derive(PartialEq)] pub struct Private { @@ -24,10 +24,10 @@ impl Private { let message = try!(SecpMessage::from_slice(message)); let signature = try!(context.sign(&message, &secret)); let data = signature.serialize_der(context); - Ok(Signature::DER(data)) + Ok(data.into()) } - pub fn sign_compact(&self, message: &Message) -> Result { + pub fn sign_compact(&self, message: &Message) -> Result { let context = &SECP256K1; let secret = try!(key::SecretKey::from_slice(context, &self.secret)); let message = try!(SecpMessage::from_slice(message)); @@ -40,7 +40,7 @@ impl Private { true => 27 + recovery_id + 4, false => 27 + recovery_id, }; - Ok(Signature::Compact(signature)) + Ok(signature.into()) } } diff --git a/src/keys/signature.rs b/src/keys/signature.rs index 78f54496..add1dcfc 100644 --- a/src/keys/signature.rs +++ b/src/keys/signature.rs @@ -1,3 +1,7 @@ +//! Bitcoin signatures. +//! +//! http://bitcoin.stackexchange.com/q/12554/40688 + use std::fmt; use std::cmp::PartialEq; use std::ops::Deref; @@ -6,43 +10,26 @@ use hex::{ToHex, FromHex}; use hash::H520; use keys::Error; -/// http://bitcoin.stackexchange.com/q/12554/40688 -pub enum Signature { - DER(Vec), - Compact(H520), +#[derive(PartialEq)] +pub struct Signature(Vec); + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.to_hex().fmt(f) + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.to_hex().fmt(f) + } } impl Deref for Signature { type Target = [u8]; fn deref(&self) -> &Self::Target { - match *self { - Signature::DER(ref hash) => hash, - Signature::Compact(ref hash) => hash, - } - } -} - -impl PartialEq for Signature { - fn eq(&self, other: &Signature) -> bool { - let s_slice: &[u8] = self; - let o_slice: &[u8] = other; - s_slice == o_slice - } -} - -impl fmt::Debug for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Signature::DER(ref hash) => writeln!(f, "normal: {}", hash.to_hex()), - Signature::Compact(ref hash) => writeln!(f, "compact: {}", hash.to_hex()), - } - } -} - -impl fmt::Display for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_hex().fmt(f) + &self.0 } } @@ -51,15 +38,7 @@ impl FromStr for Signature { fn from_str(s: &str) -> Result { let vec = try!(s.from_hex().map_err(|_| Error::InvalidSignature)); - let signature = match vec.len() { - 65 => { - let mut compact = [0u8; 65]; - compact.copy_from_slice(&vec); - Signature::Compact(compact) - }, - _ => Signature::DER(vec), - }; - Ok(signature) + Ok(Signature(vec)) } } @@ -68,3 +47,67 @@ impl From<&'static str> for Signature { s.parse().unwrap() } } + +impl From> for Signature { + fn from(v: Vec) -> Self { + Signature(v) + } +} + +pub struct CompactSignature(H520); + +impl fmt::Debug for CompactSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.to_hex().fmt(f) + } +} + +impl fmt::Display for CompactSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.to_hex().fmt(f) + } +} + +impl Deref for CompactSignature { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl PartialEq for CompactSignature { + fn eq(&self, other: &Self) -> bool { + let s_slice: &[u8] = self; + let o_slice: &[u8] = other; + s_slice == o_slice + } +} + +impl FromStr for CompactSignature { + type Err = Error; + + fn from_str(s: &str) -> Result { + let vec = try!(s.from_hex().map_err(|_| Error::InvalidSignature)); + match vec.len() { + 65 => { + let mut compact = [0u8; 65]; + compact.copy_from_slice(&vec); + Ok(CompactSignature(compact)) + }, + _ => Err(Error::InvalidSignature) + } + } +} + +impl From<&'static str> for CompactSignature { + fn from(s: &'static str) -> Self { + s.parse().unwrap() + } +} + +impl From for CompactSignature { + fn from(h: H520) -> Self { + CompactSignature(h) + } +}