cborrs/
cbordet.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
/* FIXME: This module to be rewritten with `pub use crate::cbordetver`,
 * once Karamel can extract Rust code with documentation (coming from
 * FStar attributes), abstract types, references instead of one-sized
 * slices, proper casing of type names, and native Rust
 * `std::Option`. */
//! This module is an implementation of Deterministically Encoded CBOR
//! (RFC 8949 Section 4.2.1) minus floating-point values, fully
//! formally verified for functional correctness and absence of panics
//! related to breach of abstraction, buffer overruns or arithmetic
//! overflow/underflow. This module never allocates into the heap.

/* FIXME: `cbordet` to be defined as abstract in cbordetveraux
 * already. I cannot abstract it here since `cbor_det_mk_tagged`,
 * `cbor_det_mk_array` and `cbor_det_mk_map` use references and arrays
 * of `cbordet` elements as input arguments.
 */
/// An abstract type to represent a Deterministic CBOR object, which
/// can be obtained either using "constructor" functions of this
/// module, or by parsing from serialized data. Declared in
/// `pulse/CBOR.Pulse.Det.API.Rust.fsti`. Its corresponding pure
/// ("mathematical") functional specification is the `cbor` type in
/// `spec/CBOR.Spec.Type.fsti`.
pub type CborDet <'a> = crate::cbordetver::cbordet <'a>;

/// Tries to parse a Deterministic CBOR object from the first bytes of
/// `input`, following RFC 8949 Section 4.2.1, minus floating-point
/// values. Returns `None` in case of failure, or `Some(object, rem)`
/// in case of success, where `rem` is the remainder of the input
/// slice past those first bytes of `input` that contain the valid
/// binary representation of
/// `input`. This function does not perform a deep parse of `input`,
/// it only copies the object type, tag and/or size of the top-most
/// object. As such, it uses constant stack space (including data
/// validation.) "Destructor" functions are to be used on the returned
/// object, to examine each level of nesting one at a time. NOTE: This
/// implementation checks for the basic validity constraints of
/// Section 5.3.1, i.e. the absence of duplicate map keys (which is a
/// consequence of the deterministic encoding.), and the
/// well-formedness of UTF-8 text strings.
pub fn cbor_det_parse <'a>(input: &'a [u8]) ->
    Option<(CborDet<'a>, &'a [u8])>
{
    match crate::cbordetver::cbor_det_parse(input) {
	crate::cbordetver::option__·CBOR_Pulse_Raw_Type_cbor_raw···Pulse_Lib_Slice_slice·uint8_t·::None => {
	    return None;
	}
	crate::cbordetver::option__·CBOR_Pulse_Raw_Type_cbor_raw···Pulse_Lib_Slice_slice·uint8_t·::Some {v} => {
	    let (object, rem) = v;
	    return Some((object, rem));
	}
    }
}

/// Computes the byte size of the binary representation of the
/// Deterministic CBOR object `x` following RFC 8949 Section 4.2.1,
/// but without serializing `x`. Returns `None` if that size is
/// strictly larger than `bound`; `Some(size)` otherwise. This function
/// uses stack space in the order of the level of nesting of the use
/// of "constructor" functions used to build `x`; the computation of
/// the sizes of those "subobjects" of `x` obtained from
/// `cbor_det_parse` uses only constant extra stack space for each
/// such subobject (in the sense that the computation does not
/// recursively nest into such subobjects.)
pub fn cbor_det_size <'a>(x: CborDet <'a>, bound: usize) -> Option<usize>
{
    match crate::cbordetver::cbor_det_size(x, bound) {
	crate::cbordetver::option__size_t::None => {
	    return None;
	}
	crate::cbordetver::option__size_t::Some {v} => {
	    return Some(v);
	}
    }
}

/// Writes the binary representation of the Deterministic CBOR object
/// `x` into the first bytes of the `output` byte slice, following RFC
/// 8949 Section 4.2.1. This function first checks the size of `x` and
/// returns `None` if it is larger than the size of `output`;
/// otherwise it returns `Some(size)`, where `size` is the byte size
/// of `x`, the number of bytes written to `output`. This function
/// uses stack space in the order of the level of nesting of the use
/// of "constructor" functions used to build `x`; the serialization of
/// those "subobjects" of `x` obtained from `cbor_det_parse` uses only
/// constant extra stack space for each such subobject (in the sense
/// that the serialization does not recursively nest into such
/// subobjects.)
pub fn cbor_det_serialize <'a>(x: CborDet <'a>, output: &'a mut [u8]) ->
    Option<usize>
{
    match crate::cbordetver::cbor_det_serialize(x, output) {
	crate::cbordetver::option__size_t::None => {
	    return None;
	}
	crate::cbordetver::option__size_t::Some {v} => {
	    return Some(v);
	}
    }
}

