1use core::convert::TryFrom;
2
3use crate::{DecodeAccumulator, DecodeError, DecodeLimits, checked_len_add};
4
5use super::{
6 LENGTH_RADIX, LONG_LIST_OFFSET, LONG_STRING_OFFSET, RlpInteger, RlpItem, RlpList, RlpScalar,
7 SHORT_LIST_OFFSET, SHORT_STRING_LIMIT, SHORT_STRING_OFFSET,
8 integer::validate_rlp_integer_payload, list::validate_list_payload,
9};
10
11pub fn encoded_rlp_scalar_len(payload: &[u8]) -> Result<usize, DecodeError> {
13 if payload.len() == 1 && payload.first().is_some_and(|byte| *byte <= 0x7f) {
14 return Ok(1);
15 }
16 encoded_payload_len(payload.len())
17}
18
19pub fn encoded_rlp_integer_len(payload: &[u8]) -> Result<usize, DecodeError> {
24 validate_rlp_integer_payload(payload)?;
25 encoded_rlp_scalar_len(payload)
26}
27
28pub fn encoded_rlp_list_len(payload: &[u8], limits: DecodeLimits) -> Result<usize, DecodeError> {
32 validate_encoded_list_payload(payload, limits)?;
33 encoded_payload_len(payload.len())
34}
35
36pub fn encoded_rlp_list_header_len(payload_len: usize) -> Result<usize, DecodeError> {
42 let total_len = encoded_payload_len(payload_len)?;
43 total_len
44 .checked_sub(payload_len)
45 .ok_or(DecodeError::LengthOverflow)
46}
47
48pub fn encode_rlp_scalar(payload: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
53 encode_payload(
54 payload,
55 output,
56 SHORT_STRING_OFFSET,
57 LONG_STRING_OFFSET,
58 ScalarSingleByte::Enabled,
59 )
60}
61
62pub fn encode_rlp_integer(payload: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
67 validate_rlp_integer_payload(payload)?;
68 encode_rlp_scalar(payload, output)
69}
70
71pub fn encode_rlp_list_payload(
77 payload: &[u8],
78 limits: DecodeLimits,
79 output: &mut [u8],
80) -> Result<usize, DecodeError> {
81 validate_encoded_list_payload(payload, limits)?;
82 encode_rlp_list_payload_unchecked(payload, output)
83}
84
85pub fn encode_rlp_list_header(payload_len: usize, output: &mut [u8]) -> Result<usize, DecodeError> {
91 let required_len = encoded_rlp_list_header_len(payload_len)?;
92 if output.len() < required_len {
93 return Err(DecodeError::OffsetOutOfBounds);
94 }
95 if payload_len <= SHORT_STRING_LIMIT {
96 write_short_header(output, SHORT_LIST_OFFSET, payload_len)
97 } else {
98 write_long_header(output, LONG_LIST_OFFSET, payload_len)
99 }
100}
101
102fn encode_rlp_list_payload_unchecked(
103 payload: &[u8],
104 output: &mut [u8],
105) -> Result<usize, DecodeError> {
106 encode_payload(
107 payload,
108 output,
109 SHORT_LIST_OFFSET,
110 LONG_LIST_OFFSET,
111 ScalarSingleByte::Disabled,
112 )
113}
114
115pub fn encode_decoded_scalar(
120 scalar: RlpScalar<'_>,
121 output: &mut [u8],
122) -> Result<usize, DecodeError> {
123 encode_rlp_scalar(scalar.payload(), output)
124}
125
126pub fn encode_decoded_integer(
131 integer: RlpInteger<'_>,
132 output: &mut [u8],
133) -> Result<usize, DecodeError> {
134 encode_rlp_integer(integer.payload(), output)
135}
136
137pub fn encode_decoded_list(list: RlpList<'_>, output: &mut [u8]) -> Result<usize, DecodeError> {
142 encode_rlp_list_payload_unchecked(list.payload(), output)
143}
144
145pub fn encode_decoded_item(item: RlpItem<'_>, output: &mut [u8]) -> Result<usize, DecodeError> {
150 match item {
151 RlpItem::Scalar(scalar) => encode_decoded_scalar(scalar, output),
152 RlpItem::List(list) => encode_decoded_list(list, output),
153 }
154}
155
156#[derive(Clone, Copy)]
157enum ScalarSingleByte {
158 Enabled,
159 Disabled,
160}
161
162fn encoded_payload_len(payload_len: usize) -> Result<usize, DecodeError> {
163 if payload_len <= SHORT_STRING_LIMIT {
164 return checked_len_add(1, payload_len);
165 }
166 let len_of_len = length_of_length(payload_len)?;
167 checked_len_add(checked_len_add(1, len_of_len)?, payload_len)
168}
169
170fn encode_payload(
171 payload: &[u8],
172 output: &mut [u8],
173 short_offset: u8,
174 long_offset: u8,
175 scalar_single_byte: ScalarSingleByte,
176) -> Result<usize, DecodeError> {
177 let required_len = if matches!(scalar_single_byte, ScalarSingleByte::Enabled)
178 && payload.len() == 1
179 && payload.first().is_some_and(|byte| *byte <= 0x7f)
180 {
181 1
182 } else {
183 encoded_payload_len(payload.len())?
184 };
185 if output.len() < required_len {
186 return Err(DecodeError::OffsetOutOfBounds);
187 }
188
189 if matches!(scalar_single_byte, ScalarSingleByte::Enabled)
190 && payload.len() == 1
191 && payload.first().is_some_and(|byte| *byte <= 0x7f)
192 {
193 let byte = *payload.first().ok_or(DecodeError::OffsetOutOfBounds)?;
194 write_byte(output, byte)?;
195 return Ok(1);
196 }
197
198 let header_len = if payload.len() <= SHORT_STRING_LIMIT {
199 write_short_header(output, short_offset, payload.len())?
200 } else {
201 write_long_header(output, long_offset, payload.len())?
202 };
203 write_payload(output, header_len, payload)?;
204 checked_len_add(header_len, payload.len())
205}
206
207fn write_short_header(
208 output: &mut [u8],
209 short_offset: u8,
210 payload_len: usize,
211) -> Result<usize, DecodeError> {
212 let payload_len = u8::try_from(payload_len).map_err(|_| DecodeError::LengthOverflow)?;
213 let prefix = short_offset
214 .checked_add(payload_len)
215 .ok_or(DecodeError::LengthOverflow)?;
216 write_byte(output, prefix)?;
217 Ok(1)
218}
219
220fn write_long_header(
221 output: &mut [u8],
222 long_offset: u8,
223 payload_len: usize,
224) -> Result<usize, DecodeError> {
225 let len_of_len = length_of_length(payload_len)?;
226 let len_of_len_byte = u8::try_from(len_of_len).map_err(|_| DecodeError::LengthOverflow)?;
227 let prefix = long_offset
228 .checked_add(len_of_len_byte)
229 .ok_or(DecodeError::LengthOverflow)?;
230 let header_len = checked_len_add(1, len_of_len)?;
231 write_byte(output, prefix)?;
232
233 let len_bytes = payload_len.to_be_bytes();
234 let start = len_bytes
235 .len()
236 .checked_sub(len_of_len)
237 .ok_or(DecodeError::LengthOverflow)?;
238 let source = len_bytes
239 .get(start..)
240 .ok_or(DecodeError::OffsetOutOfBounds)?;
241 let target = output
242 .get_mut(1..header_len)
243 .ok_or(DecodeError::OffsetOutOfBounds)?;
244 target.copy_from_slice(source);
245 Ok(header_len)
246}
247
248fn write_byte(output: &mut [u8], byte: u8) -> Result<(), DecodeError> {
249 let target = output.first_mut().ok_or(DecodeError::OffsetOutOfBounds)?;
250 *target = byte;
251 Ok(())
252}
253
254fn write_payload(output: &mut [u8], header_len: usize, payload: &[u8]) -> Result<(), DecodeError> {
255 let end = checked_len_add(header_len, payload.len())?;
256 let target = output
257 .get_mut(header_len..end)
258 .ok_or(DecodeError::OffsetOutOfBounds)?;
259 target.copy_from_slice(payload);
260 Ok(())
261}
262
263fn length_of_length(payload_len: usize) -> Result<usize, DecodeError> {
264 if payload_len <= SHORT_STRING_LIMIT {
265 return Err(DecodeError::Malformed);
266 }
267
268 let mut value = payload_len;
269 let mut len = 0usize;
270 while value > 0 {
271 len = checked_len_add(len, 1)?;
272 value = value
273 .checked_div(LENGTH_RADIX)
274 .ok_or(DecodeError::LengthOverflow)?;
277 }
278 Ok(len)
279}
280
281fn validate_encoded_list_payload(
282 payload: &[u8],
283 limits: DecodeLimits,
284) -> Result<usize, DecodeError> {
285 let mut accumulator: DecodeAccumulator = limits.accumulator();
286 accumulator.check_input_len(payload.len())?;
287 validate_list_payload(payload, &mut accumulator)
288}