Reduce API surface of tagged wrapped hash types

Recently we made it so that wrapper types created with `hash_newtype`
were not general purpose hash types i.e., one could not easily hash
arbitrary data into them. We would like to do the same for tagged
wrapped hash types.

In `hashes` do:

- Create a new macro `sha256t_tag` that does just the tag/engine stuff
out of the `sha256t_hash_newtype` macro.
- Deprecate the `sha256t_hash_newtype` macro.

In `bitcoin` do:

- Use a combination of `sha256t_tag` and `hash_newtype` to create tagged
wrapped hash types.

Note that we do not add private helper functions `engine` and
`from_engine` to the tagged wrapper types as we do for legacy/segwit in
`sighash`. Can be done later if wanted/needed.
This commit is contained in:
Tobin C. Harding 2024-08-20 10:11:57 +10:00
parent c061d936fb
commit 39f7dcb816
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
4 changed files with 123 additions and 60 deletions

View File

@ -13,14 +13,14 @@
use core::{fmt, str}; use core::{fmt, str};
use hashes::{hash_newtype, sha256, sha256d, sha256t_hash_newtype}; use hashes::{hash_newtype, sha256, sha256d, sha256t, sha256t_tag};
use internals::write_err; use internals::write_err;
use io::Write; use io::Write;
use crate::address::script_pubkey::ScriptExt as _; use crate::address::script_pubkey::ScriptExt as _;
use crate::consensus::{encode, Encodable}; use crate::consensus::{encode, Encodable};
use crate::prelude::{Borrow, BorrowMut, String, ToOwned, Vec}; use crate::prelude::{Borrow, BorrowMut, String, ToOwned, Vec};
use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX}; use crate::taproot::{LeafVersion, TapLeafHash, TapLeafTag, TAPROOT_ANNEX_PREFIX};
use crate::witness::Witness; use crate::witness::Witness;
use crate::{transaction, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut}; use crate::{transaction, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
@ -68,13 +68,15 @@ impl SegwitV0Sighash {
fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) }
} }
sha256t_hash_newtype! { sha256t_tag! {
pub struct TapSighashTag = hash_str("TapSighash"); pub struct TapSighashTag = hash_str("TapSighash");
}
hash_newtype! {
/// Taproot-tagged hash with tag \"TapSighash\". /// Taproot-tagged hash with tag \"TapSighash\".
/// ///
/// This hash type is used for computing Taproot signature hash." /// This hash type is used for computing Taproot signature hash."
pub struct TapSighash(_); pub struct TapSighash(sha256t::Hash<TapSighashTag>);
} }
impl_message_from_hash!(TapSighash); impl_message_from_hash!(TapSighash);
@ -322,7 +324,7 @@ impl<'s> ScriptPath<'s> {
pub fn with_defaults(script: &'s Script) -> Self { Self::new(script, LeafVersion::TapScript) } pub fn with_defaults(script: &'s Script) -> Self { Self::new(script, LeafVersion::TapScript) }
/// Computes the leaf hash for this `ScriptPath`. /// Computes the leaf hash for this `ScriptPath`.
pub fn leaf_hash(&self) -> TapLeafHash { pub fn leaf_hash(&self) -> TapLeafHash {
let mut enc = TapLeafHash::engine(); let mut enc = sha256t::Hash::<TapLeafTag>::engine();
self.leaf_version self.leaf_version
.to_consensus() .to_consensus()
@ -330,7 +332,8 @@ impl<'s> ScriptPath<'s> {
.expect("writing to hash enging should never fail"); .expect("writing to hash enging should never fail");
self.script.consensus_encode(&mut enc).expect("writing to hash enging should never fail"); self.script.consensus_encode(&mut enc).expect("writing to hash enging should never fail");
TapLeafHash::from_engine(enc) let inner = sha256t::Hash::<TapLeafTag>::from_engine(enc);
TapLeafHash::from_byte_array(inner.to_byte_array())
} }
} }
@ -588,9 +591,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// Encodes the BIP341 signing data for any flag type into a given object implementing the /// Encodes the BIP341 signing data for any flag type into a given object implementing the
/// [`io::Write`] trait. /// [`io::Write`] trait.
/// ///
/// In order to sign, the data written by this function must be hashed using a tagged hash. This /// In order to sign, the data written by this function must be hashed using a tagged hash. For
/// can be achieved by using the [`TapSighash::engine()`] function, writing to the engine, then /// example usage see [`Self::taproot_signature_hash`] and
/// finalizing the hash with [`TapSighash::from_engine()`]. /// [`Self::taproot_key_spend_signature_hash`].
pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>( pub fn taproot_encode_signing_data_to<W: Write + ?Sized, T: Borrow<TxOut>>(
&mut self, &mut self,
writer: &mut W, writer: &mut W,
@ -719,7 +722,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
leaf_hash_code_separator: Option<(TapLeafHash, u32)>, leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
sighash_type: TapSighashType, sighash_type: TapSighashType,
) -> Result<TapSighash, TaprootError> { ) -> Result<TapSighash, TaprootError> {
let mut enc = TapSighash::engine(); let mut enc = sha256t::Hash::<TapSighashTag>::engine();
self.taproot_encode_signing_data_to( self.taproot_encode_signing_data_to(
&mut enc, &mut enc,
input_index, input_index,
@ -729,7 +732,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
sighash_type, sighash_type,
) )
.map_err(SigningDataError::unwrap_sighash)?; .map_err(SigningDataError::unwrap_sighash)?;
Ok(TapSighash::from_engine(enc)) let inner = sha256t::Hash::<TapSighashTag>::from_engine(enc);
Ok(TapSighash::from_byte_array(inner.to_byte_array()))
} }
/// Computes the BIP341 sighash for a key spend. /// Computes the BIP341 sighash for a key spend.
@ -739,7 +743,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
prevouts: &Prevouts<T>, prevouts: &Prevouts<T>,
sighash_type: TapSighashType, sighash_type: TapSighashType,
) -> Result<TapSighash, TaprootError> { ) -> Result<TapSighash, TaprootError> {
let mut enc = TapSighash::engine(); let mut enc = sha256t::Hash::<TapSighashTag>::engine();
self.taproot_encode_signing_data_to( self.taproot_encode_signing_data_to(
&mut enc, &mut enc,
input_index, input_index,
@ -749,7 +753,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
sighash_type, sighash_type,
) )
.map_err(SigningDataError::unwrap_sighash)?; .map_err(SigningDataError::unwrap_sighash)?;
Ok(TapSighash::from_engine(enc)) let inner = sha256t::Hash::<TapSighashTag>::from_engine(enc);
Ok(TapSighash::from_byte_array(inner.to_byte_array()))
} }
/// Computes the BIP341 sighash for a script spend. /// Computes the BIP341 sighash for a script spend.
@ -763,7 +768,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
leaf_hash: S, leaf_hash: S,
sighash_type: TapSighashType, sighash_type: TapSighashType,
) -> Result<TapSighash, TaprootError> { ) -> Result<TapSighash, TaprootError> {
let mut enc = TapSighash::engine(); let mut enc = sha256t::Hash::<TapSighashTag>::engine();
self.taproot_encode_signing_data_to( self.taproot_encode_signing_data_to(
&mut enc, &mut enc,
input_index, input_index,
@ -773,7 +778,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
sighash_type, sighash_type,
) )
.map_err(SigningDataError::unwrap_sighash)?; .map_err(SigningDataError::unwrap_sighash)?;
Ok(TapSighash::from_engine(enc)) let inner = sha256t::Hash::<TapSighashTag>::from_engine(enc);
Ok(TapSighash::from_byte_array(inner.to_byte_array()))
} }
/// Encodes the BIP143 signing data for any flag type into a given object implementing the /// Encodes the BIP143 signing data for any flag type into a given object implementing the
@ -1540,9 +1546,9 @@ mod tests {
fn test_tap_sighash_hash() { fn test_tap_sighash_hash() {
let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000"); let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000");
let expected = hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0"); let expected = hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0");
let mut enc = TapSighash::engine(); let mut enc = sha256t::Hash::<TapSighashTag>::engine();
enc.input(&bytes); enc.input(&bytes);
let hash = TapSighash::from_engine(enc); let hash = sha256t::Hash::<TapSighashTag>::from_engine(enc);
assert_eq!(expected, hash.to_byte_array()); assert_eq!(expected, hash.to_byte_array());
} }

