What changed, and why it matters
This commit is a routine internal code reorganization in the rust-bitcoin library. It moves several key-related wrapper types into a single private 'encapsulate' module and re-exports them, without changing their public behavior or adding any security fixes. There is no indication of a vulnerability being patched.
No security action required. Treat as normal maintenance/refactoring commit. Reviewers may verify that public re-exports preserve API compatibility and that no methods were accidentally removed or changed in behavior.
Security signals we found
No security fix or vulnerability mention in commit title or message
No functional changes to cryptographic operations
No new input validation or boundary checks introduced
Refactoring-only: moving definitions into a private module with re-exports
Evidence from the diff
The change refactors key wrapper types (XOnlyPublicKey, Keypair, CompressedPublicKey, TweakedPublicKey, TweakedKeypair, SerializedXOnlyPublicKey) into a new private encapsulate submodule in bitcoin/src/crypto/key.rs. The public API is preserved via re-exports, and existing methods are moved but not substantively altered. The dangerous_assume_tweaked constructors retain their warnings. No security-relevant logic changes are visible in the diff.
Changed components
bitcoin/src/crypto/key.rsInspect captured patch +149 / −133
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index 622c4d16..4f7a4ae9 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -28,17 +28,158 @@ use crate::taproot::{TapNodeHash, TapTweakHash};
pub use secp256k1::{constants, Parity, Verification};
#[cfg(all(feature = "rand", feature = "std"))]
pub use secp256k1::rand;
-pub use serialized_x_only::SerializedXOnlyPublicKey;
+pub use encapsulate::{
+ CompressedPublicKey, Keypair, SerializedXOnlyPublicKey, TweakedKeypair,
+ TweakedPublicKey, XOnlyPublicKey,
+};
+
+/// Encapsulation module to provide a clear barrier for construction/destruction of types.
+mod encapsulate {
+ /// A Bitcoin Schnorr X-only public key used for BIP-0340 signatures.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct XOnlyPublicKey(secp256k1::XOnlyPublicKey);
+
+ impl XOnlyPublicKey {
+ /// Constructs a new x-only public key from the provided generic secp256k1 x-only public key.
+ pub fn new(key: impl Into<secp256k1::XOnlyPublicKey>) -> Self { Self(key.into()) }
+
+ /// Returns the inner secp256k1 x-only public key.
+ #[inline]
+ pub fn to_inner(self) -> secp256k1::XOnlyPublicKey { self.0 }
+
+ /// Returns the inner secp256k1 x-only public key.
+ #[inline]
+ #[deprecated(since = "TBD", note = "use `to_inner()` instead")]
+ pub fn into_inner(self) -> secp256k1::XOnlyPublicKey { self.to_inner() }
+ }
+
+ /// A Bitcoin secret and public key pair.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Keypair(secp256k1::Keypair);
+
+ impl Keypair {
+ /// Constructs a keypair from a provided secp256k1 keypair.
+ #[inline]
+ pub fn from_secp(keypair: impl Into<secp256k1::Keypair>) -> Self { Self(keypair.into()) }
+
+ /// Returns the inner [`secp256k1::Keypair`].
+ #[inline]
+ pub fn to_inner(self) -> secp256k1::Keypair { self.0 }
+ }
+
+ /// An always-compressed Bitcoin ECDSA public key.
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct CompressedPublicKey(secp256k1::PublicKey);
+
+ impl CompressedPublicKey {
+ /// Constructs a new compressed public key from the provided secp public key.
+ #[inline]
+ pub fn from_secp(inner: secp256k1::PublicKey) -> Self { Self(inner) }
+
+ /// Returns the inner [`secp256k1::PublicKey`].
+ #[inline]
+ pub fn to_inner(self) -> secp256k1::PublicKey { self.0 }
+ }
+
+ /// Tweaked BIP-0340 X-coord-only public key.
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ #[cfg_attr(feature = "serde", serde(transparent))]
+ pub struct TweakedPublicKey(XOnlyPublicKey);
+
+ impl TweakedPublicKey {
+ /// Returns the [`TweakedPublicKey`] for `keypair`.
+ #[inline]
+ pub fn from_keypair(keypair: TweakedKeypair) -> Self {
+ let (xonly, _parity) = keypair.to_keypair().to_x_only_public_key();
+ Self(xonly)
+ }
-/// A Bitcoin Schnorr X-only public key used for BIP-0340 signatures.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct XOnlyPublicKey(secp256k1::XOnlyPublicKey);
+ /// Constructs a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
+ /// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
+ ///
+ /// This method is dangerous and can lead to loss of funds if used incorrectly.
+ /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
+ ///
+ /// [`UntweakedPublicKey`]: super::UntweakedPublicKey
+ #[inline]
+ pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> Self { Self(key) }
-impl XOnlyPublicKey {
- /// Constructs a new x-only public key from the provided generic secp256k1 x-only public key.
- pub fn new(key: impl Into<secp256k1::XOnlyPublicKey>) -> Self { Self(key.into()) }
+ /// Returns the underlying x-only public key.
+ #[inline]
+ pub fn to_x_only_public_key(self) -> XOnlyPublicKey { self.0 }
+
+ /// Returns a reference to the underlying x-only public key.
+ #[inline]
+ pub fn as_x_only_public_key(&self) -> &XOnlyPublicKey { &self.0 }
+ }
+
+ /// Tweaked BIP-0340 key pair.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #[cfg(all(feature = "rand", feature = "std"))] {
+ /// # use bitcoin::key::{Keypair, TweakedKeypair, TweakedPublicKey};
+ /// # use bitcoin::secp256k1::rand;
+ /// # let keypair = TweakedKeypair::dangerous_assume_tweaked(Keypair::generate(&mut rand::rng()));
+ /// // There are various conversion methods available to get a tweaked pubkey from a tweaked keypair.
+ /// let (_pk, _parity) = keypair.public_parts();
+ /// let _pk = TweakedPublicKey::from_keypair(keypair);
+ /// let _pk = TweakedPublicKey::from(keypair);
+ /// # }
+ /// ```
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ #[cfg_attr(feature = "serde", serde(transparent))]
+ pub struct TweakedKeypair(Keypair);
+
+ impl TweakedKeypair {
+ /// Constructs a new [`TweakedKeypair`] from a [`Keypair`]. No tweak is applied, consider
+ /// calling `tap_tweak` on an [`UntweakedKeypair`](super::UntweakedKeypair) instead of using this constructor.
+ ///
+ /// This method is dangerous and can lead to loss of funds if used incorrectly.
+ /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
+ #[inline]
+ pub fn dangerous_assume_tweaked(pair: Keypair) -> Self { Self(pair) }
+
+ /// Returns the underlying key pair.
+ #[inline]
+ pub fn to_keypair(self) -> Keypair { self.0 }
+
+ /// Returns a reference to the underlying key pair.
+ #[inline]
+ pub fn as_keypair(&self) -> &Keypair { &self.0 }
+ }
+
+ internals::transparent_newtype! {
+ /// An array of bytes that's semantically an x-only public but was **not** validated.
+ ///
+ /// This can be useful when validation is not desired but semantics of the bytes should be
+ /// preserved. The validation can still happen using `to_validated()` method.
+ #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct SerializedXOnlyPublicKey([u8; 32]);
+ impl SerializedXOnlyPublicKey {
+ pub(crate) fn from_bytes_ref(bytes: &_) -> Self;
+ }
+ }
+
+ impl SerializedXOnlyPublicKey {
+ /// Marks the supplied bytes as a serialized x-only public key.
+ pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self(bytes) }
+
+ /// Returns the raw bytes.
+ pub const fn to_byte_array(self) -> [u8; 32] { self.0 }
+
+ /// Returns a reference to the raw bytes.
+ pub const fn as_byte_array(&self) -> &[u8; 32] { &self.0 }
+ }
+}
+
+impl XOnlyPublicKey {
/// Constructs an x-only public key from a keypair.
///
/// Returns the x-only public key and the parity of the full public key.
@@ -60,15 +201,6 @@ impl XOnlyPublicKey {
.map_err(|_| ParseXOnlyPublicKeyError::InvalidXCoordinate)
}
- /// Returns the inner secp256k1 x-only public key.
- #[inline]
- pub fn to_inner(self) -> secp256k1::XOnlyPublicKey { self.0 }
-
- /// Returns the inner secp256k1 x-only public key.
- #[inline]
- #[deprecated(since = "TBD", note = "use `to_inner()` instead")]
- pub fn into_inner(self) -> secp256k1::XOnlyPublicKey { self.to_inner() }
-
/// Serializes the x-only public key as a byte-encoded x coordinate value (32 bytes).
#[inline]
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { self.to_inner().serialize() }
@@ -144,20 +276,7 @@ impl fmt::Display for XOnlyPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.to_inner(), f) }
}
-/// A Bitcoin secret and public key pair.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct Keypair(secp256k1::Keypair);
-
impl Keypair {
- /// Constructs a keypair from a provided secp256k1 keypair.
- #[inline]
- pub fn from_secp(keypair: impl Into<secp256k1::Keypair>) -> Self { Self(keypair.into()) }
-
- /// Returns the inner [`secp256k1::Keypair`].
- #[inline]
- pub fn to_inner(self) -> secp256k1::Keypair { self.0 }
-
/// Generates a new random key pair.
///
/// # Examples
@@ -475,19 +594,7 @@ impl From<&PublicKey> for PubkeyHash {
fn from(key: &PublicKey) -> Self { key.pubkey_hash() }
}
-/// An always-compressed Bitcoin ECDSA public key.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct CompressedPublicKey(secp256k1::PublicKey);
-
impl CompressedPublicKey {
- /// Constructs a new compressed public key from the provided secp public key.
- #[inline]
- pub fn from_secp(inner: secp256k1::PublicKey) -> Self { Self(inner) }
-
- /// Returns the inner [`secp256k1::PublicKey`].
- #[inline]
- pub fn to_inner(self) -> secp256k1::PublicKey { self.0 }
-
/// Returns bitcoin 160-bit hash of the public key.
pub fn pubkey_hash(&self) -> PubkeyHash { PubkeyHash(hash160::Hash::hash(&self.to_bytes())) }
@@ -931,12 +1038,6 @@ impl<'de> serde::Deserialize<'de> for CompressedPublicKey {
/// Untweaked BIP-0340 X-coord-only public key.
pub type UntweakedPublicKey = XOnlyPublicKey;
-/// Tweaked BIP-0340 X-coord-only public key.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "serde", serde(transparent))]
-pub struct TweakedPublicKey(XOnlyPublicKey);
-
impl fmt::LowerHex for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_x_only_public_key(), f) }
}
@@ -950,26 +1051,6 @@ impl fmt::Display for TweakedPublicKey {
/// Untweaked BIP-0340 key pair.
pub type UntweakedKeypair = Keypair;
-/// Tweaked BIP-0340 key pair.
-///
-/// # Examples
-///
-/// ```
-/// # #[cfg(all(feature = "rand", feature = "std"))] {
-/// # use bitcoin::key::{Keypair, TweakedKeypair, TweakedPublicKey};
-/// # use bitcoin::secp256k1::rand;
-/// # let keypair = TweakedKeypair::dangerous_assume_tweaked(Keypair::generate(&mut rand::rng()));
-/// // There are various conversion methods available to get a tweaked pubkey from a tweaked keypair.
-/// let (_pk, _parity) = keypair.public_parts();
-/// let _pk = TweakedPublicKey::from_keypair(keypair);
-/// let _pk = TweakedPublicKey::from(keypair);
-/// # }
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "serde", serde(transparent))]
-pub struct TweakedKeypair(Keypair);
-
/// A trait for tweaking BIP-0340 key types (x-only public keys and key pairs).
pub trait TapTweak {
/// Tweaked key type with optional auxiliary information.
@@ -1052,63 +1133,24 @@ impl TapTweak for UntweakedKeypair {
}
impl TweakedPublicKey {
- /// Returns the [`TweakedPublicKey`] for `keypair`.
- #[inline]
- pub fn from_keypair(keypair: TweakedKeypair) -> Self {
- let (xonly, _parity) = keypair.to_keypair().to_x_only_public_key();
- Self(xonly)
- }
-
- /// Constructs a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
- /// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
- ///
- /// This method is dangerous and can lead to loss of funds if used incorrectly.
- /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
- #[inline]
- pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> Self { Self(key) }
-
/// Returns the underlying public key.
#[inline]
#[doc(hidden)]
#[deprecated(since = "0.32.6", note = "use to_x_only_public_key() instead")]
pub fn to_inner(self) -> XOnlyPublicKey { self.to_x_only_public_key() }
- /// Returns the underlying x-only public key.
- #[inline]
- pub fn to_x_only_public_key(self) -> XOnlyPublicKey { self.0 }
-
- /// Returns a reference to the underlying x-only public key.
- #[inline]
- pub fn as_x_only_public_key(&self) -> &XOnlyPublicKey { &self.0 }
-
/// Serializes the key as a byte-encoded x coordinate value (32 bytes).
#[inline]
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { self.as_x_only_public_key().serialize() }
}
impl TweakedKeypair {
- /// Constructs a new [`TweakedKeypair`] from a [`Keypair`]. No tweak is applied, consider
- /// calling `tap_tweak` on an [`UntweakedKeypair`] instead of using this constructor.
- ///
- /// This method is dangerous and can lead to loss of funds if used incorrectly.
- /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
- #[inline]
- pub fn dangerous_assume_tweaked(pair: Keypair) -> Self { Self(pair) }
-
/// Returns the underlying key pair.
#[inline]
#[doc(hidden)]
#[deprecated(since = "0.32.6", note = "use to_keypair() instead")]
pub fn to_inner(self) -> Keypair { self.to_keypair() }
- /// Returns the underlying key pair.
- #[inline]
- pub fn to_keypair(self) -> Keypair { self.0 }
-
- /// Returns a reference to the underlying key pair.
- #[inline]
- pub fn as_keypair(&self) -> &Keypair { &self.0 }
-
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeypair`].
#[inline]
pub fn public_parts(&self) -> (TweakedPublicKey, Parity) {
@@ -1420,32 +1462,6 @@ impl fmt::Display for InvalidWifCompressionFlagError {
#[cfg(feature = "std")]
impl std::error::Error for InvalidWifCompressionFlagError {}
-mod serialized_x_only {
- internals::transparent_newtype! {
- /// An array of bytes that's semantically an x-only public but was **not** validated.
- ///
- /// This can be useful when validation is not desired but semantics of the bytes should be
- /// preserved. The validation can still happen using `to_validated()` method.
- #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
- pub struct SerializedXOnlyPublicKey([u8; 32]);
-
- impl SerializedXOnlyPublicKey {
- pub(crate) fn from_bytes_ref(bytes: &_) -> Self;
- }
- }
-
- impl SerializedXOnlyPublicKey {
- /// Marks the supplied bytes as a serialized x-only public key.
- pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self(bytes) }
-
- /// Returns the raw bytes.
- pub const fn to_byte_array(self) -> [u8; 32] { self.0 }
-
- /// Returns a reference to the raw bytes.
- pub const fn as_byte_array(&self) -> &[u8; 32] { &self.0 }
- }
-}
-
impl SerializedXOnlyPublicKey {
/// Returns `XOnlyPublicKey` if the bytes are valid.
pub fn to_validated(self) -> Result<XOnlyPublicKey, ParseXOnlyPublicKeyError> {
Why this scored 17/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.