1mod encode;
2mod integer;
3mod list;
4
5#[cfg(test)]
6mod tests;
7
8use crate::{
9 DecodeAccumulator, DecodeError, DecodeLimits, checked_len_add, require_exact_consumption,
10 require_range_in_bounds,
11};
12
13pub use encode::{
14 encode_decoded_integer, encode_decoded_item, encode_decoded_list, encode_decoded_scalar,
15 encode_rlp_integer, encode_rlp_list_header, encode_rlp_list_payload, encode_rlp_scalar,
16 encoded_rlp_integer_len, encoded_rlp_list_header_len, encoded_rlp_list_len,
17 encoded_rlp_scalar_len,
18};
19pub use integer::{
20 MAX_RLP_U256_BYTES, RlpInteger, decode_rlp_integer, decode_rlp_integer_partial, decode_rlp_u64,
21 decode_rlp_u128, decode_rlp_u256_bytes, rlp_integer_payload_to_u64,
22 rlp_integer_payload_to_u128, rlp_integer_payload_to_u256_bytes, validate_rlp_integer_payload,
23};
24pub use list::{
25 MAX_RLP_LIST_TRAVERSAL_DEPTH, RlpItem, RlpList, RlpListForm, RlpListItems, decode_rlp_list,
26 decode_rlp_list_partial,
27};
28
29pub(super) const SHORT_STRING_OFFSET: u8 = 0x80;
30pub(super) const LONG_STRING_OFFSET: u8 = 0xb7;
34pub(super) const SHORT_LIST_OFFSET: u8 = 0xc0;
35pub(super) const LONG_LIST_OFFSET: u8 = 0xf7;
39pub(super) const SHORT_STRING_LIMIT: usize = 55;
40pub(super) const LENGTH_RADIX: usize = 256;
41
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub enum RlpScalarForm {
45 SingleByte,
47 ShortString,
49 LongString,
51}
52
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
58pub struct RlpScalar<'a> {
59 payload: &'a [u8],
60 encoded_len: usize,
61 header_len: usize,
62 form: RlpScalarForm,
63}
64
65impl<'a> RlpScalar<'a> {
66 #[must_use]
68 pub const fn payload(self) -> &'a [u8] {
69 self.payload
70 }
71
72 #[must_use]
74 pub const fn encoded_len(self) -> usize {
75 self.encoded_len
76 }
77
78 #[must_use]
80 pub const fn header_len(self) -> usize {
81 self.header_len
82 }
83
84 #[must_use]
86 pub const fn form(self) -> RlpScalarForm {
87 self.form
88 }
89
90 #[must_use]
92 pub const fn is_empty(self) -> bool {
93 self.payload.is_empty()
94 }
95}
96
97pub fn decode_rlp_scalar<'a>(
99 input: &'a [u8],
100 limits: DecodeLimits,
101) -> Result<RlpScalar<'a>, DecodeError> {
102 let mut accumulator = limits.accumulator();
103 let scalar = decode_rlp_scalar_partial(input, &mut accumulator)?;
104 require_exact_consumption(scalar.encoded_len, input.len())?;
105 Ok(scalar)
106}
107
108pub fn decode_rlp_scalar_partial<'a>(
120 input: &'a [u8],
121 accumulator: &mut DecodeAccumulator,
122) -> Result<RlpScalar<'a>, DecodeError> {
123 accumulator.check_input_len(input.len())?;
124 accumulator.account_items(1)?;
125
126 let prefix = *input.first().ok_or(DecodeError::Malformed)?;
127 match prefix {
128 0x00..=0x7f => decode_single_byte(input),
129 SHORT_STRING_OFFSET..=LONG_STRING_OFFSET => decode_short_string(input, prefix),
130 0xb8..=0xbf => decode_long_string(input, prefix),
131 SHORT_LIST_OFFSET..=0xff => Err(DecodeError::UnexpectedList),
132 }
133}
134
135fn decode_single_byte(input: &[u8]) -> Result<RlpScalar<'_>, DecodeError> {
136 let payload = input.get(..1).ok_or(DecodeError::OffsetOutOfBounds)?;
137 Ok(RlpScalar {
138 payload,
139 encoded_len: 1,
140 header_len: 0,
141 form: RlpScalarForm::SingleByte,
142 })
143}
144
145pub(super) fn decode_short_string(input: &[u8], prefix: u8) -> Result<RlpScalar<'_>, DecodeError> {
146 let payload_len = usize::from(prefix.saturating_sub(SHORT_STRING_OFFSET));
147 let payload = payload(input, 1, payload_len)?;
148 if payload_len == 1 && payload.first().is_some_and(|byte| *byte <= 0x7f) {
149 return Err(DecodeError::Malformed);
150 }
151 Ok(RlpScalar {
152 payload,
153 encoded_len: checked_len_add(1, payload_len)?,
154 header_len: 1,
155 form: RlpScalarForm::ShortString,
156 })
157}
158
159pub(super) fn decode_long_string(input: &[u8], prefix: u8) -> Result<RlpScalar<'_>, DecodeError> {
160 let len_of_len = usize::from(prefix.saturating_sub(LONG_STRING_OFFSET));
161 let payload_len = parse_payload_len(input, 1, len_of_len)?;
162 if payload_len <= SHORT_STRING_LIMIT {
163 return Err(DecodeError::Malformed);
164 }
165 let header_len = checked_len_add(1, len_of_len)?;
166 let payload = payload(input, header_len, payload_len)?;
167 Ok(RlpScalar {
168 payload,
169 encoded_len: checked_len_add(header_len, payload_len)?,
170 header_len,
171 form: RlpScalarForm::LongString,
172 })
173}
174
175pub(super) fn parse_payload_len(
176 input: &[u8],
177 offset: usize,
178 len: usize,
179) -> Result<usize, DecodeError> {
180 let end = require_range_in_bounds(offset, len, input.len())?;
181 let bytes = input
182 .get(offset..end)
183 .ok_or(DecodeError::OffsetOutOfBounds)?;
184 if bytes.first().is_some_and(|byte| *byte == 0) {
185 return Err(DecodeError::Malformed);
186 }
187
188 let mut value = 0usize;
189 for byte in bytes {
190 value = value
191 .checked_mul(LENGTH_RADIX)
192 .ok_or(DecodeError::LengthOverflow)?;
193 value = value
194 .checked_add(usize::from(*byte))
195 .ok_or(DecodeError::LengthOverflow)?;
196 }
197 Ok(value)
198}
199
200pub(super) fn payload(input: &[u8], offset: usize, len: usize) -> Result<&[u8], DecodeError> {
201 let end = require_range_in_bounds(offset, len, input.len())?;
202 input.get(offset..end).ok_or(DecodeError::OffsetOutOfBounds)
203}