Implement fmt::LowerHex and fmt::UpperHex for Witness
What changed, and why it matters
This commit adds the ability to print a Bitcoin transaction witness as a hexadecimal string, mirroring functionality already available for other types. It is a routine feature addition with no security relevance visible in the code or commit message.
No security action required. Review as a normal API addition if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements std::fmt::LowerHex and std::fmt::UpperHex for the Witness type in rust-bitcoin primitives. The implementation delegates to the existing HexPrimitive helper, which serializes the consensus encoding (compact-size element count followed by compact-size prefixed elements) as hex. It also updates the public API snapshot and adds unit tests for empty and non-empty witnesses. No parsing, serialization bounds, cryptographic, or memory-safety changes are introduced.
Changed components
primitives/src/witness.rsprimitives/api/all-features.txtInspect captured patch +44 / −0
diff --git a/primitives/api/all-features.txt b/primitives/api/all-features.txt
index b467ccd6..124b8183 100644
--- a/primitives/api/all-features.txt
+++ b/primitives/api/all-features.txt
@@ -5094,6 +5094,8 @@ impl core::default::Default for bitcoin_primitives::witness::Witness
pub fn bitcoin_primitives::witness::Witness::default() -> Self
impl core::fmt::Debug for bitcoin_primitives::witness::Witness
pub fn bitcoin_primitives::witness::Witness::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::fmt::LowerHex for bitcoin_primitives::witness::Witness
+impl core::fmt::UpperHex for bitcoin_primitives::witness::Witness
impl core::hash::Hash for bitcoin_primitives::witness::Witness
pub fn bitcoin_primitives::witness::Witness::hash<__H: core::hash::Hasher>(&self, state: &mut __H)
impl core::marker::StructuralPartialEq for bitcoin_primitives::witness::Witness
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index 9f9db89e..c74fa692 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -20,6 +20,8 @@ use hex::DecodeVariableLengthBytesError;
use internals::slice::SliceExt;
use internals::wrap_debug::WrapDebug;
+#[cfg(feature = "hex")]
+use crate::hex_codec::HexPrimitive;
use crate::prelude::{Box, Vec};
#[cfg(doc)]
use crate::TxIn;
@@ -636,6 +638,24 @@ impl fmt::Debug for Witness {
}
}
+/// Formats the witness as a hex string using its consensus encoding.
+///
+/// This is the compact size encoded number of elements followed by each element
+/// prefixed with its compact size encoded length.
+#[cfg(feature = "hex")]
+impl fmt::LowerHex for Witness {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::LowerHex::fmt(&HexPrimitive(self), f)
+ }
+}
+
+#[cfg(feature = "hex")]
+impl fmt::UpperHex for Witness {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::UpperHex::fmt(&HexPrimitive(self), f)
+ }
+}
+
/// An iterator returning individual witness elements.
#[derive(Clone)]
pub struct Iter<'a> {
@@ -1351,6 +1371,28 @@ mod test {
assert_eq!(witness.len(), 2);
}
+ #[test]
+ #[cfg(feature = "hex")]
+ fn empty_witness_lower_hex() {
+ let empty = Witness::new();
+ assert_eq!(format!("{:x}", empty), "00");
+ }
+
+ #[test]
+ #[cfg(feature = "hex")]
+ fn witness_lower_hex() {
+ let witness = Witness::from_iter([[1u8, 2, 3].as_slice(), [4u8, 5].as_slice()]);
+ // count (0x02), then len-prefixed elements: 03 010203, 02 0405.
+ assert_eq!(format!("{:x}", witness), "0203010203020405");
+ }
+
+ #[test]
+ #[cfg(feature = "hex")]
+ fn witness_upper_hex() {
+ let witness = Witness::from_iter([[0xABu8, 0xCD].as_slice()]);
+ assert_eq!(format!("{:X}", witness), "0102ABCD");
+ }
+
#[test]
fn encode() {
let bytes1 = [1u8, 2, 3];
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.