Skip to main content

vest_lib/cbor/
head.rs

1//! CBOR initial-byte and argument formats.
2use crate::combinators::{
3    mapped::spec::{LosslessMapper, LossyMapper, SpecMap, SpecMapper},
4    Bind, Bits, Const, Empty, Mapped, Refined, Sum, U16Be, U32Be, U64Be, Void, U8,
5};
6use crate::core::exec::{
7    input::{InputBuf, InputSlice},
8    output::OutputBuf,
9    parser::{PResult, Parser},
10    serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
11    ParseError,
12};
13use crate::core::{proof::*, spec::*};
14use crate::Never;
15use vstd::assert_seqs_equal;
16use vstd::prelude::*;
17
18use super::CborFloat;
19use Sum::Inl as L;
20use Sum::Inr as R;
21
22verus! {
23
24pub const ADDITIONAL_INFO_MASK: u8 = 0x1fu8;
25
26/// The two bit fields in a CBOR initial byte (RFC 8949 section 3).
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Structural)]
28pub struct CborInitial {
29    /// Three-bit major-type code.
30    pub major: u8,
31    /// Five-bit additional-information value.
32    pub additional: u8,
33}
34
35impl DeepView for CborInitial {
36    type V = Self;
37
38    open spec fn deep_view(&self) -> Self::V {
39        *self
40    }
41}
42
43#[verifier::allow_in_spec]
44pub fn unpack_initial(raw: u8) -> (fields: (u8, u8))
45    returns
46        ((raw >> 5, raw & ADDITIONAL_INFO_MASK)),
47{
48    (raw >> 5, raw & ADDITIONAL_INFO_MASK)
49}
50
51#[verifier::allow_in_spec]
52pub fn pack_initial(major: u8, additional: u8) -> (raw: u8)
53    returns
54        ((major << 5) | additional),
55{
56    (major << 5) | additional
57}
58
59#[verifier::allow_in_spec]
60pub fn initial_fields_in_bounds(major: u8, additional: u8) -> (valid: bool)
61    returns
62        (major < 8u8 && additional < 32u8),
63{
64    major < 8u8 && additional < 32u8
65}
66
67pub broadcast proof fn lemma_initial_unpack_pack(raw: u8)
68    by (bit_vector)
69    ensures
70        #[trigger] pack_initial(unpack_initial(raw).0, unpack_initial(raw).1) == raw,
71{
72}
73
74pub broadcast proof fn lemma_initial_pack_unpack(major: u8, additional: u8)
75    by (bit_vector)
76    requires
77        #[trigger] initial_fields_in_bounds(major, additional),
78    ensures
79        unpack_initial(pack_initial(major, additional)).0 == major,
80        unpack_initial(pack_initial(major, additional)).1 == additional,
81{
82}
83
84pub broadcast proof fn lemma_initial_unpack_in_bounds(raw: u8)
85    by (bit_vector)
86    ensures
87        #[trigger] initial_fields_in_bounds(unpack_initial(raw).0, unpack_initial(raw).1),
88{
89}
90
91type CborInitialInnerFmt = Bits<U8, (u8, u8), CborInitial>;
92
93pub open spec fn cbor_initial_fmt() -> CborInitialInnerFmt {
94    Bits {
95        repr: U8,
96        unpack: |raw: u8| unpack_initial(raw),
97        pack: |fields: (u8, u8)| pack_initial(fields.0, fields.1),
98        refinement: |_fields: (u8, u8)| true,
99        ctor: |fields: (u8, u8)| CborInitial { major: fields.0, additional: fields.1 },
100        dtor: |initial: CborInitial| (initial.major, initial.additional),
101        consistent: |initial: CborInitial|
102            { initial_fields_in_bounds(initial.major, initial.additional) },
103    }
104}
105
106/// The fixed-width initial-byte bit-field format.
107#[derive(Debug, Clone, Copy)]
108pub struct CborInitialFmt;
109
110impl<'i> Parser<&'i [u8]> for CborInitialFmt {
111    type PT = CborInitial;
112
113    fn parse(&self, input: &&'i [u8]) -> PResult<Self::PT> {
114        let (n, raw) = U8.parse(input)?;
115        let (major, additional) = unpack_initial(raw);
116        Ok((n, CborInitial { major, additional }))
117    }
118}
119
120impl<Output: OutputBuf> Serializer<Output, CborInitial> for CborInitialFmt {
121    fn serialize_into(&self, value: &CborInitial, out: &mut Output) {
122        broadcast use crate::core::exec::output::outbuf_lemmas;
123
124        let ghost old_out = out@;
125        let r = pack_initial(value.major, value.additional);
126        U8.serialize_into(&r, out);
127        assert(out@ == old_out + self.spec_serialize(value.deep_view()));
128    }
129}
130
131impl Prepare<CborInitial> for CborInitialFmt {
132    fn prepare(&self, value: &CborInitial) -> Result<usize, PreSerializeError> {
133        if !initial_fields_in_bounds(value.major, value.additional) {
134            Err(PreSerializeError::custom("CBOR initial-byte field is out of range"))
135        } else {
136            let r = pack_initial(value.major, value.additional);
137            U8.prepare(&r)
138        }
139    }
140}
141
142impl ByteLen<CborInitial> for CborInitialFmt {
143    fn length(&self, value: &CborInitial) -> usize {
144        let r = pack_initial(value.major, value.additional);
145        U8.length(&r)
146    }
147}
148
149/// The eight CBOR major types from RFC 8949 section 3.1.
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Structural)]
151pub enum MajorType {
152    Unsigned,
153    Negative,
154    Bytes,
155    Text,
156    Array,
157    Map,
158    Tag,
159    Simple,
160}
161
162impl DeepView for MajorType {
163    type V = Self;
164
165    open spec fn deep_view(&self) -> Self::V {
166        *self
167    }
168}
169
170/// Semantic payload carried by a decoded CBOR head.
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Structural)]
172pub enum CborHeadValue {
173    Argument(u64),
174    Indefinite,
175    Simple(u8),
176    Float(CborFloat),
177    Break,
178}
179
180impl DeepView for CborHeadValue {
181    type V = Self;
182
183    open spec fn deep_view(&self) -> Self::V {
184        *self
185    }
186}
187
188/// A normalized CBOR initial byte and its optional argument.
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Structural)]
190pub struct CborHead {
191    pub major: MajorType,
192    pub value: CborHeadValue,
193}
194
195impl DeepView for CborHead {
196    type V = Self;
197
198    open spec fn deep_view(&self) -> Self::V {
199        *self
200    }
201}
202
203#[verifier::allow_in_spec]
204pub fn major_from_code(code: u8) -> MajorType
205    returns
206        (match code {
207            0 => MajorType::Unsigned,
208            1 => MajorType::Negative,
209            2 => MajorType::Bytes,
210            3 => MajorType::Text,
211            4 => MajorType::Array,
212            5 => MajorType::Map,
213            6 => MajorType::Tag,
214            _ => MajorType::Simple,
215        }),
216{
217    match code {
218        0 => MajorType::Unsigned,
219        1 => MajorType::Negative,
220        2 => MajorType::Bytes,
221        3 => MajorType::Text,
222        4 => MajorType::Array,
223        5 => MajorType::Map,
224        6 => MajorType::Tag,
225        _ => MajorType::Simple,
226    }
227}
228
229#[verifier::allow_in_spec]
230pub fn major_code(major: MajorType) -> u8
231    returns
232        (match major {
233            MajorType::Unsigned => 0u8,
234            MajorType::Negative => 1u8,
235            MajorType::Bytes => 2u8,
236            MajorType::Text => 3u8,
237            MajorType::Array => 4u8,
238            MajorType::Map => 5u8,
239            MajorType::Tag => 6u8,
240            MajorType::Simple => 7u8,
241        }),
242{
243    match major {
244        MajorType::Unsigned => 0u8,
245        MajorType::Negative => 1u8,
246        MajorType::Bytes => 2u8,
247        MajorType::Text => 3u8,
248        MajorType::Array => 4u8,
249        MajorType::Map => 5u8,
250        MajorType::Tag => 6u8,
251        MajorType::Simple => 7u8,
252    }
253}
254
255#[verifier::allow_in_spec]
256pub fn valid_simple(value: u8) -> bool
257    returns
258        (value <= 23u8 || value >= 32u8),
259{
260    value <= 23u8 || value >= 32u8
261}
262
263#[verifier::allow_in_spec]
264pub fn valid_head<const DET: bool>(head: CborHead) -> bool
265    returns
266        (match head.value {
267            CborHeadValue::Argument(_) => head.major != MajorType::Simple,
268            CborHeadValue::Indefinite => !DET && {
269                head.major == MajorType::Bytes || head.major == MajorType::Text || head.major
270                    == MajorType::Array || head.major == MajorType::Map
271            },
272            CborHeadValue::Simple(value) => head.major == MajorType::Simple && valid_simple(value),
273            CborHeadValue::Float(_) => head.major == MajorType::Simple,
274            CborHeadValue::Break => head.major == MajorType::Simple,
275        }),
276{
277    match head.value {
278        CborHeadValue::Argument(_) => head.major != MajorType::Simple,
279        CborHeadValue::Indefinite => !DET && {
280            head.major == MajorType::Bytes || head.major == MajorType::Text || head.major
281                == MajorType::Array || head.major == MajorType::Map
282        },
283        CborHeadValue::Simple(value) => head.major == MajorType::Simple && valid_simple(value),
284        CborHeadValue::Float(_) => head.major == MajorType::Simple,
285        CborHeadValue::Break => head.major == MajorType::Simple,
286    }
287}
288
289#[verifier::allow_in_spec]
290pub fn minimal_u8_argument(value: u8) -> bool
291    returns
292        (value >= 24u8),
293{
294    value >= 24u8
295}
296
297#[verifier::allow_in_spec]
298pub fn minimal_u16_argument(value: u16) -> bool
299    returns
300        (value > u8::MAX as u16),
301{
302    value > u8::MAX as u16
303}
304
305#[verifier::allow_in_spec]
306pub fn minimal_u32_argument(value: u32) -> bool
307    returns
308        (value > u16::MAX as u32),
309{
310    value > u16::MAX as u32
311}
312
313#[verifier::allow_in_spec]
314pub fn minimal_u64_argument(value: u64) -> bool
315    returns
316        (value > u32::MAX as u64),
317{
318    value > u32::MAX as u64
319}
320
321type HeadWireValue = Sum<(), Sum<u8, Sum<u16, Sum<u32, Sum<u64, Sum<(), Never>>>>>>;
322
323type HeadBranchesFmt = Sum<Empty, Sum<U8, Sum<U16Be, Sum<U32Be, Sum<U64Be, Sum<Empty, Void>>>>>>;
324
325type HeadWireFmt<const DET: bool> = Bind<CborInitialFmt, spec_fn(CborInitial) -> HeadBranchesFmt>;
326
327type RefinedHeadWireFmt<const DET: bool> = Refined<
328    HeadWireFmt<DET>,
329    PredFnSpec<(CborInitial, HeadWireValue)>,
330>;
331
332type HeadMappedFmt<const DET: bool> = Mapped<RefinedHeadWireFmt<DET>, HeadMapper<DET>>;
333
334pub open spec fn head_wire<const DET: bool>() -> HeadWireFmt<DET> {
335    Bind(
336        CborInitialFmt,
337        |initial: CborInitial|
338            {
339                let major = major_from_code(initial.major);
340                match initial.additional {
341                    ai if ai <= 23u8 => L(Empty),
342                    24u8 => R(L(U8)),
343                    25u8 => R(R(L(U16Be))),
344                    26u8 => R(R(R(L(U32Be)))),
345                    27u8 => R(R(R(R(L(U64Be))))),
346                    31u8 if major == MajorType::Bytes || major == MajorType::Text || major
347                        == MajorType::Array || major == MajorType::Map || major
348                        == MajorType::Simple => R(R(R(R(R(L(Empty)))))),
349                    _ => R(R(R(R(R(R(Void("Reserved or invalid CBOR additional information"))))))),
350                }
351            },
352    )
353}
354
355pub open spec fn valid_head_wire<const DET: bool>(wire: (CborInitial, HeadWireValue)) -> bool {
356    let major = major_from_code(wire.0.major);
357    match wire.1 {
358        L(()) => true,
359        R(L(value)) => {
360            if major == MajorType::Simple {
361                value >= 32u8
362            } else {
363                DET ==> minimal_u8_argument(value)
364            }
365        },
366        R(R(L(value))) => major == MajorType::Simple || (DET ==> minimal_u16_argument(value)),
367        R(R(R(L(value)))) => major == MajorType::Simple || (DET ==> minimal_u32_argument(value)),
368        R(R(R(R(L(value))))) => major == MajorType::Simple || (DET ==> minimal_u64_argument(value)),
369        R(R(R(R(R(L(())))))) => major == MajorType::Simple || !DET,
370        _ => false,
371    }
372}
373
374pub open spec fn decode_head_wire(wire: (CborInitial, HeadWireValue)) -> CborHead {
375    let (initial, rest) = wire;
376    let major = major_from_code(initial.major);
377    let ai = initial.additional;
378    let value = match rest {
379        L(()) => {
380            if major == MajorType::Simple {
381                CborHeadValue::Simple(ai)
382            } else {
383                CborHeadValue::Argument(ai as u64)
384            }
385        },
386        R(L(value)) => {
387            if major == MajorType::Simple {
388                CborHeadValue::Simple(value)
389            } else {
390                CborHeadValue::Argument(value as u64)
391            }
392        },
393        R(R(L(value))) => {
394            if major == MajorType::Simple {
395                CborHeadValue::Float(CborFloat::F16(value))
396            } else {
397                CborHeadValue::Argument(value as u64)
398            }
399        },
400        R(R(R(L(value)))) => {
401            if major == MajorType::Simple {
402                CborHeadValue::Float(CborFloat::F32(value))
403            } else {
404                CborHeadValue::Argument(value as u64)
405            }
406        },
407        R(R(R(R(L(value))))) => {
408            if major == MajorType::Simple {
409                CborHeadValue::Float(CborFloat::F64(value))
410            } else {
411                CborHeadValue::Argument(value)
412            }
413        },
414        R(R(R(R(R(L(())))))) => {
415            if major == MajorType::Simple {
416                CborHeadValue::Break
417            } else {
418                CborHeadValue::Indefinite
419            }
420        },
421        _ => arbitrary(),
422    };
423    CborHead { major, value }
424}
425
426pub open spec fn encode_head_wire(head: CborHead) -> (CborInitial, HeadWireValue) {
427    let major = major_code(head.major);
428    match head.value {
429        CborHeadValue::Argument(value) => {
430            if value <= 23u64 {
431                (CborInitial { major, additional: value as u8 }, L(()))
432            } else if value <= u8::MAX as u64 {
433                (CborInitial { major, additional: 24u8 }, R(L(value as u8)))
434            } else if value <= u16::MAX as u64 {
435                (CborInitial { major, additional: 25u8 }, R(R(L(value as u16))))
436            } else if value <= u32::MAX as u64 {
437                (CborInitial { major, additional: 26u8 }, R(R(R(L(value as u32)))))
438            } else {
439                (CborInitial { major, additional: 27u8 }, R(R(R(R(L(value))))))
440            }
441        },
442        CborHeadValue::Indefinite => (
443            CborInitial { major, additional: 31u8 },
444            R(R(R(R(R(L(())))))),
445        ),
446        CborHeadValue::Simple(value) => {
447            if value <= 23u8 {
448                (CborInitial { major, additional: value }, L(()))
449            } else {
450                (CborInitial { major, additional: 24u8 }, R(L(value)))
451            }
452        },
453        CborHeadValue::Float(CborFloat::F16(value)) => {
454            (CborInitial { major, additional: 25u8 }, R(R(L(value))))
455        },
456        CborHeadValue::Float(CborFloat::F32(value)) => {
457            (CborInitial { major, additional: 26u8 }, R(R(R(L(value)))))
458        },
459        CborHeadValue::Float(CborFloat::F64(value)) => {
460            (CborInitial { major, additional: 27u8 }, R(R(R(R(L(value))))))
461        },
462        CborHeadValue::Break => (CborInitial { major, additional: 31u8 }, R(R(R(R(R(L(()))))))),
463    }
464}
465
466#[derive(Clone, Copy)]
467pub struct HeadMapper<const DET: bool>;
468
469impl<const DET: bool> SpecMapper for HeadMapper<DET> {
470    type In = (CborInitial, HeadWireValue);
471
472    type Out = CborHead;
473
474    open spec fn spec_map(&self, wire: Self::In) -> Self::Out {
475        decode_head_wire(wire)
476    }
477
478    open spec fn spec_map_rev(&self, head: Self::Out) -> Self::In {
479        encode_head_wire(head)
480    }
481
482    open spec fn wf_in(&self, wire: Self::In) -> bool {
483        &&& head_wire::<DET>().consistent(wire)
484        &&& valid_head_wire::<DET>(wire)
485    }
486
487    open spec fn wf_out(&self, head: Self::Out) -> bool {
488        valid_head::<DET>(head)
489    }
490}
491
492impl<const DET: bool> LossyMapper for HeadMapper<DET> {
493    proof fn lemma_sound_mapper(&self, head: Self::Out) {
494        match head.value {
495            CborHeadValue::Argument(value) => {
496                if value <= 23u64 {
497                    assert((value as u8) as u64 == value) by (bit_vector)
498                        requires
499                            value <= 23u64,
500                    ;
501                } else if value <= u8::MAX as u64 {
502                    assert((value as u8) as u64 == value) by (bit_vector)
503                        requires
504                            value <= u8::MAX as u64,
505                    ;
506                } else if value <= u16::MAX as u64 {
507                    assert((value as u16) as u64 == value) by (bit_vector)
508                        requires
509                            value <= u16::MAX as u64,
510                    ;
511                } else if value <= u32::MAX as u64 {
512                    assert((value as u32) as u64 == value) by (bit_vector)
513                        requires
514                            value <= u32::MAX as u64,
515                    ;
516                }
517            },
518            _ => {},
519        }
520    }
521
522    proof fn lemma_mapper_wf_out_in(&self, head: Self::Out) {
523    }
524}
525
526impl LosslessMapper for HeadMapper<true> {
527    proof fn lemma_lossless_mapper(&self, wire: Self::In) {
528    }
529
530    proof fn lemma_mapper_wf_in_out(&self, wire: Self::In) {
531    }
532}
533
534pub open spec fn cbor_head_fmt<const DET: bool>() -> HeadMappedFmt<DET> {
535    Mapped {
536        inner: Refined(
537            head_wire::<DET>(),
538            |wire: (CborInitial, HeadWireValue)| valid_head_wire::<DET>(wire),
539        ),
540        mapper: HeadMapper::<DET>,
541    }
542}
543
544/// One normalized CBOR head.
545///
546/// `DET = true` rejects nonminimal integer, length, and tag arguments and
547/// rejects indefinite-length heads. Floating-point payload widths remain an
548/// explicit part of [`CborFloat`] and are not shortened here.
549#[derive(Debug, Clone, Copy)]
550pub struct CborHeadFmt<const DET: bool>;
551
552pub type BreakFmt = Const<U8, u8>;
553
554/// The CBOR break stop code (`0xff`).
555pub const BREAK: BreakFmt = Const(U8, 0xffu8);
556
557impl<'i, const DET: bool> Parser<&'i [u8]> for CborHeadFmt<DET> {
558    type PT = CborHead;
559
560    fn parse(&self, input: &&'i [u8]) -> PResult<Self::PT> {
561        broadcast use crate::core::spec::SafeParser::lemma_parse_safe;
562
563        let (n1, initial) = CborInitialFmt.parse(input)?;
564        let major = major_from_code(initial.major);
565        let ai = initial.additional;
566        let rest = input.skip(n1);
567
568        match ai {
569            0..=23 => {
570                let value = if major == MajorType::Simple {
571                    CborHeadValue::Simple(ai)
572                } else {
573                    CborHeadValue::Argument(ai as u64)
574                };
575                Ok((1, CborHead { major, value }))
576            },
577            24 => {
578                let (_, value) = U8.parse(&rest)?;
579                if major == MajorType::Simple {
580                    if value < 32 {
581                        Err(ParseError::invalid_tag())
582                    } else {
583                        Ok((2, CborHead { major, value: CborHeadValue::Simple(value) }))
584                    }
585                } else if DET && !minimal_u8_argument(value) {
586                    Err(ParseError::non_canonical())
587                } else {
588                    Ok((2, CborHead { major, value: CborHeadValue::Argument(value as u64) }))
589                }
590            },
591            25 => {
592                let (_, value) = U16Be.parse(&rest)?;
593                if major == MajorType::Simple {
594                    Ok((3, CborHead { major, value: CborHeadValue::Float(CborFloat::F16(value)) }))
595                } else if DET && !minimal_u16_argument(value) {
596                    Err(ParseError::non_canonical())
597                } else {
598                    Ok((3, CborHead { major, value: CborHeadValue::Argument(value as u64) }))
599                }
600            },
601            26 => {
602                let (_, value) = U32Be.parse(&rest)?;
603                if major == MajorType::Simple {
604                    Ok((5, CborHead { major, value: CborHeadValue::Float(CborFloat::F32(value)) }))
605                } else if DET && !minimal_u32_argument(value) {
606                    Err(ParseError::non_canonical())
607                } else {
608                    Ok((5, CborHead { major, value: CborHeadValue::Argument(value as u64) }))
609                }
610            },
611            27 => {
612                let (_, value) = U64Be.parse(&rest)?;
613                if major == MajorType::Simple {
614                    Ok((9, CborHead { major, value: CborHeadValue::Float(CborFloat::F64(value)) }))
615                } else if DET && !minimal_u64_argument(value) {
616                    Err(ParseError::non_canonical())
617                } else {
618                    Ok((9, CborHead { major, value: CborHeadValue::Argument(value) }))
619                }
620            },
621            31 => {
622                if !DET && (major == MajorType::Bytes || major == MajorType::Text || major
623                    == MajorType::Array || major == MajorType::Map) {
624                    Ok((1, CborHead { major, value: CborHeadValue::Indefinite }))
625                } else if major == MajorType::Simple {
626                    Ok((1, CborHead { major, value: CborHeadValue::Break }))
627                } else {
628                    Err(ParseError::invalid_tag())
629                }
630            },
631            _ => Err(ParseError::invalid_tag()),
632        }
633    }
634}
635
636impl<Output: OutputBuf, const DET: bool> Serializer<Output, CborHead> for CborHeadFmt<DET> {
637    fn serialize_into(&self, head: &CborHead, out: &mut Output) {
638        broadcast use crate::core::exec::output::outbuf_lemmas;
639
640        let ghost old_out = out@;
641        let major = major_code(head.major);
642        match head.value {
643            CborHeadValue::Argument(value) => {
644                if value <= 23 {
645                    CborInitialFmt.serialize_into(
646                        &CborInitial { major, additional: value as u8 },
647                        out,
648                    );
649                } else if value <= u8::MAX as u64 {
650                    CborInitialFmt.serialize_into(&CborInitial { major, additional: 24 }, out);
651                    U8.serialize_into(&(value as u8), out);
652                } else if value <= u16::MAX as u64 {
653                    CborInitialFmt.serialize_into(&CborInitial { major, additional: 25 }, out);
654                    U16Be.serialize_into(&(value as u16), out);
655                } else if value <= u32::MAX as u64 {
656                    CborInitialFmt.serialize_into(&CborInitial { major, additional: 26 }, out);
657                    U32Be.serialize_into(&(value as u32), out);
658                } else {
659                    CborInitialFmt.serialize_into(&CborInitial { major, additional: 27 }, out);
660                    U64Be.serialize_into(&value, out);
661                }
662            },
663            CborHeadValue::Indefinite => {
664                CborInitialFmt.serialize_into(&CborInitial { major, additional: 31 }, out);
665            },
666            CborHeadValue::Simple(value) => {
667                if value <= 23 {
668                    CborInitialFmt.serialize_into(&CborInitial { major, additional: value }, out);
669                } else {
670                    CborInitialFmt.serialize_into(&CborInitial { major, additional: 24 }, out);
671                    U8.serialize_into(&value, out);
672                }
673            },
674            CborHeadValue::Float(CborFloat::F16(value)) => {
675                CborInitialFmt.serialize_into(&CborInitial { major, additional: 25 }, out);
676                U16Be.serialize_into(&value, out);
677            },
678            CborHeadValue::Float(CborFloat::F32(value)) => {
679                CborInitialFmt.serialize_into(&CborInitial { major, additional: 26 }, out);
680                U32Be.serialize_into(&value, out);
681            },
682            CborHeadValue::Float(CborFloat::F64(value)) => {
683                CborInitialFmt.serialize_into(&CborInitial { major, additional: 27 }, out);
684                U64Be.serialize_into(&value, out);
685            },
686            CborHeadValue::Break => {
687                CborInitialFmt.serialize_into(
688                    &CborInitial { major: major_code(MajorType::Simple), additional: 31 },
689                    out,
690                );
691            },
692        }
693
694        assert(out@ =~= old_out + self.spec_serialize(head.deep_view()));
695    }
696}
697
698pub fn head_len<const DET: bool>(head: &CborHead) -> (len: usize)
699    ensures
700        len == CborHeadFmt::<DET>.byte_len(head.deep_view()),
701{
702    let len = match head.value {
703        CborHeadValue::Argument(value) => {
704            if value <= 23 {
705                1
706            } else if value <= u8::MAX as u64 {
707                2
708            } else if value <= u16::MAX as u64 {
709                3
710            } else if value <= u32::MAX as u64 {
711                5
712            } else {
713                9
714            }
715        },
716        CborHeadValue::Indefinite => 1,
717        CborHeadValue::Simple(value) => if value <= 23 {
718            1
719        } else {
720            2
721        },
722        CborHeadValue::Float(CborFloat::F16(_)) => 3,
723        CborHeadValue::Float(CborFloat::F32(_)) => 5,
724        CborHeadValue::Float(CborFloat::F64(_)) => 9,
725        CborHeadValue::Break => 1,
726    };
727    len
728}
729
730impl<const DET: bool> Prepare<CborHead> for CborHeadFmt<DET> {
731    fn prepare(&self, head: &CborHead) -> Result<usize, PreSerializeError> {
732        if !valid_head::<DET>(*head) {
733            Err(PreSerializeError::custom("Invalid CBOR head"))
734        } else {
735            let len = head_len::<DET>(head);
736            Ok(len)
737        }
738    }
739}
740
741impl<const DET: bool> ByteLen<CborHead> for CborHeadFmt<DET> {
742    fn length(&self, head: &CborHead) -> usize {
743        head_len::<DET>(head)
744    }
745}
746
747mod derived_specs {
748    use super::*;
749
750    impl SpecParser for CborInitialFmt {
751        type PVal = CborInitial;
752
753        open spec fn spec_parse(&self, input: Seq<u8>) -> Option<(int, Self::PVal)> {
754            cbor_initial_fmt().spec_parse(input)
755        }
756    }
757
758    impl Consistency for CborInitialFmt {
759        type Val = CborInitial;
760
761        open spec fn consistent(&self, value: Self::Val) -> bool {
762            cbor_initial_fmt().consistent(value)
763        }
764    }
765
766    impl SpecSerializerDps for CborInitialFmt {
767        type SValue = CborInitial;
768
769        open spec fn spec_serialize_dps(&self, value: Self::SValue, out: Seq<u8>) -> Seq<u8> {
770            cbor_initial_fmt().spec_serialize_dps(value, out)
771        }
772    }
773
774    impl SpecSerializer for CborInitialFmt {
775        type SVal = CborInitial;
776
777        open spec fn spec_serialize(&self, value: Self::SVal) -> Seq<u8> {
778            cbor_initial_fmt().spec_serialize(value)
779        }
780    }
781
782    impl SpecByteLen for CborInitialFmt {
783        type T = CborInitial;
784
785        open spec fn byte_len(&self, value: Self::T) -> nat {
786            cbor_initial_fmt().byte_len(value)
787        }
788    }
789
790    impl<const DET: bool> SpecParser for CborHeadFmt<DET> {
791        type PVal = CborHead;
792
793        open spec fn spec_parse(&self, input: Seq<u8>) -> Option<(int, Self::PVal)> {
794            cbor_head_fmt::<DET>().spec_parse(input)
795        }
796    }
797
798    impl<const DET: bool> Consistency for CborHeadFmt<DET> {
799        type Val = CborHead;
800
801        open spec fn consistent(&self, value: Self::Val) -> bool {
802            cbor_head_fmt::<DET>().consistent(value)
803        }
804    }
805
806    impl<const DET: bool> SpecSerializerDps for CborHeadFmt<DET> {
807        type SValue = CborHead;
808
809        open spec fn spec_serialize_dps(&self, value: Self::SValue, out: Seq<u8>) -> Seq<u8> {
810            cbor_head_fmt::<DET>().spec_serialize_dps(value, out)
811        }
812    }
813
814    impl<const DET: bool> SpecSerializer for CborHeadFmt<DET> {
815        type SVal = CborHead;
816
817        open spec fn spec_serialize(&self, value: Self::SVal) -> Seq<u8> {
818            cbor_head_fmt::<DET>().spec_serialize(value)
819        }
820    }
821
822    impl<const DET: bool> SpecByteLen for CborHeadFmt<DET> {
823        type T = CborHead;
824
825        open spec fn byte_len(&self, value: Self::T) -> nat {
826            cbor_head_fmt::<DET>().byte_len(value)
827        }
828    }
829
830}
831
832mod derived_proofs {
833    use super::*;
834
835    impl SafeParser for CborInitialFmt {
836        proof fn lemma_parse_safe(&self, input: Seq<u8>) {
837            cbor_initial_fmt().lemma_parse_safe(input);
838        }
839    }
840
841    impl Productive for CborInitialFmt {
842        proof fn lemma_productive(&self, input: Seq<u8>) {
843            cbor_initial_fmt().lemma_productive(input);
844        }
845    }
846
847    impl SoundParser for CborInitialFmt {
848        proof fn lemma_parse_sound_consumption(&self, input: Seq<u8>) {
849            broadcast use lemma_initial_unpack_pack, lemma_initial_unpack_in_bounds;
850
851            let fmt = cbor_initial_fmt();
852            assert(fmt.sound_inv());
853            fmt.lemma_parse_sound_consumption(input);
854        }
855
856        proof fn lemma_parse_sound_value(&self, input: Seq<u8>) {
857            broadcast use lemma_initial_unpack_pack, lemma_initial_unpack_in_bounds;
858
859            let fmt = cbor_initial_fmt();
860            assert(fmt.sound_inv());
861            fmt.lemma_parse_sound_value(input);
862        }
863    }
864
865    impl NonTailFmt for CborInitialFmt {
866        proof fn lemma_serialize_dps_prepend(&self, value: Self::SValue, out: Seq<u8>) {
867            cbor_initial_fmt().lemma_serialize_dps_prepend(value, out);
868        }
869
870        proof fn lemma_serialize_dps_len(&self, value: Self::SValue, out: Seq<u8>) {
871            cbor_initial_fmt().lemma_serialize_dps_len(value, out);
872        }
873    }
874
875    impl GoodSerializer for CborInitialFmt {
876        proof fn lemma_serialize_len(&self, value: Self::SVal) {
877            cbor_initial_fmt().lemma_serialize_len(value);
878        }
879    }
880
881    impl SPRoundTripDps for CborInitialFmt {
882        proof fn theorem_serialize_dps_parse_roundtrip(&self, value: Self::T, out: Seq<u8>) {
883            broadcast use lemma_initial_pack_unpack;
884
885            let fmt = cbor_initial_fmt();
886            assert(fmt.unambiguous());
887            fmt.theorem_serialize_dps_parse_roundtrip(value, out);
888        }
889    }
890
891    impl NonMalleable for CborInitialFmt {
892        proof fn lemma_parse_non_malleable(&self, left: Seq<u8>, right: Seq<u8>) {
893            broadcast use lemma_initial_unpack_pack, lemma_initial_unpack_in_bounds;
894
895            cbor_initial_fmt().lemma_parse_non_malleable(left, right);
896        }
897    }
898
899    impl NoLookAhead for CborInitialFmt {
900        proof fn lemma_no_lookahead(&self, left: Seq<u8>, right: Seq<u8>) {
901            cbor_initial_fmt().lemma_no_lookahead(left, right);
902        }
903    }
904
905    impl EquivSerializersGeneral for CborInitialFmt {
906        proof fn lemma_serialize_equiv(&self, value: Self::SVal, out: Seq<u8>) {
907            cbor_initial_fmt().lemma_serialize_equiv(value, out);
908        }
909    }
910
911    impl EquivSerializers for CborInitialFmt {
912        proof fn lemma_serialize_equiv_on_empty(&self, value: Self::SVal) {
913            cbor_initial_fmt().lemma_serialize_equiv_on_empty(value);
914        }
915    }
916
917    impl<const DET: bool> SafeParser for CborHeadFmt<DET> {
918        proof fn lemma_parse_safe(&self, input: Seq<u8>) {
919            cbor_head_fmt::<DET>().lemma_parse_safe(input);
920        }
921    }
922
923    impl<const DET: bool> Productive for CborHeadFmt<DET> {
924        proof fn lemma_productive(&self, input: Seq<u8>) {
925            cbor_head_fmt::<DET>().lemma_productive(input);
926        }
927    }
928
929    impl SoundParser for CborHeadFmt<true> {
930        proof fn lemma_parse_sound_consumption(&self, input: Seq<u8>) {
931            cbor_head_fmt::<true>().lemma_parse_sound_consumption(input);
932        }
933
934        proof fn lemma_parse_sound_value(&self, input: Seq<u8>) {
935            cbor_head_fmt::<true>().lemma_parse_sound_value(input);
936        }
937    }
938
939    impl<const DET: bool> GoodSerializer for CborHeadFmt<DET> {
940        proof fn lemma_serialize_len(&self, value: Self::SVal) {
941            cbor_head_fmt::<DET>().lemma_serialize_len(value);
942        }
943    }
944
945    impl<const DET: bool> NonTailFmt for CborHeadFmt<DET> {
946        proof fn lemma_serialize_dps_prepend(&self, value: Self::SValue, out: Seq<u8>) {
947            cbor_head_fmt::<DET>().lemma_serialize_dps_prepend(value, out);
948        }
949
950        proof fn lemma_serialize_dps_len(&self, value: Self::SValue, out: Seq<u8>) {
951            cbor_head_fmt::<DET>().lemma_serialize_dps_len(value, out);
952        }
953    }
954
955    impl<const DET: bool> SPRoundTripDps for CborHeadFmt<DET> {
956        proof fn theorem_serialize_dps_parse_roundtrip(&self, value: Self::T, out: Seq<u8>) {
957            cbor_head_fmt::<DET>().theorem_serialize_dps_parse_roundtrip(value, out);
958        }
959    }
960
961    impl NonMalleable for CborHeadFmt<true> {
962        proof fn lemma_parse_non_malleable(&self, left: Seq<u8>, right: Seq<u8>) {
963            cbor_head_fmt::<true>().lemma_parse_non_malleable(left, right);
964        }
965    }
966
967    impl<const DET: bool> NoLookAhead for CborHeadFmt<DET> {
968        proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>) {
969            cbor_head_fmt::<DET>().lemma_no_lookahead(i1, i2);
970        }
971    }
972
973    impl<const DET: bool> EquivSerializersGeneral for CborHeadFmt<DET> {
974        proof fn lemma_serialize_equiv(&self, value: Self::SVal, out: Seq<u8>) {
975            cbor_head_fmt::<DET>().lemma_serialize_equiv(value, out);
976        }
977    }
978
979    impl<const DET: bool> EquivSerializers for CborHeadFmt<DET> {
980        proof fn lemma_serialize_equiv_on_empty(&self, value: Self::SVal) {
981            cbor_head_fmt::<DET>().lemma_serialize_equiv_on_empty(value);
982        }
983    }
984
985}
986
987} // verus!