/// Constructs a Deterministic CBOR object of "simple value" type,
/// with value `v`. Returns `None` if the value `v` lies in the
/// reserved range (`24..31`), as specified by Table 4 of RFC 8949
/// Section 3.3; `Some(object)` otherwise.
pub fn cbor_det_mk_simple_value <'a>(v: u8) -> Option<CborDet<'a>>
{
    match crate::cbordetver::cbor_det_mk_simple_value(v) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    return None;
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
	    return Some(v);
	}
    }
}

/// The kind of 64-bit integer: unsigned (to represent non-negative
/// values), or negative (to represent negative values in two's
/// complement.)
#[derive(PartialEq, Clone, Copy)]
pub enum CborDetIntKind
{
    UInt64,
    NegInt64
}

/// Constructs a Deterministic CBOR object of "integer" type, with
/// kind `ty` and value `v`.
pub fn cbor_det_mk_int64 <'a>(ty: CborDetIntKind, v: u64) ->
    CborDet <'a>
{
    let ty· : crate::cbordetver::cbor_det_int_kind =
	match ty {
	    CborDetIntKind::UInt64 => {
		crate::cbordetver::cbor_det_int_kind::UInt64
	    }
	    CborDetIntKind::NegInt64 => {
		crate::cbordetver::cbor_det_int_kind::NegInt64
	    }
	};
    crate::cbordetver::cbor_det_mk_int64(ty·, v)
}

/// Constructs a Deterministic CBOR object of "text string" type, with
/// the contents of `s` as value. This function does not perform any
/// copy of its input `s`. It returns `None` if the byte size of `s`
/// is larger than $2^64 - 1$, `Some(object)` otherwise. This function
/// respects the UTF-8 well-formedness invariants.
pub fn cbor_det_mk_text_string <'a>(s: &'a str) ->
    Option<CborDet<'a>>
{
    let ty· : crate::cbordetver::cbor_det_string_kind =
	crate::cbordetver::cbor_det_string_kind::TextString;
    match crate::cbordetver::cbor_det_mk_string(ty·, s.as_bytes()) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some { v } => {
	    Some(v)
	}
    }
}

/// Constructs a Deterministic CBOR object of "byte string" type, with
/// the contents of `s` as value. This function does not perform any
/// copy of its input `s`. It returns `None` if the byte size of `s`
/// is larger than $2^64 - 1$, `Some(object)` otherwise.
pub fn cbor_det_mk_byte_string <'a>(s: &'a [u8]) ->
    Option<CborDet<'a>>
{
    let ty· : crate::cbordetver::cbor_det_string_kind =
	crate::cbordetver::cbor_det_string_kind::ByteString;
    match crate::cbordetver::cbor_det_mk_string(ty·, s) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some { v } => {
	    Some(v)
	}
    }
}

/* FIXME: this function to be extracted with references instead of
 * slices. The verified FStar/Pulse code is already using references,
 * but Karamel extracts them as slices. Because of that, I need to
 * manually write this piece of glue code to convert a reference into
 * a slice, which Karamel cannot extract (and FStar/Pulse cannot
 * currently model.)
 */
/// Constructs a Deterministic CBOR object of Tagged type, with tag
/// `tag`, and the contents of `r` as value. This function does not
/// perform any copy of its input `r`.
pub fn cbor_det_mk_tagged <'a>(tag: u64, r: &'a CborDet <'a>) ->
    CborDet <'a>
{
    return crate::cbordetver::cbor_det_mk_tagged(tag, std::slice::from_ref(r));
}

/// Constructs a Deterministic CBOR of "array" type. This function
/// does not copy its input array. It returns `None` if the input
/// array has more than $2^64 - 1$ elements, `Some(object)` otherwise.
pub fn cbor_det_mk_array <'a>(a: &'a [CborDet <'a>]) ->
    Option<CborDet<'a>>
{
    match crate::cbordetver::cbor_det_mk_array(a) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
	    Some(v)
	}
    }
}

/* FIXME: this type to be defined as abstract in cbordetveraux
 * already. I cannot abstract it here since `cbor_det_mk_map` uses
 * arrays of map entry elements as input arguments.
 */
/// The type of key-value map entries.
pub type CborDetMapEntry <'a> = crate::cbordetveraux::cbor_map_entry <'a>;

