crypto: Move SerializedLegacyPublicKey to crypto
What changed, and why it matters
This commit is a simple internal code reorganization. It moves the SerializedLegacyPublicKey type from the main bitcoin crate into the lower-level crypto crate and re-exports it so existing code keeps working. No behavior changes, no bug fixes, and no security implications are visible in the diff.
No security action needed. Review as normal refactoring if auditing the crate split.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch relocates SerializedLegacyPublicKey and its supporting AsRef/Borrow/Deref implementations from bitcoin/src/crypto/key.rs to crypto/src/key.rs. It also moves the to_bytes() method from a private extension trait in bitcoin onto LegacyPublicKey in crypto, and moves the associated roundtrip test. The public API surface is preserved via a re-export. The change is purely structural and removes a dependency on PushBytes from the crypto-side type.
Changed components
bitcoin/src/crypto/key.rscrypto/src/key.rsInspect captured patch +69 / −69
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index cffb3c1d..1a35f55d 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -24,49 +24,10 @@ pub use crypto::key::{
};
#[doc(inline)]
pub use crypto::key::{
- FullPublicKey, Keypair, LegacyPublicKey, PrivateKey, PubkeyHash, SerializedXOnlyPublicKey,
- TweakedKeypair, TweakedPublicKey, UntweakedKeypair, UntweakedPublicKey, WPubkeyHash, WifKey,
- XOnlyPublicKey,
+ FullPublicKey, Keypair, LegacyPublicKey, PrivateKey, PubkeyHash, SerializedLegacyPublicKey,
+ SerializedXOnlyPublicKey, TweakedKeypair, TweakedPublicKey, UntweakedKeypair,
+ UntweakedPublicKey, WPubkeyHash, WifKey, XOnlyPublicKey,
};
-pub use serialized_legacy_public_key::SerializedLegacyPublicKey;
-
-mod serialized_legacy_public_key {
- use internals::array_vec::ArrayVec;
-
- /// A serialized form of `LegacyPublicKey`.
- ///
- /// This type contains the legacy public key in serialized as either compressed or
- /// uncompressed. The type implements the standard conversion traits so it behaves a lot like
- /// an array. In addition, the type implements `AsRef<PushBytes>`, so you can pass it into
- /// script.
- #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
- pub struct SerializedLegacyPublicKey(ArrayVec<u8, 65>);
-
- impl SerializedLegacyPublicKey {
- pub(crate) fn new_compressed(compressed: &[u8; 33]) -> Self {
- Self(ArrayVec::from_slice(compressed))
- }
-
- pub(crate) fn new_uncompressed(uncompressed: &[u8; 65]) -> Self {
- Self(ArrayVec::from_slice(uncompressed))
- }
- }
-
- impl core::ops::Deref for SerializedLegacyPublicKey {
- type Target = [u8];
-
- #[inline]
- fn deref(&self) -> &Self::Target { &self.0 }
- }
-}
-
-impl AsRef<[u8]> for SerializedLegacyPublicKey {
- fn as_ref(&self) -> &[u8] { self }
-}
-
-impl Borrow<[u8]> for SerializedLegacyPublicKey {
- fn borrow(&self) -> &[u8] { self }
-}
impl AsRef<PushBytes> for SerializedLegacyPublicKey {
fn as_ref(&self) -> &PushBytes { self.borrow() }
@@ -114,15 +75,6 @@ define_extension_trait! {
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())
- }
- }
}
}
@@ -298,22 +250,4 @@ mod tests {
.unwrap()
);
}
-
- #[test]
- #[cfg(feature = "rand")]
- #[cfg(feature = "std")]
- fn serialized_legacy_public_key_roundtrip() {
- let key = Keypair::generate().to_public_key();
- assert!(key.compressed());
- let serialized = &key.to_bytes();
- assert_eq!(serialized.len(), 33);
- let deser = LegacyPublicKey::from_slice(serialized).unwrap();
- assert_eq!(deser, key);
-
- let key = LegacyPublicKey::from_secp_uncompressed(key.to_inner());
- let serialized = &key.to_bytes();
- assert_eq!(serialized.len(), 65);
- let deser = LegacyPublicKey::from_slice(serialized).unwrap();
- assert_eq!(deser, key);
- }
}
diff --git a/crypto/src/key.rs b/crypto/src/key.rs
index 5be6c7d9..b2c90222 100644
--- a/crypto/src/key.rs
+++ b/crypto/src/key.rs
@@ -5,6 +5,7 @@
//! This module provides keys used in Bitcoin that can be roundtrip
//! (de)serialized.
+use alloc::borrow::Borrow;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
@@ -34,6 +35,7 @@ pub use encapsulate::{
FullPublicKey, Keypair, LegacyPublicKey, PrivateKey, SerializedXOnlyPublicKey, TweakedKeypair,
TweakedPublicKey, XOnlyPublicKey,
};
+pub use serialized_legacy_public_key::SerializedLegacyPublicKey;
#[doc(no_inline)]
pub use self::error::{
@@ -281,6 +283,43 @@ mod encapsulate {
}
}
+mod serialized_legacy_public_key {
+ use internals::array_vec::ArrayVec;
+
+ /// A serialized form of `LegacyPublicKey`.
+ ///
+ /// This type contains the legacy public key in serialized as either compressed or
+ /// uncompressed. The type implements the standard conversion traits so it behaves a lot like
+ /// an array.
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct SerializedLegacyPublicKey(ArrayVec<u8, 65>);
+
+ impl SerializedLegacyPublicKey {
+ pub(crate) fn new_compressed(compressed: &[u8; 33]) -> Self {
+ Self(ArrayVec::from_slice(compressed))
+ }
+
+ pub(crate) fn new_uncompressed(uncompressed: &[u8; 65]) -> Self {
+ Self(ArrayVec::from_slice(uncompressed))
+ }
+ }
+
+ impl core::ops::Deref for SerializedLegacyPublicKey {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &Self::Target { &self.0 }
+ }
+}
+
+impl AsRef<[u8]> for SerializedLegacyPublicKey {
+ fn as_ref(&self) -> &[u8] { self }
+}
+
+impl Borrow<[u8]> for SerializedLegacyPublicKey {
+ fn borrow(&self) -> &[u8] { self }
+}
+
impl XOnlyPublicKey {
/// Constructs an x-only public key from a keypair.
///
@@ -640,6 +679,15 @@ impl LegacyPublicKey {
buf
}
+ /// 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 into a `SortKey`.
///
/// `SortKey` is not too useful by itself, but it can be used to sort a
@@ -2262,4 +2310,22 @@ mod tests {
secp256k1::SecretKey::from_secret_bytes(bitcoin_key.to_secret_bytes()).unwrap();
assert_eq!(PrivateKey::from_secp(secp_key), bitcoin_key);
}
+
+ #[test]
+ #[cfg(feature = "rand")]
+ #[cfg(feature = "std")]
+ fn serialized_legacy_public_key_roundtrip() {
+ let key = Keypair::generate().to_public_key();
+ assert!(key.compressed());
+ let serialized = &key.to_bytes();
+ assert_eq!(serialized.len(), 33);
+ let deser = LegacyPublicKey::from_slice(serialized).unwrap();
+ assert_eq!(deser, key);
+
+ let key = LegacyPublicKey::from_secp_uncompressed(key.to_inner());
+ let serialized = &key.to_bytes();
+ assert_eq!(serialized.len(), 65);
+ let deser = LegacyPublicKey::from_slice(serialized).unwrap();
+ assert_eq!(deser, key);
+ }
}
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.