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