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.
This commit is contained in:
Andrew Poelstra 2024-06-16 14:55:45 +00:00
parent 8c4899f2cc
commit 91265977f8
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
4 changed files with 66 additions and 57 deletions

View File

@ -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! {

View File

@ -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::<TestNewtype>().expect("failed to parse hex");
assert_eq!(rinsed, orig)

View File

@ -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<B, I>(byte_slices: I) -> Self
where
B: AsRef<[u8]>,
I: IntoIterator<Item = B>,
{
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))
}
}
}
}

View File

@ -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<B, I>(byte_slices: I) -> Self
where
B: AsRef<[u8]>,
I: IntoIterator<Item = B>,
{
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> {