Merge rust-bitcoin/rust-bitcoin#1773: Make `sha256t_hash_newtype!` evocative of the output.
91f45a214f
Replace hardcoded values with compile-time hashing (Martin Habovstiak)095b7958dd
Make `sha256t_hash_newtype!` evocative of the output. (Martin Habovstiak) Pull request description: The Rust API guidelines state that macros should be evocative of the output, which is a sensible recommendation. We already had this for `hash_newtype!` macro but didn't for sha256t version. This changes the macro to have this syntax: ```rust sha256t_hash_newtype! { // Order of these structs is fixed. /// Optional documentation details here. Summary is auto-generated. /*pub*/ struct Tag = raw(MIDSTATE_BYTES, LEN); /// Documentation here #[hash_newtype(forward)] // optional, default is backward /*pub*/ struct HashType(/* attributes allowed here */ _); } ``` Closes https://github.com/rust-bitcoin/rust-bitcoin/issues/1427 Depends on #1769 How do you like the syntax? Is weird `struct Foo = bar(..);` acceptable? ACKs for top commit: tcharding: ACK91f45a214f
apoelstra: ACK91f45a214f
Tree-SHA512: f6b555b20311a4c1cb097bc296c92459f6fbe16ba102d8c977eb2383dbcae3cc8ffce32e3cb771e7e22197fda26379971aa4feaadc5e2e70d37fa690ae8b8859
This commit is contained in:
commit
350b413e59
|
@ -33,13 +33,6 @@ pub(crate) const UINT256_ONE: [u8; 32] = [
|
||||||
0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The SHA-256 midstate value for the [`TapSighash`].
|
|
||||||
pub(crate) const MIDSTATE_TAPSIGHASH: [u8; 32] = [
|
|
||||||
245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188,
|
|
||||||
120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159,
|
|
||||||
];
|
|
||||||
// f504a425d7f8783b1363868ae3e556586eee945dbc7888dd02a6e2c31873fe9f
|
|
||||||
|
|
||||||
macro_rules! impl_thirty_two_byte_hash {
|
macro_rules! impl_thirty_two_byte_hash {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl secp256k1::ThirtyTwoByteHash for $ty {
|
impl secp256k1::ThirtyTwoByteHash for $ty {
|
||||||
|
@ -61,16 +54,15 @@ hash_newtype! {
|
||||||
impl_thirty_two_byte_hash!(LegacySighash);
|
impl_thirty_two_byte_hash!(LegacySighash);
|
||||||
impl_thirty_two_byte_hash!(SegwitV0Sighash);
|
impl_thirty_two_byte_hash!(SegwitV0Sighash);
|
||||||
|
|
||||||
sha256t_hash_newtype!(
|
sha256t_hash_newtype! {
|
||||||
TapSighash,
|
pub struct TapSighashTag = hash_str("TapSighash");
|
||||||
TapSighashTag,
|
|
||||||
MIDSTATE_TAPSIGHASH,
|
|
||||||
64,
|
|
||||||
doc = "Taproot-tagged hash with tag \"TapSighash\".
|
|
||||||
|
|
||||||
This hash type is used for computing taproot signature hash.",
|
/// Taproot-tagged hash with tag \"TapSighash\".
|
||||||
forward
|
///
|
||||||
);
|
/// This hash type is used for computing taproot signature hash."
|
||||||
|
#[hash_newtype(forward)]
|
||||||
|
pub struct TapSighash(_);
|
||||||
|
}
|
||||||
|
|
||||||
impl_thirty_two_byte_hash!(TapSighash);
|
impl_thirty_two_byte_hash!(TapSighash);
|
||||||
|
|
||||||
|
|
|
@ -21,43 +21,32 @@ pub use crate::crypto::taproot::{Error, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{io, Script, ScriptBuf};
|
use crate::{io, Script, ScriptBuf};
|
||||||
|
|
||||||
/// The SHA-256 midstate value for the TapLeaf hash.
|
|
||||||
const MIDSTATE_TAPLEAF: [u8; 32] = [
|
|
||||||
156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108,
|
|
||||||
71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
|
|
||||||
];
|
|
||||||
// 9ce0e4e67c116c3938b3caf2c30f5089d3f3936c47636e607db33eeaddc6f0c9
|
|
||||||
|
|
||||||
/// The SHA-256 midstate value for the TapBranch hash.
|
|
||||||
const MIDSTATE_TAPBRANCH: [u8; 32] = [
|
|
||||||
35, 168, 101, 169, 184, 164, 13, 167, 151, 124, 30, 4, 196, 158, 36, 111, 181, 190, 19, 118,
|
|
||||||
157, 36, 201, 183, 181, 131, 181, 212, 168, 210, 38, 210,
|
|
||||||
];
|
|
||||||
// 23a865a9b8a40da7977c1e04c49e246fb5be13769d24c9b7b583b5d4a8d226d2
|
|
||||||
|
|
||||||
/// The SHA-256 midstate value for the TapTweak hash.
|
|
||||||
const MIDSTATE_TAPTWEAK: [u8; 32] = [
|
|
||||||
209, 41, 162, 243, 112, 28, 101, 93, 101, 131, 182, 195, 185, 65, 151, 39, 149, 244, 226, 50,
|
|
||||||
148, 253, 84, 244, 162, 174, 141, 133, 71, 202, 89, 11,
|
|
||||||
];
|
|
||||||
// d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b
|
|
||||||
|
|
||||||
// Taproot test vectors from BIP-341 state the hashes without any reversing
|
// Taproot test vectors from BIP-341 state the hashes without any reversing
|
||||||
#[rustfmt::skip]
|
sha256t_hash_newtype! {
|
||||||
sha256t_hash_newtype!(TapLeafHash, TapLeafTag, MIDSTATE_TAPLEAF, 64,
|
pub struct TapLeafTag = hash_str("TapLeaf");
|
||||||
doc="Taproot-tagged hash with tag \"TapLeaf\".
|
|
||||||
|
|
||||||
This is used for computing tapscript script spend hash.", forward
|
/// Taproot-tagged hash with tag \"TapLeaf\".
|
||||||
);
|
///
|
||||||
#[rustfmt::skip]
|
/// This is used for computing tapscript script spend hash.
|
||||||
sha256t_hash_newtype!(TapNodeHash, TapBranchTag, MIDSTATE_TAPBRANCH, 64,
|
#[hash_newtype(forward)]
|
||||||
doc="Tagged hash used in taproot trees; see BIP-340 for tagging rules", forward
|
pub struct TapLeafHash(_);
|
||||||
);
|
|
||||||
#[rustfmt::skip]
|
pub struct TapBranchTag = hash_str("TapBranch");
|
||||||
sha256t_hash_newtype!(TapTweakHash, TapTweakTag, MIDSTATE_TAPTWEAK, 64,
|
|
||||||
doc="Taproot-tagged hash with tag \"TapTweak\".
|
/// Tagged hash used in taproot trees.
|
||||||
This hash type is used while computing the tweaked public key", forward
|
///
|
||||||
);
|
/// See BIP-340 for tagging rules.
|
||||||
|
#[hash_newtype(forward)]
|
||||||
|
pub struct TapNodeHash(_);
|
||||||
|
|
||||||
|
pub struct TapTweakTag = hash_str("TapTweak");
|
||||||
|
|
||||||
|
/// Taproot-tagged hash with tag \"TapTweak\".
|
||||||
|
///
|
||||||
|
/// This hash type is used while computing the tweaked public key.
|
||||||
|
#[hash_newtype(forward)]
|
||||||
|
pub struct TapTweakHash(_);
|
||||||
|
}
|
||||||
|
|
||||||
impl TapTweakHash {
|
impl TapTweakHash {
|
||||||
/// Creates a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where
|
/// Creates a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where
|
||||||
|
@ -1595,14 +1584,6 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_midstates() {
|
fn test_midstates() {
|
||||||
use crate::crypto::sighash::MIDSTATE_TAPSIGHASH;
|
|
||||||
|
|
||||||
// check midstate against hard-coded values
|
|
||||||
assert_eq!(MIDSTATE_TAPLEAF, tag_engine("TapLeaf").midstate().to_byte_array());
|
|
||||||
assert_eq!(MIDSTATE_TAPBRANCH, tag_engine("TapBranch").midstate().to_byte_array());
|
|
||||||
assert_eq!(MIDSTATE_TAPTWEAK, tag_engine("TapTweak").midstate().to_byte_array());
|
|
||||||
assert_eq!(MIDSTATE_TAPSIGHASH, tag_engine("TapSighash").midstate().to_byte_array());
|
|
||||||
|
|
||||||
// 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());
|
||||||
|
|
|
@ -133,14 +133,12 @@ mod tests {
|
||||||
/// A hash tagged with `$name`.
|
/// A hash tagged with `$name`.
|
||||||
pub type TestHash = sha256t::Hash<TestHashTag>;
|
pub type TestHash = sha256t::Hash<TestHashTag>;
|
||||||
|
|
||||||
sha256t_hash_newtype!(
|
sha256t_hash_newtype! {
|
||||||
NewTypeHash,
|
struct NewTypeTag = raw(TEST_MIDSTATE, 64);
|
||||||
NewTypeTag,
|
|
||||||
TEST_MIDSTATE,
|
#[hash_newtype(backward)]
|
||||||
64,
|
struct NewTypeHash(_);
|
||||||
doc = "test hash",
|
}
|
||||||
backward
|
|
||||||
);
|
|
||||||
static HASH_BYTES: [u8; 32] = [
|
static HASH_BYTES: [u8; 32] = [
|
||||||
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6,
|
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6,
|
||||||
0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c,
|
0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c,
|
||||||
|
|
|
@ -151,7 +151,7 @@ impl Midstate {
|
||||||
const DISPLAY_BACKWARD: bool = true;
|
const DISPLAY_BACKWARD: bool = true;
|
||||||
|
|
||||||
/// Construct a new [`Midstate`] from the inner value.
|
/// Construct a new [`Midstate`] from the inner value.
|
||||||
pub fn from_byte_array(inner: [u8; 32]) -> Self { Midstate(inner) }
|
pub const fn from_byte_array(inner: [u8; 32]) -> Self { Midstate(inner) }
|
||||||
|
|
||||||
/// Copies a byte slice into the [`Midstate`] object.
|
/// Copies a byte slice into the [`Midstate`] object.
|
||||||
pub fn from_slice(sl: &[u8]) -> Result<Midstate, Error> {
|
pub fn from_slice(sl: &[u8]) -> Result<Midstate, Error> {
|
||||||
|
|
|
@ -80,42 +80,91 @@ fn from_engine<T: Tag>(e: sha256::HashEngine) -> Hash<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro used to define a newtype tagged hash.
|
/// Macro used to define a newtype tagged hash.
|
||||||
/// It creates two public types:
|
///
|
||||||
/// - a sha256t::Tag struct,
|
/// This macro creates two types:
|
||||||
/// - a sha256t::Hash type alias.
|
///
|
||||||
|
/// * a tag struct
|
||||||
|
/// * a hash wrapper
|
||||||
|
///
|
||||||
|
/// The syntax is:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # 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 in case of hash_newtype! macro.
|
||||||
|
/// #[hash_newtype(forward)]
|
||||||
|
/// 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_LENGHT)` 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.
|
||||||
|
///
|
||||||
|
/// The macro accepts multiple inputs so you can define multiple hash newtypes in one macro call.
|
||||||
|
/// Just make sure to enter the structs in order `Tag0`, `Hash0`, `Tag1`, `Hash1`...
|
||||||
|
///
|
||||||
|
/// [`hash_newtype`]: crate::hash_newtype
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! sha256t_hash_newtype {
|
macro_rules! sha256t_hash_newtype {
|
||||||
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction: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)*])* _);)+) => {
|
||||||
sha256t_hash_newtype!(
|
$(
|
||||||
$newtype,
|
$crate::sha256t_hash_newtype_tag!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*);
|
||||||
$tag,
|
|
||||||
$midstate,
|
|
||||||
$midstate_len,
|
|
||||||
$docs,
|
|
||||||
$direction,
|
|
||||||
stringify!($newtype)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction:tt, $sname:expr) => {
|
|
||||||
#[doc = "The tag used for ["]
|
|
||||||
#[doc = $sname]
|
|
||||||
#[doc = "]"]
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct $tag;
|
|
||||||
|
|
||||||
impl $crate::sha256t::Tag for $tag {
|
impl $crate::sha256t::Tag for $tag {
|
||||||
|
#[inline]
|
||||||
fn engine() -> $crate::sha256::HashEngine {
|
fn engine() -> $crate::sha256::HashEngine {
|
||||||
let midstate = $crate::sha256::Midstate::from_byte_array($midstate);
|
const MIDSTATE: ($crate::sha256::Midstate, usize) = $crate::sha256t_hash_newtype_tag_constructor!($constructor, $($tag_value)+);
|
||||||
$crate::sha256::HashEngine::from_midstate(midstate, $midstate_len)
|
#[allow(unused)]
|
||||||
|
const _LENGTH_CHECK: () = [(); 1][MIDSTATE.1 % 64];
|
||||||
|
$crate::sha256::HashEngine::from_midstate(MIDSTATE.0, MIDSTATE.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$crate::hash_newtype! {
|
$crate::hash_newtype! {
|
||||||
#[$docs]
|
$(#[$($hash_attr)*])*
|
||||||
#[hash_newtype($direction)]
|
$hash_vis struct $hash_name($(#[$($field_attr)*])* $crate::sha256t::Hash<$tag>);
|
||||||
pub struct $newtype($crate::sha256t::Hash<$tag>);
|
|
||||||
}
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround macros being unavailable in attributes.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! sha256t_hash_newtype_tag {
|
||||||
|
($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => {
|
||||||
|
#[doc = "The tag used for [`"]
|
||||||
|
#[doc = $name]
|
||||||
|
#[doc = "`]\n\n"]
|
||||||
|
$(#[$($attr)*])*
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
|
||||||
|
$vis struct $tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! sha256t_hash_newtype_tag_constructor {
|
||||||
|
(hash_str, $value:expr) => {
|
||||||
|
($crate::sha256::Midstate::hash_tag($value.as_bytes()), 64)
|
||||||
|
};
|
||||||
|
(hash_bytes, $value:expr) => {
|
||||||
|
($crate::sha256::Midstate::hash_tag($value), 64)
|
||||||
|
};
|
||||||
|
(raw, $bytes:expr, $len:expr) => {
|
||||||
|
($crate::sha256::Midstate::from_byte_array($bytes), $len)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +195,14 @@ mod tests {
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub type TestHash = sha256t::Hash<TestHashTag>;
|
pub type TestHash = sha256t::Hash<TestHashTag>;
|
||||||
|
|
||||||
sha256t_hash_newtype!(NewTypeHash, NewTypeTag, TEST_MIDSTATE, 64, doc = "test hash", backward);
|
sha256t_hash_newtype! {
|
||||||
|
/// Test detailed explanation.
|
||||||
|
struct NewTypeTag = raw(TEST_MIDSTATE, 64);
|
||||||
|
|
||||||
|
/// A test hash.
|
||||||
|
#[hash_newtype(backward)]
|
||||||
|
struct NewTypeHash(_);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
|
Loading…
Reference in New Issue