/// Constructs a map entry from a key `xk` and a value `xv`.
pub fn cbor_det_mk_map_entry <'a>(
    xk: CborDet <'a>,
    xv: CborDet <'a>
) ->
    CborDetMapEntry <'a>
{
    return crate::cbordetver::cbor_det_mk_map_entry(xk, xv);
}

/// Constructs a map from a slice of map entries. This function does
/// not copy its input array. If the input slice has more than $2^64 -
/// 1$ entries, then this function returns `None` and does not change
/// the input slice. Otherwise, this function tries to sort the input
/// slice in-place with respect to the key order specified in Section
/// 4.2.1 of RFC 8949 (without actually serializing the map entries.)
/// If the sorting detects duplicate keys, then this function returns
/// `None`. Otherwise, it returns `Some(object)`. Due to the sorting,
/// this function consumes stack space logarithmic in the size of the
/// input slice, and linear in the maximum nesting of map entry keys,
/// and the function may have changed the order of map entries in the
/// input slice.
pub fn cbor_det_mk_map <'a>(a: &'a mut [CborDetMapEntry <'a>]) ->
    Option<CborDet<'a>>
{
    match crate::cbordetver::cbor_det_mk_map(a) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
	    Some(v)
	}
    }
}

/// Compares Deterministic CBOR objects for semantic equality. This
/// function consumes stack space linear in the maximum nesting of its
/// two arguments.
pub fn cbor_det_equal <'a>(
    x1: CborDet <'a>,
    x2: CborDet <'a>
) ->
    bool
{
    crate::cbordetver::cbor_det_equal(x1, x2)
}

/// The read-only type of Deterministic CBOR arrays. Values of this
/// type cannot be manually constructed by the user, they are meant to
/// be obtained only via `cbor_det_destruct` below. The abstraction is
/// justified by the use of a refinement type, as per the definition
/// of `cbor_det_array` in `pulse/CBOR.Pulse.Det.API.Rust.fst`
#[derive(PartialEq, Clone, Copy)]
pub struct CborDetArray <'a> { array: crate::cbordetver::cbor_det_array <'a> }

/// The read-only type of Deterministic CBOR maps. Values of this
/// type cannot be manually constructed by the user, they are meant to
/// be obtained only via `cbor_det_destruct` below. The abstraction is
/// justified by the use of a refinement type, as per the definition
/// of `cbor_det_map` in `pulse/CBOR.Pulse.Det.API.Rust.fst`
#[derive(PartialEq, Clone, Copy)]
pub struct CborDetMap <'a> { map: crate::cbordetver::cbor_det_map <'a> }

