netget/server/devp2p/
rlp.rs1use anyhow::{bail, ensure, Context, Result};
15
16pub const MAX_RLP_DEPTH: usize = 16;
18pub const MAX_RLP_ITEMS: usize = 200_000;
20
21#[derive(Clone, Debug, PartialEq, Eq)]
23pub enum Rlp {
24 Bytes(Vec<u8>),
25 List(Vec<Rlp>),
26}
27
28impl Rlp {
29 pub fn empty_list() -> Rlp {
30 Rlp::List(Vec::new())
31 }
32
33 pub fn uint(n: u64) -> Rlp {
35 Rlp::Bytes(trim_leading_zeros(&n.to_be_bytes()).to_vec())
36 }
37
38 pub fn big_uint(be: &[u8]) -> Rlp {
40 Rlp::Bytes(trim_leading_zeros(be).to_vec())
41 }
42
43 pub fn bytes(b: &[u8]) -> Rlp {
44 Rlp::Bytes(b.to_vec())
45 }
46
47 pub fn string(s: &str) -> Rlp {
48 Rlp::Bytes(s.as_bytes().to_vec())
49 }
50
51 pub fn as_bytes(&self) -> Result<&[u8]> {
52 match self {
53 Rlp::Bytes(b) => Ok(b),
54 Rlp::List(_) => bail!("expected a byte string, found a list"),
55 }
56 }
57
58 pub fn as_list(&self) -> Result<&[Rlp]> {
59 match self {
60 Rlp::List(l) => Ok(l),
61 Rlp::Bytes(_) => bail!("expected a list, found a byte string"),
62 }
63 }
64
65 pub fn as_u64(&self) -> Result<u64> {
67 let b = self.as_bytes()?;
68 ensure!(
69 b.len() <= 8,
70 "integer of {} bytes is above 64 bits",
71 b.len()
72 );
73 ensure!(
74 b.first() != Some(&0),
75 "non-canonical integer (leading zero byte)"
76 );
77 Ok(b.iter().fold(0u64, |n, d| (n << 8) | u64::from(*d)))
78 }
79
80 pub fn as_big_uint(&self) -> Result<&[u8]> {
82 let b = self.as_bytes()?;
83 ensure!(
84 b.len() <= 32,
85 "integer of {} bytes is above 256 bits",
86 b.len()
87 );
88 ensure!(
89 b.first() != Some(&0),
90 "non-canonical integer (leading zero byte)"
91 );
92 Ok(b)
93 }
94
95 pub fn as_bool(&self) -> Result<bool> {
97 match self.as_u64()? {
98 0 => Ok(false),
99 1 => Ok(true),
100 n => bail!("boolean {n} is neither 0 nor 1"),
101 }
102 }
103
104 pub fn as_fixed<const N: usize>(&self) -> Result<[u8; N]> {
106 let b = self.as_bytes()?;
107 b.try_into()
108 .map_err(|_| anyhow::anyhow!("expected {N} bytes, found {}", b.len()))
109 }
110
111 pub fn encode(&self) -> Vec<u8> {
113 let mut out = Vec::new();
114 self.encode_into(&mut out);
115 out
116 }
117
118 fn encode_into(&self, out: &mut Vec<u8>) {
119 match self {
120 Rlp::Bytes(b) => {
121 if b.len() == 1 && b[0] < 0x80 {
122 out.push(b[0]);
123 } else {
124 put_length(out, 0x80, b.len());
125 out.extend_from_slice(b);
126 }
127 }
128 Rlp::List(items) => {
129 let mut payload = Vec::new();
130 for item in items {
131 item.encode_into(&mut payload);
132 }
133 put_length(out, 0xc0, payload.len());
134 out.extend_from_slice(&payload);
135 }
136 }
137 }
138}
139
140fn trim_leading_zeros(b: &[u8]) -> &[u8] {
141 let start = b.iter().position(|d| *d != 0).unwrap_or(b.len());
142 &b[start..]
143}
144
145fn put_length(out: &mut Vec<u8>, offset: u8, len: usize) {
146 if len <= 55 {
147 out.push(offset + len as u8);
148 } else {
149 let be = (len as u64).to_be_bytes();
150 let be = trim_leading_zeros(&be);
151 out.push(offset + 55 + be.len() as u8);
152 out.extend_from_slice(be);
153 }
154}
155
156pub fn decode(input: &[u8]) -> Result<Rlp> {
158 let (item, used) = decode_prefix(input)?;
159 ensure!(
160 used == input.len(),
161 "{} bytes trail the RLP item",
162 input.len() - used
163 );
164 Ok(item)
165}
166
167pub fn decode_prefix(input: &[u8]) -> Result<(Rlp, usize)> {
170 let mut items = 0usize;
171 decode_at(input, 0, &mut items)
172}
173
174fn header(input: &[u8]) -> Result<(bool, usize, usize)> {
176 let b = *input.first().context("RLP item is empty")?;
177 let (list, start, len) = match b {
178 0x00..=0x7f => return Ok((false, 0, 1)),
179 0x80..=0xb7 => (false, 1, usize::from(b - 0x80)),
180 0xc0..=0xf7 => (true, 1, usize::from(b - 0xc0)),
181 0xb8..=0xbf | 0xf8..=0xff => {
182 let list = b >= 0xf8;
183 let len_of_len = usize::from(b - if list { 0xf7 } else { 0xb7 });
184 let len_bytes = input
185 .get(1..1 + len_of_len)
186 .context("RLP length runs past the input")?;
187 ensure!(len_bytes[0] != 0, "non-canonical RLP length (leading zero)");
188 ensure!(
189 len_of_len <= 8,
190 "RLP length of {len_of_len} bytes is impossible"
191 );
192 let len = len_bytes.iter().fold(0u64, |n, d| (n << 8) | u64::from(*d));
193 ensure!(
194 len > 55,
195 "non-canonical RLP length: long form for {len} bytes"
196 );
197 let len = usize::try_from(len).context("RLP length above usize")?;
198 (list, 1 + len_of_len, len)
199 }
200 };
201 let end = start.checked_add(len).context("RLP length overflows")?;
202 ensure!(
203 end <= input.len(),
204 "RLP item declares {len} bytes, {} remain",
205 input.len() - start.min(input.len())
206 );
207 if !list && start == 1 && len == 1 {
208 ensure!(
209 input[1] >= 0x80,
210 "non-canonical RLP: single byte {:#04x} with a length prefix",
211 input[1]
212 );
213 }
214 Ok((list, start, len))
215}
216
217fn decode_at(input: &[u8], depth: usize, items: &mut usize) -> Result<(Rlp, usize)> {
218 *items += 1;
219 ensure!(
220 *items <= MAX_RLP_ITEMS,
221 "RLP holds more than {MAX_RLP_ITEMS} items"
222 );
223 let (list, start, len) = header(input)?;
224 let payload = &input[start..start + len];
225 if !list {
226 if start == 0 {
227 return Ok((Rlp::Bytes(vec![input[0]]), 1));
228 }
229 return Ok((Rlp::Bytes(payload.to_vec()), start + len));
230 }
231 ensure!(
232 depth < MAX_RLP_DEPTH,
233 "RLP nesting deeper than {MAX_RLP_DEPTH} levels"
234 );
235 let mut out = Vec::new();
236 let mut pos = 0;
237 while pos < payload.len() {
238 let (item, used) = decode_at(&payload[pos..], depth + 1, items)?;
239 out.push(item);
240 pos += used;
241 }
242 Ok((Rlp::List(out), start + len))
243}
244
245pub fn split_code(frame: &[u8]) -> Result<(u64, &[u8])> {
247 let (list, start, len) = header(frame)?;
248 ensure!(!list, "message code is a list");
249 let code_bytes = if start == 0 {
250 &frame[..1]
251 } else {
252 &frame[start..start + len]
253 };
254 let code = Rlp::Bytes(code_bytes.to_vec())
255 .as_u64()
256 .context("message code")?;
257 let used = if start == 0 { 1 } else { start + len };
258 Ok((code, &frame[used..]))
259}