1mod integer;
2mod list;
3
4#[cfg(test)]
5mod tests;
6
7use crate::{
8 DecodeAccumulator, DecodeError, DecodeLimits, checked_len_add, require_exact_consumption,
9 require_range_in_bounds,
10};
11
12pub use integer::{
13 MAX_RLP_U256_BYTES, RlpInteger, decode_rlp_integer, decode_rlp_integer_partial, decode_rlp_u64,
14 decode_rlp_u128, decode_rlp_u256_bytes,
15};
16pub use list::{
17 MAX_RLP_LIST_TRAVERSAL_DEPTH, RlpItem, RlpList, RlpListForm, RlpListItems, decode_rlp_list,
18 decode_rlp_list_partial,
19};
20
21pub(super) const SHORT_STRING_OFFSET: u8 = 0x80;
22pub(super) const LONG_STRING_OFFSET: u8 = 0xb7;
26pub(super) const SHORT_LIST_OFFSET: u8 = 0xc0;
27pub(super) const LONG_LIST_OFFSET: u8 = 0xf7;
31pub(super) const SHORT_STRING_LIMIT: usize = 55;
32pub(super) const LENGTH_RADIX: usize = 256;
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum RlpScalarForm {
37 SingleByte,
39 ShortString,
41 LongString,
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub struct RlpScalar<'a> {
48 payload: &'a [u8],
49 encoded_len: usize,
50 header_len: usize,
51 form: RlpScalarForm,
52}
53
54impl<'a> RlpScalar<'a> {
55 #[must_use]
57 pub const fn payload(self) -> &'a [u8] {
58 self.payload
59 }
60
61 #[must_use]
63 pub const fn encoded_len(self) -> usize {
64 self.encoded_len
65 }
66
67 #[must_use]
69 pub const fn header_len(self) -> usize {
70 self.header_len
71 }
72
73 #[must_use]
75 pub const fn form(self) -> RlpScalarForm {
76 self.form
77 }
78
79 #[must_use]
81 pub const fn is_empty(self) -> bool {
82 self.payload.is_empty()
83 }
84}
85
86pub fn decode_rlp_scalar<'a>(
88 input: &'a [u8],
89 limits: DecodeLimits,
90) -> Result<RlpScalar<'a>, DecodeError> {
91 let mut accumulator = limits.accumulator();
92 let scalar = decode_rlp_scalar_partial(input, &mut accumulator)?;
93 require_exact_consumption(scalar.encoded_len, input.len())?;
94 Ok(scalar)
95}
96
97pub fn decode_rlp_scalar_partial<'a>(
109 input: &'a [u8],
110 accumulator: &mut DecodeAccumulator,
111) -> Result<RlpScalar<'a>, DecodeError> {
112 accumulator.check_input_len(input.len())?;
113 accumulator.account_items(1)?;
114
115 let prefix = *input.first().ok_or(DecodeError::Malformed)?;
116 match prefix {
117 0x00..=0x7f => decode_single_byte(input),
118 SHORT_STRING_OFFSET..=LONG_STRING_OFFSET => decode_short_string(input, prefix),
119 0xb8..=0xbf => decode_long_string(input, prefix),
120 SHORT_LIST_OFFSET..=0xff => Err(DecodeError::UnexpectedList),
121 }
122}
123
124fn decode_single_byte(input: &[u8]) -> Result<RlpScalar<'_>, DecodeError> {
125 let payload = input.get(..1).ok_or(DecodeError::OffsetOutOfBounds)?;
126 Ok(RlpScalar {
127 payload,
128 encoded_len: 1,
129 header_len: 0,
130 form: RlpScalarForm::SingleByte,
131 })
132}
133
134pub(super) fn decode_short_string(input: &[u8], prefix: u8) -> Result<RlpScalar<'_>, DecodeError> {
135 let payload_len = usize::from(prefix.saturating_sub(SHORT_STRING_OFFSET));
136 let payload = payload(input, 1, payload_len)?;
137 if payload_len == 1 && payload.first().is_some_and(|byte| *byte <= 0x7f) {
138 return Err(DecodeError::Malformed);
139 }
140 Ok(RlpScalar {
141 payload,
142 encoded_len: checked_len_add(1, payload_len)?,
143 header_len: 1,
144 form: RlpScalarForm::ShortString,
145 })
146}
147
148pub(super) fn decode_long_string(input: &[u8], prefix: u8) -> Result<RlpScalar<'_>, DecodeError> {
149 let len_of_len = usize::from(prefix.saturating_sub(LONG_STRING_OFFSET));
150 let payload_len = parse_payload_len(input, 1, len_of_len)?;
151 if payload_len <= SHORT_STRING_LIMIT {
152 return Err(DecodeError::Malformed);
153 }
154 let header_len = checked_len_add(1, len_of_len)?;
155 let payload = payload(input, header_len, payload_len)?;
156 Ok(RlpScalar {
157 payload,
158 encoded_len: checked_len_add(header_len, payload_len)?,
159 header_len,
160 form: RlpScalarForm::LongString,
161 })
162}
163
164pub(super) fn parse_payload_len(
165 input: &[u8],
166 offset: usize,
167 len: usize,
168) -> Result<usize, DecodeError> {
169 let end = require_range_in_bounds(offset, len, input.len())?;
170 let bytes = input
171 .get(offset..end)
172 .ok_or(DecodeError::OffsetOutOfBounds)?;
173 if bytes.first().is_some_and(|byte| *byte == 0) {
174 return Err(DecodeError::Malformed);
175 }
176
177 let mut value = 0usize;
178 for byte in bytes {
179 value = value
180 .checked_mul(LENGTH_RADIX)
181 .ok_or(DecodeError::LengthOverflow)?;
182 value = value
183 .checked_add(usize::from(*byte))
184 .ok_or(DecodeError::LengthOverflow)?;
185 }
186 Ok(value)
187}
188
189pub(super) fn payload(input: &[u8], offset: usize, len: usize) -> Result<&[u8], DecodeError> {
190 let end = require_range_in_bounds(offset, len, input.len())?;
191 input.get(offset..end).ok_or(DecodeError::OffsetOutOfBounds)
192}