/// A read-only view of a Deterministic CBOR object, as obtained by
/// peeling the first layer of nesting via `cbor_det_destruct` below.
#[derive(PartialEq, Clone, Copy)]
pub enum CborDetView <'a>
{
    Int64 { kind: CborDetIntKind, value: u64 },
    ByteString { payload: &'a [u8] },
    TextString { payload: &'a str },
    Array { _0: CborDetArray <'a> },
    Map { _0: CborDetMap <'a> },
    Tagged { tag: u64, payload: CborDet <'a> },
    SimpleValue { _0: u8 }
}

/// Destructs a Deterministic CBOR object by peeling its first layer
/// of nesting. This function does not recursively descend into array
/// or map payloads, and only reads the header of a tagged payload. As
/// such, it consumes constant stack space. This function respects the
/// UTF-8 well-formedness invariants.
pub fn cbor_det_destruct <'a>(c: CborDet <'a>) -> CborDetView <'a>
{
    match crate::cbordetver::cbor_det_destruct(c) {
	crate::cbordetver::cbor_det_view::Int64 { kind, value } => {
	    let kind· : CborDetIntKind =
		match kind {
		    crate::cbordetver::cbor_det_int_kind::UInt64 => {
			CborDetIntKind::UInt64
		    }
		    crate::cbordetver::cbor_det_int_kind::NegInt64 => {
			CborDetIntKind::NegInt64
		    }
		};
	    CborDetView::Int64 {kind: kind·, value}
	}
	crate::cbordetver::cbor_det_view::String { kind, payload } => {
	    match kind {
		crate::cbordetver::cbor_det_string_kind::ByteString => {
		    CborDetView::ByteString {payload}
		}
		crate::cbordetver::cbor_det_string_kind::TextString => {
		    CborDetView::TextString {payload: std::str::from_utf8(payload).unwrap()}
		}
	    }
	}
	crate::cbordetver::cbor_det_view::Array { _0 } => {
	    CborDetView::Array { _0: CborDetArray {array: _0 } }
	}
	crate::cbordetver::cbor_det_view::Map { _0 } => {
	    CborDetView::Map { _0: CborDetMap {map: _0 } }
	}
	crate::cbordetver::cbor_det_view::Tagged { tag, payload } => {
	    CborDetView::Tagged {tag, payload}
	}
	crate::cbordetver::cbor_det_view::SimpleValue { _0 } => {
	    CborDetView::SimpleValue {_0}
	}
    }
}

/// Returns the number of elements in a Deterministic CBOR array.
pub fn cbor_det_get_array_length <'a>(x: CborDetArray <'a>) -> u64
{
    crate::cbordetver::cbor_det_get_array_length(x.array)
}

/// The type of iterators over Deterministic CBOR arrays. It is made
/// abstract since it is meant to be used with an implementation of
/// the `Iterator` trait only.
pub struct CborDetArrayIterator <'a> { iter: crate::cbordetveraux::cbor_raw_iterator__CBOR_Pulse_Raw_Type_cbor_raw <'a> }

impl <'a> Iterator for CborDetArrayIterator <'a> {
    type Item = CborDet <'a>;
    fn next(&mut self) -> Option<Self::Item> {
	if crate::cbordetver::cbor_det_array_iterator_is_empty(self.iter) {
	    None
	} else {
	    Some (crate::cbordetver::cbor_det_array_iterator_next(std::slice::from_mut(& mut self.iter)))
	}
    }
}

impl <'a> IntoIterator for CborDetArray <'a> {
    type Item = CborDet <'a>;
    type IntoIter = CborDetArrayIterator <'a>;
    fn into_iter(self) -> Self::IntoIter {
	CborDetArrayIterator { iter: crate::cbordetver::cbor_det_array_iterator_start(self.array) }
    }
}

/// Returns the `i`th element of the CBOR array `x`. Returns `None` if
/// `i` is equal to or larger than the number of array elements,
/// `Some(object)` otherwise.
pub fn cbor_det_get_array_item <'a>(x: CborDetArray <'a>, i: u64) ->
    Option<CborDet<'a>>
{
    match crate::cbordetver::cbor_det_get_array_item(x.array, i) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
	    Some(v)
	}
    }
}

/// Returns the number of elements in a Deterministic CBOR map.
pub fn cbor_det_get_map_length <'a>(x: CborDetMap <'a>) -> u64
{
    crate::cbordetver::cbor_det_map_length(x.map)
}

/// The type of iterators over Deterministic CBOR maps. It is made
/// abstract since it is meant to be used with an implementation of
/// the `Iterator` trait only.
pub struct CborDetMapIterator <'a> { iter: crate::cbordetveraux::cbor_raw_iterator__CBOR_Pulse_Raw_Type_cbor_map_entry <'a> }

impl <'a> Iterator for CborDetMapIterator <'a> {
    type Item = CborDetMapEntry <'a>;
    fn next(&mut self) -> Option<Self::Item> {
	if crate::cbordetver::cbor_det_map_iterator_is_empty(self.iter) {
	    None
	} else {
	    Some (crate::cbordetver::cbor_det_map_iterator_next(std::slice::from_mut(& mut self.iter)))
	}
    }
}

impl <'a> IntoIterator for CborDetMap <'a> {
    type Item = CborDetMapEntry <'a>;
    type IntoIter = CborDetMapIterator <'a>;
    fn into_iter(self) -> Self::IntoIter {
	CborDetMapIterator { iter: crate::cbordetver::cbor_det_map_iterator_start(self.map) }
    }
}

/// Read the key of a map entry.
pub fn cbor_det_map_entry_key <'a>(x2: CborDetMapEntry <'a>) ->
    CborDet
    <'a>
{ crate::cbordetver::cbor_det_map_entry_key(x2) }

/// Read the value of a map entry.
pub fn cbor_det_map_entry_value <'a>(x2: CborDetMapEntry <'a>) ->
    CborDet
    <'a>
{ crate::cbordetver::cbor_det_map_entry_value(x2) }

/// Looks up a map `x` for an entry associated to the key `k`. If such
/// an entry exists, returns `Some(object)` where `object` is the
/// value associated to that key. Otherwise, returns `None`.
pub fn cbor_det_map_get <'a>(
    x: CborDetMap <'a>,
    k: CborDet <'a>
) ->
    Option<CborDet<'a>>
{
    match crate::cbordetver::cbor_det_map_get(x.map, k) {
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::None => {
	    None
	}
	crate::cbordetver::option__CBOR_Pulse_Raw_Type_cbor_raw::Some {v} => {
	    Some(v)
	}
    }
}