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