diff --git a/.travis.yml b/.travis.yml index 15302cf13..db01f4fa0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ matrix: script: - cargo build --verbose --no-default-features + - cargo build --verbose --no-default-features --features="bitcoin_hashes" - cargo build --verbose --no-default-features --features="serde" - cargo build --verbose --no-default-features --features="lowmemory" - cargo build --verbose --no-default-features --features="rand" @@ -29,6 +30,7 @@ script: - cargo build --verbose --no-default-features --features="fuzztarget recovery" - cargo build --verbose --features=rand - cargo test --no-run --features=fuzztarget + - cargo test --verbose --features="bitcoin_hashes" - cargo test --verbose --features=rand - cargo test --verbose --features="rand rand-std" - cargo test --verbose --features="rand serde" diff --git a/Cargo.toml b/Cargo.toml index d93d7f07c..9ccdb3120 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,10 @@ rand_core = "0.4" serde_test = "1.0" bitcoin_hashes = "0.7" +[dependencies.bitcoin_hashes] +version = "0.7" +optional = true + [dependencies.rand] version = "0.6" optional = true diff --git a/src/lib.rs b/src/lib.rs index 5e66c46e5..dd77123c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -147,6 +147,7 @@ pub extern crate secp256k1_sys; pub use secp256k1_sys as ffi; +#[cfg(feature = "bitcoin_hashes")] extern crate bitcoin_hashes; #[cfg(all(test, feature = "unstable"))] extern crate test; #[cfg(any(test, feature = "rand"))] pub extern crate rand; #[cfg(any(test))] extern crate rand_core; @@ -173,6 +174,9 @@ use core::marker::PhantomData; use core::ops::Deref; use ffi::CPtr; +#[cfg(feature = "bitcoin_hashes")] +use bitcoin_hashes::Hash; + /// An ECDSA signature #[derive(Copy, Clone, PartialEq, Eq)] pub struct Signature(ffi::Signature); @@ -219,6 +223,27 @@ pub trait ThirtyTwoByteHash { fn into_32(self) -> [u8; 32]; } +#[cfg(feature = "bitcoin_hashes")] +impl ThirtyTwoByteHash for bitcoin_hashes::sha256::Hash { + fn into_32(self) -> [u8; 32] { + self.into_inner() + } +} + +#[cfg(feature = "bitcoin_hashes")] +impl ThirtyTwoByteHash for bitcoin_hashes::sha256d::Hash { + fn into_32(self) -> [u8; 32] { + self.into_inner() + } +} + +#[cfg(feature = "bitcoin_hashes")] +impl ThirtyTwoByteHash for bitcoin_hashes::sha256t::Hash { + fn into_32(self) -> [u8; 32] { + self.into_inner() + } +} + impl SerializedSignature { /// Get a pointer to the underlying data with the specified capacity. pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 { @@ -467,6 +492,24 @@ impl Message { _ => Err(Error::InvalidMessage) } } + + /// Constructs a `Message` by hashing `data` with hash algorithm `H`. + /// ```rust + /// extern crate bitcoin_hashes; + /// use secp256k1::Message; + /// use bitcoin_hashes::sha256; + /// use bitcoin_hashes::Hash; + /// + /// let m1 = Message::from_hashed_data::("Hello world!".as_bytes()); + /// // is equivalent to + /// let m2 = Message::from(sha256::Hash::hash("Hello world!".as_bytes())); + /// + /// assert_eq!(m1, m2); + /// ``` + #[cfg(feature = "bitcoin_hashes")] + pub fn from_hashed_data(data: &[u8]) -> Self { + ::hash(data).into() + } } impl From for Message { @@ -1060,6 +1103,31 @@ mod tests { assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); } + + #[cfg(feature = "bitcoin_hashes")] + #[test] + fn test_from_hash() { + use bitcoin_hashes; + use bitcoin_hashes::Hash; + + let test_bytes = "Hello world!".as_bytes(); + + let hash = bitcoin_hashes::sha256::Hash::hash(test_bytes); + let msg = Message::from(hash); + assert_eq!(msg.0, hash.into_inner()); + assert_eq!( + msg, + Message::from_hashed_data::(test_bytes) + ); + + let hash = bitcoin_hashes::sha256d::Hash::hash(test_bytes); + let msg = Message::from(hash); + assert_eq!(msg.0, hash.into_inner()); + assert_eq!( + msg, + Message::from_hashed_data::(test_bytes) + ); + } } #[cfg(all(test, feature = "unstable"))]