Implement new Encodable trait for Script<T>
What changed, and why it matters
This commit adds a new way to serialize (encode) Bitcoin scripts in the rust-bitcoin library. It is a routine feature addition: it lets Script<T> be encoded with a length prefix, matching Bitcoin's consensus format. There is no indication of a security bug, fix, or vulnerability.
No security action required. Review as normal code-quality/feature addition.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements the Encodable trait for Script
Changed components
primitives/src/script/borrowed.rsprimitives/src/script/mod.rsInspect captured patch +32 / −1
diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs
index 22028875..7a3edbf5 100644
--- a/primitives/src/script/borrowed.rs
+++ b/primitives/src/script/borrowed.rs
@@ -7,6 +7,7 @@ use core::ops::{
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
+use encoding::{BytesEncoder, Encodable};
use super::ScriptBuf;
use crate::prelude::{Box, ToOwned, Vec};
@@ -152,6 +153,22 @@ impl<T> Script<T> {
pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) }
}
+encoding::encoder_newtype! {
+ /// The encoder for the [`Script<T>`] type.
+ pub struct ScriptEncoder<'e>(BytesEncoder<'e>);
+}
+
+impl<T> Encodable for Script<T> {
+ type Encoder<'a>
+ = ScriptEncoder<'a>
+ where
+ Self: 'a;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ ScriptEncoder(BytesEncoder::with_length_prefix(self.as_bytes()))
+ }
+}
+
#[cfg(feature = "arbitrary")]
impl<'a, T> Arbitrary<'a> for &'a Script<T> {
#[inline]
@@ -248,4 +265,18 @@ mod tests {
assert_eq!(script[1..=3].as_bytes(), &[2, 3, 4]);
assert_eq!(script[..=2].as_bytes(), &[1, 2, 3]);
}
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn encode() {
+ // Consensus encoding includes the length of the encoded data
+ // (compact size encoded length prefix).
+ let consensus_encoded: [u8; 6] = [0x05, 1, 2, 3, 4, 5];
+
+ // `from_bytes` does not expect the prefix.
+ let script = Script::from_bytes(&consensus_encoded[1..]);
+
+ let got = encoding::encode_to_vec(script);
+ assert_eq!(got, consensus_encoded);
+ }
}
diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs
index 4bc68cac..30d64f6c 100644
--- a/primitives/src/script/mod.rs
+++ b/primitives/src/script/mod.rs
@@ -26,7 +26,7 @@ use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
pub use self::{
- borrowed::Script,
+ borrowed::{Script, ScriptEncoder},
owned::ScriptBuf,
tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, TapScriptTag, WitnessScriptTag},
};
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.