diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 3895c239b..0cabd2ec1 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -13,14 +13,14 @@ 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 io::Write; use crate::address::script_pubkey::ScriptExt as _; use crate::consensus::{encode, Encodable}; 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::{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)) } } -sha256t_hash_newtype! { +sha256t_tag! { pub struct TapSighashTag = hash_str("TapSighash"); +} +hash_newtype! { /// Taproot-tagged hash with tag \"TapSighash\". /// /// This hash type is used for computing Taproot signature hash." - pub struct TapSighash(_); + pub struct TapSighash(sha256t::Hash); } 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) } /// Computes the leaf hash for this `ScriptPath`. pub fn leaf_hash(&self) -> TapLeafHash { - let mut enc = TapLeafHash::engine(); + let mut enc = sha256t::Hash::::engine(); self.leaf_version .to_consensus() @@ -330,7 +332,8 @@ impl<'s> ScriptPath<'s> { .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::::from_engine(enc); + TapLeafHash::from_byte_array(inner.to_byte_array()) } } @@ -588,9 +591,9 @@ impl> SighashCache { /// Encodes the BIP341 signing data for any flag type into a given object implementing the /// [`io::Write`] trait. /// - /// In order to sign, the data written by this function must be hashed using a tagged hash. This - /// can be achieved by using the [`TapSighash::engine()`] function, writing to the engine, then - /// finalizing the hash with [`TapSighash::from_engine()`]. + /// In order to sign, the data written by this function must be hashed using a tagged hash. For + /// example usage see [`Self::taproot_signature_hash`] and + /// [`Self::taproot_key_spend_signature_hash`]. pub fn taproot_encode_signing_data_to>( &mut self, writer: &mut W, @@ -719,7 +722,7 @@ impl> SighashCache { leaf_hash_code_separator: Option<(TapLeafHash, u32)>, sighash_type: TapSighashType, ) -> Result { - let mut enc = TapSighash::engine(); + let mut enc = sha256t::Hash::::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -729,7 +732,8 @@ impl> SighashCache { sighash_type, ) .map_err(SigningDataError::unwrap_sighash)?; - Ok(TapSighash::from_engine(enc)) + let inner = sha256t::Hash::::from_engine(enc); + Ok(TapSighash::from_byte_array(inner.to_byte_array())) } /// Computes the BIP341 sighash for a key spend. @@ -739,7 +743,7 @@ impl> SighashCache { prevouts: &Prevouts, sighash_type: TapSighashType, ) -> Result { - let mut enc = TapSighash::engine(); + let mut enc = sha256t::Hash::::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -749,7 +753,8 @@ impl> SighashCache { sighash_type, ) .map_err(SigningDataError::unwrap_sighash)?; - Ok(TapSighash::from_engine(enc)) + let inner = sha256t::Hash::::from_engine(enc); + Ok(TapSighash::from_byte_array(inner.to_byte_array())) } /// Computes the BIP341 sighash for a script spend. @@ -763,7 +768,7 @@ impl> SighashCache { leaf_hash: S, sighash_type: TapSighashType, ) -> Result { - let mut enc = TapSighash::engine(); + let mut enc = sha256t::Hash::::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -773,7 +778,8 @@ impl> SighashCache { sighash_type, ) .map_err(SigningDataError::unwrap_sighash)?; - Ok(TapSighash::from_engine(enc)) + let inner = sha256t::Hash::::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 @@ -1540,9 +1546,9 @@ mod tests { fn test_tap_sighash_hash() { let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000"); let expected = hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0"); - let mut enc = TapSighash::engine(); + let mut enc = sha256t::Hash::::engine(); enc.input(&bytes); - let hash = TapSighash::from_engine(enc); + let hash = sha256t::Hash::::from_engine(enc); assert_eq!(expected, hash.to_byte_array()); } diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index eb68be30a..b85837a84 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -11,7 +11,7 @@ use core::cmp::Reverse; use core::fmt; use core::iter::FusedIterator; -use hashes::{sha256t_hash_newtype, HashEngine}; +use hashes::{hash_newtype, sha256t_tag, sha256t, HashEngine}; use internals::write_err; use io::Write; use secp256k1::{Scalar, Secp256k1}; @@ -29,31 +29,37 @@ pub use crate::crypto::taproot::{SigFromSliceError, Signature}; pub use merkle_branch::TaprootMerkleBranch; // Taproot test vectors from BIP-341 state the hashes without any reversing -sha256t_hash_newtype! { +sha256t_tag! { pub struct TapLeafTag = hash_str("TapLeaf"); +} +hash_newtype! { /// Taproot-tagged hash with tag \"TapLeaf\". /// /// This is used for computing tapscript script spend hash. - pub struct TapLeafHash(_); + pub struct TapLeafHash(sha256t::Hash); } -sha256t_hash_newtype! { +sha256t_tag! { pub struct TapBranchTag = hash_str("TapBranch"); +} +hash_newtype! { /// Tagged hash used in Taproot trees. /// /// See BIP-340 for tagging rules. - pub struct TapNodeHash(_); + pub struct TapNodeHash(sha256t::Hash); } -sha256t_hash_newtype! { +sha256t_tag! { pub struct TapTweakTag = hash_str("TapTweak"); +} +hash_newtype! { /// Taproot-tagged hash with tag \"TapTweak\". /// /// This hash type is used while computing the tweaked public key. - pub struct TapTweakHash(_); + pub struct TapTweakHash(sha256t::Hash); } impl TapTweakHash { @@ -63,7 +69,7 @@ impl TapTweakHash { internal_key: UntweakedPublicKey, merkle_root: Option, ) -> TapTweakHash { - let mut eng = TapTweakHash::engine(); + let mut eng = sha256t::Hash::::engine(); // always hash the key eng.input(&internal_key.serialize()); if let Some(h) = merkle_root { @@ -71,7 +77,8 @@ impl TapTweakHash { } else { // nothing to hash } - TapTweakHash::from_engine(eng) + let inner = sha256t::Hash::::from_engine(eng); + TapTweakHash::from_byte_array(inner.to_byte_array()) } /// Converts a `TapTweakHash` into a `Scalar` ready for use with key tweaking API. @@ -84,10 +91,11 @@ impl TapTweakHash { impl TapLeafHash { /// Computes the leaf hash from components. pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash { - let mut eng = TapLeafHash::engine(); + let mut eng = sha256t::Hash::::engine(); ver.to_consensus().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::::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 /// whether the left node was the one hashed first. fn combine_node_hashes(a: TapNodeHash, b: TapNodeHash) -> (TapNodeHash, bool) { - let mut eng = TapNodeHash::engine(); + let mut eng = sha256t::Hash::::engine(); if a < b { eng.input(a.as_ref()); eng.input(b.as_ref()); @@ -116,7 +124,8 @@ impl TapNodeHash { eng.input(b.as_ref()); eng.input(a.as_ref()); }; - (TapNodeHash::from_engine(eng), a < b) + let inner = sha256t::Hash::::from_engine(eng); + (TapNodeHash::from_byte_array(inner.to_byte_array()), a < b) } /// Assumes the given 32 byte array as hidden [`TapNodeHash`]. @@ -1545,7 +1554,7 @@ mod test { use super::*; use crate::script::ScriptBufExt as _; - use crate::sighash::{TapSighash, TapSighashTag}; + use crate::sighash::TapSighashTag; use crate::{Address, KnownHrp}; extern crate serde_json; @@ -1566,6 +1575,7 @@ mod test { #[test] fn test_midstates() { + use sha256t::Hash; // test that engine creation roundtrips assert_eq!(tag_engine("TapLeaf").midstate(), TapLeafTag::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] { let mut e = tag_engine(tag_name); e.input(&[]); - TapNodeHash::from_engine(e).to_byte_array() + Hash::::from_engine(e).to_byte_array() } - assert_eq!(empty_hash("TapLeaf"), TapLeafHash::hash(&[]).to_byte_array()); - assert_eq!(empty_hash("TapBranch"), TapNodeHash::hash(&[]).to_byte_array()); - assert_eq!(empty_hash("TapTweak"), TapTweakHash::hash(&[]).to_byte_array()); - assert_eq!(empty_hash("TapSighash"), TapSighash::hash(&[]).to_byte_array()); + assert_eq!(empty_hash("TapLeaf"), Hash::::hash(&[]).to_byte_array()); + assert_eq!(empty_hash("TapBranch"), Hash::::hash(&[]).to_byte_array()); + assert_eq!(empty_hash("TapTweak"), Hash::::hash(&[]).to_byte_array()); + assert_eq!(empty_hash("TapSighash"), Hash::::hash(&[]).to_byte_array()); } #[test] fn test_vectors_core() { //! Test vectors taken from Core + use sha256t::Hash; // uninitialized writers // CHashWriter writer = HasherTapLeaf; // writer.GetSHA256().GetHex() assert_eq!( - TapLeafHash::from_engine(TapLeafTag::engine()).to_string(), + Hash::::from_engine(TapLeafTag::engine()).to_string(), "5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb" ); assert_eq!( - TapNodeHash::from_engine(TapBranchTag::engine()).to_string(), + Hash::::from_engine(TapBranchTag::engine()).to_string(), "53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf" ); assert_eq!( - TapTweakHash::from_engine(TapTweakTag::engine()).to_string(), + Hash::::from_engine(TapTweakTag::engine()).to_string(), "8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4" ); assert_eq!( - TapSighash::from_engine(TapSighashTag::engine()).to_string(), + Hash::::from_engine(TapSighashTag::engine()).to_string(), "dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803" ); @@ -1614,19 +1625,19 @@ mod test { // writer.GetSHA256().GetHex() // Note that Core writes the 0 length prefix when an empty vector is written. assert_eq!( - TapLeafHash::hash(&[0]).to_string(), + Hash::::hash(&[0]).to_string(), "ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829" ); assert_eq!( - TapNodeHash::hash(&[0]).to_string(), + Hash::::hash(&[0]).to_string(), "92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d" ); assert_eq!( - TapTweakHash::hash(&[0]).to_string(), + Hash::::hash(&[0]).to_string(), "cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e" ); assert_eq!( - TapSighash::hash(&[0]).to_string(), + Hash::::hash(&[0]).to_string(), "c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd" ); } diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 15b7faee1..3ebd6916e 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -14,7 +14,7 @@ use hex::DisplayHex; use crate::{sha256d, HashEngine as _}; #[cfg(doc)] -use crate::{sha256t, sha256t_hash_newtype}; +use crate::{sha256t, sha256t_tag}; crate::internal_macros::hash_type! { 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, /// 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`] -/// macro which will create the midstate for you in const context and use it for tagged hashing. +/// For BIP-340 support we provide the [`sha256t`] module, and the [`sha256t_tag`] macro which will +/// create the midstate for you in const context. #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Midstate { /// Raw bytes of the midstate i.e., the already-hashed contents of the hash engine. diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs index 2a0a24870..98c4c76cb 100644 --- a/hashes/src/sha256t.rs +++ b/hashes/src/sha256t.rs @@ -157,6 +157,41 @@ where 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. /// /// This macro creates two types: @@ -195,14 +230,15 @@ where /// /// [`hash_newtype`]: crate::hash_newtype #[macro_export] +#[deprecated(since = "0.0.0-NEXT-RELEASE", note = "use `sha256_tag!` combined with `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)*])* _);) => { - $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 { #[inline] 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) } } @@ -266,7 +302,7 @@ macro_rules! sha256t_hash_newtype { // Workaround macros being unavailable in attributes. #[doc(hidden)] #[macro_export] -macro_rules! sha256t_hash_newtype_tag { +macro_rules! sha256t_tag_struct { ($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => { #[doc = "The tag used for [`"] #[doc = $name] @@ -279,7 +315,7 @@ macro_rules! sha256t_hash_newtype_tag { #[doc(hidden)] #[macro_export] -macro_rules! sha256t_hash_newtype_tag_constructor { +macro_rules! sha256t_tag_constructor { (hash_str, $value:expr) => { $crate::sha256::Midstate::hash_tag($value.as_bytes()) }; @@ -330,35 +366,45 @@ mod tests { assert_eq!(TestHash::hash(&[0]).to_string(), HASH_ZERO_FORWARD); } - // We also provide a macro to create the tag and the hash type. - sha256t_hash_newtype! { + // We also provide macros to create the tag and the hash type. + sha256t_tag! { /// Test detailed explanation. struct NewTypeTagBackward = raw(TEST_MIDSTATE, 64); - + } + hash_newtype! { /// A test hash. #[hash_newtype(backward)] - struct NewTypeHashBackward(_); + struct NewTypeHashBackward(sha256t::Hash); } #[test] #[cfg(feature = "alloc")] fn macro_created_sha256t_hash_type_backward() { - assert_eq!(NewTypeHashBackward::hash(&[0]).to_string(), HASH_ZERO_BACKWARD); + let inner = sha256t::Hash::::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::::hash(&[0]).to_string(), HASH_ZERO_FORWARD); } // We also provide a macro to create the tag and the hash type. - sha256t_hash_newtype! { + sha256t_tag! { /// Test detailed explanation. struct NewTypeTagForward = raw(TEST_MIDSTATE, 64); - + } + hash_newtype! { /// A test hash. #[hash_newtype(forward)] - struct NewTypeHashForward(_); + struct NewTypeHashForward(sha256t::Hash); } #[test] #[cfg(feature = "alloc")] fn macro_created_sha256t_hash_type_prints_forward() { - assert_eq!(NewTypeHashForward::hash(&[0]).to_string(), HASH_ZERO_FORWARD); + let inner = sha256t::Hash::::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::::hash(&[0]).to_string(), HASH_ZERO_FORWARD); } }