View File

@ -11,7 +11,7 @@ use core::cmp::Reverse;
use core::fmt; use core::fmt;
use core::iter::FusedIterator; use core::iter::FusedIterator;
use hashes::{sha256t_hash_newtype, HashEngine}; use hashes::{hash_newtype, sha256t_tag, sha256t, HashEngine};
use internals::write_err; use internals::write_err;
use io::Write; use io::Write;
use secp256k1::{Scalar, Secp256k1}; use secp256k1::{Scalar, Secp256k1};
@ -29,31 +29,37 @@ pub use crate::crypto::taproot::{SigFromSliceError, Signature};
pub use merkle_branch::TaprootMerkleBranch; pub use merkle_branch::TaprootMerkleBranch;
// Taproot test vectors from BIP-341 state the hashes without any reversing // Taproot test vectors from BIP-341 state the hashes without any reversing
sha256t_hash_newtype! { sha256t_tag! {
pub struct TapLeafTag = hash_str("TapLeaf"); pub struct TapLeafTag = hash_str("TapLeaf");
}
hash_newtype! {
/// Taproot-tagged hash with tag \"TapLeaf\". /// Taproot-tagged hash with tag \"TapLeaf\".
/// ///
/// This is used for computing tapscript script spend hash. /// This is used for computing tapscript script spend hash.
pub struct TapLeafHash(_); pub struct TapLeafHash(sha256t::Hash<TapLeafTag>);
} }
sha256t_hash_newtype! { sha256t_tag! {
pub struct TapBranchTag = hash_str("TapBranch"); pub struct TapBranchTag = hash_str("TapBranch");
}
hash_newtype! {
/// Tagged hash used in Taproot trees. /// Tagged hash used in Taproot trees.
/// ///
/// See BIP-340 for tagging rules. /// See BIP-340 for tagging rules.
pub struct TapNodeHash(_); pub struct TapNodeHash(sha256t::Hash<TapBranchTag>);
} }
sha256t_hash_newtype! { sha256t_tag! {
pub struct TapTweakTag = hash_str("TapTweak"); pub struct TapTweakTag = hash_str("TapTweak");
}
hash_newtype! {
/// Taproot-tagged hash with tag \"TapTweak\". /// Taproot-tagged hash with tag \"TapTweak\".
/// ///
/// This hash type is used while computing the tweaked public key. /// This hash type is used while computing the tweaked public key.
pub struct TapTweakHash(_); pub struct TapTweakHash(sha256t::Hash<TapTweakTag>);
} }
impl TapTweakHash { impl TapTweakHash {
@ -63,7 +69,7 @@ impl TapTweakHash {
internal_key: UntweakedPublicKey, internal_key: UntweakedPublicKey,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> TapTweakHash { ) -> TapTweakHash {
let mut eng = TapTweakHash::engine(); let mut eng = sha256t::Hash::<TapTweakTag>::engine();
// always hash the key // always hash the key
eng.input(&internal_key.serialize()); eng.input(&internal_key.serialize());
if let Some(h) = merkle_root { if let Some(h) = merkle_root {
@ -71,7 +77,8 @@ impl TapTweakHash {
} else { } else {
// nothing to hash // nothing to hash
} }
TapTweakHash::from_engine(eng) let inner = sha256t::Hash::<TapTweakTag>::from_engine(eng);
TapTweakHash::from_byte_array(inner.to_byte_array())
} }
/// Converts a `TapTweakHash` into a `Scalar` ready for use with key tweaking API. /// Converts a `TapTweakHash` into a `Scalar` ready for use with key tweaking API.
@ -84,10 +91,11 @@ impl TapTweakHash {
impl TapLeafHash { impl TapLeafHash {
/// Computes the leaf hash from components. /// Computes the leaf hash from components.
pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash { pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash {
let mut eng = TapLeafHash::engine(); let mut eng = sha256t::Hash::<TapLeafTag>::engine();
ver.to_consensus().consensus_encode(&mut eng).expect("engines don't error"); ver.to_consensus().consensus_encode(&mut eng).expect("engines don't error");
script.consensus_encode(&mut eng).expect("engines don't error"); script.consensus_encode(&mut eng).expect("engines don't error");
TapLeafHash::from_engine(eng) let inner = sha256t::Hash::<TapTweakTag>::from_engine(eng);
TapLeafHash::from_byte_array(inner.to_byte_array())
} }
} }
@ -108,7 +116,7 @@ impl TapNodeHash {
/// Computes branch hash given two hashes of the nodes underneath it and returns /// Computes branch hash given two hashes of the nodes underneath it and returns
/// whether the left node was the one hashed first. /// whether the left node was the one hashed first.
fn combine_node_hashes(a: TapNodeHash, b: TapNodeHash) -> (TapNodeHash, bool) { fn combine_node_hashes(a: TapNodeHash, b: TapNodeHash) -> (TapNodeHash, bool) {
let mut eng = TapNodeHash::engine(); let mut eng = sha256t::Hash::<TapBranchTag>::engine();
if a < b { if a < b {
eng.input(a.as_ref()); eng.input(a.as_ref());
eng.input(b.as_ref()); eng.input(b.as_ref());
@ -116,7 +124,8 @@ impl TapNodeHash {
eng.input(b.as_ref()); eng.input(b.as_ref());
eng.input(a.as_ref()); eng.input(a.as_ref());
}; };
(TapNodeHash::from_engine(eng), a < b) let inner = sha256t::Hash::<TapBranchTag>::from_engine(eng);
(TapNodeHash::from_byte_array(inner.to_byte_array()), a < b)
} }
/// Assumes the given 32 byte array as hidden [`TapNodeHash`]. /// Assumes the given 32 byte array as hidden [`TapNodeHash`].
@ -1545,7 +1554,7 @@ mod test {
use super::*; use super::*;
use crate::script::ScriptBufExt as _; use crate::script::ScriptBufExt as _;
use crate::sighash::{TapSighash, TapSighashTag}; use crate::sighash::TapSighashTag;
use crate::{Address, KnownHrp}; use crate::{Address, KnownHrp};
extern crate serde_json; extern crate serde_json;
@ -1566,6 +1575,7 @@ mod test {
#[test] #[test]
fn test_midstates() { fn test_midstates() {
use sha256t::Hash;
// test that engine creation roundtrips // test that engine creation roundtrips
assert_eq!(tag_engine("TapLeaf").midstate(), TapLeafTag::engine().midstate()); assert_eq!(tag_engine("TapLeaf").midstate(), TapLeafTag::engine().midstate());
assert_eq!(tag_engine("TapBranch").midstate(), TapBranchTag::engine().midstate()); assert_eq!(tag_engine("TapBranch").midstate(), TapBranchTag::engine().midstate());
@ -1576,35 +1586,36 @@ mod test {
fn empty_hash(tag_name: &str) -> [u8; 32] { fn empty_hash(tag_name: &str) -> [u8; 32] {
let mut e = tag_engine(tag_name); let mut e = tag_engine(tag_name);
e.input(&[]); e.input(&[]);
TapNodeHash::from_engine(e).to_byte_array() Hash::<TapBranchTag>::from_engine(e).to_byte_array()
} }
assert_eq!(empty_hash("TapLeaf"), TapLeafHash::hash(&[]).to_byte_array()); assert_eq!(empty_hash("TapLeaf"), Hash::<TapLeafTag>::hash(&[]).to_byte_array());
assert_eq!(empty_hash("TapBranch"), TapNodeHash::hash(&[]).to_byte_array()); assert_eq!(empty_hash("TapBranch"), Hash::<TapBranchTag>::hash(&[]).to_byte_array());
assert_eq!(empty_hash("TapTweak"), TapTweakHash::hash(&[]).to_byte_array()); assert_eq!(empty_hash("TapTweak"), Hash::<TapTweakTag>::hash(&[]).to_byte_array());
assert_eq!(empty_hash("TapSighash"), TapSighash::hash(&[]).to_byte_array()); assert_eq!(empty_hash("TapSighash"), Hash::<TapSighashTag>::hash(&[]).to_byte_array());
} }
#[test] #[test]
fn test_vectors_core() { fn test_vectors_core() {
//! Test vectors taken from Core //! Test vectors taken from Core
use sha256t::Hash;
// uninitialized writers // uninitialized writers
// CHashWriter writer = HasherTapLeaf; // CHashWriter writer = HasherTapLeaf;
// writer.GetSHA256().GetHex() // writer.GetSHA256().GetHex()
assert_eq!( assert_eq!(
TapLeafHash::from_engine(TapLeafTag::engine()).to_string(), Hash::<TapLeafTag>::from_engine(TapLeafTag::engine()).to_string(),
"5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb" "5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb"
); );
assert_eq!( assert_eq!(
TapNodeHash::from_engine(TapBranchTag::engine()).to_string(), Hash::<TapBranchTag>::from_engine(TapBranchTag::engine()).to_string(),
"53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf" "53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf"
); );
assert_eq!( assert_eq!(
TapTweakHash::from_engine(TapTweakTag::engine()).to_string(), Hash::<TapTweakTag>::from_engine(TapTweakTag::engine()).to_string(),
"8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4" "8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4"
); );
assert_eq!( assert_eq!(
TapSighash::from_engine(TapSighashTag::engine()).to_string(), Hash::<TapSighashTag>::from_engine(TapSighashTag::engine()).to_string(),
"dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803" "dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803"
); );
@ -1614,19 +1625,19 @@ mod test {
// writer.GetSHA256().GetHex() // writer.GetSHA256().GetHex()
// Note that Core writes the 0 length prefix when an empty vector is written. // Note that Core writes the 0 length prefix when an empty vector is written.
assert_eq!( assert_eq!(
TapLeafHash::hash(&[0]).to_string(), Hash::<TapLeafTag>::hash(&[0]).to_string(),
"ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829" "ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829"
); );
assert_eq!( assert_eq!(
TapNodeHash::hash(&[0]).to_string(), Hash::<TapBranchTag>::hash(&[0]).to_string(),
"92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d" "92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d"
); );
assert_eq!( assert_eq!(
TapTweakHash::hash(&[0]).to_string(), Hash::<TapTweakTag>::hash(&[0]).to_string(),
"cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e" "cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e"
); );
assert_eq!( assert_eq!(
TapSighash::hash(&[0]).to_string(), Hash::<TapSighashTag>::hash(&[0]).to_string(),
"c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd" "c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd"
); );
} }

View File

@ -14,7 +14,7 @@ use hex::DisplayHex;
use crate::{sha256d, HashEngine as _}; use crate::{sha256d, HashEngine as _};
#[cfg(doc)] #[cfg(doc)]
use crate::{sha256t, sha256t_hash_newtype}; use crate::{sha256t, sha256t_tag};
crate::internal_macros::hash_type! { crate::internal_macros::hash_type! {
256, 256,
@ -169,8 +169,8 @@ impl Hash {
/// fixed 64-byte prefix, it makes sense to hash the prefix once, store the midstate as a constant, /// fixed 64-byte prefix, it makes sense to hash the prefix once, store the midstate as a constant,
/// and hash any future data starting from the constant rather than from a fresh hash engine. /// and hash any future data starting from the constant rather than from a fresh hash engine.
/// ///
/// For BIP-340 support we provide the [`sha256t`] module, and the [`sha256t_hash_newtype`] /// For BIP-340 support we provide the [`sha256t`] module, and the [`sha256t_tag`] macro which will
/// macro which will create the midstate for you in const context and use it for tagged hashing. /// create the midstate for you in const context.
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Midstate { pub struct Midstate {
/// Raw bytes of the midstate i.e., the already-hashed contents of the hash engine. /// Raw bytes of the midstate i.e., the already-hashed contents of the hash engine.

View File

@ -157,6 +157,41 @@ where
Hash::from_byte_array(sha256::Hash::from_engine(e).to_byte_array()) Hash::from_byte_array(sha256::Hash::from_engine(e).to_byte_array())
} }
/// Macro used to define a tag.
///
/// Defines new struct and implements `Tag` for it.
///
/// The syntax is:
///
/// ```
/// # use bitcoin_hashes::sha256t_tag;
/// sha256t_tag! {
/// /// Optional documentation details here.
/// /// Summary is always generated.
/// pub struct FooTag = hash_str("foo");
/// }
/// ```
///
/// The `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, note that HASHED_BYTES_LENGTH must
/// be a multiple of 64.
#[macro_export]
macro_rules! sha256t_tag {
($(#[$($tag_attr:tt)*])* $tag_vis:vis struct $tag:ident = $constructor:tt($($tag_value: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)
}
}
}
}
/// Macro used to define a newtype tagged hash. /// Macro used to define a newtype tagged hash.
/// ///
/// This macro creates two types: /// This macro creates two types:
@ -195,14 +230,15 @@ where
/// ///
/// [`hash_newtype`]: crate::hash_newtype /// [`hash_newtype`]: crate::hash_newtype
#[macro_export] #[macro_export]
#[deprecated(since = "0.0.0-NEXT-RELEASE", note = "use `sha256_tag!` combined with `hash_newtype!`")]
macro_rules! sha256t_hash_newtype { 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)*])* _);) => { ($(#[$($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_hash_newtype_tag!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*); $crate::sha256t_tag_struct!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*);
impl $crate::sha256t::Tag for $tag { impl $crate::sha256t::Tag for $tag {
#[inline] #[inline]
fn engine() -> $crate::sha256::HashEngine { fn engine() -> $crate::sha256::HashEngine {
const MIDSTATE: $crate::sha256::Midstate = $crate::sha256t_hash_newtype_tag_constructor!($constructor, $($tag_value)+); const MIDSTATE: $crate::sha256::Midstate = $crate::sha256t_tag_constructor!($constructor, $($tag_value)+);
$crate::sha256::HashEngine::from_midstate(MIDSTATE) $crate::sha256::HashEngine::from_midstate(MIDSTATE)
} }
} }
@ -266,7 +302,7 @@ macro_rules! sha256t_hash_newtype {
// Workaround macros being unavailable in attributes. // Workaround macros being unavailable in attributes.
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! sha256t_hash_newtype_tag { macro_rules! sha256t_tag_struct {
($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => { ($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => {
#[doc = "The tag used for [`"] #[doc = "The tag used for [`"]
#[doc = $name] #[doc = $name]
@ -279,7 +315,7 @@ macro_rules! sha256t_hash_newtype_tag {
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! sha256t_hash_newtype_tag_constructor { macro_rules! sha256t_tag_constructor {
(hash_str, $value:expr) => { (hash_str, $value:expr) => {
$crate::sha256::Midstate::hash_tag($value.as_bytes()) $crate::sha256::Midstate::hash_tag($value.as_bytes())
}; };
@ -330,35 +366,45 @@ mod tests {
assert_eq!(TestHash::hash(&[0]).to_string(), HASH_ZERO_FORWARD); assert_eq!(TestHash::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
} }
// We also provide a macro to create the tag and the hash type. // We also provide macros to create the tag and the hash type.
sha256t_hash_newtype! { sha256t_tag! {
/// Test detailed explanation. /// Test detailed explanation.
struct NewTypeTagBackward = raw(TEST_MIDSTATE, 64); struct NewTypeTagBackward = raw(TEST_MIDSTATE, 64);
}
hash_newtype! {
/// A test hash. /// A test hash.
#[hash_newtype(backward)] #[hash_newtype(backward)]
struct NewTypeHashBackward(_); struct NewTypeHashBackward(sha256t::Hash<NewTypeTagBackward>);
} }
#[test] #[test]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn macro_created_sha256t_hash_type_backward() { fn macro_created_sha256t_hash_type_backward() {
assert_eq!(NewTypeHashBackward::hash(&[0]).to_string(), HASH_ZERO_BACKWARD); let inner = sha256t::Hash::<NewTypeTagBackward>::hash(&[0]);
let hash = NewTypeHashBackward::from_byte_array(inner.to_byte_array());
assert_eq!(hash.to_string(), HASH_ZERO_BACKWARD);
// Note one has to use the new wrapper type to get backwards formatting.
assert_eq!(sha256t::Hash::<NewTypeTagBackward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
} }
// We also provide a macro to create the tag and the hash type. // We also provide a macro to create the tag and the hash type.
sha256t_hash_newtype! { sha256t_tag! {
/// Test detailed explanation. /// Test detailed explanation.
struct NewTypeTagForward = raw(TEST_MIDSTATE, 64); struct NewTypeTagForward = raw(TEST_MIDSTATE, 64);
}
hash_newtype! {
/// A test hash. /// A test hash.
#[hash_newtype(forward)] #[hash_newtype(forward)]
struct NewTypeHashForward(_); struct NewTypeHashForward(sha256t::Hash<NewTypeTagForward>);
} }
#[test] #[test]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn macro_created_sha256t_hash_type_prints_forward() { fn macro_created_sha256t_hash_type_prints_forward() {
assert_eq!(NewTypeHashForward::hash(&[0]).to_string(), HASH_ZERO_FORWARD); let inner = sha256t::Hash::<NewTypeTagForward>::hash(&[0]);
let hash = NewTypeHashForward::from_byte_array(inner.to_byte_array());
assert_eq!(hash.to_string(), HASH_ZERO_FORWARD);
// We can also just use the `sha256t::Hash` type directly.
assert_eq!(sha256t::Hash::<NewTypeTagForward>::hash(&[0]).to_string(), HASH_ZERO_FORWARD);
} }
} }