diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 6ace63289..b846e309a 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -9,7 +9,7 @@ use core::ops::Index; use core::str::FromStr; use core::{fmt, slice}; -use hashes::{hash160, hash_newtype, sha512, Hash, HashEngine, Hmac, HmacEngine}; +use hashes::{hash160, hash_newtype, sha512, GeneralHash, HashEngine, Hmac, HmacEngine}; use internals::{impl_array_newtype, write_err}; use io::Write; use secp256k1::{Secp256k1, XOnlyPublicKey}; diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs index 3e7dbe919..10606fde9 100644 --- a/bitcoin/src/consensus/encode.rs +++ b/bitcoin/src/consensus/encode.rs @@ -16,7 +16,7 @@ use core::{fmt, mem}; -use hashes::{sha256, sha256d, Hash}; +use hashes::{sha256, sha256d, GeneralHash, Hash}; use hex::error::{InvalidCharError, OddLengthStringError}; use internals::write_err; use io::{BufRead, Cursor, Read, Write}; @@ -768,7 +768,7 @@ impl Decodable for Box<[u8]> { /// Does a double-SHA256 on `data` and returns the first 4 bytes. fn sha2_checksum(data: &[u8]) -> [u8; 4] { - let checksum = ::hash(data); + let checksum = ::hash(data); [checksum[0], checksum[1], checksum[2], checksum[3]] } diff --git a/bitcoin/src/psbt/macros.rs b/bitcoin/src/psbt/macros.rs index fb06bbcdf..86284cb33 100644 --- a/bitcoin/src/psbt/macros.rs +++ b/bitcoin/src/psbt/macros.rs @@ -121,7 +121,7 @@ macro_rules! psbt_insert_hash_pair { match $slf.$map.entry(key_val) { btree_map::Entry::Vacant(empty_key) => { let val: Vec = Deserialize::deserialize(&$raw_value)?; - if <$hash as hashes::Hash>::hash(&val) != key_val { + if <$hash as hashes::GeneralHash>::hash(&val) != key_val { return Err(psbt::Error::InvalidPreimageHashPair { preimage: val.into_boxed_slice(), hash: Box::from(key_val.borrow()), diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs index 6f2da18fd..6993dadd7 100644 --- a/hashes/src/hash160.rs +++ b/hashes/src/hash160.rs @@ -34,7 +34,8 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{hash160, Hash, HashEngine}; + use super::Hash; + use crate::{hash160, HashEngine}; #[derive(Clone)] #[cfg(feature = "alloc")] @@ -111,7 +112,7 @@ mod tests { mod benches { use test::Bencher; - use crate::{hash160, Hash, HashEngine}; + use crate::{hash160, GeneralHash as _, Hash as _, HashEngine}; #[bench] pub fn hash160_10(bh: &mut Bencher) { diff --git a/hashes/src/hkdf.rs b/hashes/src/hkdf.rs index e22418a94..62ad499ff 100644 --- a/hashes/src/hkdf.rs +++ b/hashes/src/hkdf.rs @@ -11,7 +11,7 @@ use alloc::vec; use alloc::vec::Vec; use core::fmt; -use crate::{Hash, HashEngine, Hmac, HmacEngine}; +use crate::{GeneralHash, HashEngine, Hmac, HmacEngine}; /// Output keying material max length multiple. const MAX_OUTPUT_BLOCKS: usize = 255; @@ -32,12 +32,12 @@ impl fmt::Display for MaxLengthError { impl std::error::Error for MaxLengthError {} /// HMAC-based Extract-and-Expand Key Derivation Function (HKDF). -pub struct Hkdf { +pub struct Hkdf { /// Pseudorandom key based on the extract step. prk: Hmac, } -impl Hkdf { +impl Hkdf { /// Initialize a HKDF by performing the extract step. pub fn new(salt: &[u8], ikm: &[u8]) -> Self { let mut hmac_engine: HmacEngine = HmacEngine::new(salt); diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs index 80268f489..1e0f60a06 100644 --- a/hashes/src/hmac.rs +++ b/hashes/src/hmac.rs @@ -12,15 +12,15 @@ use core::{convert, fmt, str}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::{FromSliceError, Hash, HashEngine}; +use crate::{FromSliceError, GeneralHash, Hash, HashEngine}; /// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -pub struct Hmac(T); +pub struct Hmac(T); #[cfg(feature = "schemars")] -impl schemars::JsonSchema for Hmac { +impl schemars::JsonSchema for Hmac { fn is_referenceable() -> bool { ::is_referenceable() } fn schema_name() -> std::string::String { ::schema_name() } @@ -30,13 +30,13 @@ impl schemars::JsonSchema for Hmac { } } -impl str::FromStr for Hmac { +impl str::FromStr for Hmac { type Err = ::Err; fn from_str(s: &str) -> Result { Ok(Hmac(str::FromStr::from_str(s)?)) } } /// Pair of underlying hash midstates which represent the current state of an `HmacEngine`. -pub struct HmacMidState { +pub struct HmacMidState { /// Midstate of the inner hash engine pub inner: ::MidState, /// Midstate of the outer hash engine @@ -45,16 +45,16 @@ pub struct HmacMidState { /// Pair of underlying hash engines, used for the inner and outer hash of HMAC. #[derive(Clone)] -pub struct HmacEngine { +pub struct HmacEngine { iengine: T::Engine, oengine: T::Engine, } -impl Default for HmacEngine { +impl Default for HmacEngine { fn default() -> Self { HmacEngine::new(&[]) } } -impl HmacEngine { +impl HmacEngine { /// Constructs a new keyed HMAC from `key`. /// /// We only support underlying hashes whose block sizes are ≤ 128 bytes. @@ -67,10 +67,13 @@ impl HmacEngine { let mut ipad = [0x36u8; 128]; let mut opad = [0x5cu8; 128]; - let mut ret = HmacEngine { iengine: ::engine(), oengine: ::engine() }; + let mut ret = HmacEngine { + iengine: ::engine(), + oengine: ::engine(), + }; if key.len() > T::Engine::BLOCK_SIZE { - let hash = ::hash(key); + let hash = ::hash(key); for (b_i, b_h) in ipad.iter_mut().zip(hash.as_ref()) { *b_i ^= *b_h; } @@ -97,7 +100,7 @@ impl HmacEngine { } } -impl HashEngine for HmacEngine { +impl HashEngine for HmacEngine { type MidState = HmacMidState; fn midstate(&self) -> Self::MidState { @@ -111,25 +114,24 @@ impl HashEngine for HmacEngine { fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) } } -impl fmt::Debug for Hmac { +impl fmt::Debug for Hmac { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) } } -impl fmt::Display for Hmac { +impl fmt::Display for Hmac { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -impl fmt::LowerHex for Hmac { +impl fmt::LowerHex for Hmac { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } } -impl convert::AsRef<[u8]> for Hmac { +impl convert::AsRef<[u8]> for Hmac { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } -impl Hash for Hmac { +impl GeneralHash for Hmac { type Engine = HmacEngine; - type Bytes = T::Bytes; fn from_engine(mut e: HmacEngine) -> Hmac { let ihash = T::from_engine(e.iengine); @@ -137,7 +139,10 @@ impl Hash for Hmac { let ohash = T::from_engine(e.oengine); Hmac(ohash) } +} +impl Hash for Hmac { + type Bytes = T::Bytes; const LEN: usize = T::LEN; fn from_slice(sl: &[u8]) -> Result, FromSliceError> { T::from_slice(sl).map(Hmac) } @@ -150,14 +155,14 @@ impl Hash for Hmac { } #[cfg(feature = "serde")] -impl Serialize for Hmac { +impl Serialize for Hmac { fn serialize(&self, s: S) -> Result { Serialize::serialize(&self.0, s) } } #[cfg(feature = "serde")] -impl<'de, T: Hash + Deserialize<'de>> Deserialize<'de> for Hmac { +impl<'de, T: GeneralHash + Deserialize<'de>> Deserialize<'de> for Hmac { fn deserialize>(d: D) -> Result, D::Error> { let bytes = Deserialize::deserialize(d)?; Ok(Hmac(bytes)) @@ -169,7 +174,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha256, Hash, HashEngine, Hmac, HmacEngine}; + use crate::{sha256, GeneralHash as _, Hash as _, HashEngine, Hmac, HmacEngine}; #[derive(Clone)] struct Test { @@ -297,7 +302,7 @@ mod tests { fn hmac_sha512_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{sha512, Hash, Hmac}; + use crate::{sha512, Hash as _, Hmac}; #[rustfmt::skip] static HASH_BYTES: [u8; 64] = [ @@ -327,7 +332,7 @@ mod tests { mod benches { use test::Bencher; - use crate::{sha256, Hash, HashEngine, Hmac}; + use crate::{sha256, GeneralHash as _, HashEngine, Hmac}; #[bench] pub fn hmac_sha256_10(bh: &mut Bencher) { diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs index 340161f88..bf9f0b8d4 100644 --- a/hashes/src/impls.rs +++ b/hashes/src/impls.rs @@ -60,14 +60,16 @@ impl_write!( Ok(buf.len()) }, |_us| { Ok(()) }, - T: crate::Hash + T: crate::GeneralHash ); #[cfg(test)] mod tests { use bitcoin_io::Write; - use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash}; + use crate::{ + hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, GeneralHash as _, + }; macro_rules! write_test { ($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => { diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 41006c4df..82445d67e 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -99,16 +99,19 @@ macro_rules! hash_trait_impls { } } - impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> { + impl<$($gen: $gent),*> crate::GeneralHash for Hash<$($gen),*> { type Engine = HashEngine; - type Bytes = [u8; $bits / 8]; - - const LEN: usize = $bits / 8; - const DISPLAY_BACKWARD: bool = $reverse; fn engine() -> HashEngine { Self::engine() } fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) } + } + + impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> { + type Bytes = [u8; $bits / 8]; + + const LEN: usize = $bits / 8; + const DISPLAY_BACKWARD: bool = $reverse; fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result, FromSliceError> { Self::from_slice(sl) diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index f12f7de8c..9623819bd 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -12,7 +12,7 @@ //! Hashing a single byte slice or a string: //! //! ```rust -//! use bitcoin_hashes::{sha256, Hash as _}; +//! use bitcoin_hashes::{sha256, GeneralHash as _}; //! //! let bytes = [0u8; 5]; //! let hash_of_bytes = sha256::Hash::hash(&bytes); @@ -23,7 +23,7 @@ //! Hashing content from a reader: //! //! ```rust -//! use bitcoin_hashes::{sha256, Hash as _}; +//! use bitcoin_hashes::{sha256, GeneralHash as _}; //! //! #[cfg(std)] //! # fn main() -> std::io::Result<()> { @@ -147,40 +147,19 @@ pub trait HashEngine: Clone + Default { fn n_bytes_hashed(&self) -> usize; } -/// Trait which applies to hashes of all types. -pub trait Hash: - Copy - + Clone - + PartialEq - + Eq - + PartialOrd - + Ord - + hash::Hash - + fmt::Debug - + fmt::Display - + fmt::LowerHex - + convert::AsRef<[u8]> -{ +/// Trait describing hash digests which can be constructed by hashing arbitrary data. +pub trait GeneralHash: Hash { /// A hashing engine which bytes can be serialized into. It is expected /// to implement the `io::Write` trait, and to never return errors under /// any conditions. type Engine: HashEngine; - /// The byte array that represents the hash internally. - type Bytes: hex::FromHex + Copy; - /// Constructs a new engine. fn engine() -> Self::Engine { Self::Engine::default() } /// Produces a hash from the current state of a given engine. fn from_engine(e: Self::Engine) -> Self; - /// Length of the hash, in bytes. - const LEN: usize; - - /// Copies a byte slice into a hash object. - fn from_slice(sl: &[u8]) -> Result; - /// Hashes some bytes. fn hash(data: &[u8]) -> Self { let mut engine = Self::engine(); @@ -200,6 +179,30 @@ pub trait Hash: } Self::from_engine(engine) } +} + +/// Trait which applies to hashes of all types. +pub trait Hash: + Copy + + Clone + + PartialEq + + Eq + + PartialOrd + + Ord + + hash::Hash + + fmt::Debug + + fmt::Display + + fmt::LowerHex + + convert::AsRef<[u8]> +{ + /// The byte array that represents the hash internally. + type Bytes: hex::FromHex + Copy; + + /// Length of the hash, in bytes. + const LEN: usize; + + /// Copies a byte slice into a hash object. + fn from_slice(sl: &[u8]) -> Result; /// Flag indicating whether user-visible serializations of this hash /// should be backward. For some reason Satoshi decided this should be diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 37be2ff8b..6900ae583 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -101,7 +101,7 @@ impl crate::HashEngine for HashEngine { impl Hash { /// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash pub fn hash_again(&self) -> sha256d::Hash { - crate::Hash::from_byte_array(::hash(&self.0).0) + crate::Hash::from_byte_array(::hash(&self.0).0) } /// Computes hash from `bytes` in `const` context. diff --git a/hashes/src/util.rs b/hashes/src/util.rs index 51f25b4a2..87a3b2ab4 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -210,13 +210,13 @@ macro_rules! hash_newtype { } /// Constructs a new engine. - pub fn engine() -> <$hash as $crate::Hash>::Engine { - <$hash as $crate::Hash>::engine() + pub fn engine() -> <$hash as $crate::GeneralHash>::Engine { + <$hash as $crate::GeneralHash>::engine() } /// Produces a hash from the current state of a given engine. - pub fn from_engine(e: <$hash as $crate::Hash>::Engine) -> Self { - Self::from(<$hash as $crate::Hash>::from_engine(e)) + pub fn from_engine(e: <$hash as $crate::GeneralHash>::Engine) -> Self { + Self::from(<$hash as $crate::GeneralHash>::from_engine(e)) } /// Copies a byte slice into a hash object. @@ -279,16 +279,12 @@ macro_rules! hash_newtype { } impl $crate::Hash for $newtype { - type Engine = <$hash as $crate::Hash>::Engine; type Bytes = <$hash as $crate::Hash>::Bytes; const LEN: usize = <$hash as $crate::Hash>::LEN; const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*); - fn engine() -> <$hash as $crate::Hash>::Engine { Self::engine() } - - fn from_engine(e: <$hash as $crate::Hash>::Engine) -> $newtype { Self::from_engine(e) } - + #[inline] fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<$newtype, $crate::FromSliceError> { Self::from_slice(sl) } @@ -300,6 +296,19 @@ macro_rules! hash_newtype { fn from_byte_array(bytes: Self::Bytes) -> Self { Self::from_byte_array(bytes) } } + // To be dropped in the next commit + impl $crate::GeneralHash for $newtype { + type Engine = <$hash as $crate::GeneralHash>::Engine; + + fn engine() -> Self::Engine { + <$hash as $crate::GeneralHash>::engine() + } + + fn from_engine(e: <$hash as $crate::GeneralHash>::Engine) -> $newtype { + Self::from_engine(e) + } + } + impl $crate::_export::_core::str::FromStr for $newtype { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> { diff --git a/hashes/tests/regression.rs b/hashes/tests/regression.rs index 73de4fa3a..c4572a8d0 100644 --- a/hashes/tests/regression.rs +++ b/hashes/tests/regression.rs @@ -2,7 +2,7 @@ use bitcoin_hashes::{ hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24, - Hash as _, HashEngine as _, Hmac, HmacEngine, + GeneralHash as _, HashEngine as _, Hmac, HmacEngine, }; const DATA: &str = "arbitrary data to hash as a regression test";