signature tests and tweaks
This commit is contained in:
parent
23ef558ba4
commit
238afb59a9
|
@ -94,8 +94,7 @@ impl KeyPair {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use keys::Message;
|
use crypto::dhash;
|
||||||
use crypto::hash;
|
|
||||||
use super::KeyPair;
|
use super::KeyPair;
|
||||||
|
|
||||||
/// Tests from:
|
/// Tests from:
|
||||||
|
@ -111,6 +110,11 @@ mod tests {
|
||||||
const ADDRESS_1C: &'static str = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
|
const ADDRESS_1C: &'static str = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
|
||||||
const ADDRESS_2C: &'static str = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
|
const ADDRESS_2C: &'static str = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
|
||||||
const SIGN_1: &'static str = "304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6";
|
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 {
|
fn check_addresses(secret: &'static str, address: &'static str) -> bool {
|
||||||
let kp = KeyPair::from_private(secret.into()).unwrap();
|
let kp = KeyPair::from_private(secret.into()).unwrap();
|
||||||
|
@ -122,6 +126,18 @@ mod tests {
|
||||||
kp.private().compressed == compressed
|
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]
|
#[test]
|
||||||
fn test_keypair_address() {
|
fn test_keypair_address() {
|
||||||
assert!(check_addresses(SECRET_0, ADDRESS_0));
|
assert!(check_addresses(SECRET_0, ADDRESS_0));
|
||||||
|
@ -140,15 +156,21 @@ mod tests {
|
||||||
assert!(check_compressed(SECRET_2C, true));
|
assert!(check_compressed(SECRET_2C, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn test_sign() {
|
fn test_sign() {
|
||||||
use hex::ToHex;
|
let message = b"Very deterministic message";
|
||||||
let message = hash(b"Very deterministic message");
|
assert!(check_sign(SECRET_1, message, SIGN_1));
|
||||||
println!("message: {}", message.to_hex());
|
assert!(check_sign(SECRET_1C, message, SIGN_1));
|
||||||
let kp = KeyPair::from_private(SECRET_1.into()).unwrap();
|
assert!(check_sign(SECRET_2, message, SIGN_2));
|
||||||
let signature = kp.private().sign(&message).unwrap();
|
assert!(check_sign(SECRET_2C, message, SIGN_2));
|
||||||
assert_eq!(signature, SIGN_1.into());
|
}
|
||||||
|
|
||||||
|
#[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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub use self::keypair::KeyPair;
|
||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use self::private::Private;
|
pub use self::private::Private;
|
||||||
pub use self::public::Public;
|
pub use self::public::Public;
|
||||||
pub use self::signature::Signature;
|
pub use self::signature::{Signature, CompactSignature};
|
||||||
|
|
||||||
use hash::{H160, H256};
|
use hash::{H160, H256};
|
||||||
pub type AddressHash = H160;
|
pub type AddressHash = H160;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use secp256k1::Message as SecpMessage;
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use base58::{ToBase58, FromBase58};
|
use base58::{ToBase58, FromBase58};
|
||||||
use network::Network;
|
use network::Network;
|
||||||
use keys::{Secret, DisplayLayout, checksum, Error, Message, Signature, SECP256K1};
|
use keys::{Secret, DisplayLayout, checksum, Error, Message, Signature, CompactSignature, SECP256K1};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub struct Private {
|
pub struct Private {
|
||||||
|
@ -24,10 +24,10 @@ impl Private {
|
||||||
let message = try!(SecpMessage::from_slice(message));
|
let message = try!(SecpMessage::from_slice(message));
|
||||||
let signature = try!(context.sign(&message, &secret));
|
let signature = try!(context.sign(&message, &secret));
|
||||||
let data = signature.serialize_der(context);
|
let data = signature.serialize_der(context);
|
||||||
Ok(Signature::DER(data))
|
Ok(data.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_compact(&self, message: &Message) -> Result<Signature, Error> {
|
pub fn sign_compact(&self, message: &Message) -> Result<CompactSignature, Error> {
|
||||||
let context = &SECP256K1;
|
let context = &SECP256K1;
|
||||||
let secret = try!(key::SecretKey::from_slice(context, &self.secret));
|
let secret = try!(key::SecretKey::from_slice(context, &self.secret));
|
||||||
let message = try!(SecpMessage::from_slice(message));
|
let message = try!(SecpMessage::from_slice(message));
|
||||||
|
@ -40,7 +40,7 @@ impl Private {
|
||||||
true => 27 + recovery_id + 4,
|
true => 27 + recovery_id + 4,
|
||||||
false => 27 + recovery_id,
|
false => 27 + recovery_id,
|
||||||
};
|
};
|
||||||
Ok(Signature::Compact(signature))
|
Ok(signature.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
//! Bitcoin signatures.
|
||||||
|
//!
|
||||||
|
//! http://bitcoin.stackexchange.com/q/12554/40688
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -6,43 +10,26 @@ use hex::{ToHex, FromHex};
|
||||||
use hash::H520;
|
use hash::H520;
|
||||||
use keys::Error;
|
use keys::Error;
|
||||||
|
|
||||||
/// http://bitcoin.stackexchange.com/q/12554/40688
|
#[derive(PartialEq)]
|
||||||
pub enum Signature {
|
pub struct Signature(Vec<u8>);
|
||||||
DER(Vec<u8>),
|
|
||||||
Compact(H520),
|
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 {
|
impl Deref for Signature {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match *self {
|
&self.0
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,15 +38,7 @@ impl FromStr for Signature {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Error> {
|
fn from_str(s: &str) -> Result<Self, Error> {
|
||||||
let vec = try!(s.from_hex().map_err(|_| Error::InvalidSignature));
|
let vec = try!(s.from_hex().map_err(|_| Error::InvalidSignature));
|
||||||
let signature = match vec.len() {
|
Ok(Signature(vec))
|
||||||
65 => {
|
|
||||||
let mut compact = [0u8; 65];
|
|
||||||
compact.copy_from_slice(&vec);
|
|
||||||
Signature::Compact(compact)
|
|
||||||
},
|
|
||||||
_ => Signature::DER(vec),
|
|
||||||
};
|
|
||||||
Ok(signature)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,3 +47,67 @@ impl From<&'static str> for Signature {
|
||||||
s.parse().unwrap()
|
s.parse().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for Signature {
|
||||||
|
fn from(v: Vec<u8>) -> 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<Self, Error> {
|
||||||
|
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<H520> for CompactSignature {
|
||||||
|
fn from(h: H520) -> Self {
|
||||||
|
CompactSignature(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue