primitives: Refactor `WitnessEncoder` to use CompactSizeEncoder
What changed, and why it matters
This commit is a straightforward internal code cleanup. It replaces a custom hand-written encoding helper for Bitcoin transaction witness data with a reusable, already-existing encoder component. There is no indication of a bug fix or security change.
No security action required. Treat as normal refactoring review; verify tests pass and encoding remains byte-for-byte compatible if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors WitnessEncoder in primitives/src/witness.rs. Previously it manually managed an ArrayVec for the compact-size count of witness elements and a slice for the element bytes, implementing current_chunk/advance itself. The new implementation composes CompactSizeEncoder and BytesEncoder via Encoder2, delegating the same methods. The encoded output is intended to be identical; no functional or security behavior changes are visible in the diff.
Changed components
primitives/src/witness.rsWitnessEncoderInspect captured patch +8 / −33
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index 083272fc..225b9d41 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -9,10 +9,9 @@ use core::ops::Index;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
-use encoding::{Encodable, Encoder};
+use encoding::{BytesEncoder, CompactSizeEncoder, Encodable, Encoder, Encoder2};
#[cfg(feature = "hex")]
use hex::{error::HexToBytesError, FromHex};
-use internals::array_vec::ArrayVec;
use internals::compact_size;
use internals::slice::SliceExt;
use internals::wrap_debug::WrapDebug;
@@ -262,19 +261,8 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
bytes.get_array::<4>(start).map(|index_bytes| u32::from_ne_bytes(*index_bytes) as usize)
}
-/// The maximum length of a compact size encoding.
-const SIZE: usize = compact_size::MAX_ENCODING_SIZE;
-
/// The encoder for the [`Witness`] type.
-// This is basically an exact copy of the `encoding::BytesEncoder` except we prefix
-// with the number of witness elements not the byte slice length.
-pub struct WitnessEncoder<'a> {
- /// A slice of all the elements without the initial length prefix
- /// but with the length prefix on each element.
- witness_elements: Option<&'a [u8]>,
- /// Encoding of the number of witness elements.
- num_elements: Option<ArrayVec<u8, SIZE>>,
-}
+pub struct WitnessEncoder<'a>(Encoder2<CompactSizeEncoder, BytesEncoder<'a>>);
impl Encodable for Witness {
type Encoder<'a>
@@ -283,33 +271,20 @@ impl Encodable for Witness {
Self: 'a;
fn encoder(&self) -> Self::Encoder<'_> {
- let num_elements = Some(compact_size::encode(self.len()));
- let witness_elements = Some(&self.content[..self.indices_start]);
+ let num_elements = CompactSizeEncoder::new(self.len());
+ let witness_elements =
+ BytesEncoder::without_length_prefix(&self.content[..self.indices_start]);
- WitnessEncoder { witness_elements, num_elements }
+ WitnessEncoder(Encoder2::new(num_elements, witness_elements))
}
}
impl<'a> Encoder for WitnessEncoder<'a> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> {
- if let Some(num_elements) = self.num_elements.as_ref() {
- Some(num_elements)
- } else {
- self.witness_elements
- }
- }
+ fn current_chunk(&self) -> Option<&[u8]> { self.0.current_chunk() }
#[inline]
- fn advance(&mut self) -> bool {
- if self.num_elements.is_some() {
- self.num_elements = None;
- true
- } else {
- self.witness_elements = None;
- false
- }
- }
+ fn advance(&mut self) -> bool { self.0.advance() }
}
// Note: we use `Borrow` in the following `PartialEq` impls specifically because of its additional
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.