From 91265977f864e67a510820700a39a15b8d6d0c95 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 16 Jun 2024 14:55:45 +0000 Subject: [PATCH] hashes: stop exposing engine/from_engine and general hashing methods in hash_newtype We manually implement these methods (and the GeneralHash trait) on newtypes around sha256t::Hash, because tagged hashes require a bit more work. In the next commit (API diff) you will see that this affects two hashes, which are the only things that appear green in the diff. Users who want to implement their own engine/from_engine types now need to do it on their own. We do this for the non-Taproot sighash types in `bitcoin` (though only privately) to demonstrate that it's possible. --- bitcoin/src/crypto/sighash.rs | 11 +++----- hashes/src/lib.rs | 12 ++++++-- hashes/src/sha256t.rs | 52 +++++++++++++++++++++++++++++++++++ hashes/src/util.rs | 48 -------------------------------- 4 files changed, 66 insertions(+), 57 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 7d5fb0154..b23d52488 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -58,16 +58,13 @@ impl_message_from_hash!(SegwitV0Sighash); // Implement private engine/from_engine methods for use within this module; // but outside of it, it should not be possible to construct these hash // types from arbitrary data (except by casting via to/from_byte_array). -// -// These will be uncommented in the next commit; in this one they cause -// "duplicate definition" errors against the `hash_newtype!` macro. impl LegacySighash { - //fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } - //fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } + fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } + fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } } impl SegwitV0Sighash { - //fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } - //fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } + fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } + fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } } sha256t_hash_newtype! { diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index 9623819bd..09a57d410 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -255,9 +255,17 @@ mod tests { struct TestNewtype2(sha256d::Hash); } + #[rustfmt::skip] + const DUMMY: TestNewtype = TestNewtype::from_byte_array([ + 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, + 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, 0x8a, + 0x14, 0x25, 0x36, 0x47, 0x58, 0x69, 0x7a, 0x8b, + 0x15, 0x26, 0x37, 0x48, 0x59, 0x6a, 0x7b, 0x8c, + ]); + #[test] fn convert_newtypes() { - let h1 = TestNewtype::hash(&[]); + let h1 = DUMMY; let h2: TestNewtype2 = h1.to_raw_hash().into(); assert_eq!(&h1[..], &h2[..]); @@ -268,7 +276,7 @@ mod tests { #[test] fn newtype_fmt_roundtrip() { - let orig = TestNewtype::hash(&[]); + let orig = DUMMY; let hex = format!("{}", orig); let rinsed = hex.parse::().expect("failed to parse hex"); assert_eq!(rinsed, orig) diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs index 20924d633..3a924e136 100644 --- a/hashes/src/sha256t.rs +++ b/hashes/src/sha256t.rs @@ -207,6 +207,58 @@ macro_rules! sha256t_hash_newtype { $(#[$($hash_attr)*])* $hash_vis struct $hash_name($(#[$($field_attr)*])* $crate::sha256t::Hash<$tag>); } + + impl $hash_name { + /// Constructs a new engine. + #[allow(unused)] // the user of macro may not need this + pub fn engine() -> <$hash_name as $crate::GeneralHash>::Engine { + <$hash_name as $crate::GeneralHash>::engine() + } + + /// Produces a hash from the current state of a given engine. + #[allow(unused)] // the user of macro may not need this + pub fn from_engine(e: <$hash_name as $crate::GeneralHash>::Engine) -> Self { + <$hash_name as $crate::GeneralHash>::from_engine(e) + } + + /// 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. + #[allow(unused)] // the user of macro may not need this + 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) + } + } + + impl $crate::GeneralHash for $hash_name { + type Engine = <$crate::sha256t::Hash<$tag> as $crate::GeneralHash>::Engine; + + fn engine() -> Self::Engine { + <$crate::sha256t::Hash<$tag> as $crate::GeneralHash>::engine() + } + + fn from_engine(e: Self::Engine) -> $hash_name { + Self::from(<$crate::sha256t::Hash<$tag> as $crate::GeneralHash>::from_engine(e)) + } + } } } diff --git a/hashes/src/util.rs b/hashes/src/util.rs index 87a3b2ab4..746828b7c 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -209,46 +209,11 @@ macro_rules! hash_newtype { &self.0 } - /// Constructs a new 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::GeneralHash>::Engine) -> Self { - Self::from(<$hash as $crate::GeneralHash>::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 const fn to_byte_array(self) -> <$hash as $crate::Hash>::Bytes { self.0.to_byte_array() @@ -296,19 +261,6 @@ 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> {