From cf12ba262a646a6341098ee3f4c178a52fc90211 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 26 Feb 2025 15:44:53 +1100 Subject: [PATCH] Move taproot back to bitcoin crate I don't know what I was thinking when I move the taproot hash types to `primitives`. As correctly pointed out by Kix we agreed to only have blockdata in `primitives`. Move the taproot hash types back to `bitcoin::taproot` and remove the extension traits. --- bitcoin/src/blockdata/script/borrowed.rs | 2 +- bitcoin/src/crypto/key.rs | 2 +- bitcoin/src/crypto/sighash.rs | 2 - bitcoin/src/taproot/mod.rs | 157 ++++++++++++++--------- primitives/src/lib.rs | 2 - primitives/src/taproot.rs | 57 -------- 6 files changed, 96 insertions(+), 126 deletions(-) diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 14c32e314..624feb3b5 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -14,7 +14,7 @@ use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::policy::{DUST_RELAY_TX_FEE, MAX_OP_RETURN_RELAY}; use crate::prelude::{sink, DisplayHex, String, ToString}; -use crate::taproot::{LeafVersion, TapLeafHash, TapLeafHashExt as _}; +use crate::taproot::{LeafVersion, TapLeafHash}; use crate::{Amount, FeeRate}; #[rustfmt::skip] // Keep public re-exports separate. diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 1b3c3a484..68a3c965b 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -21,7 +21,7 @@ use crate::internal_macros::impl_asref_push_bytes; use crate::network::NetworkKind; use crate::prelude::{DisplayHex, String, Vec}; use crate::script::{self, ScriptBuf}; -use crate::taproot::{TapNodeHash, TapTweakHash, TapTweakHashExt as _}; +use crate::taproot::{TapNodeHash, TapTweakHash}; #[rustfmt::skip] // Keep public re-exports separate. pub use secp256k1::{constants, Keypair, Parity, Secp256k1, Verification, XOnlyPublicKey}; diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 6fd66d045..e1deed7e2 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -1864,8 +1864,6 @@ mod tests { fn bip_341_sighash_tests() { use hex::DisplayHex; - use crate::taproot::TapTweakHashExt as _; - fn sighash_deser_numeric<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index 775357f07..5511431ac 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -12,7 +12,7 @@ use core::convert::Infallible; use core::fmt; use core::iter::FusedIterator; -use hashes::{sha256t, HashEngine}; +use hashes::{hash_newtype, sha256t, sha256t_tag, HashEngine}; use internals::{impl_to_hex_from_lower_hex, write_err}; use io::Write; use secp256k1::{Scalar, Secp256k1}; @@ -28,50 +28,91 @@ use crate::{Script, ScriptBuf}; pub use crate::crypto::taproot::{SigFromSliceError, Signature}; #[doc(inline)] pub use merkle_branch::TaprootMerkleBranch; -pub use primitives::taproot::{ - TapBranchTag, TapLeafHash, TapLeafTag, TapNodeHash, TapTweakHash, TapTweakTag, -}; -crate::internal_macros::define_extension_trait! { - /// Extension functionality for the [`TapTweakHash`] type. - pub trait TapTweakHashExt impl for TapTweakHash { - /// Constructs a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where - /// `P` is the internal key and `R` is the Merkle root. - fn from_key_and_tweak( - internal_key: UntweakedPublicKey, - merkle_root: Option, - ) -> TapTweakHash { - let mut eng = sha256t::Hash::::engine(); - // always hash the key - eng.input(&internal_key.serialize()); - if let Some(h) = merkle_root { - eng.input(h.as_ref()); - } else { - // nothing to hash - } - let inner = sha256t::Hash::::from_engine(eng); - TapTweakHash::from_byte_array(inner.to_byte_array()) - } +// Taproot test vectors from BIP-341 state the hashes without any reversing +sha256t_tag! { + pub struct TapLeafTag = hash_str("TapLeaf"); +} - /// Converts a `TapTweakHash` into a `Scalar` ready for use with key tweaking API. - fn to_scalar(self) -> Scalar { - // This is statistically extremely unlikely to panic. - Scalar::from_be_bytes(self.to_byte_array()).expect("hash value greater than curve order") +hash_newtype! { + /// Taproot-tagged hash with tag \"TapLeaf\". + /// + /// This is used for computing tapscript script spend hash. + pub struct TapLeafHash(sha256t::Hash); +} + +hashes::impl_hex_for_newtype!(TapLeafHash); +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapLeafHash); + +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(sha256t::Hash); +} + +hashes::impl_hex_for_newtype!(TapNodeHash); +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapNodeHash); + +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(sha256t::Hash); +} + +hashes::impl_hex_for_newtype!(TapTweakHash); +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapTweakHash); + +impl From for TapNodeHash { + fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) } +} + +impl TapTweakHash { + /// Constructs a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where + /// `P` is the internal key and `R` is the Merkle root. + pub fn from_key_and_tweak( + internal_key: UntweakedPublicKey, + merkle_root: Option, + ) -> TapTweakHash { + let mut eng = sha256t::Hash::::engine(); + // always hash the key + eng.input(&internal_key.serialize()); + if let Some(h) = merkle_root { + eng.input(h.as_ref()); + } else { + // nothing to hash } + 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. + pub fn to_scalar(self) -> Scalar { + // This is statistically extremely unlikely to panic. + Scalar::from_be_bytes(self.to_byte_array()).expect("hash value greater than curve order") } } -crate::internal_macros::define_extension_trait! { - /// Extension functionality for the [`TapLeafHash`] type. - pub trait TapLeafHashExt impl for TapLeafHash { - /// Computes the leaf hash from components. - fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash { - 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"); - let inner = sha256t::Hash::::from_engine(eng); - TapLeafHash::from_byte_array(inner.to_byte_array()) - } +impl TapLeafHash { + /// Computes the leaf hash from components. + pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash { + 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"); + let inner = sha256t::Hash::::from_engine(eng); + TapLeafHash::from_byte_array(inner.to_byte_array()) } } @@ -83,25 +124,22 @@ impl From<&LeafNode> for TapNodeHash { fn from(leaf: &LeafNode) -> TapNodeHash { leaf.node_hash() } } -crate::internal_macros::define_extension_trait! { - /// Extension functionality for the [`TapNodeHash`] type. - pub trait TapNodeHashExt impl for TapNodeHash { - /// Computes branch hash given two hashes of the nodes underneath it. - fn from_node_hashes(a: TapNodeHash, b: TapNodeHash) -> TapNodeHash { - combine_node_hashes(a, b).0 - } +impl TapNodeHash { + /// Computes branch hash given two hashes of the nodes underneath it. + pub fn from_node_hashes(a: TapNodeHash, b: TapNodeHash) -> TapNodeHash { + combine_node_hashes(a, b).0 + } - /// Assumes the given 32 byte array as hidden [`TapNodeHash`]. - /// - /// Similar to [`TapLeafHash::from_byte_array`], but explicitly conveys that the - /// hash is constructed from a hidden node. This also has better ergonomics - /// because it does not require the caller to import the Hash trait. - fn assume_hidden(hash: [u8; 32]) -> TapNodeHash { TapNodeHash::from_byte_array(hash) } + /// Assumes the given 32 byte array as hidden [`TapNodeHash`]. + /// + /// Similar to [`TapLeafHash::from_byte_array`], but explicitly conveys that the + /// hash is constructed from a hidden node. This also has better ergonomics + /// because it does not require the caller to import the Hash trait. + pub fn assume_hidden(hash: [u8; 32]) -> TapNodeHash { TapNodeHash::from_byte_array(hash) } - /// Computes the [`TapNodeHash`] from a script and a leaf version. - fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash { - TapNodeHash::from(TapLeafHash::from_script(script, ver)) - } + /// Computes the [`TapNodeHash`] from a script and a leaf version. + pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash { + TapNodeHash::from(TapLeafHash::from_script(script, ver)) } } @@ -1554,13 +1592,6 @@ impl fmt::Display for InvalidControlBlockSizeError { #[cfg(feature = "std")] impl std::error::Error for InvalidControlBlockSizeError {} -mod sealed { - pub trait Sealed {} - impl Sealed for super::TapTweakHash {} - impl Sealed for super::TapLeafHash {} - impl Sealed for super::TapNodeHash {} -} - #[cfg(test)] mod test { use hashes::sha256; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 5cd715063..451a3c166 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -49,7 +49,6 @@ pub mod pow; #[cfg(feature = "alloc")] pub mod script; pub mod sequence; -pub mod taproot; pub mod transaction; #[cfg(feature = "alloc")] pub mod witness; @@ -80,7 +79,6 @@ pub use self::{ opcodes::Opcode, pow::CompactTarget, sequence::Sequence, - taproot::{TapBranchTag, TapLeafHash, TapLeafTag, TapNodeHash, TapTweakHash, TapTweakTag}, transaction::{OutPoint, Txid, Wtxid}, }; diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 743980dcd..e69de29bb 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Bitcoin Taproot. -//! -//! This module provides support for Taproot tagged hashes. - -use hashes::{hash_newtype, sha256t, sha256t_tag}; - -// Taproot test vectors from BIP-341 state the hashes without any reversing -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(sha256t::Hash); -} - -hashes::impl_hex_for_newtype!(TapLeafHash); -#[cfg(feature = "serde")] -hashes::impl_serde_for_newtype!(TapLeafHash); - -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(sha256t::Hash); -} - -hashes::impl_hex_for_newtype!(TapNodeHash); -#[cfg(feature = "serde")] -hashes::impl_serde_for_newtype!(TapNodeHash); - -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(sha256t::Hash); -} - -hashes::impl_hex_for_newtype!(TapTweakHash); -#[cfg(feature = "serde")] -hashes::impl_serde_for_newtype!(TapTweakHash); - -impl From for TapNodeHash { - fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) } -}