Move from_key_and_merkle_root back to taproot-primitives
What changed, and why it matters
This commit is a routine internal code reorganization. It moves a helper function that computes a Taproot tweak hash from one module to another and removes an extension trait that was only used to attach that function. There is no security fix or behavior change visible in the diff.
No security action required; treat as normal maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates from_key_and_merkle_root from bitcoin/src/taproot/mod.rs (via the TapTweakHashExt extension trait) to taproot-primitives/src/lib.rs as an inherent method on TapTweakHash. It also adds a bitcoin-crypto dependency to taproot-primitives so the new location can use UntweakedPublicKey. Callers in bitcoin/src/crypto/key.rs are updated to drop the extension trait import. The implementation body is identical, so this is a pure refactor.
Changed components
bitcoin/src/taproot/mod.rsbitcoin/src/crypto/key.rstaproot-primitives/src/lib.rstaproot-primitives/Cargo.tomlInspect captured patch +25 / −27
diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock
index d4ceae3a..9cefd9f3 100644
--- a/Cargo-minimal.lock
+++ b/Cargo-minimal.lock
@@ -246,6 +246,7 @@ name = "bitcoin-taproot-primitives"
version = "0.1.0"
dependencies = [
"arbitrary",
+ "bitcoin-crypto",
"bitcoin-internals 0.5.0",
"bitcoin_hashes 1.0.0",
"secp256k1 0.32.0-beta.2",
diff --git a/Cargo-recent.lock b/Cargo-recent.lock
index 3da5568e..5532b0fe 100644
--- a/Cargo-recent.lock
+++ b/Cargo-recent.lock
@@ -239,6 +239,7 @@ name = "bitcoin-taproot-primitives"
version = "0.1.0"
dependencies = [
"arbitrary",
+ "bitcoin-crypto",
"bitcoin-internals 0.5.0",
"bitcoin_hashes 1.0.0",
"secp256k1 0.32.0-beta.2",
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index bf1c4aae..acf9ad68 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -9,7 +9,7 @@ use crate::internal_macros::define_extension_trait;
use crate::script::{self, WitnessScriptBuf};
#[cfg(feature = "secp-recovery")]
use crate::sign_message::MessageSignature;
-use crate::taproot::{TapNodeHash, TapTweakHash, TapTweakHashExt as _};
+use crate::taproot::{TapNodeHash, TapTweakHash};
#[rustfmt::skip] // Keep public re-exports separate.
pub use secp256k1::{constants, Parity};
diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs
index 24ece6c5..f3554668 100644
--- a/bitcoin/src/taproot/mod.rs
+++ b/bitcoin/src/taproot/mod.rs
@@ -99,35 +99,10 @@ crate::internal_macros::define_extension_trait! {
}
}
-crate::internal_macros::define_extension_trait! {
- /// Extension functionality for the [`TapTweakHash`] type.
- pub trait TapTweakHashExt impl for TapTweakHash {
- /// Constructs a new BIP-0341 [`TapTweakHash`] from key and Merkle root. Produces `H_taptweak(P||R)` where
- /// `P` is the internal key and `R` is the Merkle root.
- fn from_key_and_merkle_root<K: Into<UntweakedPublicKey>>(
- internal_key: K,
- merkle_root: Option<TapNodeHash>,
- ) -> Self {
- let internal_key = internal_key.into();
- let mut eng = sha256t::Hash::<TapTweakTag>::engine();
- // always hash the key
- eng.input(&internal_key.serialize().0);
- if let Some(h) = merkle_root {
- eng.input(h.as_ref());
- } else {
- // nothing to hash
- }
- let inner = sha256t::Hash::<TapTweakTag>::from_engine(eng);
- Self::from_byte_array(inner.to_byte_array())
- }
- }
-}
-
mod sealed {
pub trait Sealed {}
impl Sealed for super::TapLeafHash {}
impl Sealed for super::TapNodeHash {}
- impl Sealed for super::TapTweakHash {}
}
/// Computes branch hash given two hashes of the nodes underneath it and returns
diff --git a/taproot-primitives/Cargo.toml b/taproot-primitives/Cargo.toml
index e80f1cee..54c97d60 100644
--- a/taproot-primitives/Cargo.toml
+++ b/taproot-primitives/Cargo.toml
@@ -21,6 +21,7 @@ arbitrary = ["dep:arbitrary", "secp256k1/arbitrary"]
hex = ["hashes/hex"]
[dependencies]
+crypto = { package = "bitcoin-crypto", path = "../crypto", version = "0.2.0", default-features = false }
hashes = { package = "bitcoin_hashes", path = "../hashes", version = "1.0.0", default-features = false }
internals = { package = "bitcoin-internals", path = "../internals", version = "0.5.0" }
diff --git a/taproot-primitives/src/lib.rs b/taproot-primitives/src/lib.rs
index cb972688..5e848796 100644
--- a/taproot-primitives/src/lib.rs
+++ b/taproot-primitives/src/lib.rs
@@ -36,7 +36,8 @@ use core::fmt;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
-use hashes::{hash_newtype, sha256t, sha256t_tag};
+use crypto::key::UntweakedPublicKey;
+use hashes::{hash_newtype, sha256t, sha256t_tag, HashEngine as _};
use secp256k1::Scalar;
/// Maximum depth of a Taproot tree script spend path.
@@ -124,6 +125,25 @@ impl TapTweakHash {
// This is statistically extremely unlikely to panic.
Scalar::from_be_bytes(self.to_byte_array()).expect("hash value greater than curve order")
}
+
+ /// Constructs a new BIP-0341 [`TapTweakHash`] from key and Merkle root. Produces `H_taptweak(P||R)` where
+ /// `P` is the internal key and `R` is the Merkle root.
+ pub fn from_key_and_merkle_root<K: Into<UntweakedPublicKey>>(
+ internal_key: K,
+ merkle_root: Option<TapNodeHash>,
+ ) -> Self {
+ let internal_key = internal_key.into();
+ let mut eng = sha256t::Hash::<TapTweakTag>::engine();
+ // always hash the key
+ eng.input(&internal_key.serialize().0);
+ if let Some(h) = merkle_root {
+ eng.input(h.as_ref());
+ } else {
+ // nothing to hash
+ }
+ let inner = sha256t::Hash::<TapTweakTag>::from_engine(eng);
+ Self::from_byte_array(inner.to_byte_array())
+ }
}
/// The leaf version for tapleafs.
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.