bitcoin_consensus_encoding/
compact_size.rs1use internals::array_vec::ArrayVec;
10
11use crate::decode::Decoder;
12use crate::encode::{Encoder, ExactSizeEncoder};
13use crate::error::{
14 CompactSizeDecoderError, CompactSizeDecoderErrorInner, LengthPrefixExceedsMaxError,
15};
16
17const MAX_COMPACT_SIZE: usize = 0x0200_0000;
25
26const SIZE: usize = 9;
28
29const PREFIX_U16: u8 = 0xFD;
31const PREFIX_U32: u8 = 0xFE;
33const PREFIX_U64: u8 = 0xFF;
35
36#[derive(Debug, Clone)]
38pub struct CompactSizeEncoder {
39 buf: Option<ArrayVec<u8, SIZE>>,
40}
41
42impl CompactSizeEncoder {
43 pub fn new(value: usize) -> Self {
56 Self { buf: Some(Self::encode(u64::try_from(value).unwrap_or(u64::MAX))) }
57 }
58
59 pub fn new_u64(value: u64) -> Self { Self { buf: Some(Self::encode(value)) } }
67
68 #[inline]
77 pub const fn encoded_size(value: usize) -> usize {
78 match value {
79 0..=0xFC => 1,
80 0xFD..=0xFFFF => 3,
81 0x10000..=0xFFFF_FFFF => 5,
82 _ => 9,
83 }
84 }
85
86 #[inline]
88 fn encode(value: u64) -> ArrayVec<u8, SIZE> {
89 let mut res = ArrayVec::<u8, SIZE>::new();
90 match value {
91 0..=0xFC => {
92 res.push(value as u8); }
94 0xFD..=0xFFFF => {
95 let v = value as u16; res.push(PREFIX_U16);
97 res.extend_from_slice(&v.to_le_bytes());
98 }
99 0x10000..=0xFFFF_FFFF => {
100 let v = value as u32; res.push(PREFIX_U32);
102 res.extend_from_slice(&v.to_le_bytes());
103 }
104 _ => {
105 res.push(PREFIX_U64);
106 res.extend_from_slice(&value.to_le_bytes());
107 }
108 }
109 res
110 }
111}
112
113impl Encoder for CompactSizeEncoder {
114 #[inline]
115 fn current_chunk(&self) -> &[u8] { self.buf.as_ref().map(|b| &b[..]).unwrap_or_default() }
116
117 #[inline]
118 fn advance(&mut self) -> bool {
119 self.buf = None;
120 false
121 }
122}
123
124impl ExactSizeEncoder for CompactSizeEncoder {
125 #[inline]
126 fn len(&self) -> usize { self.buf.map_or(0, |buf| buf.len()) }
127}
128
129#[derive(Debug, Clone)]
142pub struct CompactSizeDecoder {
143 buf: ArrayVec<u8, 9>,
144 limit: usize,
145}
146
147impl CompactSizeDecoder {
148 pub const fn new() -> Self { Self { buf: ArrayVec::new(), limit: MAX_COMPACT_SIZE } }
150
151 pub const fn new_with_limit(limit: usize) -> Self { Self { buf: ArrayVec::new(), limit } }
157}
158
159impl Default for CompactSizeDecoder {
160 fn default() -> Self { Self::new() }
161}
162
163impl Decoder for CompactSizeDecoder {
164 type Output = usize;
165 type Error = CompactSizeDecoderError;
166
167 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
168 Ok(compact_size_push_bytes(&mut self.buf, bytes))
169 }
170
171 fn end(self) -> Result<Self::Output, Self::Error> {
172 use CompactSizeDecoderErrorInner as E;
173
174 let dec_value = compact_size_decode_u64(&self.buf)?;
175
176 let make_err = || {
179 CompactSizeDecoderError(E::ValueExceedsLimit(LengthPrefixExceedsMaxError {
180 value: dec_value,
181 limit: self.limit,
182 }))
183 };
184
185 usize::try_from(dec_value).map_err(|_| make_err()).and_then(|nsize| {
186 if nsize > self.limit {
187 Err(make_err())
188 } else {
189 Ok(nsize)
190 }
191 })
192 }
193
194 fn read_limit(&self) -> usize { compact_size_read_limit(&self.buf) }
195}
196
197#[derive(Debug, Clone)]
216pub struct CompactSizeU64Decoder {
217 buf: ArrayVec<u8, 9>,
218}
219
220impl CompactSizeU64Decoder {
221 pub const fn new() -> Self { Self { buf: ArrayVec::new() } }
226}
227
228impl Default for CompactSizeU64Decoder {
229 fn default() -> Self { Self::new() }
230}
231
232impl Decoder for CompactSizeU64Decoder {
233 type Output = u64;
234 type Error = CompactSizeDecoderError;
235
236 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
237 Ok(compact_size_push_bytes(&mut self.buf, bytes))
238 }
239
240 fn end(self) -> Result<Self::Output, Self::Error> { compact_size_decode_u64(&self.buf) }
241
242 fn read_limit(&self) -> usize { compact_size_read_limit(&self.buf) }
243}
244
245fn compact_size_push_bytes(buf: &mut ArrayVec<u8, 9>, bytes: &mut &[u8]) -> bool {
247 if bytes.is_empty() {
248 return true;
249 }
250
251 if buf.is_empty() {
252 buf.push(bytes[0]);
253 *bytes = &bytes[1..];
254 }
255 let len = match buf[0] {
256 PREFIX_U64 => 9,
257 PREFIX_U32 => 5,
258 PREFIX_U16 => 3,
259 _ => 1,
260 };
261 let to_copy = bytes.len().min(len - buf.len());
262 buf.extend_from_slice(&bytes[..to_copy]);
263 *bytes = &bytes[to_copy..];
264
265 buf.len() != len
266}
267
268fn compact_size_read_limit(buf: &ArrayVec<u8, 9>) -> usize {
270 match buf.len() {
271 0 => 1,
272 already_read => match buf[0] {
273 PREFIX_U64 => 9_usize.saturating_sub(already_read),
274 PREFIX_U32 => 5_usize.saturating_sub(already_read),
275 PREFIX_U16 => 3_usize.saturating_sub(already_read),
276 _ => 0,
277 },
278 }
279}
280
281fn compact_size_decode_u64(buf: &ArrayVec<u8, 9>) -> Result<u64, CompactSizeDecoderError> {
283 use CompactSizeDecoderErrorInner as E;
284
285 fn arr<const N: usize>(slice: &[u8]) -> Result<[u8; N], CompactSizeDecoderError> {
286 slice.try_into().map_err(|_| {
287 CompactSizeDecoderError(E::UnexpectedEof { required: N, received: slice.len() })
288 })
289 }
290
291 let (first, payload) = buf
292 .split_first()
293 .ok_or(CompactSizeDecoderError(E::UnexpectedEof { required: 1, received: 0 }))?;
294
295 match *first {
296 PREFIX_U64 => {
297 let x = u64::from_le_bytes(arr(payload)?);
298 if x < 0x100_000_000 {
299 Err(CompactSizeDecoderError(E::NonMinimal { value: x }))
300 } else {
301 Ok(x)
302 }
303 }
304 PREFIX_U32 => {
305 let x = u32::from_le_bytes(arr(payload)?);
306 if x < 0x10000 {
307 Err(CompactSizeDecoderError(E::NonMinimal { value: x.into() }))
308 } else {
309 Ok(x.into())
310 }
311 }
312 PREFIX_U16 => {
313 let x = u16::from_le_bytes(arr(payload)?);
314 if x < 0xFD {
315 Err(CompactSizeDecoderError(E::NonMinimal { value: x.into() }))
316 } else {
317 Ok(x.into())
318 }
319 }
320 n => Ok(n.into()),
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327
328 #[test]
329 fn encoded_value_1_byte() {
330 for v in [0x00u64, 0x01, 0x02, 0xFA, 0xFB, 0xFC] {
332 assert_eq!(CompactSizeEncoder::encoded_size(v as usize), 1);
333 let want = [v as u8];
335 let got = CompactSizeEncoder::encode(v);
336 assert_eq!(got.as_slice().len(), 1); assert_eq!(got.as_slice(), want);
338 }
339 }
340
341 macro_rules! check_encode {
342 ($($test_name:ident, $size:expr, $value:expr, $want:expr);* $(;)?) => {
343 $(
344 #[test]
345 fn $test_name() {
346 let value = $value as u64; assert_eq!(CompactSizeEncoder::encoded_size(value as usize), $size);
348 let got = CompactSizeEncoder::encode(value);
349 assert_eq!(got.as_slice().len(), $size); assert_eq!(got.as_slice(), &$want);
351 }
352 )*
353 }
354 }
355
356 check_encode! {
357 encoded_value_3_byte_lower_bound, 3, 0xFD, [0xFD, 0xFD, 0x00]; encoded_value_3_byte_endianness, 3, 0xABCD, [0xFD, 0xCD, 0xAB];
360 encoded_value_3_byte_upper_bound, 3, 0xFFFF, [0xFD, 0xFF, 0xFF];
361 encoded_value_5_byte_lower_bound, 5, 0x0001_0000, [0xFE, 0x00, 0x00, 0x01, 0x00];
363 encoded_value_5_byte_endianness, 5, 0x0123_4567, [0xFE, 0x67, 0x45, 0x23, 0x01];
364 encoded_value_5_byte_upper_bound, 5, 0xFFFF_FFFF, [0xFE, 0xFF, 0xFF, 0xFF, 0xFF];
365 }
366
367 #[cfg(target_pointer_width = "64")]
369 check_encode! {
370 encoded_value_9_byte_lower_bound, 9, 0x0000_0001_0000_0000u64, [0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
371 encoded_value_9_byte_endianness, 9, 0x0123_4567_89AB_CDEFu64, [0xFF, 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01];
372 encoded_value_9_byte_upper_bound, 9, u64::MAX, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
373 }
374
375 #[test]
376 fn compact_size_new_values_too_large() {
377 use CompactSizeDecoderErrorInner as E;
378
379 const EXCESS_COMPACT_SIZE: u64 = (MAX_COMPACT_SIZE + 1) as u64;
380
381 let mut decoder = CompactSizeDecoder::new();
384 decoder.push_bytes(&mut [0xFE, 0x00, 0x00, 0x00, 0x02].as_slice()).unwrap();
385 let got = decoder.end().unwrap();
386 assert_eq!(got, MAX_COMPACT_SIZE);
387
388 let mut decoder = CompactSizeDecoder::new();
391 decoder.push_bytes(&mut [0xFE, 0x01, 0x00, 0x00, 0x02].as_slice()).unwrap();
392 let got = decoder.end().unwrap_err();
393 assert!(matches!(
394 got,
395 CompactSizeDecoderError(E::ValueExceedsLimit(LengthPrefixExceedsMaxError {
396 limit: MAX_COMPACT_SIZE,
397 value: EXCESS_COMPACT_SIZE,
398 })),
399 ));
400 }
401
402 #[test]
403 fn compact_size_new_with_limit_values_too_large() {
404 use CompactSizeDecoderErrorInner as E;
405
406 let mut decoder = CompactSizeDecoder::new_with_limit(240);
408 decoder.push_bytes(&mut [0xf0].as_slice()).unwrap();
409 let got = decoder.end().unwrap();
410 assert_eq!(got, 240);
411
412 let mut decoder = CompactSizeDecoder::new_with_limit(240);
414 decoder.push_bytes(&mut [0xf1].as_slice()).unwrap();
415 let got = decoder.end().unwrap_err();
416 assert!(matches!(
417 got,
418 CompactSizeDecoderError(E::ValueExceedsLimit(LengthPrefixExceedsMaxError {
419 limit: 240,
420 value: 241,
421 })),
422 ));
423 }
424}