const_varint/ruint_impl/
v1.rs

1use crate::*;
2
3use ruint_1::Uint;
4
5impl<const BITS: usize, const LBITS: usize> Varint for Uint<BITS, LBITS> {
6  const MIN_ENCODED_LEN: usize = const {
7    if BITS == 0 {
8      0
9    } else {
10      1
11    }
12  };
13  const MAX_ENCODED_LEN: usize = BITS.div_ceil(7);
14
15  fn encoded_len(&self) -> usize {
16    match BITS {
17      0 => 0,
18      1..=8 => encoded_u8_varint_len(self.to()),
19      9..=16 => encoded_u16_varint_len(self.to()),
20      17..=32 => encoded_u32_varint_len(self.to()),
21      33..=64 => encoded_u64_varint_len(self.to()),
22      65..=128 => encoded_u128_varint_len(self.to()),
23      _ => {
24        // Each byte in LEB128 can store 7 bits
25        // Special case for 0 since it always needs 1 byte
26        if self.is_zero() {
27          return 1;
28        }
29
30        // Calculate position of highest set bit
31        let highest_bit = BITS - self.leading_zeros();
32        // Convert to number of LEB128 bytes needed
33        // Each byte holds 7 bits, but we need to round up
34        highest_bit.div_ceil(7)
35      }
36    }
37  }
38
39  fn encode(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
40    match BITS {
41      0 => Ok(0),
42      1..=8 => encode_u8_varint_to(self.to(), buf),
43      9..=16 => encode_u16_varint_to(self.to(), buf),
44      17..=32 => encode_u32_varint_to(self.to(), buf),
45      33..=64 => encode_u64_varint_to(self.to(), buf),
46      65..=128 => encode_u128_varint_to(self.to(), buf),
47      _ => {
48        let len = self.encoded_len();
49        let buf_len = buf.len();
50        if buf_len < len {
51          return Err(EncodeError::underflow(len, buf_len));
52        }
53
54        let mut value = *self;
55        let mut bytes_written = 0;
56
57        loop {
58          let mut byte = (value & Uint::from(0x7f)).to::<u8>();
59          value >>= 7;
60
61          // If there are more bits to encode, set the continuation bit
62          if !value.is_zero() {
63            byte |= 0x80;
64          }
65
66          buf[bytes_written] = byte;
67          bytes_written += 1;
68
69          if value.is_zero() {
70            break;
71          }
72        }
73
74        Ok(bytes_written)
75      }
76    }
77  }
78
79  fn decode(buf: &[u8]) -> Result<(usize, Self), DecodeError>
80  where
81    Self: Sized,
82  {
83    if BITS == 0 {
84      return Ok((0, Self::ZERO));
85    }
86
87    if buf.is_empty() {
88      return Err(DecodeError::Underflow);
89    }
90
91    let mut result = Self::ZERO;
92    let mut shift = 0;
93    let mut bytes_read = 0;
94
95    while bytes_read < buf.len() {
96      let byte = buf[bytes_read];
97      // Extract the 7 data bits
98      let value = Self::from(byte & 0x7f);
99
100      // Check for overflow
101      if shift >= BITS {
102        return Err(DecodeError::Overflow);
103      }
104
105      // Add the bits to the result
106      // Need to handle potential overflow
107      if let Some(shifted) = value.checked_shl(shift) {
108        result |= shifted;
109      } else {
110        return Err(DecodeError::Overflow);
111      }
112
113      bytes_read += 1;
114
115      // If continuation bit is not set, we're done
116      if byte & 0x80 == 0 {
117        return Ok((bytes_read, result));
118      }
119
120      shift += 7;
121    }
122
123    // If we get here, the input ended with a continuation bit set
124    Err(DecodeError::Underflow)
125  }
126}
127
128#[cfg(test)]
129mod tests_ruint_1 {
130  use super::*;
131
132  use ruint_1::aliases::{
133    U0, U1, U1024, U128, U16, U2048, U256, U32, U320, U384, U4096, U448, U512, U64, U768,
134  };
135
136  use quickcheck_macros::quickcheck;
137
138  macro_rules! fuzzy {
139    ($($ty:ident), +$(,)?) => {
140      $(
141        paste::paste! {
142          #[quickcheck]
143          fn [< fuzzy_ $ty:snake >](value: $ty) -> bool {
144            let mut buf = [0; <$ty>::MAX_ENCODED_LEN];
145            let Ok(encoded_len) = value.encode(&mut buf) else { return false; };
146            if encoded_len != value.encoded_len() || !(value.encoded_len() <= <$ty>::MAX_ENCODED_LEN) {
147              return false;
148            }
149
150            let Ok(consumed) = crate::consume_varint(&buf) else {
151              return false;
152            };
153            if consumed != encoded_len {
154              return false;
155            }
156
157            if let Ok((bytes_read, decoded)) = <$ty>::decode(&buf) {
158              value == decoded && encoded_len == bytes_read
159            } else {
160              false
161            }
162          }
163        }
164      )*
165    };
166  }
167
168  fuzzy!(U0, U1, U16, U32, U64, U128, U256, U320, U384, U448, U512, U768, U1024, U2048, U4096);
169
170  macro_rules! max_encoded_len {
171    ($($ty:ident), +$(,)?) => {
172      $(
173        paste::paste! {
174          #[test]
175          fn [< test_ $ty:snake _min_max_encoded_len>]() {
176            let max = $ty::MAX;
177            let min = $ty::MIN;
178            assert_eq!(max.encoded_len(), $ty::MAX_ENCODED_LEN);
179            assert_eq!(min.encoded_len(), $ty::MIN_ENCODED_LEN);
180          }
181        }
182      )*
183    };
184  }
185
186  max_encoded_len!(
187    U0, U1, U16, U32, U64, U128, U256, U320, U384, U448, U512, U768, U1024, U2048, U4096
188  );
189
190  #[cfg(feature = "std")]
191  mod with_std {
192    extern crate std;
193
194    use super::*;
195
196    use std::{vec, vec::Vec};
197
198    // Helper type to generate fixed size arrays
199    #[derive(Debug, Clone)]
200    struct ByteArray<const N: usize>([u8; N]);
201
202    impl<const N: usize> quickcheck::Arbitrary for ByteArray<N> {
203      fn arbitrary(g: &mut quickcheck::Gen) -> Self {
204        let mut arr = [0u8; N];
205        for b in arr.iter_mut() {
206          *b = u8::arbitrary(g);
207        }
208        ByteArray(arr)
209      }
210    }
211
212    // Underflow tests for different sizes
213    #[quickcheck]
214    fn fuzzy_u256_buffer_underflow(bytes: ByteArray<32>, short_len: usize) -> bool {
215      let uint = Uint::<256, 4>::from_be_bytes(bytes.0);
216      let short_len = short_len % (Uint::<256, 4>::MAX_ENCODED_LEN - 1);
217      if short_len >= uint.encoded_len() {
218        return true;
219      }
220      let mut short_buffer = vec![0u8; short_len];
221      matches!(
222        uint.encode(&mut short_buffer),
223        Err(EncodeError::Underflow { .. })
224      )
225    }
226
227    #[quickcheck]
228    fn fuzzy_u512_buffer_underflow(bytes: ByteArray<64>, short_len: usize) -> bool {
229      let uint = Uint::<512, 8>::from_be_bytes(bytes.0);
230      let short_len = short_len % (Uint::<512, 8>::MAX_ENCODED_LEN - 1);
231      if short_len >= uint.encoded_len() {
232        return true;
233      }
234      let mut short_buffer = vec![0u8; short_len];
235      matches!(
236        uint.encode(&mut short_buffer),
237        Err(EncodeError::Underflow { .. })
238      )
239    }
240
241    #[test]
242    fn t() {
243      std::println!("{} {}", U0::MAX, U0::MAX_ENCODED_LEN);
244    }
245
246    #[quickcheck]
247    fn fuzzy_invalid_sequences(bytes: Vec<u8>) -> bool {
248      if bytes.is_empty() {
249        return matches!(U256::decode(&bytes), Err(DecodeError::Underflow));
250      }
251
252      // Only test sequences up to max varint length
253      if bytes.len() > 10 {
254        return true;
255      }
256
257      // If all bytes have continuation bit set, should get Underflow
258      if bytes.iter().all(|b| b & 0x80 != 0) {
259        return matches!(U256::decode(&bytes), Err(DecodeError::Underflow));
260      }
261
262      // For other cases, we should get either a valid decode or an error
263      match U256::decode(&bytes) {
264        Ok(_) => true,
265        Err(_) => true,
266      }
267    }
268  }
269}