Split methods to extension traits on public keys
What changed, and why it matters
This commit is a routine internal code reorganization. It moves a few public-key helper methods into Rust 'extension traits' so the underlying key types can be relocated to a different crate later. The actual behavior of the moved functions is unchanged, and there is no indication of a bug fix or security patch.
No security action required. Reviewers may want to verify that downstream callers importing the old inherent methods are updated to import the extension traits, but the commit already re-exports them in `bitcoin::ext`.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates p2wpkh_script_code from FullPublicKey/LegacyPublicKey to new sealed extension traits FullPublicKeyExt and LegacyPublicKeyExt, and moves LegacyPublicKey::to_bytes to LegacyPublicKeyExt::to_bytes. The implementations are copied verbatim. A sealed trait is added to prevent downstream implementations. The extension traits are re-exported in bitcoin::ext. This is preparatory refactoring for a future crate split, not a functional or security change.
Changed components
bitcoin/src/crypto/key.rsbitcoin/src/lib.rsInspect captured patch +50 / −33
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index c819d317..671915c1 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -19,7 +19,7 @@ use io::{Read, Write};
use crate::crypto::ecdsa;
use crate::hex::{self, DecodeFixedLengthBytesError};
-use crate::internal_macros::impl_asref_push_bytes;
+use crate::internal_macros::{define_extension_trait, impl_asref_push_bytes};
use crate::network::NetworkKind;
use crate::prelude::{DisplayHex, String, Vec};
use crate::script::{self, PushBytes, WitnessScriptBuf};
@@ -651,20 +651,6 @@ impl LegacyPublicKey {
}
}
- /// Returns the script code used to spend a P2WPKH input.
- ///
- /// While the type returned is [`WitnessScriptBuf`], this is **not** a witness script and
- /// should not be used as one. It is a special template defined in BIP 143 which is used
- /// in place of a witness script for purposes of sighash computation.
- ///
- /// # Errors
- ///
- /// Errors if this key is not compressed.
- pub fn p2wpkh_script_code(&self) -> Result<WitnessScriptBuf, UncompressedPublicKeyError> {
- let key = FullPublicKey::try_from(*self)?;
- Ok(key.p2wpkh_script_code())
- }
-
/// Converts this [`LegacyPublicKey`] into a [`FullPublicKey`] infallibly.
///
/// Unlike the `TryFrom` implementation, this function will discard compressedness
@@ -709,15 +695,6 @@ impl LegacyPublicKey {
})
}
- /// Serializes the public key to bytes.
- pub fn to_bytes(self) -> SerializedLegacyPublicKey {
- if self.compressed() {
- SerializedLegacyPublicKey::new_compressed(&self.serialize_compressed())
- } else {
- SerializedLegacyPublicKey::new_uncompressed(&self.serialize_uncompressed())
- }
- }
-
/// Serializes the public key to bytes.
#[allow(clippy::missing_panics_doc)]
pub fn to_vec(self) -> Vec<u8> {
@@ -833,6 +810,34 @@ impl LegacyPublicKey {
}
}
+define_extension_trait! {
+ /// Extension functionality for the [`LegacyPublicKey`] type.
+ pub trait LegacyPublicKeyExt impl for LegacyPublicKey {
+ /// Returns the script code used to spend a P2WPKH input.
+ ///
+ /// While the type returned is [`WitnessScriptBuf`], this is **not** a witness script and
+ /// should not be used as one. It is a special template defined in BIP 143 which is used
+ /// in place of a witness script for purposes of sighash computation.
+ ///
+ /// # Errors
+ ///
+ /// Errors if this key is not compressed.
+ fn p2wpkh_script_code(&self) -> Result<WitnessScriptBuf, UncompressedPublicKeyError> {
+ let key = FullPublicKey::try_from(*self)?;
+ Ok(key.p2wpkh_script_code())
+ }
+
+ /// Serializes the public key to bytes.
+ fn to_bytes(self) -> SerializedLegacyPublicKey {
+ if self.compressed() {
+ SerializedLegacyPublicKey::new_compressed(&self.serialize_compressed())
+ } else {
+ SerializedLegacyPublicKey::new_uncompressed(&self.serialize_uncompressed())
+ }
+ }
+ }
+}
+
impl From<secp256k1::PublicKey> for LegacyPublicKey {
fn from(pk: secp256k1::PublicKey) -> Self { Self::from_secp(pk) }
}
@@ -915,15 +920,6 @@ impl FullPublicKey {
WPubkeyHash::from_byte_array(hash160::Hash::hash(&self.to_bytes()).to_byte_array())
}
- /// Returns the script code used to spend a P2WPKH input.
- ///
- /// While the type returned is [`WitnessScriptBuf`], this is **not** a witness script and
- /// should not be used as one. It is a special template defined in BIP 143 which is used
- /// in place of a witness script for purposes of sighash computation.
- pub fn p2wpkh_script_code(&self) -> WitnessScriptBuf {
- script::p2wpkh_script_code(self.wpubkey_hash())
- }
-
/// Writes the public key into a writer.
///
/// # Errors
@@ -1015,6 +1011,20 @@ impl FullPublicKey {
}
}
+define_extension_trait! {
+ /// Extension functionality for the [`FullPublicKey`] type.
+ pub trait FullPublicKeyExt impl for FullPublicKey {
+ /// Returns the script code used to spend a P2WPKH input.
+ ///
+ /// While the type returned is [`WitnessScriptBuf`], this is **not** a witness script and
+ /// should not be used as one. It is a special template defined in BIP 143 which is used
+ /// in place of a witness script for purposes of sighash computation.
+ fn p2wpkh_script_code(&self) -> WitnessScriptBuf {
+ script::p2wpkh_script_code(self.wpubkey_hash())
+ }
+ }
+}
+
impl fmt::Display for FullPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.to_bytes().as_hex(), f)
@@ -1075,6 +1085,12 @@ impl From<&FullPublicKey> for WPubkeyHash {
fn from(key: &FullPublicKey) -> Self { key.wpubkey_hash() }
}
+mod sealed {
+ pub trait Sealed {}
+ impl Sealed for super::FullPublicKey {}
+ impl Sealed for super::LegacyPublicKey {}
+}
+
impl PrivateKey {
/// Constructs a new compressed ECDSA private key using the secp256k1 algorithm and
/// a secure random number generator.
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 89af016e..83afa6c6 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -101,6 +101,7 @@ pub mod ext {
#[rustfmt::skip] // Use terse custom grouping.
pub use crate::{
block::{BlockCheckedExt as _, HeaderExt as _},
+ key::{FullPublicKeyExt as _, LegacyPublicKeyExt as _},
pow::CompactTargetExt as _,
script::{ScriptExt as _, ScriptBufExt as _, TapScriptExt as _, ScriptPubKeyExt as _, ScriptPubKeyBufExt as _, WitnessScriptExt as _, ScriptSigExt as _},
transaction::{TxidExt as _, WtxidExt as _, OutPointExt as _, TxInExt as _, TxOutExt as _, TransactionExt as _},
Why this scored 18/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.