1use crate::{
6 deterministic::{try_string_copy, try_vec_with_capacity},
7 DeterministicCborError, DeterministicCborInteger, DeterministicCborMapEntry,
8 DeterministicCborMapKey, DeterministicCborValue,
9 MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES,
10 MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES, MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES,
11 MAX_DETERMINISTIC_CBOR_INPUT_LEN, MAX_DETERMINISTIC_CBOR_NESTING_DEPTH,
12 MAX_DETERMINISTIC_CBOR_NODES,
13};
14use std::cmp::Ordering;
15use std::str;
16
17const MT_UINT: u8 = 0;
18const MT_NEGINT: u8 = 1;
19const MT_BYTES: u8 = 2;
20const MT_STRING: u8 = 3;
21const MT_ARRAY: u8 = 4;
22const MT_MAP: u8 = 5;
23const MT_TAG: u8 = 6;
24const MT_SIMPLE: u8 = 7;
25const SIMPLE_FALSE: u64 = 20;
26const SIMPLE_TRUE: u64 = 21;
27const SIMPLE_NULL: u64 = 22;
28const MIN_ELEMENT_ENCODED_LEN: usize = 1;
29
30pub fn decode_deterministic_cbor(
36 bytes: &[u8],
37) -> Result<DeterministicCborValue, DeterministicCborError> {
38 if bytes.len() > MAX_DETERMINISTIC_CBOR_INPUT_LEN {
39 return Err(DeterministicCborError::InputTooLarge);
40 }
41 let mut limits = DecodeLimits::default();
42 let (value, offset) = decode_value(bytes, 0, 0, &mut limits)?;
43 if offset != bytes.len() {
44 return Err(DeterministicCborError::TrailingBytes);
45 }
46 Ok(value)
47}
48
49#[derive(Default)]
50struct DecodeLimits {
51 nodes: usize,
52 aggregate_text_bytes: usize,
53 aggregate_byte_string_bytes: usize,
54}
55
56impl DecodeLimits {
57 fn add_node(&mut self) -> Result<(), DeterministicCborError> {
58 self.nodes = checked_add(self.nodes, 1)?;
59 if self.nodes > MAX_DETERMINISTIC_CBOR_NODES {
60 return Err(DeterministicCborError::NodeLimitExceeded);
61 }
62 Ok(())
63 }
64
65 fn add_text_bytes(&mut self, len: usize) -> Result<(), DeterministicCborError> {
66 self.aggregate_text_bytes = checked_add(self.aggregate_text_bytes, len)?;
67 if self.aggregate_text_bytes > MAX_DETERMINISTIC_CBOR_AGGREGATE_TEXT_BYTES {
68 return Err(DeterministicCborError::AggregateTextBytesExceeded);
69 }
70 Ok(())
71 }
72
73 fn add_byte_string_bytes(&mut self, len: usize) -> Result<(), DeterministicCborError> {
74 self.aggregate_byte_string_bytes = checked_add(self.aggregate_byte_string_bytes, len)?;
75 if self.aggregate_byte_string_bytes > MAX_DETERMINISTIC_CBOR_AGGREGATE_BYTE_STRING_BYTES {
76 return Err(DeterministicCborError::AggregateByteStringBytesExceeded);
77 }
78 Ok(())
79 }
80}
81
82fn decode_value(
83 bytes: &[u8],
84 offset: usize,
85 depth: usize,
86 limits: &mut DecodeLimits,
87) -> Result<(DeterministicCborValue, usize), DeterministicCborError> {
88 limits.add_node()?;
89 let (major, argument, mut offset) = read_head(bytes, offset)?;
90
91 match major {
92 MT_UINT => Ok((
93 DeterministicCborValue::Integer(DeterministicCborInteger::unsigned(argument)),
94 offset,
95 )),
96 MT_NEGINT => Ok((
97 DeterministicCborValue::Integer(DeterministicCborInteger::negative(negative_value(
98 argument,
99 )?)?),
100 offset,
101 )),
102 MT_BYTES => {
103 let (value, next) = extract_bytes(bytes, offset, argument, limits)?;
104 Ok((DeterministicCborValue::Bytes(value), next))
105 }
106 MT_STRING => {
107 let (value, next) = extract_string(bytes, offset, argument, limits)?;
108 Ok((DeterministicCborValue::Text(value), next))
109 }
110 MT_ARRAY => {
111 let child_depth = descend(depth)?;
112 let item_count = container_count(argument)?;
113 bounded_capacity(item_count, bytes.len(), offset, MIN_ELEMENT_ENCODED_LEN)?;
114 let mut values = try_vec_with_capacity(item_count)?;
119 for _ in 0..item_count {
120 let (value, next) = decode_value(bytes, offset, child_depth, limits)?;
121 values.push(value);
122 offset = next;
123 }
124 Ok((DeterministicCborValue::Array(values), offset))
125 }
126 MT_MAP => {
127 let child_depth = descend(depth)?;
128 let entry_count = container_count(argument)?;
129 let min_entry_len = checked_mul(MIN_ELEMENT_ENCODED_LEN, 2)?;
130 bounded_capacity(entry_count, bytes.len(), offset, min_entry_len)?;
131 let mut entries = try_vec_with_capacity(entry_count)?;
132 let mut previous_key_range: Option<(usize, usize)> = None;
133
134 for _ in 0..entry_count {
135 let key_start = offset;
136 let (key, key_end) = decode_key(bytes, offset, limits)?;
137 if let Some((previous_start, previous_end)) = previous_key_range {
138 let previous_key = checked_slice(bytes, previous_start, previous_end)?;
139 let current_key = checked_slice(bytes, key_start, key_end)?;
140 match compare_encoded_keys(previous_key, current_key) {
141 Ordering::Less => {}
142 Ordering::Equal => return Err(DeterministicCborError::DuplicateMapKey),
143 Ordering::Greater => {
144 return Err(DeterministicCborError::MapKeysOutOfOrder);
145 }
146 }
147 }
148 previous_key_range = Some((key_start, key_end));
149 offset = key_end;
150
151 let (value, next) = decode_value(bytes, offset, child_depth, limits)?;
152 entries.push(DeterministicCborMapEntry::new(key, value));
153 offset = next;
154 }
155 Ok((DeterministicCborValue::Map(entries), offset))
156 }
157 MT_SIMPLE => match argument {
158 SIMPLE_FALSE => Ok((DeterministicCborValue::Bool(false), offset)),
159 SIMPLE_TRUE => Ok((DeterministicCborValue::Bool(true), offset)),
160 SIMPLE_NULL => Ok((DeterministicCborValue::Null, offset)),
161 _ => Err(DeterministicCborError::UnsupportedSimpleValue),
162 },
163 _ => Err(DeterministicCborError::UnsupportedMajorType),
164 }
165}
166
167fn decode_key(
168 bytes: &[u8],
169 offset: usize,
170 limits: &mut DecodeLimits,
171) -> Result<(DeterministicCborMapKey, usize), DeterministicCborError> {
172 limits.add_node()?;
173 let (major, argument, offset) = read_head(bytes, offset)?;
174 match major {
175 MT_UINT => Ok((
176 DeterministicCborMapKey::Integer(DeterministicCborInteger::unsigned(argument)),
177 offset,
178 )),
179 MT_NEGINT => Ok((
180 DeterministicCborMapKey::Integer(DeterministicCborInteger::negative(negative_value(
181 argument,
182 )?)?),
183 offset,
184 )),
185 MT_STRING => {
186 let (value, next) = extract_string(bytes, offset, argument, limits)?;
187 Ok((DeterministicCborMapKey::text(value), next))
188 }
189 _ => Err(DeterministicCborError::UnsupportedMapKeyType),
190 }
191}
192
193fn read_head(bytes: &[u8], offset: usize) -> Result<(u8, u64, usize), DeterministicCborError> {
194 if offset >= bytes.len() {
195 return Err(DeterministicCborError::UnexpectedEnd);
196 }
197 let first = *bytes
198 .get(offset)
199 .ok_or(DeterministicCborError::UnexpectedEnd)?;
200 let next_offset = checked_add(offset, 1)?;
201 let major = first >> 5;
202 let additional = first & 0x1f;
203 if major == MT_TAG {
208 return Err(DeterministicCborError::UnsupportedMajorType);
209 }
210 if major == MT_SIMPLE && additional >= 24 {
211 return match additional {
212 24..=27 => Err(DeterministicCborError::UnsupportedSimpleValue),
213 _ => Err(DeterministicCborError::UnsupportedAdditionalInfo),
214 };
215 }
216 let (argument, after_argument) = read_argument(bytes, next_offset, additional)?;
217 Ok((major, argument, after_argument))
218}
219
220fn read_argument(
221 bytes: &[u8],
222 offset: usize,
223 additional: u8,
224) -> Result<(u64, usize), DeterministicCborError> {
225 match additional {
226 value @ 0..=23 => Ok((u64::from(value), offset)),
227 24 => {
228 let end = checked_end(offset, 1)?;
229 let value = u64::from(
230 *bytes
231 .get(offset)
232 .ok_or(DeterministicCborError::TruncatedArgument)?,
233 );
234 if value < 24 {
235 return Err(DeterministicCborError::NonCanonicalInteger);
236 }
237 Ok((value, end))
238 }
239 25 => {
240 let end = checked_end(offset, 2)?;
241 let encoded = checked_argument_slice(bytes, offset, end)?;
242 let value = u16::from_be_bytes(
243 <[u8; 2]>::try_from(encoded)
244 .map_err(|_| DeterministicCborError::TruncatedArgument)?,
245 );
246 if value < 0x100 {
247 return Err(DeterministicCborError::NonCanonicalInteger);
248 }
249 Ok((u64::from(value), end))
250 }
251 26 => {
252 let end = checked_end(offset, 4)?;
253 let encoded = checked_argument_slice(bytes, offset, end)?;
254 let value = u32::from_be_bytes(
255 <[u8; 4]>::try_from(encoded)
256 .map_err(|_| DeterministicCborError::TruncatedArgument)?,
257 );
258 if value < 0x1_0000 {
259 return Err(DeterministicCborError::NonCanonicalInteger);
260 }
261 Ok((u64::from(value), end))
262 }
263 27 => {
264 let end = checked_end(offset, 8)?;
265 let encoded = checked_argument_slice(bytes, offset, end)?;
266 let value = u64::from_be_bytes(
267 <[u8; 8]>::try_from(encoded)
268 .map_err(|_| DeterministicCborError::TruncatedArgument)?,
269 );
270 if value < 0x1_0000_0000 {
271 return Err(DeterministicCborError::NonCanonicalInteger);
272 }
273 Ok((value, end))
274 }
275 _ => Err(DeterministicCborError::UnsupportedAdditionalInfo),
276 }
277}
278
279fn extract_bytes(
280 bytes: &[u8],
281 offset: usize,
282 len: u64,
283 limits: &mut DecodeLimits,
284) -> Result<(Vec<u8>, usize), DeterministicCborError> {
285 let len = usize::try_from(len).map_err(|_| DeterministicCborError::LengthTooLarge)?;
286 limits.add_byte_string_bytes(len)?;
287 let end = checked_end(offset, len)?;
288 let encoded =
289 checked_slice(bytes, offset, end).map_err(|_| DeterministicCborError::TruncatedBytes)?;
290 let mut value = try_vec_with_capacity(len)?;
291 value.extend_from_slice(encoded);
292 Ok((value, end))
293}
294
295fn extract_string(
296 bytes: &[u8],
297 offset: usize,
298 len: u64,
299 limits: &mut DecodeLimits,
300) -> Result<(String, usize), DeterministicCborError> {
301 let len = usize::try_from(len).map_err(|_| DeterministicCborError::LengthTooLarge)?;
302 limits.add_text_bytes(len)?;
303 let end = checked_end(offset, len)?;
304 let encoded =
305 checked_slice(bytes, offset, end).map_err(|_| DeterministicCborError::TruncatedBytes)?;
306 let text =
307 try_string_copy(str::from_utf8(encoded).map_err(|_| DeterministicCborError::InvalidUtf8)?)?;
308 Ok((text, end))
309}
310
311fn negative_value(argument: u64) -> Result<i64, DeterministicCborError> {
312 let value = (-1_i128)
313 .checked_sub(i128::from(argument))
314 .ok_or(DeterministicCborError::NegativeIntegerOutOfRange)?;
315 i64::try_from(value).map_err(|_| DeterministicCborError::NegativeIntegerOutOfRange)
316}
317
318fn container_count(argument: u64) -> Result<usize, DeterministicCborError> {
319 let count = usize::try_from(argument).map_err(|_| DeterministicCborError::LengthTooLarge)?;
320 if count > MAX_DETERMINISTIC_CBOR_CONTAINER_ENTRIES {
321 return Err(DeterministicCborError::ContainerEntriesExceeded);
322 }
323 Ok(count)
324}
325
326fn bounded_capacity(
327 count: usize,
328 total_len: usize,
329 offset: usize,
330 min_element_len: usize,
331) -> Result<(), DeterministicCborError> {
332 let remaining = checked_sub(total_len, offset)?;
333 let max_possible = remaining / min_element_len.max(1);
334 if count > max_possible {
335 return Err(DeterministicCborError::ContainerLengthExceedsInput);
336 }
337 Ok(())
338}
339
340fn compare_encoded_keys(left: &[u8], right: &[u8]) -> Ordering {
341 match left.len().cmp(&right.len()) {
342 Ordering::Equal => left.cmp(right),
343 ordering => ordering,
344 }
345}
346
347fn descend(depth: usize) -> Result<usize, DeterministicCborError> {
348 let next = checked_add(depth, 1)?;
349 if next > MAX_DETERMINISTIC_CBOR_NESTING_DEPTH {
350 return Err(DeterministicCborError::DepthExceeded);
351 }
352 Ok(next)
353}
354
355fn checked_end(offset: usize, len: usize) -> Result<usize, DeterministicCborError> {
356 checked_add(offset, len)
357}
358
359fn checked_argument_slice(
360 bytes: &[u8],
361 start: usize,
362 end: usize,
363) -> Result<&[u8], DeterministicCborError> {
364 checked_slice(bytes, start, end).map_err(|_| DeterministicCborError::TruncatedArgument)
365}
366
367fn checked_slice(bytes: &[u8], start: usize, end: usize) -> Result<&[u8], DeterministicCborError> {
368 bytes
369 .get(start..end)
370 .ok_or(DeterministicCborError::OffsetOverflow)
371}
372
373fn checked_add(left: usize, right: usize) -> Result<usize, DeterministicCborError> {
374 left.checked_add(right)
375 .ok_or(DeterministicCborError::OffsetOverflow)
376}
377
378fn checked_sub(left: usize, right: usize) -> Result<usize, DeterministicCborError> {
379 left.checked_sub(right)
380 .ok_or(DeterministicCborError::OffsetOverflow)
381}
382
383fn checked_mul(left: usize, right: usize) -> Result<usize, DeterministicCborError> {
384 left.checked_mul(right)
385 .ok_or(DeterministicCborError::OffsetOverflow)
386}