Skip to content

Commit

Permalink
Move taproot back to bitcoin crate
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tcharding committed Feb 26, 2025
1 parent aebda6e commit cf12ba2
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 127 deletions.
2 changes: 1 addition & 1 deletion bitcoin/src/blockdata/script/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion bitcoin/src/crypto/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
2 changes: 0 additions & 2 deletions bitcoin/src/crypto/sighash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TapSighashType, D::Error>
where
D: serde::Deserializer<'de>,
Expand Down
159 changes: 95 additions & 64 deletions bitcoin/src/taproot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<TapNodeHash>,
) -> TapTweakHash {
let mut eng = sha256t::Hash::<TapTweakTag>::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::<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.
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")
// 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<TapLeafTag>);
}

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<TapBranchTag>);
}

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<TapTweakTag>);
}

hashes::impl_hex_for_newtype!(TapTweakHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapTweakHash);

impl From<TapLeafHash> 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<TapNodeHash>,
) -> TapTweakHash {
let mut eng = sha256t::Hash::<TapTweakTag>::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::<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.
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::<TapLeafTag>::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::<TapLeafTag>::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::<TapLeafTag>::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::<TapLeafTag>::from_engine(eng);
TapLeafHash::from_byte_array(inner.to_byte_array())
}
}

Expand All @@ -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))
}
}

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -80,7 +79,6 @@ pub use self::{
opcodes::Opcode,
pow::CompactTarget,
sequence::Sequence,
taproot::{TapBranchTag, TapLeafHash, TapLeafTag, TapNodeHash, TapTweakHash, TapTweakTag},
transaction::{OutPoint, Txid, Wtxid},
};

Expand Down
57 changes: 0 additions & 57 deletions primitives/src/taproot.rs
Original file line number Diff line number Diff line change
@@ -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<TapLeafTag>);
}

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<TapBranchTag>);
}

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<TapTweakTag>);
}

hashes::impl_hex_for_newtype!(TapTweakHash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapTweakHash);

impl From<TapLeafHash> for TapNodeHash {
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) }
}

0 comments on commit cf12ba2

Please sign in to comment.