From 9dce0b4b8c6c905fa09585c0814e09b1bdf599b0 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 13 Nov 2024 12:55:40 +1100 Subject: [PATCH] Remove hex string trait bounds from GeneralHash For the `hashes` crate we would like to make `hex` an optional dependency. In preparation for doing so do the following: - Remove the trait bounds from `GeneralHash` - Split the hex/string stuff out of `impl_bytelike_traits` into a separate macro. --- bitcoin/src/bip158.rs | 1 + bitcoin/src/bip32.rs | 1 + bitcoin/src/blockdata/script/mod.rs | 1 + bitcoin/src/crypto/key.rs | 1 + bitcoin/src/crypto/sighash.rs | 2 + hashes/src/hmac.rs | 6 +-- hashes/src/internal_macros.rs | 3 +- hashes/src/lib.rs | 18 ++----- hashes/src/macros.rs | 82 ++++++++++++++++++++--------- hashes/src/sha256t.rs | 2 + primitives/src/block.rs | 1 + primitives/src/merkle_tree.rs | 1 + primitives/src/taproot.rs | 3 ++ primitives/src/transaction.rs | 1 + 14 files changed, 82 insertions(+), 41 deletions(-) diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs index d0a81aa83..55a290730 100644 --- a/bitcoin/src/bip158.rs +++ b/bitcoin/src/bip158.rs @@ -62,6 +62,7 @@ hashes::hash_newtype! { pub struct FilterHeader(sha256d::Hash); } +hashes::impl_hex_for_newtype!(FilterHash, FilterHeader); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(FilterHash, FilterHeader); diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index a3477c765..8f11e67b8 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -58,6 +58,7 @@ hash_newtype! { pub struct XKeyIdentifier(hash160::Hash); } +hashes::impl_hex_for_newtype!(XKeyIdentifier); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(XKeyIdentifier); diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs index be3bf676a..55947e43a 100644 --- a/bitcoin/src/blockdata/script/mod.rs +++ b/bitcoin/src/blockdata/script/mod.rs @@ -93,6 +93,7 @@ hashes::hash_newtype! { pub struct WScriptHash(sha256::Hash); } +hashes::impl_hex_for_newtype!(ScriptHash, WScriptHash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash); diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 753d81ac5..9772f39d4 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -265,6 +265,7 @@ hashes::hash_newtype! { pub struct WPubkeyHash(hash160::Hash); } +hashes::impl_hex_for_newtype!(PubkeyHash, WPubkeyHash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(PubkeyHash, WPubkeyHash); diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index f5a59e897..d5651de35 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -56,6 +56,7 @@ hash_newtype! { pub struct SegwitV0Sighash(sha256d::Hash); } +hashes::impl_hex_for_newtype!(LegacySighash, SegwitV0Sighash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(LegacySighash, SegwitV0Sighash); @@ -85,6 +86,7 @@ hash_newtype! { pub struct TapSighash(sha256t::Hash); } +hashes::impl_hex_for_newtype!(TapSighash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TapSighash); diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs index a14a54455..283bdc7d0 100644 --- a/hashes/src/hmac.rs +++ b/hashes/src/hmac.rs @@ -96,15 +96,15 @@ 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) } } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 9702444a3..f74f49d49 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -20,7 +20,8 @@ /// `from_engine` obviously implements the finalization algorithm. macro_rules! hash_trait_impls { ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => { - $crate::impl_bytelike_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*); + $crate::impl_bytelike_traits!(Hash, { $bits / 8 } $(, $gen: $gent)*); + $crate::impl_hex_string_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*); impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> { type Engine = HashEngine; diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index 11acde41d..972c7bf57 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -126,7 +126,7 @@ pub mod serde_macros { } } -use core::{convert, fmt, hash}; +use core::{convert, hash}; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -261,20 +261,10 @@ pub trait GeneralHash: Hash { /// 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]> + Copy + Clone + PartialEq + Eq + PartialOrd + Ord + hash::Hash + convert::AsRef<[u8]> { /// The byte array that represents the hash internally. - type Bytes: hex::FromHex + Copy + IsByteArray; + type Bytes: Copy + IsByteArray; /// Length of the hash, in bytes. const LEN: usize = Self::Bytes::LEN; @@ -335,6 +325,8 @@ mod tests { struct TestNewtype2(sha256d::Hash); } + crate::impl_hex_for_newtype!(TestNewtype, TestNewtype2); + #[test] #[cfg(feature = "alloc")] fn newtype_fmt_roundtrip() { diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs index 3501a564c..b8207f6f2 100644 --- a/hashes/src/macros.rs +++ b/hashes/src/macros.rs @@ -4,6 +4,7 @@ //! //! - [`sha256t_tag`](crate::sha256t_tag) //! - [`hash_newtype`](crate::hash_newtype) +//! - [`impl_hex_for_newtype`](crate::impl_hex_for_newtype) //! - [`impl_serde_for_newtype`](crate::impl_serde_for_newtype) /// Macro used to define a tag. @@ -133,7 +134,7 @@ macro_rules! hash_newtype { $({ $($type_attrs)* })* } - $crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, <$newtype as $crate::Hash>::DISPLAY_BACKWARD); + $crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN }); #[allow(unused)] // Private wrapper types may not need all functions. impl $newtype { @@ -194,17 +195,67 @@ macro_rules! hash_newtype { }; } +/// Implements string functions using hex for a new type crated with [`crate::hash_newtype`] macro. +/// +/// Implements: +/// +/// * `str::FromStr` +/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative` +/// * `fmt::{Display, Debug}` by calling `LowerHex` +#[macro_export] +macro_rules! impl_hex_for_newtype { + ($($newtype:ident),*) => { + $( + $crate::impl_hex_string_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, { <$newtype as $crate::Hash>::DISPLAY_BACKWARD }); + )* + } +} + /// Adds trait impls to a bytelike type. /// /// Implements: /// +/// * `AsRef[u8; $len]` +/// * `AsRef[u8]` +/// * `Borrow<[u8; $len]>` +/// * `Borrow<[u8]>` +/// +/// ## Parameters +/// +/// * `ty` - The bytelike type to implement the traits on. +/// * `$len` - The number of bytes this type has. +/// * `$gen: $gent` - generic type(s) and trait bound(s). +#[doc(hidden)] +#[macro_export] +macro_rules! impl_bytelike_traits { + ($ty:ident, $len:expr $(, $gen:ident: $gent:ident)*) => { + impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> { + #[inline] + fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() } + } + + impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> { + #[inline] + fn as_ref(&self) -> &[u8] { self.as_byte_array() } + } + + impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8; { $len }]> for $ty<$($gen),*> { + fn borrow(&self) -> &[u8; { $len }] { self.as_byte_array() } + } + + impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> { + fn borrow(&self) -> &[u8] { self.as_byte_array() } + } + } +} + +/// Adds hex string trait impls to a bytelike type using hex. +/// +/// Implements: +/// /// * `str::FromStr` /// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`. /// * `fmt::{Display, Debug}` by calling `LowerHex` -/// * `AsRef[u8; $len]` -/// * `AsRef[u8]` -/// * `Borrow<[u8; $len]>` -/// * `Borrow<[u8]>` /// /// Requires: /// @@ -223,7 +274,7 @@ macro_rules! hash_newtype { /// [`hex-conservative`]: #[doc(hidden)] #[macro_export] -macro_rules! impl_bytelike_traits { +macro_rules! impl_hex_string_traits { ($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => { impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for $ty<$($gen),*> { type Err = $crate::hex::HexToArrayError; @@ -245,24 +296,6 @@ macro_rules! impl_bytelike_traits { const LENGTH: usize = ($len); // parens required due to rustc parser weirdness } } - - impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> { - #[inline] - fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() } - } - - impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> { - #[inline] - fn as_ref(&self) -> &[u8] { self.as_byte_array() } - } - - impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8; { $len }]> for $ty<$($gen),*> { - fn borrow(&self) -> &[u8; { $len }] { self.as_byte_array() } - } - - impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> { - fn borrow(&self) -> &[u8] { self.as_byte_array() } - } } } @@ -509,6 +542,7 @@ mod test { /// Test hash. struct TestHash(crate::sha256d::Hash); } + crate::impl_hex_for_newtype!(TestHash); impl TestHash { fn all_zeros() -> Self { Self::from_byte_array([0; 32]) } diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs index 1b4188d2c..262a4ec3f 100644 --- a/hashes/src/sha256t.rs +++ b/hashes/src/sha256t.rs @@ -321,6 +321,7 @@ mod tests { #[hash_newtype(backward)] struct NewTypeHashBackward(sha256t::Hash); } + crate::impl_hex_for_newtype!(NewTypeHashBackward); #[test] #[cfg(feature = "alloc")] @@ -344,6 +345,7 @@ mod tests { #[hash_newtype(forward)] struct NewTypeHashForward(sha256t::Hash); } + crate::impl_hex_for_newtype!(NewTypeHashForward); #[test] #[cfg(feature = "alloc")] diff --git a/primitives/src/block.rs b/primitives/src/block.rs index 4fdd9d605..9edea1470 100644 --- a/primitives/src/block.rs +++ b/primitives/src/block.rs @@ -162,6 +162,7 @@ hashes::hash_newtype! { pub struct WitnessCommitment(sha256d::Hash); } +hashes::impl_hex_for_newtype!(BlockHash, WitnessCommitment); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(BlockHash, WitnessCommitment); diff --git a/primitives/src/merkle_tree.rs b/primitives/src/merkle_tree.rs index 5f3c5de71..18a16a5a9 100644 --- a/primitives/src/merkle_tree.rs +++ b/primitives/src/merkle_tree.rs @@ -11,5 +11,6 @@ hashes::hash_newtype! { pub struct WitnessMerkleNode(sha256d::Hash); } +hashes::impl_hex_for_newtype!(TxMerkleNode, WitnessMerkleNode); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode); diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index b85ac5617..743980dcd 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -18,6 +18,7 @@ hash_newtype! { pub struct TapLeafHash(sha256t::Hash); } +hashes::impl_hex_for_newtype!(TapLeafHash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TapLeafHash); @@ -32,6 +33,7 @@ hash_newtype! { pub struct TapNodeHash(sha256t::Hash); } +hashes::impl_hex_for_newtype!(TapNodeHash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TapNodeHash); @@ -46,6 +48,7 @@ hash_newtype! { pub struct TapTweakHash(sha256t::Hash); } +hashes::impl_hex_for_newtype!(TapTweakHash); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TapTweakHash); diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index dbfc3c896..68b7d2393 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -476,6 +476,7 @@ hashes::hash_newtype! { pub struct Wtxid(sha256d::Hash); } +hashes::impl_hex_for_newtype!(Txid, Wtxid); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(Txid, Wtxid);