Merge rust-bitcoin/rust-bitcoin#6711: primitives: Make `ScriptHash` and `WScriptHash` no-alloc
What changed, and why it matters
This commit is a routine feature-gating refactor. It makes two small hash types (ScriptHash and WScriptHash) available even when the library is compiled without an allocator. It does not change how those types behave, does not fix a bug, and does not alter any security-sensitive logic.
No security action required. Review as normal library maintenance if relevant to downstream feature usage.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch removes the #[cfg(feature = "alloc")] guard from the script_hash and witness_script_hash modules and re-exports ScriptHash/WScriptHash in a minimal script module when alloc is disabled. Functionality that actually needs allocation (script-size checking, PushBytes, Display formatting, error types) remains gated behind alloc. The change is purely about crate feature availability and API surface, not about correctness or security.
Changed components
primitives/src/hash_types/mod.rsprimitives/src/hash_types/script_hash.rsprimitives/src/hash_types/witness_script_hash.rsprimitives/src/lib.rsInspect captured patch +136 / −6
### primitives/api/no-features.txt
@@ -1148,6 +1148,113 @@ impl<T> core::clone::CloneToUninit for bitcoin_primitives::opcodes::Opcode where
pub unsafe fn bitcoin_primitives::opcodes::Opcode::clone_to_uninit(&self, dest: *mut u8) [impl: impl<T> core::clone::CloneToUninit for bitcoin_primitives::opcodes::Opcode where T: core::clone::Clone]
impl<T> core::convert::From<T> for bitcoin_primitives::opcodes::Opcode
pub fn bitcoin_primitives::opcodes::Opcode::from(t: T) -> T [impl: impl<T> core::convert::From<T> for bitcoin_primitives::opcodes::Opcode]
+pub mod bitcoin_primitives::script
+pub struct bitcoin_primitives::script::ScriptHash(_)
+impl bitcoin_primitives::script::ScriptHash
+pub const fn bitcoin_primitives::script::ScriptHash::as_byte_array(&self) -> &[u8; 20]
+pub const fn bitcoin_primitives::script::ScriptHash::from_byte_array(bytes: [u8; 20]) -> Self
+pub const fn bitcoin_primitives::script::ScriptHash::to_byte_array(self) -> [u8; 20]
+impl core::borrow::Borrow<[u8; 20]> for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::borrow(&self) -> &[u8; 20] [impl: impl core::borrow::Borrow<[u8; 20]> for bitcoin_primitives::script::ScriptHash]
+impl core::borrow::Borrow<[u8]> for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::borrow(&self) -> &[u8] [impl: impl core::borrow::Borrow<[u8]> for bitcoin_primitives::script::ScriptHash]
+impl core::clone::Clone for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::clone(&self) -> bitcoin_primitives::script::ScriptHash [impl: impl core::clone::Clone for bitcoin_primitives::script::ScriptHash]
+impl core::cmp::Eq for bitcoin_primitives::script::ScriptHash
+impl core::cmp::Ord for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::cmp(&self, other: &bitcoin_primitives::script::ScriptHash) -> core::cmp::Ordering [impl: impl core::cmp::Ord for bitcoin_primitives::script::ScriptHash]
+impl core::cmp::PartialEq for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::eq(&self, other: &bitcoin_primitives::script::ScriptHash) -> bool [impl: impl core::cmp::PartialEq for bitcoin_primitives::script::ScriptHash]
+impl core::cmp::PartialOrd for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::partial_cmp(&self, other: &bitcoin_primitives::script::ScriptHash) -> core::option::Option<core::cmp::Ordering> [impl: impl core::cmp::PartialOrd for bitcoin_primitives::script::ScriptHash]
+impl core::convert::AsRef<[u8; 20]> for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::as_ref(&self) -> &[u8; 20] [impl: impl core::convert::AsRef<[u8; 20]> for bitcoin_primitives::script::ScriptHash]
+impl core::convert::AsRef<[u8]> for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::as_ref(&self) -> &[u8] [impl: impl core::convert::AsRef<[u8]> for bitcoin_primitives::script::ScriptHash]
+impl core::fmt::Debug for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result [impl: impl core::fmt::Debug for bitcoin_primitives::script::ScriptHash]
+impl core::hash::Hash for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::hash<__H: core::hash::Hasher>(&self, state: &mut __H) [impl: impl core::hash::Hash for bitcoin_primitives::script::ScriptHash]
+impl core::marker::Copy for bitcoin_primitives::script::ScriptHash
+impl core::marker::StructuralPartialEq for bitcoin_primitives::script::ScriptHash
+impl core::marker::Freeze for bitcoin_primitives::script::ScriptHash
+impl core::marker::Send for bitcoin_primitives::script::ScriptHash
+impl core::marker::Sync for bitcoin_primitives::script::ScriptHash
+impl core::marker::Unpin for bitcoin_primitives::script::ScriptHash
+impl core::marker::UnsafeUnpin for bitcoin_primitives::script::ScriptHash
+impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_primitives::script::ScriptHash
+impl core::panic::unwind_safe::UnwindSafe for bitcoin_primitives::script::ScriptHash
+impl<T, U> core::convert::Into<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::From<T>
+ pub fn bitcoin_primitives::script::ScriptHash::into(self) -> U [impl: impl<T, U> core::convert::Into<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::From<T>]
+impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::Into<T>
+ pub type bitcoin_primitives::script::ScriptHash::Error = core::convert::Infallible [impl: impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::Into<T>]
+ pub fn bitcoin_primitives::script::ScriptHash::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error> [impl: impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::Into<T>]
+impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::TryFrom<T>
+ pub type bitcoin_primitives::script::ScriptHash::Error = <U as core::convert::TryFrom<T>>::Error [impl: impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::TryFrom<T>]
+ pub fn bitcoin_primitives::script::ScriptHash::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error> [impl: impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::ScriptHash where U: core::convert::TryFrom<T>]
+impl<T> core::any::Any for bitcoin_primitives::script::ScriptHash where T: 'static + ?core::marker::Sized
+ pub fn bitcoin_primitives::script::ScriptHash::type_id(&self) -> core::any::TypeId [impl: impl<T> core::any::Any for bitcoin_primitives::script::ScriptHash where T: 'static + ?core::marker::Sized]
+impl<T> core::borrow::Borrow<T> for bitcoin_primitives::script::ScriptHash where T: ?core::marker::Sized
+ pub fn bitcoin_primitives::script::ScriptHash::borrow(&self) -> &T [impl: impl<T> core::borrow::Borrow<T> for bitcoin_primitives::script::ScriptHash where T: ?core::marker::Sized]
+impl<T> core::borrow::BorrowMut<T> for bitcoin_primitives::script::ScriptHash where T: ?core::marker::Sized
+ pub fn bitcoin_primitives::script::ScriptHash::borrow_mut(&mut self) -> &mut T [impl: impl<T> core::borrow::BorrowMut<T> for bitcoin_primitives::script::ScriptHash where T: ?core::marker::Sized]
+impl<T> core::clone::CloneToUninit for bitcoin_primitives::script::ScriptHash where T: core::clone::Clone
+ pub unsafe fn bitcoin_primitives::script::ScriptHash::clone_to_uninit(&self, dest: *mut u8) [impl: impl<T> core::clone::CloneToUninit for bitcoin_primitives::script::ScriptHash where T: core::clone::Clone]
+impl<T> core::convert::From<T> for bitcoin_primitives::script::ScriptHash
+ pub fn bitcoin_primitives::script::ScriptHash::from(t: T) -> T [impl: impl<T> core::convert::From<T> for bitcoin_primitives::script::ScriptHash]
+pub struct bitcoin_primitives::script::WScriptHash(_)
+impl bitcoin_primitives::script::WScriptHash
+pub const fn bitcoin_primitives::script::WScriptHash::as_byte_array(&self) -> &[u8; 32]
+pub const fn bitcoin_primitives::script::WScriptHash::from_byte_array(bytes: [u8; 32]) -> Self
+pub const fn bitcoin_primitives::script::WScriptHash::to_byte_array(self) -> [u8; 32]
+impl core::borrow::Borrow<[u8; 32]> for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::borrow(&self) -> &[u8; 32] [impl: impl core::borrow::Borrow<[u8; 32]> for bitcoin_primitives::script::WScriptHash]
+impl core::borrow::Borrow<[u8]> for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::borrow(&self) -> &[u8] [impl: impl core::borrow::Borrow<[u8]> for bitcoin_primitives::script::WScriptHash]
+impl core::clone::Clone for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::clone(&self) -> bitcoin_primitives::script::WScriptHash [impl: impl core::clone::Clone for bitcoin_primitives::script::WScriptHash]
+impl core::cmp::Eq for bitcoin_primitives::script::WScriptHash
+impl core::cmp::Ord for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::cmp(&self, other: &bitcoin_primitives::script::WScriptHash) -> core::cmp::Ordering [impl: impl core::cmp::Ord for bitcoin_primitives::script::WScriptHash]
+impl core::cmp::PartialEq for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::eq(&self, other: &bitcoin_primitives::script::WScriptHash) -> bool [impl: impl core::cmp::PartialEq for bitcoin_primitives::script::WScriptHash]
+impl core::cmp::PartialOrd for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::partial_cmp(&self, other: &bitcoin_primitives::script::WScriptHash) -> core::option::Option<core::cmp::Ordering> [impl: impl core::cmp::PartialOrd for bitcoin_primitives::script::WScriptHash]
+impl core::convert::AsRef<[u8; 32]> for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::as_ref(&self) -> &[u8; 32] [impl: impl core::convert::AsRef<[u8; 32]> for bitcoin_primitives::script::WScriptHash]
+impl core::convert::AsRef<[u8]> for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::as_ref(&self) -> &[u8] [impl: impl core::convert::AsRef<[u8]> for bitcoin_primitives::script::WScriptHash]
+impl core::fmt::Debug for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result [impl: impl core::fmt::Debug for bitcoin_primitives::script::WScriptHash]
+impl core::hash::Hash for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::hash<__H: core::hash::Hasher>(&self, state: &mut __H) [impl: impl core::hash::Hash for bitcoin_primitives::script::WScriptHash]
+impl core::marker::Copy for bitcoin_primitives::script::WScriptHash
+impl core::marker::StructuralPartialEq for bitcoin_primitives::script::WScriptHash
+impl core::marker::Freeze for bitcoin_primitives::script::WScriptHash
+impl core::marker::Send for bitcoin_primitives::script::WScriptHash
+impl core::marker::Sync for bitcoin_primitives::script::WScriptHash
+impl core::marker::Unpin for bitcoin_primitives::script::WScriptHash
+impl core::marker::UnsafeUnpin for bitcoin_primitives::script::WScriptHash
+impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_primitives::script::WScriptHash
+impl core::panic::unwind_safe::UnwindSafe for bitcoin_primitives::script::WScriptHash
+impl<T, U> core::convert::Into<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::From<T>
+ pub fn bitcoin_primitives::script::WScriptHash::into(self) -> U [impl: impl<T, U> core::convert::Into<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::From<T>]
+impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::Into<T>
+ pub type bitcoin_primitives::script::WScriptHash::Error = core::convert::Infallible [impl: impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::Into<T>]
+ pub fn bitcoin_primitives::script::WScriptHash::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error> [impl: impl<T, U> core::convert::TryFrom<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::Into<T>]
+impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::TryFrom<T>
+ pub type bitcoin_primitives::script::WScriptHash::Error = <U as core::convert::TryFrom<T>>::Error [impl: impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::TryFrom<T>]
+ pub fn bitcoin_primitives::script::WScriptHash::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error> [impl: impl<T, U> core::convert::TryInto<U> for bitcoin_primitives::script::WScriptHash where U: core::convert::TryFrom<T>]
+impl<T> core::any::Any for bitcoin_primitives::script::WScriptHash where T: 'static + ?core::marker::Sized
+ pub fn bitcoin_primitives::script::WScriptHash::type_id(&self) -> core::any::TypeId [impl: impl<T> core::any::Any for bitcoin_primitives::script::WScriptHash where T: 'static + ?core::marker::Sized]
+impl<T> core::borrow::Borrow<T> for bitcoin_primitives::script::WScriptHash where T: ?core::marker::Sized
+ pub fn bitcoin_primitives::script::WScriptHash::borrow(&self) -> &T [impl: impl<T> core::borrow::Borrow<T> for bitcoin_primitives::script::WScriptHash where T: ?core::marker::Sized]
+impl<T> core::borrow::BorrowMut<T> for bitcoin_primitives::script::WScriptHash where T: ?core::marker::Sized
+ pub fn bitcoin_primitives::script::WScriptHash::borrow_mut(&mut self) -> &mut T [impl: impl<T> core::borrow::BorrowMut<T> for bitcoin_primitives::script::WScriptHash where T: ?core::marker::Sized]
+impl<T> core::clone::CloneToUninit for bitcoin_primitives::script::WScriptHash where T: core::clone::Clone
+ pub unsafe fn bitcoin_primitives::script::WScriptHash::clone_to_uninit(&self, dest: *mut u8) [impl: impl<T> core::clone::CloneToUninit for bitcoin_primitives::script::WScriptHash where T: core::clone::Clone]
+impl<T> core::convert::From<T> for bitcoin_primitives::script::WScriptHash
+ pub fn bitcoin_primitives::script::WScriptHash::from(t: T) -> T [impl: impl<T> core::convert::From<T> for bitcoin_primitives::script::WScriptHash]
pub mod bitcoin_primitives::transaction
pub mod bitcoin_primitives::transaction::error
pub struct bitcoin_primitives::transaction::error::OutPointDecoderError(_)
### primitives/src/hash_types/mod.rs
@@ -6,13 +6,11 @@
mod block_hash;
mod ntxid;
-#[cfg(feature = "alloc")]
mod script_hash;
mod transaction_merkle_node;
mod txid;
mod witness_commitment;
mod witness_merkle_node;
-#[cfg(feature = "alloc")]
mod witness_script_hash;
mod wtxid;
@@ -21,18 +19,17 @@ mod wtxid;
pub use self::{
block_hash::{BlockHash, BlockHashDecoder, BlockHashDecoderError, BlockHashEncoder},
ntxid::Ntxid,
+ script_hash::ScriptHash,
transaction_merkle_node::{TxMerkleNode, TxMerkleNodeEncoder, TxMerkleNodeDecoder, TxMerkleNodeDecoderError},
txid::{Txid},
wtxid::Wtxid,
witness_commitment::WitnessCommitment,
witness_merkle_node::WitnessMerkleNode,
+ witness_script_hash::WScriptHash,
};
#[cfg(feature = "alloc")]
#[doc(inline)]
-pub use self::{
- script_hash::{RedeemScriptSizeError, ScriptHash},
- witness_script_hash::{WScriptHash, WitnessScriptSizeError},
-};
+pub use self::{script_hash::RedeemScriptSizeError, witness_script_hash::WitnessScriptSizeError};
/// Adds trait impls to a bytelike type.
///
### primitives/src/hash_types/script_hash.rs
@@ -2,7 +2,9 @@
//! The `ScriptHash` type.
+#[cfg(feature = "alloc")]
use core::convert::Infallible;
+#[cfg(any(feature = "alloc", feature = "hex"))]
use core::fmt;
#[cfg(feature = "hex")]
use core::str;
@@ -11,6 +13,7 @@ use core::str;
use arbitrary::{Arbitrary, Unstructured};
use hashes::hash160;
+#[cfg(feature = "alloc")]
use crate::script::{PushBytes, PushBytesBuf, Script, ScriptHashableTag, MAX_REDEEM_SCRIPT_SIZE};
/// A 160-bit hash of Bitcoin Script bytecode.
@@ -22,8 +25,10 @@ use crate::script::{PushBytes, PushBytesBuf, Script, ScriptHashableTag, MAX_REDE
pub struct ScriptHash(hash160::Hash);
super::impl_debug!(ScriptHash);
+#[cfg(feature = "alloc")]
crate::impl_asref_push_bytes!(ScriptHash);
+#[cfg(feature = "alloc")]
impl ScriptHash {
/// Constructs a new `ScriptHash` after first checking the script size.
///
@@ -65,22 +70,26 @@ impl ScriptHash {
}
/// Error while hashing a redeem script.
+#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RedeemScriptSizeError {
/// Invalid redeem script size (cannot exceed 520 bytes).
size: usize,
}
+#[cfg(feature = "alloc")]
impl RedeemScriptSizeError {
/// Returns the invalid redeem script size.
pub fn invalid_size(&self) -> usize { self.size }
}
+#[cfg(feature = "alloc")]
impl From<Infallible> for RedeemScriptSizeError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
+#[cfg(feature = "alloc")]
impl fmt::Display for RedeemScriptSizeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
### primitives/src/hash_types/witness_script_hash.rs
@@ -2,7 +2,9 @@
//! The `WScriptHash` type.
+#[cfg(feature = "alloc")]
use core::convert::Infallible;
+#[cfg(any(feature = "alloc", feature = "hex"))]
use core::fmt;
#[cfg(feature = "hex")]
use core::str;
@@ -11,6 +13,7 @@ use core::str;
use arbitrary::{Arbitrary, Unstructured};
use hashes::sha256;
+#[cfg(feature = "alloc")]
use crate::script::{PushBytes, PushBytesBuf, WitnessScript, MAX_WITNESS_SCRIPT_SIZE};
/// SegWit (256-bit) version of a Bitcoin Script bytecode hash.
@@ -22,8 +25,10 @@ use crate::script::{PushBytes, PushBytesBuf, WitnessScript, MAX_WITNESS_SCRIPT_S
pub struct WScriptHash(sha256::Hash);
super::impl_debug!(WScriptHash);
+#[cfg(feature = "alloc")]
crate::impl_asref_push_bytes!(WScriptHash);
+#[cfg(feature = "alloc")]
impl WScriptHash {
/// Constructs a new `WScriptHash` after first checking the script size.
///
@@ -60,22 +65,26 @@ impl WScriptHash {
}
/// Error while hashing a witness script.
+#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WitnessScriptSizeError {
/// Invalid witness script size (cannot exceed 10,000 bytes).
size: usize,
}
+#[cfg(feature = "alloc")]
impl WitnessScriptSizeError {
/// Returns the invalid witness script size.
pub fn invalid_size(&self) -> usize { self.size }
}
+#[cfg(feature = "alloc")]
impl From<Infallible> for WitnessScriptSizeError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
+#[cfg(feature = "alloc")]
impl fmt::Display for WitnessScriptSizeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
### primitives/src/lib.rs
@@ -131,6 +131,14 @@ mod prelude {
pub use alloc::sync;
}
+#[cfg(not(feature = "alloc"))]
+pub mod script {
+ //! Bitcoin scripts.
+
+ #[doc(inline)]
+ pub use crate::hash_types::{ScriptHash, WScriptHash};
+}
+
#[cfg(feature = "alloc")]
use encoding::Encoder;
#[cfg(feature = "alloc")]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.