Merge rust-bitcoin/rust-bitcoin#4010: Add a tagged hash engine
6002ccdc56
Add a tagged sha256t hash engine (Tobin C. Harding)3e8e2e46bf
Use Self::Engine in GeneralHash impl (Tobin C. Harding)a0211906fe
sha256t: Remove standalone from_engine function (Tobin C. Harding)5ce8781162
Remove the Tag::engine method (Tobin C. Harding)ba6425947f
hashes: Use associated cost for pre-tagging (Tobin C. Harding)613fddc82b
Delete deprecated sha256t_hash_newtype macro (Tobin C. Harding) Pull request description: Add a new hash engine to the `sha256t` module and put the tag on it. Note the issue suggests adding the tag to `sha256::HashEngine` but this PR adds a new type to `sha256t` and adds the tag on it. Resolve: #1552 ACKs for top commit: apoelstra: ACK 6002ccdc567b26c69f6b55173f5d11b95b4d6966; successfully ran local tests Kixunil: ACK6002ccdc56
Tree-SHA512: 8a8945bdb89841b87af2eb94073b4d01993338f34a7a3e919bccf4e8edea0fe9d5d2818b6484700b2e72143f315633338692a436149935c5156b77757b025f5e
This commit is contained in:
commit
329aaf452b
|
@ -1564,7 +1564,6 @@ mod sealed {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use hashes::sha256;
|
||||
use hashes::sha256t::Tag;
|
||||
use hex::{DisplayHex, FromHex};
|
||||
use secp256k1::VerifyOnly;
|
||||
|
||||
|
@ -1590,18 +1589,18 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn midstates() {
|
||||
use sha256t::Hash;
|
||||
use sha256t::{Hash, Tag};
|
||||
// test that engine creation roundtrips
|
||||
assert_eq!(tag_engine("TapLeaf").midstate(), TapLeafTag::engine().midstate());
|
||||
assert_eq!(tag_engine("TapBranch").midstate(), TapBranchTag::engine().midstate());
|
||||
assert_eq!(tag_engine("TapTweak").midstate(), TapTweakTag::engine().midstate());
|
||||
assert_eq!(tag_engine("TapSighash").midstate(), TapSighashTag::engine().midstate());
|
||||
assert_eq!(tag_engine("TapLeaf").midstate().unwrap(), TapLeafTag::MIDSTATE);
|
||||
assert_eq!(tag_engine("TapBranch").midstate().unwrap(), TapBranchTag::MIDSTATE);
|
||||
assert_eq!(tag_engine("TapTweak").midstate().unwrap(), TapTweakTag::MIDSTATE);
|
||||
assert_eq!(tag_engine("TapSighash").midstate().unwrap(), TapSighashTag::MIDSTATE);
|
||||
|
||||
// check that hash creation is the same as building into the same engine
|
||||
fn empty_hash(tag_name: &str) -> [u8; 32] {
|
||||
let mut e = tag_engine(tag_name);
|
||||
e.input(&[]);
|
||||
Hash::<TapBranchTag>::from_engine(e).to_byte_array()
|
||||
sha256::Hash::from_engine(e).to_byte_array()
|
||||
}
|
||||
assert_eq!(empty_hash("TapLeaf"), Hash::<TapLeafTag>::hash(&[]).to_byte_array());
|
||||
assert_eq!(empty_hash("TapBranch"), Hash::<TapBranchTag>::hash(&[]).to_byte_array());
|
||||
|
@ -1618,19 +1617,19 @@ mod test {
|
|||
// CHashWriter writer = HasherTapLeaf;
|
||||
// writer.GetSHA256().GetHex()
|
||||
assert_eq!(
|
||||
Hash::<TapLeafTag>::from_engine(TapLeafTag::engine()).to_string(),
|
||||
Hash::<TapLeafTag>::from_engine(Hash::<TapLeafTag>::engine()).to_string(),
|
||||
"5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb"
|
||||
);
|
||||
assert_eq!(
|
||||
Hash::<TapBranchTag>::from_engine(TapBranchTag::engine()).to_string(),
|
||||
Hash::<TapBranchTag>::from_engine(Hash::<TapBranchTag>::engine()).to_string(),
|
||||
"53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf"
|
||||
);
|
||||
assert_eq!(
|
||||
Hash::<TapTweakTag>::from_engine(TapTweakTag::engine()).to_string(),
|
||||
Hash::<TapTweakTag>::from_engine(Hash::<TapTweakTag>::engine()).to_string(),
|
||||
"8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4"
|
||||
);
|
||||
assert_eq!(
|
||||
Hash::<TapSighashTag>::from_engine(TapSighashTag::engine()).to_string(),
|
||||
Hash::<TapSighashTag>::from_engine(Hash::<TapSighashTag>::engine()).to_string(),
|
||||
"dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803"
|
||||
);
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ macro_rules! hash_trait_impls {
|
|||
$crate::impl_debug_only!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
|
||||
|
||||
impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
|
||||
type Engine = HashEngine;
|
||||
type Engine = HashEngine<$($gen),*>;
|
||||
|
||||
fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) }
|
||||
fn from_engine(e: Self::Engine) -> Hash<$($gen),*> { Self::from_engine(e) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
|
|
@ -33,11 +33,7 @@ macro_rules! sha256t_tag {
|
|||
$crate::sha256t_tag_struct!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*);
|
||||
|
||||
impl $crate::sha256t::Tag for $tag {
|
||||
#[inline]
|
||||
fn engine() -> $crate::sha256::HashEngine {
|
||||
const MIDSTATE: $crate::sha256::Midstate = $crate::sha256t_tag_constructor!($constructor, $($tag_value)+);
|
||||
$crate::sha256::HashEngine::from_midstate(MIDSTATE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
use core::cmp;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(doc)]
|
||||
use crate::sha256::Midstate;
|
||||
use crate::{sha256, FromSliceError, HashEngine as _};
|
||||
|
||||
type HashEngine = sha256::HashEngine;
|
||||
|
||||
/// Trait representing a tag that can be used as a context for SHA256t hashes.
|
||||
pub trait Tag {
|
||||
/// Returns a hash engine that is pre-tagged and is ready to be used for the data.
|
||||
fn engine() -> sha256::HashEngine;
|
||||
pub trait Tag: Clone {
|
||||
/// The [`Midstate`] after pre-tagging the hash engine.
|
||||
const MIDSTATE: sha256::Midstate;
|
||||
}
|
||||
|
||||
/// Output of the SHA256t hash function.
|
||||
|
@ -57,10 +57,12 @@ where
|
|||
}
|
||||
|
||||
/// Produces a hash from the current state of a given engine.
|
||||
pub fn from_engine(e: HashEngine) -> Hash<T> { from_engine(e) }
|
||||
pub fn from_engine(e: HashEngine<T>) -> Hash<T> {
|
||||
Hash::from_byte_array(sha256::Hash::from_engine(e.0).to_byte_array())
|
||||
}
|
||||
|
||||
/// Constructs a new engine.
|
||||
pub fn engine() -> HashEngine { T::engine() }
|
||||
pub fn engine() -> HashEngine<T> { HashEngine::default() }
|
||||
|
||||
/// Hashes some bytes.
|
||||
#[allow(clippy::self_named_constructors)] // Hash is a noun and a verb.
|
||||
|
@ -133,111 +135,32 @@ impl<T: Tag> core::hash::Hash for Hash<T> {
|
|||
|
||||
crate::internal_macros::hash_trait_impls!(256, false, T: Tag);
|
||||
|
||||
fn from_engine<T>(e: sha256::HashEngine) -> Hash<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
Hash::from_byte_array(sha256::Hash::from_engine(e).to_byte_array())
|
||||
}
|
||||
/// Engine to compute SHA256t hash function.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HashEngine<T>(sha256::HashEngine, PhantomData<T>);
|
||||
|
||||
/// Macro used to define a newtype tagged hash.
|
||||
///
|
||||
/// This macro creates two types:
|
||||
///
|
||||
/// * a tag struct
|
||||
/// * a hash wrapper
|
||||
///
|
||||
/// The syntax is:
|
||||
///
|
||||
/// ```
|
||||
/// # #[allow(deprecated)] {
|
||||
/// # use bitcoin_hashes::sha256t_hash_newtype;
|
||||
/// sha256t_hash_newtype! {
|
||||
/// /// Optional documentation details here.
|
||||
/// /// Summary is always generated.
|
||||
/// pub struct FooTag = hash_str("foo");
|
||||
///
|
||||
/// /// A foo hash.
|
||||
/// // Direction works just like the hash_newtype! macro.
|
||||
/// #[hash_newtype(backward)]
|
||||
/// pub struct FooHash(_);
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// The structs must be defined in this order - tag first, then hash type. `hash_str` marker
|
||||
/// says the midstate should be generated by hashing the supplied string in a way described in
|
||||
/// BIP-341. Alternatively, you can supply `hash_bytes` to hash raw bytes. If you have the midstate
|
||||
/// already pre-computed and prefer **compiler** performance to readability you may use
|
||||
/// `raw(MIDSTATE_BYTES, HASHED_BYTES_LENGTH)` instead.
|
||||
///
|
||||
/// Both visibility modifiers and attributes are optional and passed to inner structs (excluding
|
||||
/// `#[hash_newtype(...)]`). The attributes suffer same compiler performance limitations as in
|
||||
/// [`hash_newtype`] macro.
|
||||
///
|
||||
/// [`hash_newtype`]: crate::hash_newtype
|
||||
#[macro_export]
|
||||
#[deprecated(since = "0.15.0", note = "use `sha256_tag!` combined with `hash_newtype!` instead")]
|
||||
macro_rules! sha256t_hash_newtype {
|
||||
($(#[$($tag_attr:tt)*])* $tag_vis:vis struct $tag:ident = $constructor:tt($($tag_value:tt)+); $(#[$($hash_attr:tt)*])* $hash_vis:vis struct $hash_name:ident($(#[$($field_attr:tt)*])* _);) => {
|
||||
$crate::sha256t_tag_struct!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*);
|
||||
|
||||
impl $crate::sha256t::Tag for $tag {
|
||||
#[inline]
|
||||
fn engine() -> $crate::sha256::HashEngine {
|
||||
const MIDSTATE: $crate::sha256::Midstate = $crate::sha256t_tag_constructor!($constructor, $($tag_value)+);
|
||||
$crate::sha256::HashEngine::from_midstate(MIDSTATE)
|
||||
impl<T: Tag> Default for HashEngine<T> {
|
||||
fn default() -> Self {
|
||||
let tagged = sha256::HashEngine::from_midstate(T::MIDSTATE);
|
||||
HashEngine(tagged, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
$crate::hash_newtype! {
|
||||
$(#[$($hash_attr)*])*
|
||||
$hash_vis struct $hash_name($(#[$($field_attr)*])* $crate::sha256t::Hash<$tag>);
|
||||
impl<T: Tag> crate::HashEngine for HashEngine<T> {
|
||||
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
||||
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||
}
|
||||
|
||||
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 {
|
||||
<$hash_name as $crate::GeneralHash>::hash(data)
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
{
|
||||
<$hash_name as $crate::GeneralHash>::hash_byte_chunks(byte_slices)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::internal_macros::impl_io_write!(
|
||||
HashEngine<T>,
|
||||
|us: &mut HashEngine<T>, buf| {
|
||||
us.input(buf);
|
||||
Ok(buf.len())
|
||||
},
|
||||
|_us| { Ok(()) },
|
||||
T: crate::sha256t::Tag
|
||||
);
|
||||
|
||||
// Workaround macros being unavailable in attributes.
|
||||
#[doc(hidden)]
|
||||
|
@ -289,11 +212,7 @@ mod tests {
|
|||
pub struct TestHashTag;
|
||||
|
||||
impl sha256t::Tag for TestHashTag {
|
||||
fn engine() -> sha256::HashEngine {
|
||||
// The TapRoot TapLeaf midstate.
|
||||
let midstate = sha256::Midstate::new(TEST_MIDSTATE, 64);
|
||||
sha256::HashEngine::from_midstate(midstate)
|
||||
}
|
||||
const MIDSTATE: sha256::Midstate = sha256::Midstate::new(TEST_MIDSTATE, 64);
|
||||
}
|
||||
|
||||
// We support manually implementing `Tag` and creating a tagged hash from it.
|
||||
|
|
|
@ -40,10 +40,7 @@ impl_regression_test! {
|
|||
pub struct RegHashTag;
|
||||
|
||||
impl sha256t::Tag for RegHashTag {
|
||||
fn engine() -> sha256::HashEngine {
|
||||
let midstate = sha256::Midstate::new([0xab; 32], 64);
|
||||
sha256::HashEngine::from_midstate(midstate)
|
||||
}
|
||||
const MIDSTATE: sha256::Midstate = sha256::Midstate::new([0xab; 32], 64);
|
||||
}
|
||||
|
||||
type RegHash = sha256t::Hash<RegHashTag>;
|
||||
|
|
Loading…
Reference in New Issue