cborrs/cbordet.rs
1/* FIXME: This module to be rewritten with `pub use crate::cbordetver`,
2 * once Karamel can extract Rust code with documentation (coming from
3 * FStar attributes), abstract types, references instead of one-sized
4 * slices, proper casing of type names, and native Rust
5 * `std::Option`. */
6//! This module is an implementation of Deterministically Encoded CBOR
7//! (RFC 8949 Section 4.2.1) minus floating-point values, fully
8//! formally verified for functional correctness and absence of panics
9//! related to breach of abstraction, buffer overruns or arithmetic
10//! overflow/underflow. This module never allocates into the heap.
11
12/* FIXME: `cbordet` to be defined as abstract in cbordetveraux
13 * already. I cannot abstract it here since `cbor_det_mk_tagged`,
14 * `cbor_det_mk_array` and `cbor_det_mk_map` use references and arrays
15 * of `cbordet` elements as input arguments.
16 */
17/// An abstract type to represent a Deterministic CBOR object, which
18/// can be obtained either using "constructor" functions of this
19/// module, or by parsing from serialized data. Declared in
20/// `pulse/CBOR.Pulse.Det.API.Rust.fsti`. Its corresponding pure
21/// ("mathematical") functional specification is the `cbor` type in
22/// `spec/CBOR.Spec.Type.fsti`.
23pub type CborDet <'a> = crate::cbordetver::cbordet <'a>;
24
25/// Tries to parse a Deterministic CBOR object from the first bytes of
26/// `input`, following RFC 8949 Section 4.2.1, minus floating-point
27/// values. Returns `None` in case of failure, or `Some(object, rem)`
28/// in case of success, where `rem` is the remainder of the input
29/// slice past those first bytes of `input` that contain the valid
30/// binary representation of
31/// `input`. This function does not perform a deep parse of `input`,
32/// it only copies the object type, tag and/or size of the top-most
33/// object. As such, it uses constant stack space (including data
34/// validation.) "Destructor" functions are to be used on the returned
35/// object, to examine each level of nesting one at a time. NOTE: This
36/// implementation checks for the basic validity constraints of
37/// Section 5.3.1, i.e. the absence of duplicate map keys (which is a
38/// consequence of the deterministic encoding.), and the
39/// well-formedness of UTF-8 text strings.
40pub fn cbor_det_parse <'a>(input: &'a [u8]) ->
41 Option<(CborDet<'a>, &'a [u8])>
42{
43 match crate::cbordetver::cbor_det_parse(input) {
44 crate::cbordetver::option__·CBOR_Pulse_Raw_Type_cbor_raw···Pulse_Lib_Slice_slice·uint8_t·::None => {
45 return None;
46 }
47 crate::cbordetver::option__·CBOR_Pulse_Raw_Type_cbor_raw···Pulse_Lib_Slice_slice·uint8_t·::Some {v} => {
48 let (object, rem) = v;
49 return Some((object, rem));
50 }
51 }
52}
53
54/// Computes the byte size of the binary representation of the
55/// Deterministic CBOR object `x` following RFC 8949 Section 4.2.1,
56/// but without serializing `x`. Returns `None` if that size is
57/// strictly larger than `bound`; `Some(size)` otherwise. This function
58/// uses stack space in the order of the level of nesting of the use
59/// of "constructor" functions used to build `x`; the computation of
60/// the sizes of those "subobjects" of `x` obtained from
61/// `cbor_det_parse` uses only constant extra stack space for each
62/// such subobject (in the sense that the computation does not
63/// recursively nest into such subobjects.)
64pub fn cbor_det_size <'a>(x: CborDet <'a>, bound: usize) -> Option<usize>
65{
66 match crate::cbordetver::cbor_det_size(x, bound) {
67 crate::cbordetver::option__size_t::None => {
68 return None;
69 }
70 crate::cbordetver::option__size_t::Some {v} => {
71 return Some(v);
72 }
73 }
74}
75
76/// Writes the binary representation of the Deterministic CBOR object
77/// `x` into the first bytes of the `output` byte slice, following RFC
78/// 8949 Section 4.2.1. This function first checks the size of `x` and
79/// returns `None` if it is larger than the size of `output`;
80/// otherwise it returns `Some(size)`, where `size` is the byte size
81/// of `x`, the number of bytes written to `output`. This function
82/// uses stack space in the order of the level of nesting of the use
83/// of "constructor" functions used to build `x`; the serialization of
84/// those "subobjects" of `x` obtained from `cbor_det_parse` uses only
85/// constant extra stack space for each such subobject (in the sense
86/// that the serialization does not recursively nest into such
87/// subobjects.)
88pub fn cbor_det_serialize <'a>(x: CborDet <'a>, output: &'a mut [u8]) ->
89 Option<usize>
90{
91 match crate::cbordetver::cbor_det_serialize(x, output) {
92 crate::cbordetver::option__size_t::None => {
93 return None;
94 }
95 crate::cbordetver::option__size_t::Some {v} => {
96 return Some(v);
97 }
98 }
99}
100
101/// Constructs a Deterministic CBOR object of "simple value" type,
102/// with value `v`. Returns `None` if the value `v` lies in the
103/// reserved range (`24..31`), as specified by Table 4 of RFC 8949
104/// Section 3.3; `Some(object)` otherwise.
105pub fn cbor_det_mk_simple_value <'a>(v: u8) -> Option<CborDet<'a>>
106{
107 match crate::cbordetver::cbor_det_mk_simple_value(v) {
108 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
109 return None;
110 }
111 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
112 return Some(v);
113 }
114 }
115}
116
117/// The kind of 64-bit integer: unsigned (to represent non-negative
118/// values), or negative (to represent negative values in two's
119/// complement.)
120#[derive(PartialEq, Clone, Copy)]
121pub enum CborDetIntKind
122{
123 UInt64,
124 NegInt64
125}
126
127/// Constructs a Deterministic CBOR object of "integer" type, with
128/// kind `ty` and value `v`.
129pub fn cbor_det_mk_int64 <'a>(ty: CborDetIntKind, v: u64) ->
130 CborDet <'a>
131{
132 let ty· : crate::cbordetver::cbor_det_int_kind =
133 match ty {
134 CborDetIntKind::UInt64 => {
135 crate::cbordetver::cbor_det_int_kind::UInt64
136 }
137 CborDetIntKind::NegInt64 => {
138 crate::cbordetver::cbor_det_int_kind::NegInt64
139 }
140 };
141 crate::cbordetver::cbor_det_mk_int64(ty·, v)
142}
143
144/// Constructs a Deterministic CBOR object of "text string" type, with
145/// the contents of `s` as value. This function does not perform any
146/// copy of its input `s`. It returns `None` if the byte size of `s`
147/// is larger than $2^64 - 1$, `Some(object)` otherwise. This function
148/// respects the UTF-8 well-formedness invariants.
149pub fn cbor_det_mk_text_string <'a>(s: &'a str) ->
150 Option<CborDet<'a>>
151{
152 let ty· : crate::cbordetver::cbor_det_string_kind =
153 crate::cbordetver::cbor_det_string_kind::TextString;
154 match crate::cbordetver::cbor_det_mk_string(ty·, s.as_bytes()) {
155 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
156 None
157 }
158 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some { v } => {
159 Some(v)
160 }
161 }
162}
163
164/// Constructs a Deterministic CBOR object of "byte string" type, with
165/// the contents of `s` as value. This function does not perform any
166/// copy of its input `s`. It returns `None` if the byte size of `s`
167/// is larger than $2^64 - 1$, `Some(object)` otherwise.
168pub fn cbor_det_mk_byte_string <'a>(s: &'a [u8]) ->
169 Option<CborDet<'a>>
170{
171 let ty· : crate::cbordetver::cbor_det_string_kind =
172 crate::cbordetver::cbor_det_string_kind::ByteString;
173 match crate::cbordetver::cbor_det_mk_string(ty·, s) {
174 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
175 None
176 }
177 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some { v } => {
178 Some(v)
179 }
180 }
181}
182
183/* FIXME: this function to be extracted with references instead of
184 * slices. The verified FStar/Pulse code is already using references,
185 * but Karamel extracts them as slices. Because of that, I need to
186 * manually write this piece of glue code to convert a reference into
187 * a slice, which Karamel cannot extract (and FStar/Pulse cannot
188 * currently model.)
189 */
190/// Constructs a Deterministic CBOR object of Tagged type, with tag
191/// `tag`, and the contents of `r` as value. This function does not
192/// perform any copy of its input `r`.
193pub fn cbor_det_mk_tagged <'a>(tag: u64, r: &'a CborDet <'a>) ->
194 CborDet <'a>
195{
196 return crate::cbordetver::cbor_det_mk_tagged(tag, std::slice::from_ref(r));
197}
198
199/// Constructs a Deterministic CBOR of "array" type. This function
200/// does not copy its input array. It returns `None` if the input
201/// array has more than $2^64 - 1$ elements, `Some(object)` otherwise.
202pub fn cbor_det_mk_array <'a>(a: &'a [CborDet <'a>]) ->
203 Option<CborDet<'a>>
204{
205 match crate::cbordetver::cbor_det_mk_array(a) {
206 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
207 None
208 }
209 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
210 Some(v)
211 }
212 }
213}
214
215/* FIXME: this type to be defined as abstract in cbordetveraux
216 * already. I cannot abstract it here since `cbor_det_mk_map` uses
217 * arrays of map entry elements as input arguments.
218 */
219/// The type of key-value map entries.
220pub type CborDetMapEntry <'a> = crate::cbordetveraux::cbor_map_entry <'a>;
221
222/// Constructs a map entry from a key `xk` and a value `xv`.
223pub fn cbor_det_mk_map_entry <'a>(
224 xk: CborDet <'a>,
225 xv: CborDet <'a>
226) ->
227 CborDetMapEntry <'a>
228{
229 return crate::cbordetver::cbor_det_mk_map_entry(xk, xv);
230}
231
232/// Constructs a map from a slice of map entries. This function does
233/// not copy its input array. If the input slice has more than $2^64 -
234/// 1$ entries, then this function returns `None` and does not change
235/// the input slice. Otherwise, this function tries to sort the input
236/// slice in-place with respect to the key order specified in Section
237/// 4.2.1 of RFC 8949 (without actually serializing the map entries.)
238/// If the sorting detects duplicate keys, then this function returns
239/// `None`. Otherwise, it returns `Some(object)`. Due to the sorting,
240/// this function consumes stack space logarithmic in the size of the
241/// input slice, and linear in the maximum nesting of map entry keys,
242/// and the function may have changed the order of map entries in the
243/// input slice.
244pub fn cbor_det_mk_map <'a>(a: &'a mut [CborDetMapEntry <'a>]) ->
245 Option<CborDet<'a>>
246{
247 match crate::cbordetver::cbor_det_mk_map(a) {
248 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
249 None
250 }
251 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
252 Some(v)
253 }
254 }
255}
256
257/// Compares Deterministic CBOR objects for semantic equality. This
258/// function consumes stack space linear in the maximum nesting of its
259/// two arguments.
260pub fn cbor_det_equal <'a>(
261 x1: CborDet <'a>,
262 x2: CborDet <'a>
263) ->
264 bool
265{
266 crate::cbordetver::cbor_det_equal(x1, x2)
267}
268
269/// The read-only type of Deterministic CBOR arrays. Values of this
270/// type cannot be manually constructed by the user, they are meant to
271/// be obtained only via `cbor_det_destruct` below. The abstraction is
272/// justified by the use of a refinement type, as per the definition
273/// of `cbor_det_array` in `pulse/CBOR.Pulse.Det.API.Rust.fst`
274#[derive(PartialEq, Clone, Copy)]
275pub struct CborDetArray <'a> { array: crate::cbordetver::cbor_det_array <'a> }
276
277/// The read-only type of Deterministic CBOR maps. Values of this
278/// type cannot be manually constructed by the user, they are meant to
279/// be obtained only via `cbor_det_destruct` below. The abstraction is
280/// justified by the use of a refinement type, as per the definition
281/// of `cbor_det_map` in `pulse/CBOR.Pulse.Det.API.Rust.fst`
282#[derive(PartialEq, Clone, Copy)]
283pub struct CborDetMap <'a> { map: crate::cbordetver::cbor_det_map <'a> }
284
285/// A read-only view of a Deterministic CBOR object, as obtained by
286/// peeling the first layer of nesting via `cbor_det_destruct` below.
287#[derive(PartialEq, Clone, Copy)]
288pub enum CborDetView <'a>
289{
290 Int64 { kind: CborDetIntKind, value: u64 },
291 ByteString { payload: &'a [u8] },
292 TextString { payload: &'a str },
293 Array { _0: CborDetArray <'a> },
294 Map { _0: CborDetMap <'a> },
295 Tagged { tag: u64, payload: CborDet <'a> },
296 SimpleValue { _0: u8 }
297}
298
299/// Destructs a Deterministic CBOR object by peeling its first layer
300/// of nesting. This function does not recursively descend into array
301/// or map payloads, and only reads the header of a tagged payload. As
302/// such, it consumes constant stack space. This function respects the
303/// UTF-8 well-formedness invariants.
304pub fn cbor_det_destruct <'a>(c: CborDet <'a>) -> CborDetView <'a>
305{
306 match crate::cbordetver::cbor_det_destruct(c) {
307 crate::cbordetver::cbor_det_view::Int64 { kind, value } => {
308 let kind· : CborDetIntKind =
309 match kind {
310 crate::cbordetver::cbor_det_int_kind::UInt64 => {
311 CborDetIntKind::UInt64
312 }
313 crate::cbordetver::cbor_det_int_kind::NegInt64 => {
314 CborDetIntKind::NegInt64
315 }
316 };
317 CborDetView::Int64 {kind: kind·, value}
318 }
319 crate::cbordetver::cbor_det_view::String { kind, payload } => {
320 match kind {
321 crate::cbordetver::cbor_det_string_kind::ByteString => {
322 CborDetView::ByteString {payload}
323 }
324 crate::cbordetver::cbor_det_string_kind::TextString => {
325 CborDetView::TextString {payload: std::str::from_utf8(payload).unwrap()}
326 }
327 }
328 }
329 crate::cbordetver::cbor_det_view::Array { _0 } => {
330 CborDetView::Array { _0: CborDetArray {array: _0 } }
331 }
332 crate::cbordetver::cbor_det_view::Map { _0 } => {
333 CborDetView::Map { _0: CborDetMap {map: _0 } }
334 }
335 crate::cbordetver::cbor_det_view::Tagged { tag, payload } => {
336 CborDetView::Tagged {tag, payload}
337 }
338 crate::cbordetver::cbor_det_view::SimpleValue { _0 } => {
339 CborDetView::SimpleValue {_0}
340 }
341 }
342}
343
344/// Returns the number of elements in a Deterministic CBOR array.
345pub fn cbor_det_get_array_length <'a>(x: CborDetArray <'a>) -> u64
346{
347 crate::cbordetver::cbor_det_get_array_length(x.array)
348}
349
350/// The type of iterators over Deterministic CBOR arrays. It is made
351/// abstract since it is meant to be used with an implementation of
352/// the `Iterator` trait only.
353pub struct CborDetArrayIterator <'a> { iter: crate::cbordetveraux::cbor_raw_iterator__CBOR_Pulse_Raw_Type_cbor_raw <'a> }
354
355impl <'a> Iterator for CborDetArrayIterator <'a> {
356 type Item = CborDet <'a>;
357 fn next(&mut self) -> Option<Self::Item> {
358 if crate::cbordetver::cbor_det_array_iterator_is_empty(self.iter) {
359 None
360 } else {
361 Some (crate::cbordetver::cbor_det_array_iterator_next(std::slice::from_mut(& mut self.iter)))
362 }
363 }
364}
365
366impl <'a> IntoIterator for CborDetArray <'a> {
367 type Item = CborDet <'a>;
368 type IntoIter = CborDetArrayIterator <'a>;
369 fn into_iter(self) -> Self::IntoIter {
370 CborDetArrayIterator { iter: crate::cbordetver::cbor_det_array_iterator_start(self.array) }
371 }
372}
373
374/// Returns the `i`th element of the CBOR array `x`. Returns `None` if
375/// `i` is equal to or larger than the number of array elements,
376/// `Some(object)` otherwise.
377pub fn cbor_det_get_array_item <'a>(x: CborDetArray <'a>, i: u64) ->
378 Option<CborDet<'a>>
379{
380 match crate::cbordetver::cbor_det_get_array_item(x.array, i) {
381 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
382 None
383 }
384 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
385 Some(v)
386 }
387 }
388}
389
390/// Returns the number of elements in a Deterministic CBOR map.
391pub fn cbor_det_get_map_length <'a>(x: CborDetMap <'a>) -> u64
392{
393 crate::cbordetver::cbor_det_map_length(x.map)
394}
395
396/// The type of iterators over Deterministic CBOR maps. It is made
397/// abstract since it is meant to be used with an implementation of
398/// the `Iterator` trait only.
399pub struct CborDetMapIterator <'a> { iter: crate::cbordetveraux::cbor_raw_iterator__CBOR_Pulse_Raw_Type_cbor_map_entry <'a> }
400
401impl <'a> Iterator for CborDetMapIterator <'a> {
402 type Item = CborDetMapEntry <'a>;
403 fn next(&mut self) -> Option<Self::Item> {
404 if crate::cbordetver::cbor_det_map_iterator_is_empty(self.iter) {
405 None
406 } else {
407 Some (crate::cbordetver::cbor_det_map_iterator_next(std::slice::from_mut(& mut self.iter)))
408 }
409 }
410}
411
412impl <'a> IntoIterator for CborDetMap <'a> {
413 type Item = CborDetMapEntry <'a>;
414 type IntoIter = CborDetMapIterator <'a>;
415 fn into_iter(self) -> Self::IntoIter {
416 CborDetMapIterator { iter: crate::cbordetver::cbor_det_map_iterator_start(self.map) }
417 }
418}
419
420/// Read the key of a map entry.
421pub fn cbor_det_map_entry_key <'a>(x2: CborDetMapEntry <'a>) ->
422 CborDet
423 <'a>
424{ crate::cbordetver::cbor_det_map_entry_key(x2) }
425
426/// Read the value of a map entry.
427pub fn cbor_det_map_entry_value <'a>(x2: CborDetMapEntry <'a>) ->
428 CborDet
429 <'a>
430{ crate::cbordetver::cbor_det_map_entry_value(x2) }
431
432/// Looks up a map `x` for an entry associated to the key `k`. If such
433/// an entry exists, returns `Some(object)` where `object` is the
434/// value associated to that key. Otherwise, returns `None`.
435pub fn cbor_det_map_get <'a>(
436 x: CborDetMap <'a>,
437 k: CborDet <'a>
438) ->
439 Option<CborDet<'a>>
440{
441 match crate::cbordetver::cbor_det_map_get(x.map, k) {
442 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
443 None
444 }
445 crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
446 Some(v)
447 }
448 }
449}