From 6b7d02e5ae0bb6a3d3ba0fe30da942200a171f70 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 11 Jun 2024 12:39:49 +1000 Subject: [PATCH] Add inherent functions to hashes Currently we have a trait `Hash` that is required for `Hmac`, `Hkdf`, and other use cases. However, it is unegonomic for users who just want to do a simple hash to have to import the trait. Add inherent functions to all hash types including those created with the new wrapper type macros. This patch introduces some duplicate code but we are trying to make progress in the hashes API re-write. We can come back and de-dublicate later. Includes making `to_byte_array`,`from_byte_array`, `as_byte_array`, and `all_zeros` const where easily possible. --- base58/src/lib.rs | 2 +- bitcoin/examples/ecdsa-psbt-simple.rs | 1 - bitcoin/examples/sign-tx-segwit-v0.rs | 1 - bitcoin/examples/sign-tx-taproot.rs | 1 - bitcoin/examples/taproot-psbt-simple.rs | 1 - bitcoin/src/address/mod.rs | 2 +- bitcoin/src/bip152.rs | 2 +- bitcoin/src/bip158.rs | 2 +- bitcoin/src/blockdata/block.rs | 2 +- bitcoin/src/blockdata/constants.rs | 2 +- bitcoin/src/blockdata/script/borrowed.rs | 1 - bitcoin/src/blockdata/script/tests.rs | 1 - .../src/blockdata/script/witness_program.rs | 1 - bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/crypto/key.rs | 2 +- bitcoin/src/crypto/sighash.rs | 2 +- bitcoin/src/hash_types.rs | 1 - bitcoin/src/internal_macros.rs | 3 - bitcoin/src/merkle_tree/block.rs | 1 - bitcoin/src/p2p/message.rs | 2 +- bitcoin/src/p2p/message_blockdata.rs | 3 +- bitcoin/src/pow.rs | 7 -- bitcoin/src/psbt/mod.rs | 2 +- bitcoin/src/psbt/serialize.rs | 2 +- bitcoin/src/sign_message.rs | 4 +- bitcoin/src/taproot/mod.rs | 2 +- bitcoin/tests/serde.rs | 2 +- fuzz/fuzz_targets/hashes/ripemd160.rs | 2 +- fuzz/fuzz_targets/hashes/sha1.rs | 2 +- fuzz/fuzz_targets/hashes/sha256.rs | 2 +- fuzz/fuzz_targets/hashes/sha512.rs | 2 +- fuzz/fuzz_targets/hashes/sha512_256.rs | 2 +- hashes/src/hash160.rs | 4 +- hashes/src/internal_macros.rs | 107 ++++++++++++------ hashes/src/lib.rs | 2 +- hashes/src/ripemd160.rs | 4 +- hashes/src/sha1.rs | 4 +- hashes/src/sha256.rs | 4 +- hashes/src/sha256d.rs | 4 +- hashes/src/sha256t.rs | 70 ++++++++++-- hashes/src/sha384.rs | 2 +- hashes/src/sha512.rs | 4 +- hashes/src/sha512_256.rs | 2 +- hashes/src/siphash24.rs | 2 +- hashes/src/util.rs | 106 ++++++++++++----- 45 files changed, 248 insertions(+), 131 deletions(-) diff --git a/base58/src/lib.rs b/base58/src/lib.rs index 05544c436..d2ce2de5f 100644 --- a/base58/src/lib.rs +++ b/base58/src/lib.rs @@ -35,7 +35,7 @@ use core::{fmt, str}; #[cfg(feature = "std")] pub use std::{string::String, vec::Vec}; -use hashes::{sha256d, Hash}; +use hashes::sha256d; use crate::error::{IncorrectChecksumError, TooShortError}; diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index ac2c17f81..f9ed0feb9 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -26,7 +26,6 @@ use std::collections::BTreeMap; use std::str::FromStr; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; -use bitcoin::hashes::Hash; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; use bitcoin::secp256k1::{Secp256k1, Signing}; diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index 73507f1f7..f861ce21d 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -4,7 +4,6 @@ use std::str::FromStr; -use bitcoin::hashes::Hash; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing}; use bitcoin::sighash::{EcdsaSighashType, SighashCache}; diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 3221c560c..151bd5639 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -4,7 +4,6 @@ use std::str::FromStr; -use bitcoin::hashes::Hash; use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing, Verification}; diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index 48b9cc0a7..7ea13d443 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -24,7 +24,6 @@ use std::collections::BTreeMap; use std::str::FromStr; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; -use bitcoin::hashes::Hash; use bitcoin::key::UntweakedPublicKey; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 9eee27a6e..115d0d90b 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -33,7 +33,7 @@ use core::marker::PhantomData; use core::str::FromStr; use bech32::primitives::hrp::Hrp; -use hashes::{sha256, Hash, HashEngine}; +use hashes::{sha256, HashEngine}; use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use crate::blockdata::constants::{ diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index b20fb8b22..766a82e0e 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -8,7 +8,7 @@ use core::{convert, fmt, mem}; #[cfg(feature = "std")] use std::error; -use hashes::{sha256, siphash24, Hash}; +use hashes::{sha256, siphash24}; use internals::impl_array_newtype; use io::{BufRead, Write}; diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs index 7e54b810c..ee027d7ce 100644 --- a/bitcoin/src/bip158.rs +++ b/bitcoin/src/bip158.rs @@ -40,7 +40,7 @@ use core::cmp::{self, Ordering}; use core::fmt::{self, Display, Formatter}; -use hashes::{sha256d, siphash24, Hash}; +use hashes::{sha256d, siphash24}; use internals::write_err; use io::{BufRead, Write}; diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 9d194d625..2e61ec0f9 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -9,7 +9,7 @@ use core::fmt; -use hashes::{sha256d, Hash, HashEngine}; +use hashes::{sha256d, HashEngine}; use io::{BufRead, Write}; use super::Weight; diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index c652c4bf3..8aa42d22c 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -6,7 +6,7 @@ //! consensus code. In particular, it defines the genesis block and its //! single transaction. -use hashes::{sha256d, Hash}; +use hashes::sha256d; use internals::impl_array_newtype; use crate::blockdata::block::{self, Block}; diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index f07858d21..050e0c578 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -5,7 +5,6 @@ use core::ops::{ Bound, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -use hashes::Hash; use secp256k1::{Secp256k1, Verification}; use super::PushBytes; diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index 965e61890..5fb6da4d6 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -2,7 +2,6 @@ use core::str::FromStr; -use hashes::Hash; use hex_lit::hex; use super::*; diff --git a/bitcoin/src/blockdata/script/witness_program.rs b/bitcoin/src/blockdata/script/witness_program.rs index 9b76becc8..710753acc 100644 --- a/bitcoin/src/blockdata/script/witness_program.rs +++ b/bitcoin/src/blockdata/script/witness_program.rs @@ -9,7 +9,6 @@ use core::fmt; -use hashes::Hash as _; use internals::array_vec::ArrayVec; use secp256k1::{Secp256k1, Verification}; diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 26948bbe3..132d7a71d 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -12,7 +12,7 @@ use core::{cmp, fmt, str}; -use hashes::{sha256d, Hash}; +use hashes::sha256d; use internals::write_err; use io::{BufRead, Write}; use units::parse::{self, PrefixedHexError, UnprefixedHexError}; diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 01a7f7f18..8e5127df3 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -9,7 +9,7 @@ use core::fmt::{self, Write as _}; use core::ops; use core::str::FromStr; -use hashes::{hash160, Hash}; +use hashes::hash160; use hex::{FromHex, HexToArrayError}; use internals::array_vec::ArrayVec; use internals::write_err; diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index a11c770de..f68fb56bc 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -13,7 +13,7 @@ use core::{fmt, str}; -use hashes::{hash_newtype, sha256, sha256d, sha256t_hash_newtype, Hash}; +use hashes::{hash_newtype, sha256, sha256d, sha256t_hash_newtype}; use internals::write_err; use io::Write; diff --git a/bitcoin/src/hash_types.rs b/bitcoin/src/hash_types.rs index a7014583a..58c008a7f 100644 --- a/bitcoin/src/hash_types.rs +++ b/bitcoin/src/hash_types.rs @@ -13,7 +13,6 @@ pub use crate::{ #[cfg(test)] mod tests { use super::*; - use crate::hashes::Hash; use crate::{ LegacySighash, PubkeyHash, ScriptHash, SegwitV0Sighash, TapSighash, WPubkeyHash, WScriptHash, XKeyIdentifier, diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs index b33ac5fc5..2429009fe 100644 --- a/bitcoin/src/internal_macros.rs +++ b/bitcoin/src/internal_macros.rs @@ -185,7 +185,6 @@ macro_rules! impl_hashencode { impl $crate::consensus::Decodable for $hashtype { fn consensus_decode(r: &mut R) -> core::result::Result { - use $crate::hashes::Hash; Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?)) } } @@ -199,14 +198,12 @@ macro_rules! impl_asref_push_bytes { $( impl AsRef<$crate::blockdata::script::PushBytes> for $hashtype { fn as_ref(&self) -> &$crate::blockdata::script::PushBytes { - use $crate::hashes::Hash; self.as_byte_array().into() } } impl From<$hashtype> for $crate::blockdata::script::PushBytesBuf { fn from(hash: $hashtype) -> Self { - use $crate::hashes::Hash; hash.as_byte_array().into() } } diff --git a/bitcoin/src/merkle_tree/block.rs b/bitcoin/src/merkle_tree/block.rs index ed8f26dc7..09915eb6b 100644 --- a/bitcoin/src/merkle_tree/block.rs +++ b/bitcoin/src/merkle_tree/block.rs @@ -40,7 +40,6 @@ use core::fmt; -use hashes::Hash; use io::{BufRead, Write}; use self::MerkleBlockError::*; diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs index 239ba91c8..829e12114 100644 --- a/bitcoin/src/p2p/message.rs +++ b/bitcoin/src/p2p/message.rs @@ -7,7 +7,7 @@ use core::{fmt, iter}; -use hashes::{sha256d, Hash}; +use hashes::sha256d; use io::{BufRead, Write}; use crate::blockdata::{block, transaction}; diff --git a/bitcoin/src/p2p/message_blockdata.rs b/bitcoin/src/p2p/message_blockdata.rs index 05c4d4e01..c61421506 100644 --- a/bitcoin/src/p2p/message_blockdata.rs +++ b/bitcoin/src/p2p/message_blockdata.rs @@ -5,7 +5,7 @@ //! This module describes network messages which are used for passing //! Bitcoin data (blocks and transactions) around. -use hashes::{sha256d, Hash as _}; +use hashes::sha256d; use io::{BufRead, Write}; use crate::blockdata::block::BlockHash; @@ -144,7 +144,6 @@ impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); #[cfg(test)] mod tests { - use hashes::Hash; use hex::test_hex_unwrap as hex; use super::*; diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs index eab1f9e3e..b936644d3 100644 --- a/bitcoin/src/pow.rs +++ b/bitcoin/src/pow.rs @@ -217,7 +217,6 @@ impl Target { /// to the target. #[cfg_attr(all(test, mutate), mutate)] pub fn is_met_by(&self, hash: BlockHash) -> bool { - use hashes::Hash; let hash = U256::from_le_bytes(hash.to_byte_array()); hash <= self.0 } @@ -1784,8 +1783,6 @@ mod tests { #[test] fn compact_target_from_upwards_difficulty_adjustment_using_headers() { - use hashes::Hash; - use crate::block::Version; use crate::constants::genesis_block; use crate::TxMerkleNode; @@ -1809,8 +1806,6 @@ mod tests { #[test] fn compact_target_from_downwards_difficulty_adjustment_using_headers() { - use hashes::Hash; - use crate::block::Version; use crate::TxMerkleNode; let params = Params::new(crate::Network::Signet); @@ -1896,8 +1891,6 @@ mod tests { fn target_is_met_by_for_target_equals_hash() { use std::str::FromStr; - use hashes::Hash; - let hash = BlockHash::from_str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c") .expect("failed to parse block hash"); diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 86f1f9b47..1f12a053e 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1205,7 +1205,7 @@ pub use self::display_from_str::PsbtParseError; #[cfg(test)] mod tests { - use hashes::{hash160, ripemd160, sha256, Hash}; + use hashes::{hash160, ripemd160, sha256}; use hex::{test_hex_unwrap as hex, FromHex}; #[cfg(feature = "rand-std")] use secp256k1::{All, SecretKey}; diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 25e7890fb..972c93a97 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -5,7 +5,7 @@ //! Traits to serialize PSBT values to and from raw bytes //! according to the BIP-174 specification. -use hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use hashes::{hash160, ripemd160, sha256, sha256d}; use secp256k1::XOnlyPublicKey; use super::map::{Input, Map, Output, PsbtSighashType}; diff --git a/bitcoin/src/sign_message.rs b/bitcoin/src/sign_message.rs index 9f7bb524d..3e85a7a8c 100644 --- a/bitcoin/src/sign_message.rs +++ b/bitcoin/src/sign_message.rs @@ -5,7 +5,7 @@ //! This module provides signature related functions including secp256k1 signature recovery when //! library is used with the `secp-recovery` feature. -use hashes::{sha256d, Hash, HashEngine}; +use hashes::{sha256d, HashEngine}; use crate::consensus::{encode, Encodable}; @@ -21,7 +21,7 @@ pub const BITCOIN_SIGNED_MSG_PREFIX: &[u8] = b"\x18Bitcoin Signed Message:\n"; mod message_signing { use core::fmt; - use hashes::{sha256d, Hash}; + use hashes::sha256d; use internals::write_err; use secp256k1::ecdsa::{RecoverableSignature, RecoveryId}; diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index 138c391ce..5fe0a16b1 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -11,7 +11,7 @@ use core::cmp::Reverse; use core::fmt; use core::iter::FusedIterator; -use hashes::{sha256t_hash_newtype, Hash, HashEngine}; +use hashes::{sha256t_hash_newtype, HashEngine}; use internals::write_err; use io::Write; use secp256k1::{Scalar, Secp256k1}; diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index 014012fd3..6bd400bcc 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -30,7 +30,7 @@ use bitcoin::bip32::{ChildNumber, KeySource, Xpriv, Xpub}; use bitcoin::blockdata::locktime::{absolute, relative}; use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::deserialize; -use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::hex::FromHex; use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; diff --git a/fuzz/fuzz_targets/hashes/ripemd160.rs b/fuzz/fuzz_targets/hashes/ripemd160.rs index f311a9b5b..9b0e338ec 100644 --- a/fuzz/fuzz_targets/hashes/ripemd160.rs +++ b/fuzz/fuzz_targets/hashes/ripemd160.rs @@ -1,4 +1,4 @@ -use bitcoin::hashes::{ripemd160, Hash, HashEngine}; +use bitcoin::hashes::{ripemd160, HashEngine}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/fuzz/fuzz_targets/hashes/sha1.rs b/fuzz/fuzz_targets/hashes/sha1.rs index 81b0a2c7f..ab72db64e 100644 --- a/fuzz/fuzz_targets/hashes/sha1.rs +++ b/fuzz/fuzz_targets/hashes/sha1.rs @@ -1,4 +1,4 @@ -use bitcoin::hashes::{sha1, Hash, HashEngine}; +use bitcoin::hashes::{sha1, HashEngine}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/fuzz/fuzz_targets/hashes/sha256.rs b/fuzz/fuzz_targets/hashes/sha256.rs index a81a31e9e..c2397f193 100644 --- a/fuzz/fuzz_targets/hashes/sha256.rs +++ b/fuzz/fuzz_targets/hashes/sha256.rs @@ -1,4 +1,4 @@ -use bitcoin::hashes::{sha256, Hash, HashEngine}; +use bitcoin::hashes::{sha256, HashEngine}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/fuzz/fuzz_targets/hashes/sha512.rs b/fuzz/fuzz_targets/hashes/sha512.rs index b49ef7934..32b1d879b 100644 --- a/fuzz/fuzz_targets/hashes/sha512.rs +++ b/fuzz/fuzz_targets/hashes/sha512.rs @@ -1,4 +1,4 @@ -use bitcoin::hashes::{sha512, Hash, HashEngine}; +use bitcoin::hashes::{sha512, HashEngine}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/fuzz/fuzz_targets/hashes/sha512_256.rs b/fuzz/fuzz_targets/hashes/sha512_256.rs index 30f09302d..44c90960d 100644 --- a/fuzz/fuzz_targets/hashes/sha512_256.rs +++ b/fuzz/fuzz_targets/hashes/sha512_256.rs @@ -1,4 +1,4 @@ -use bitcoin::hashes::{sha512_256, Hash, HashEngine}; +use bitcoin::hashes::{sha512_256, HashEngine}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs index df1efc922..6f2da18fd 100644 --- a/hashes/src/hash160.rs +++ b/hashes/src/hash160.rs @@ -21,8 +21,6 @@ crate::internal_macros::hash_type! { type HashEngine = sha256::HashEngine; fn from_engine(e: HashEngine) -> Hash { - use crate::Hash as _; - let sha2 = sha256::Hash::from_engine(e); let rmd = ripemd160::Hash::hash(&sha2[..]); @@ -92,7 +90,7 @@ mod tests { fn ripemd_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{hash160, Hash}; + use crate::hash160; #[rustfmt::skip] static HASH_BYTES: [u8; 20] = [ diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index bbe40c0a4..2a52157ed 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -63,17 +63,14 @@ pub(crate) use arr_newtype_fmt_impl; /// /// * There must be a free-standing `fn from_engine(HashEngine) -> Hash` in the scope /// * `fn internal_new([u8; $bits / 8]) -> Self` must exist on `Hash` -/// * `fn internal_engine() -> HashEngine` must exist on `Hash` /// /// `from_engine` obviously implements the finalization algorithm. -/// `internal_new` is required so that types with more than one field are constructible. -/// `internal_engine` is required to initialize the engine for given hash type. macro_rules! hash_trait_impls { ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => { impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for Hash<$($gen),*> { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result { - use $crate::{Hash, hex::{FromHex}}; + use $crate::{hex::{FromHex}}; let mut bytes = <[u8; $bits / 8]>::from_hex(s)?; if $reverse { @@ -109,39 +106,21 @@ macro_rules! hash_trait_impls { const LEN: usize = $bits / 8; const DISPLAY_BACKWARD: bool = $reverse; - fn engine() -> Self::Engine { - Self::internal_engine() - } + fn engine() -> HashEngine { Self::engine() } - fn from_engine(e: HashEngine) -> Hash<$($gen),*> { - from_engine(e) - } + fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) } fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result, FromSliceError> { - if sl.len() != $bits / 8 { - Err(FromSliceError{expected: Self::LEN, got: sl.len()}) - } else { - let mut ret = [0; $bits / 8]; - ret.copy_from_slice(sl); - Ok(Self::internal_new(ret)) - } + Self::from_slice(sl) } - fn to_byte_array(self) -> Self::Bytes { - self.0 - } + fn to_byte_array(self) -> Self::Bytes { self.to_byte_array() } - fn as_byte_array(&self) -> &Self::Bytes { - &self.0 - } + fn as_byte_array(&self) -> &Self::Bytes { self.as_byte_array() } - fn from_byte_array(bytes: Self::Bytes) -> Self { - Self::internal_new(bytes) - } + fn from_byte_array(bytes: Self::Bytes) -> Self { Self::from_byte_array(bytes) } - fn all_zeros() -> Self { - Hash::internal_new([0x00; $bits / 8]) - } + fn all_zeros() -> Self { Self::all_zeros() } } } } @@ -149,8 +128,8 @@ pub(crate) use hash_trait_impls; /// Creates a type called `Hash` and implements standard interface for it. /// -/// The created type will have all standard derives, `Hash` impl and implementation of -/// `internal_engine` returning default. The created type has a single field. +/// The created type has a single field and will have all standard derives as well as an +/// implementation of [`crate::Hash`]. /// /// Arguments: /// @@ -169,9 +148,7 @@ macro_rules! hash_type { pub struct Hash([u8; $bits / 8]); impl Hash { - fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) } - - fn internal_engine() -> HashEngine { Default::default() } + const fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) } /// Zero cost conversion between a fixed length byte array shared reference and /// a shared reference to this Hash type. @@ -186,6 +163,68 @@ macro_rules! hash_type { // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] unsafe { &mut *(bytes as *mut _ as *mut Self) } } + + /// Constructs a new engine. + pub fn engine() -> HashEngine { Default::default() } + + /// Produces a hash from the current state of a given engine. + pub fn from_engine(e: HashEngine) -> Hash { from_engine(e) } + + /// Copies a byte slice into a hash object. + pub fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result { + if sl.len() != $bits / 8 { + Err(FromSliceError{expected: $bits / 8, got: sl.len()}) + } else { + let mut ret = [0; $bits / 8]; + ret.copy_from_slice(sl); + Ok(Self::internal_new(ret)) + } + } + + /// Hashes some bytes. + #[allow(clippy::self_named_constructors)] // Hash is a noun and a verb. + pub fn hash(data: &[u8]) -> Self { + use $crate::HashEngine; + + let mut engine = Self::engine(); + engine.input(data); + Self::from_engine(engine) + } + + /// Hashes all the byte slices retrieved from the iterator together. + pub fn hash_byte_chunks(byte_slices: I) -> Self + where + B: AsRef<[u8]>, + I: IntoIterator, + { + use $crate::HashEngine; + + let mut engine = Self::engine(); + for slice in byte_slices { + engine.input(slice.as_ref()); + } + Self::from_engine(engine) + } + + /// Returns the underlying byte array. + pub const fn to_byte_array(self) -> [u8; $bits / 8] { self.0 } + + /// Returns a reference to the underlying byte array. + pub const fn as_byte_array(&self) -> &[u8; $bits / 8] { &self.0 } + + /// Constructs a hash from the underlying byte array. + pub const fn from_byte_array(bytes: [u8; $bits / 8]) -> Self { + Self::internal_new(bytes) + } + + /// Returns an all zero hash. + /// + /// An all zeros hash is a made up construct because there is not a known input that can create + /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's + /// previous blockhash and the coinbase transaction's outpoint txid. + pub const fn all_zeros() -> Self { + Hash::internal_new([0x00; $bits / 8]) + } } #[cfg(feature = "schemars")] diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index ae7c01a1b..df3325bd1 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -249,7 +249,7 @@ impl std::error::Error for FromSliceError {} #[cfg(test)] mod tests { - use crate::{sha256d, Hash}; + use crate::sha256d; hash_newtype! { /// A test newtype diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs index 0a2b2d7cc..4ad076090 100644 --- a/hashes/src/ripemd160.rs +++ b/hashes/src/ripemd160.rs @@ -412,7 +412,7 @@ mod tests { fn test() { use std::convert::TryFrom; - use crate::{ripemd160, Hash, HashEngine}; + use crate::{ripemd160, HashEngine}; #[derive(Clone)] struct Test { @@ -507,7 +507,7 @@ mod tests { fn ripemd_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{ripemd160, Hash}; + use crate::ripemd160; #[rustfmt::skip] static HASH_BYTES: [u8; 20] = [ diff --git a/hashes/src/sha1.rs b/hashes/src/sha1.rs index c2584f9ca..221666301 100644 --- a/hashes/src/sha1.rs +++ b/hashes/src/sha1.rs @@ -129,7 +129,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha1, Hash, HashEngine}; + use crate::{sha1, HashEngine}; #[derive(Clone)] struct Test { @@ -199,7 +199,7 @@ mod tests { fn sha1_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{sha1, Hash}; + use crate::sha1; #[rustfmt::skip] static HASH_BYTES: [u8; 20] = [ diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 8c26ff9ec..37be2ff8b 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -154,7 +154,7 @@ impl Midstate { } /// Unwraps the [`Midstate`] and returns the underlying byte array. - pub fn to_byte_array(self) -> [u8; 32] { self.0 } + pub const fn to_byte_array(self) -> [u8; 32] { self.0 } /// Creates midstate for tagged hashes. /// @@ -815,7 +815,7 @@ impl HashEngine { #[cfg(test)] mod tests { use super::*; - use crate::{sha256, Hash as _, HashEngine}; + use crate::{sha256, HashEngine}; #[test] #[cfg(feature = "alloc")] diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs index 3d3ad5b9b..87a4cde35 100644 --- a/hashes/src/sha256d.rs +++ b/hashes/src/sha256d.rs @@ -16,8 +16,6 @@ crate::internal_macros::hash_type! { type HashEngine = sha256::HashEngine; fn from_engine(e: sha256::HashEngine) -> Hash { - use crate::Hash as _; - let sha2 = sha256::Hash::from_engine(e); let sha2d = sha256::Hash::hash(&sha2[..]); @@ -28,7 +26,7 @@ fn from_engine(e: sha256::HashEngine) -> Hash { #[cfg(test)] mod tests { - use crate::{sha256d, Hash as _}; + use crate::sha256d; #[test] #[cfg(feature = "alloc")] diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs index b4be1db90..0678f3dab 100644 --- a/hashes/src/sha256t.rs +++ b/hashes/src/sha256t.rs @@ -7,7 +7,7 @@ use core::marker::PhantomData; use core::ops::Index; use core::slice::SliceIndex; -use crate::{sha256, FromSliceError}; +use crate::{sha256, FromSliceError, HashEngine as _}; type HashEngine = sha256::HashEngine; @@ -39,8 +39,6 @@ impl schemars::JsonSchema for Hash { impl Hash { fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, Default::default()) } - fn internal_engine() -> HashEngine { T::engine() } - /// Zero cost conversion between a fixed length byte array shared reference and /// a shared reference to this Hash type. pub fn from_bytes_ref(bytes: &[u8; 32]) -> &Self { @@ -54,6 +52,68 @@ impl Hash { // Safety: Sound because Self is #[repr(transparent)] containing [u8; 32] unsafe { &mut *(bytes as *mut _ as *mut Self) } } + + /// Constructs a new engine. + pub fn engine() -> HashEngine { T::engine() } + + /// Produces a hash from the current state of a given engine. + pub fn from_engine(e: HashEngine) -> Hash { + from_engine(e) + } + + /// Copies a byte slice into a hash object. + pub fn from_slice(sl: &[u8]) -> Result, FromSliceError> { + if sl.len() != 32 { + Err(FromSliceError{expected: 32, got: sl.len()}) + } else { + let mut ret = [0; 32]; + ret.copy_from_slice(sl); + Ok(Self::internal_new(ret)) + } + } + + /// Hashes some bytes. + #[allow(clippy::self_named_constructors)] // Hash is a noun and a verb. + pub fn hash(data: &[u8]) -> Self { + use crate::HashEngine; + + let mut engine = Self::engine(); + engine.input(data); + Self::from_engine(engine) + } + + /// Hashes all the byte slices retrieved from the iterator together. + pub fn hash_byte_chunks(byte_slices: I) -> Self + where + B: AsRef<[u8]>, + I: IntoIterator, + { + let mut engine = Self::engine(); + for slice in byte_slices { + engine.input(slice.as_ref()); + } + Self::from_engine(engine) + } + + /// Returns the underlying byte array. + pub fn to_byte_array(self) -> [u8; 32] { self.0 } + + /// Returns a reference to the underlying byte array. + pub fn as_byte_array(&self) -> &[u8; 32] { &self.0 } + + /// Constructs a hash from the underlying byte array. + pub fn from_byte_array(bytes: [u8; 32]) -> Self { + Self::internal_new(bytes) + } + + /// Returns an all zero hash. + /// + /// An all zeros hash is a made up construct because there is not a known input that can create + /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's + /// previous blockhash and the coinbase transaction's outpoint txid. + pub fn all_zeros() -> Self { + Hash::internal_new([0x00; 32]) + } } impl Copy for Hash {} @@ -82,8 +142,6 @@ impl core::hash::Hash for Hash { crate::internal_macros::hash_trait_impls!(256, false, T: Tag); fn from_engine(e: sha256::HashEngine) -> Hash { - use crate::Hash as _; - Hash::from_byte_array(sha256::Hash::from_engine(e).to_byte_array()) } @@ -176,8 +234,6 @@ macro_rules! sha256t_hash_newtype_tag_constructor { #[cfg(test)] mod tests { - #[cfg(feature = "alloc")] - use crate::Hash; use crate::{sha256, sha256t}; const TEST_MIDSTATE: [u8; 32] = [ diff --git a/hashes/src/sha384.rs b/hashes/src/sha384.rs index ce23c3118..ed675ce78 100644 --- a/hashes/src/sha384.rs +++ b/hashes/src/sha384.rs @@ -47,7 +47,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha384, Hash, HashEngine}; + use crate::{sha384, HashEngine}; #[derive(Clone)] struct Test { diff --git a/hashes/src/sha512.rs b/hashes/src/sha512.rs index 904bb4d65..fb3ab5433 100644 --- a/hashes/src/sha512.rs +++ b/hashes/src/sha512.rs @@ -307,7 +307,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha512, Hash, HashEngine}; + use crate::{sha512, HashEngine}; #[derive(Clone)] struct Test { @@ -386,7 +386,7 @@ mod tests { fn sha512_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{sha512, Hash}; + use crate::sha512; #[rustfmt::skip] static HASH_BYTES: [u8; 64] = [ diff --git a/hashes/src/sha512_256.rs b/hashes/src/sha512_256.rs index bcaee9216..73d871621 100644 --- a/hashes/src/sha512_256.rs +++ b/hashes/src/sha512_256.rs @@ -57,7 +57,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha512_256, Hash, HashEngine}; + use crate::{sha512_256, HashEngine}; #[derive(Clone)] struct Test { diff --git a/hashes/src/siphash24.rs b/hashes/src/siphash24.rs index 048ab94ff..ce45cbb37 100644 --- a/hashes/src/siphash24.rs +++ b/hashes/src/siphash24.rs @@ -6,7 +6,7 @@ use core::ops::Index; use core::slice::SliceIndex; use core::{cmp, mem, ptr}; -use crate::{FromSliceError, Hash as _, HashEngine as _}; +use crate::{FromSliceError, HashEngine as _}; crate::internal_macros::hash_type! { 64, diff --git a/hashes/src/util.rs b/hashes/src/util.rs index 79ac4d052..f778f098f 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -192,24 +192,88 @@ macro_rules! hash_newtype { $crate::serde_impl!($newtype, <$newtype as $crate::Hash>::LEN); $crate::borrow_slice_impl!($newtype); + #[allow(unused)] // Private wrapper types may not need all functions. impl $newtype { /// Creates this wrapper type from the inner hash type. - #[allow(unused)] // the user of macro may not need this pub fn from_raw_hash(inner: $hash) -> $newtype { $newtype(inner) } /// Returns the inner hash (sha256, sh256d etc.). - #[allow(unused)] // the user of macro may not need this pub fn to_raw_hash(self) -> $hash { self.0 } /// Returns a reference to the inner hash (sha256, sh256d etc.). - #[allow(unused)] // the user of macro may not need this pub fn as_raw_hash(&self) -> &$hash { &self.0 } + + /// Constructs a new engine. + pub fn engine() -> <$hash as $crate::Hash>::Engine { + <$hash as $crate::Hash>::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)) + } + + /// Copies a byte slice into a hash object. + pub fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<$newtype, $crate::FromSliceError> { + Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?)) + } + + /// Hashes some bytes. + #[allow(unused)] // the user of macro may not need this + pub fn hash(data: &[u8]) -> Self { + use $crate::HashEngine; + + let mut engine = Self::engine(); + engine.input(data); + Self::from_engine(engine) + } + + /// Hashes all the byte slices retrieved from the iterator together. + pub fn hash_byte_chunks(byte_slices: I) -> Self + where + B: AsRef<[u8]>, + I: IntoIterator, + { + use $crate::HashEngine; + + let mut engine = Self::engine(); + for slice in byte_slices { + engine.input(slice.as_ref()); + } + Self::from_engine(engine) + } + + /// Returns the underlying byte array. + pub fn to_byte_array(self) -> <$hash as $crate::Hash>::Bytes { + self.0.to_byte_array() + } + + /// Returns a reference to the underlying byte array. + pub fn as_byte_array(&self) -> &<$hash as $crate::Hash>::Bytes { + self.0.as_byte_array() + } + + /// Constructs a hash from the underlying byte array. + pub fn from_byte_array(bytes: <$hash as $crate::Hash>::Bytes) -> Self { + $newtype(<$hash as $crate::Hash>::from_byte_array(bytes)) + } + + /// Returns an all zero hash. + /// + /// An all zeros hash is a made up construct because there is not a known input that can create + /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's + /// previous blockhash and the coinbase transaction's outpoint txid. + pub fn all_zeros() -> Self { + let zeros = <$hash>::all_zeros(); + $newtype(zeros) + } + } impl $crate::_export::_core::convert::From<$hash> for $newtype { @@ -232,45 +296,27 @@ macro_rules! hash_newtype { const LEN: usize = <$hash as $crate::Hash>::LEN; const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*); - fn engine() -> Self::Engine { - <$hash as $crate::Hash>::engine() - } + fn engine() -> <$hash as $crate::Hash>::Engine { Self::engine() } - fn from_engine(e: Self::Engine) -> Self { - Self::from(<$hash as $crate::Hash>::from_engine(e)) - } + 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> { - Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?)) + Self::from_slice(sl) } - #[inline] - fn from_byte_array(bytes: Self::Bytes) -> Self { - $newtype(<$hash as $crate::Hash>::from_byte_array(bytes)) - } + fn to_byte_array(self) -> Self::Bytes { self.to_byte_array() } - #[inline] - fn to_byte_array(self) -> Self::Bytes { - self.0.to_byte_array() - } + fn as_byte_array(&self) -> &Self::Bytes { self.as_byte_array() } - #[inline] - fn as_byte_array(&self) -> &Self::Bytes { - self.0.as_byte_array() - } + fn from_byte_array(bytes: Self::Bytes) -> Self { Self::from_byte_array(bytes) } - #[inline] - fn all_zeros() -> Self { - let zeros = <$hash>::all_zeros(); - $newtype(zeros) - } + fn all_zeros() -> Self { Self::all_zeros() } } 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> { - use $crate::{Hash, hex::FromHex}; + use $crate::{hex::FromHex}; let mut bytes = <[u8; ::LEN]>::from_hex(s)?; if ::DISPLAY_BACKWARD { @@ -386,7 +432,7 @@ macro_rules! hash_newtype_known_attrs { #[cfg(test)] mod test { - use crate::{sha256, Hash}; + use crate::sha256; #[test] fn hash_as_ref_array() {