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 encoded_payload_len(payload, ScalarSingleByte::Enabled)
14}
15
16pub fn encoded_rlp_integer_len(payload: &[u8]) -> Result<usize, DecodeError> {
21 validate_rlp_integer_payload(payload)?;
22 encoded_rlp_scalar_len(payload)
23}
24
25pub fn encoded_rlp_list_len(payload: &[u8], limits: DecodeLimits) -> Result<usize, DecodeError> {
29 validate_encoded_list_payload(payload, limits)?;
30 encoded_payload_len(payload, ScalarSingleByte::Disabled)
31}
32
33pub fn encode_rlp_scalar(payload: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
38 encode_payload(
39 payload,
40 output,
41 SHORT_STRING_OFFSET,
42 LONG_STRING_OFFSET,
43 ScalarSingleByte::Enabled,
44 )
45}
46
47pub fn encode_rlp_integer(payload: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
52 validate_rlp_integer_payload(payload)?;
53 encode_rlp_scalar(payload, output)
54}
55
56pub fn encode_rlp_list_payload(
62 payload: &[u8],
63 limits: DecodeLimits,
64 output: &mut [u8],
65) -> Result<usize, DecodeError> {
66 validate_encoded_list_payload(payload, limits)?;
67 encode_rlp_list_payload_unchecked(payload, output)
68}
69
70fn encode_rlp_list_payload_unchecked(
71 payload: &[u8],
72 output: &mut [u8],
73) -> Result<usize, DecodeError> {
74 encode_payload(
75 payload,
76 output,
77 SHORT_LIST_OFFSET,
78 LONG_LIST_OFFSET,
79 ScalarSingleByte::Disabled,
80 )
81}
82
83pub fn encode_decoded_scalar(
88 scalar: RlpScalar<'_>,
89 output: &mut [u8],
90) -> Result<usize, DecodeError> {
91 encode_rlp_scalar(scalar.payload(), output)
92}
93
94pub fn encode_decoded_integer(
99 integer: RlpInteger<'_>,
100 output: &mut [u8],
101) -> Result<usize, DecodeError> {
102 encode_rlp_integer(integer.payload(), output)
103}
104
105pub fn encode_decoded_list(list: RlpList<'_>, output: &mut [u8]) -> Result<usize, DecodeError> {
110 encode_rlp_list_payload_unchecked(list.payload(), output)
111}
112
113pub fn encode_decoded_item(item: RlpItem<'_>, output: &mut [u8]) -> Result<usize, DecodeError> {
118 match item {
119 RlpItem::Scalar(scalar) => encode_decoded_scalar(scalar, output),
120 RlpItem::List(list) => encode_decoded_list(list, output),
121 }
122}
123
124#[derive(Clone, Copy)]
125enum ScalarSingleByte {
126 Enabled,
127 Disabled,
128}
129
130fn encoded_payload_len(
131 payload: &[u8],
132 scalar_single_byte: ScalarSingleByte,
133) -> Result<usize, DecodeError> {
134 let payload_len = payload.len();
135 if matches!(scalar_single_byte, ScalarSingleByte::Enabled)
136 && payload_len == 1
137 && payload.first().is_some_and(|byte| *byte <= 0x7f)
138 {
139 return Ok(1);
140 }
141 if payload_len <= SHORT_STRING_LIMIT {
142 return checked_len_add(1, payload_len);
143 }
144 let len_of_len = length_of_length(payload_len)?;
145 checked_len_add(checked_len_add(1, len_of_len)?, payload_len)
146}
147
148fn encode_payload(
149 payload: &[u8],
150 output: &mut [u8],
151 short_offset: u8,
152 long_offset: u8,
153 scalar_single_byte: ScalarSingleByte,
154) -> Result<usize, DecodeError> {
155 let required_len = encoded_payload_len(payload, scalar_single_byte)?;
156 if output.len() < required_len {
157 return Err(DecodeError::OffsetOutOfBounds);
158 }
159
160 if matches!(scalar_single_byte, ScalarSingleByte::Enabled)
161 && payload.len() == 1
162 && payload.first().is_some_and(|byte| *byte <= 0x7f)
163 {
164 let byte = *payload.first().ok_or(DecodeError::OffsetOutOfBounds)?;
165 write_byte(output, byte)?;
166 return Ok(1);
167 }
168
169 let header_len = if payload.len() <= SHORT_STRING_LIMIT {
170 write_short_header(output, short_offset, payload.len())?
171 } else {
172 write_long_header(output, long_offset, payload.len())?
173 };
174 write_payload(output, header_len, payload)?;
175 checked_len_add(header_len, payload.len())
176}
177
178fn write_short_header(
179 output: &mut [u8],
180 short_offset: u8,
181 payload_len: usize,
182) -> Result<usize, DecodeError> {
183 let payload_len = u8::try_from(payload_len).map_err(|_| DecodeError::LengthOverflow)?;
184 let prefix = short_offset
185 .checked_add(payload_len)
186 .ok_or(DecodeError::LengthOverflow)?;
187 write_byte(output, prefix)?;
188 Ok(1)
189}
190
191fn write_long_header(
192 output: &mut [u8],
193 long_offset: u8,
194 payload_len: usize,
195) -> Result<usize, DecodeError> {
196 let len_of_len = length_of_length(payload_len)?;
197 let len_of_len_byte = u8::try_from(len_of_len).map_err(|_| DecodeError::LengthOverflow)?;
198 let prefix = long_offset
199 .checked_add(len_of_len_byte)
200 .ok_or(DecodeError::LengthOverflow)?;
201 let header_len = checked_len_add(1, len_of_len)?;
202 write_byte(output, prefix)?;
203
204 let len_bytes = payload_len.to_be_bytes();
205 let start = len_bytes
206 .len()
207 .checked_sub(len_of_len)
208 .ok_or(DecodeError::LengthOverflow)?;
209 let source = len_bytes
210 .get(start..)
211 .ok_or(DecodeError::OffsetOutOfBounds)?;
212 let target = output
213 .get_mut(1..header_len)
214 .ok_or(DecodeError::OffsetOutOfBounds)?;
215 target.copy_from_slice(source);
216 Ok(header_len)
217}
218
219fn write_byte(output: &mut [u8], byte: u8) -> Result<(), DecodeError> {
220 let target = output.first_mut().ok_or(DecodeError::OffsetOutOfBounds)?;
221 *target = byte;
222 Ok(())
223}
224
225fn write_payload(output: &mut [u8], header_len: usize, payload: &[u8]) -> Result<(), DecodeError> {
226 let end = checked_len_add(header_len, payload.len())?;
227 let target = output
228 .get_mut(header_len..end)
229 .ok_or(DecodeError::OffsetOutOfBounds)?;
230 target.copy_from_slice(payload);
231 Ok(())
232}
233
234fn length_of_length(payload_len: usize) -> Result<usize, DecodeError> {
235 if payload_len <= SHORT_STRING_LIMIT {
236 return Err(DecodeError::Malformed);
237 }
238
239 let mut value = payload_len;
240 let mut len = 0usize;
241 while value > 0 {
242 len = checked_len_add(len, 1)?;
243 value = value
244 .checked_div(LENGTH_RADIX)
245 .ok_or(DecodeError::LengthOverflow)?;
248 }
249 Ok(len)
250}
251
252fn validate_encoded_list_payload(
253 payload: &[u8],
254 limits: DecodeLimits,
255) -> Result<usize, DecodeError> {
256 let mut accumulator: DecodeAccumulator = limits.accumulator();
257 accumulator.check_input_len(payload.len())?;
258 validate_list_payload(payload, &mut accumulator)
259}