1use crate::combinators::{Bind, Empty, Sum};
3use crate::core::exec::input::*;
4use crate::core::exec::output::*;
5use crate::core::exec::{parser::*, serializer::*, ParseError, ParseErrorKind};
6use crate::primitives::base128::*;
7use crate::{
8 combinators::{
9 implicit::*,
10 mapped::spec::{FnSpecMapper, SpecMap},
11 Mapped, Refined, U8,
12 },
13 core::{proof::*, spec::*},
14};
15#[cfg(feature = "alloc")]
16use alloc::vec;
17use vstd::prelude::*;
18use OutputBuf;
19use Sum::Inl as L;
20use Sum::Inr as R;
21
22#[cfg(verus_only)]
23use vstd::std_specs::convert::FromSpecImpl;
24
25verus! {
26
27pub const TAG_CLASS_MASK: u8 = 0b1100_0000u8;
29
30pub const TAG_CONSTRUCTED_MASK: u8 = 0b0010_0000u8;
32
33pub const TAG_NUMBER_MASK: u8 = 0b0001_1111u8;
35
36pub const TAG_LONG_FORM_SENTINEL: u8 = 0b0001_1111u8;
38
39pub(crate) const TAG_FMT_MAX_BYTE_LEN: usize = 11;
41
42#[derive(StructuralEq, Clone, Copy, PartialEq, Eq, Debug)]
43#[verifier::ext_equal]
44#[repr(u64)]
45pub enum TagNumber {
46 EOC = 0,
47 Boolean = 1,
48 Integer = 2,
49 BitString = 3,
50 OctetString = 4,
51 Null = 5,
52 ObjectIdentifier = 6,
53 Real = 9,
54 Enumerated = 10,
55 Utf8String = 12,
56 RelativeOid = 13,
57 Sequence = 16,
58 Set = 17,
59 NumericString = 18,
60 PrintableString = 19,
61 TeletexString = 20,
62 VideotexString = 21,
63 Ia5String = 22,
64 UtcTime = 23,
65 GeneralizedTime = 24,
66 VisibleString = 26,
67 GeneralString = 27,
68 UniversalString = 28,
69 BmpString = 30,
70 Other { tag_num: UInt },
71}
72
73#[derive(StructuralEq, Clone, Copy, PartialEq, Eq, Debug)]
74#[verifier::ext_equal]
75pub enum Class {
76 Universal,
77 Application,
78 ContextSpecific,
79 Private,
80}
81
82#[derive(StructuralEq, Clone, Copy, PartialEq, Eq, Debug)]
83#[verifier::ext_equal]
84pub struct Tag {
85 pub class: Class,
86 pub constructed: bool,
87 pub number: TagNumber,
88}
89
90pub open spec fn tag_num_to_uint(num: TagNumber) -> UInt {
91 match num {
92 TagNumber::EOC => 0,
93 TagNumber::Boolean => 1,
94 TagNumber::Integer => 2,
95 TagNumber::BitString => 3,
96 TagNumber::OctetString => 4,
97 TagNumber::Null => 5,
98 TagNumber::ObjectIdentifier => 6,
99 TagNumber::Real => 9,
100 TagNumber::Enumerated => 10,
101 TagNumber::Utf8String => 12,
102 TagNumber::RelativeOid => 13,
103 TagNumber::Sequence => 16,
104 TagNumber::Set => 17,
105 TagNumber::NumericString => 18,
106 TagNumber::PrintableString => 19,
107 TagNumber::TeletexString => 20,
108 TagNumber::VideotexString => 21,
109 TagNumber::Ia5String => 22,
110 TagNumber::UtcTime => 23,
111 TagNumber::GeneralizedTime => 24,
112 TagNumber::VisibleString => 26,
113 TagNumber::GeneralString => 27,
114 TagNumber::UniversalString => 28,
115 TagNumber::BmpString => 30,
116 TagNumber::Other { tag_num } => tag_num,
117 }
118}
119
120pub open spec fn uint_to_tag_num(num: UInt) -> TagNumber {
121 match num {
122 0 => TagNumber::EOC,
123 1 => TagNumber::Boolean,
124 2 => TagNumber::Integer,
125 3 => TagNumber::BitString,
126 4 => TagNumber::OctetString,
127 5 => TagNumber::Null,
128 6 => TagNumber::ObjectIdentifier,
129 9 => TagNumber::Real,
130 10 => TagNumber::Enumerated,
131 12 => TagNumber::Utf8String,
132 13 => TagNumber::RelativeOid,
133 16 => TagNumber::Sequence,
134 17 => TagNumber::Set,
135 18 => TagNumber::NumericString,
136 19 => TagNumber::PrintableString,
137 20 => TagNumber::TeletexString,
138 21 => TagNumber::VideotexString,
139 22 => TagNumber::Ia5String,
140 23 => TagNumber::UtcTime,
141 24 => TagNumber::GeneralizedTime,
142 26 => TagNumber::VisibleString,
143 27 => TagNumber::GeneralString,
144 28 => TagNumber::UniversalString,
145 30 => TagNumber::BmpString,
146 other => TagNumber::Other { tag_num: other },
147 }
148}
149
150pub open spec fn tag_number_wf(num: TagNumber) -> bool {
151 num matches TagNumber::Other { tag_num } ==> {
152 &&& !matches!(tag_num, 0 | 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21
153 | 22 | 23 | 24 | 26 | 27 | 28 | 30)
154 &&& nat_to_base128(tag_num as nat).len() <= BASE128_MAX_BYTES
155 }
156}
157
158#[verifier::allow_in_spec]
159pub const fn tag_num_from_uint(num: u64) -> TagNumber
160 returns
161 uint_to_tag_num(num as UInt),
162{
163 match num {
164 0 => TagNumber::EOC,
165 1 => TagNumber::Boolean,
166 2 => TagNumber::Integer,
167 3 => TagNumber::BitString,
168 4 => TagNumber::OctetString,
169 5 => TagNumber::Null,
170 6 => TagNumber::ObjectIdentifier,
171 9 => TagNumber::Real,
172 10 => TagNumber::Enumerated,
173 12 => TagNumber::Utf8String,
174 13 => TagNumber::RelativeOid,
175 16 => TagNumber::Sequence,
176 17 => TagNumber::Set,
177 18 => TagNumber::NumericString,
178 19 => TagNumber::PrintableString,
179 20 => TagNumber::TeletexString,
180 21 => TagNumber::VideotexString,
181 22 => TagNumber::Ia5String,
182 23 => TagNumber::UtcTime,
183 24 => TagNumber::GeneralizedTime,
184 26 => TagNumber::VisibleString,
185 27 => TagNumber::GeneralString,
186 28 => TagNumber::UniversalString,
187 30 => TagNumber::BmpString,
188 other => TagNumber::Other { tag_num: other as UInt },
189 }
190}
191
192#[verifier::allow_in_spec]
196pub const fn tag_number_value(number: TagNumber) -> UInt
197 returns
198 tag_num_to_uint(number),
199{
200 match number {
201 TagNumber::EOC => 0,
202 TagNumber::Boolean => 1,
203 TagNumber::Integer => 2,
204 TagNumber::BitString => 3,
205 TagNumber::OctetString => 4,
206 TagNumber::Null => 5,
207 TagNumber::ObjectIdentifier => 6,
208 TagNumber::Real => 9,
209 TagNumber::Enumerated => 10,
210 TagNumber::Utf8String => 12,
211 TagNumber::RelativeOid => 13,
212 TagNumber::Sequence => 16,
213 TagNumber::Set => 17,
214 TagNumber::NumericString => 18,
215 TagNumber::PrintableString => 19,
216 TagNumber::TeletexString => 20,
217 TagNumber::VideotexString => 21,
218 TagNumber::Ia5String => 22,
219 TagNumber::UtcTime => 23,
220 TagNumber::GeneralizedTime => 24,
221 TagNumber::VisibleString => 26,
222 TagNumber::GeneralString => 27,
223 TagNumber::UniversalString => 28,
224 TagNumber::BmpString => 30,
225 TagNumber::Other { tag_num } => tag_num,
226 }
227}
228
229impl DeepView for TagNumber {
230 type V = Self;
231
232 open spec fn deep_view(&self) -> Self::V {
233 *self
234 }
235}
236
237impl DeepView for Class {
238 type V = Self;
239
240 open spec fn deep_view(&self) -> Self::V {
241 *self
242 }
243}
244
245impl DeepView for Tag {
246 type V = Self;
247
248 open spec fn deep_view(&self) -> Self::V {
249 *self
250 }
251}
252
253#[verifier::allow_in_spec]
255pub fn primitive_tag(tag: Tag) -> Tag
256 returns
257 (Tag { class: tag.class, constructed: false, number: tag.number }),
258{
259 Tag { class: tag.class, constructed: false, number: tag.number }
260}
261
262#[verifier::allow_in_spec]
264pub fn constructed_tag(tag: Tag) -> Tag
265 returns
266 (Tag { class: tag.class, constructed: true, number: tag.number }),
267{
268 Tag { class: tag.class, constructed: true, number: tag.number }
269}
270
271pub open spec fn class_of_first_byte(b1: u8) -> Class {
272 match b1 & TAG_CLASS_MASK {
273 0b0000_0000u8 => Class::Universal,
274 0b0100_0000u8 => Class::Application,
275 0b1000_0000u8 => Class::ContextSpecific,
276 _ => Class::Private,
277 }
278}
279
280pub open spec fn class_bits(class: Class) -> u8 {
281 match class {
282 Class::Universal => 0b0000_0000u8,
283 Class::Application => 0b0100_0000u8,
284 Class::ContextSpecific => 0b1000_0000u8,
285 Class::Private => 0b1100_0000u8,
286 }
287}
288
289pub open spec fn constructed_of_first_byte(b1: u8) -> bool {
290 b1 & TAG_CONSTRUCTED_MASK != 0
291}
292
293pub open spec fn constructed_bit(constructed: bool) -> u8 {
294 if constructed {
295 TAG_CONSTRUCTED_MASK
296 } else {
297 0u8
298 }
299}
300
301pub open spec fn first_byte_from_parts(class: Class, constructed: bool, low_bits: u8) -> u8 {
302 class_bits(class) | constructed_bit(constructed) | (low_bits & TAG_NUMBER_MASK)
303}
304
305type TagWireFmt = Bind<U8, spec_fn(u8) -> Sum<Empty, Refined<Base128Fmt<true>, PredFnSpec<UInt>>>>;
306
307type TagInnerFmt = Mapped<TagWireFmt, FnSpecMapper<(u8, Sum<(), UInt>), Tag>>;
308
309#[verusfmt::skip]
310pub(crate) open(crate) spec fn tag_wire() -> TagWireFmt {
311 Bind(U8, |b1: u8| {
312 if b1 & TAG_NUMBER_MASK == TAG_LONG_FORM_SENTINEL {
313 R(Refined(Base128Fmt::<true>, |n: UInt| n >= TAG_LONG_FORM_SENTINEL as UInt))
314 } else {
315 L(Empty)
316 }
317 })
318}
319
320pub(crate) open(crate) spec fn tag_fmt() -> TagInnerFmt {
321 Mapped {
322 inner: tag_wire(),
323 mapper: (
324 |r: (u8, Sum<(), UInt>)|
325 {
326 let (b1, rest) = r;
327 let num = match rest {
328 L(()) => (b1 & TAG_NUMBER_MASK) as UInt,
329 R(n) => n,
330 };
331 Tag {
332 class: class_of_first_byte(b1),
333 constructed: constructed_of_first_byte(b1),
334 number: uint_to_tag_num(num),
335 }
336 },
337 |tag: Tag|
338 {
339 let num = tag_num_to_uint(tag.number);
340 if num < TAG_LONG_FORM_SENTINEL as UInt {
341 (first_byte_from_parts(tag.class, tag.constructed, num as u8), L(()))
342 } else {
343 (
344 first_byte_from_parts(
345 tag.class,
346 tag.constructed,
347 TAG_LONG_FORM_SENTINEL,
348 ),
349 R(num),
350 )
351 }
352 },
353 ),
354 }
355}
356
357proof fn lemma_class_bits_roundtrip(b1: u8)
359 ensures
360 class_bits(class_of_first_byte(b1)) == (b1 & TAG_CLASS_MASK),
361{
362 let cls = b1 & TAG_CLASS_MASK;
363 assert({
364 ||| cls == 0b0000_0000u8
365 ||| cls == 0b0100_0000u8
366 ||| cls == 0b1000_0000u8
367 ||| cls == 0b1100_0000u8
368 }) by (bit_vector)
369 requires
370 cls == (b1 & TAG_CLASS_MASK),
371 ;
372}
373
374proof fn lemma_class_bits_only_class_mask(class: Class)
375 ensures
376 class_bits(class) & TAG_CONSTRUCTED_MASK == 0u8,
377 class_bits(class) & TAG_NUMBER_MASK == 0u8,
378 class_bits(class) & TAG_CLASS_MASK == class_bits(class),
379{
380 assert(forall|cls: u8|
381 {
382 ||| cls == 0b0000_0000u8
383 ||| cls == 0b0100_0000u8
384 ||| cls == 0b1000_0000u8
385 ||| cls == 0b1100_0000u8
386 } ==> (cls & TAG_CONSTRUCTED_MASK == 0u8 && cls & TAG_NUMBER_MASK == 0u8 && (cls
387 & TAG_CLASS_MASK) == cls)) by (bit_vector);
388}
389
390proof fn lemma_first_byte_from_parts_roundtrip(class: Class, constructed: bool, low_bits: u8)
391 ensures
392 class_of_first_byte(first_byte_from_parts(class, constructed, low_bits)) == class,
393 constructed_of_first_byte(first_byte_from_parts(class, constructed, low_bits))
394 == constructed,
395 first_byte_from_parts(class, constructed, low_bits) & TAG_NUMBER_MASK == low_bits
396 & TAG_NUMBER_MASK,
397{
398 let fb = first_byte_from_parts(class, constructed, low_bits);
399 let cb = class_bits(class);
400 let cbit = constructed_bit(constructed);
401 lemma_class_bits_only_class_mask(class);
402
403 assert(fb & TAG_CLASS_MASK == cb && (fb & TAG_CONSTRUCTED_MASK != 0u8) == constructed && fb
404 & TAG_NUMBER_MASK == low_bits & TAG_NUMBER_MASK) by (bit_vector)
405 requires
406 fb == cb | cbit | (low_bits & TAG_NUMBER_MASK),
407 cb & TAG_CONSTRUCTED_MASK == 0u8,
408 cb & TAG_NUMBER_MASK == 0u8,
409 (cb & TAG_CLASS_MASK) == cb,
410 cbit == TAG_CONSTRUCTED_MASK || cbit == 0u8,
411 constructed ==> cbit == TAG_CONSTRUCTED_MASK,
412 !constructed ==> cbit == 0u8,
413 ;
414}
415
416proof fn lemma_first_byte_roundtrip(b1: u8)
417 ensures
418 first_byte_from_parts(
419 class_of_first_byte(b1),
420 constructed_of_first_byte(b1),
421 b1 & TAG_NUMBER_MASK,
422 ) == b1,
423{
424 lemma_class_bits_roundtrip(b1);
425 let fb = first_byte_from_parts(
426 class_of_first_byte(b1),
427 constructed_of_first_byte(b1),
428 b1 & TAG_NUMBER_MASK,
429 );
430 let cb = class_bits(class_of_first_byte(b1));
431 assert(fb == b1) by (bit_vector)
432 requires
433 fb == cb | constructed_bit(constructed_of_first_byte(b1)) | ((b1 & TAG_NUMBER_MASK)
434 & TAG_NUMBER_MASK),
435 cb == (b1 & TAG_CLASS_MASK),
436 ;
437}
438
439proof fn lemma_tag_fmt_sound_nonmal_inv()
440 ensures
441 tag_fmt().sound_inv(),
442 tag_fmt().nonmal_inv(),
443{
444 let fmt = tag_fmt();
445 assert forall|v| fmt.inner.consistent(v) implies (fmt.mapper.1)((fmt.mapper.0)(v)) == v by {
446 let (b1, rest) = v;
447 lemma_first_byte_roundtrip(b1);
448 if b1 & TAG_NUMBER_MASK == TAG_LONG_FORM_SENTINEL {
449 } else {
450 let num = (b1 & TAG_NUMBER_MASK) as UInt;
451 assert(num < TAG_LONG_FORM_SENTINEL as UInt) by (bit_vector)
452 requires
453 (b1 & TAG_NUMBER_MASK) != TAG_LONG_FORM_SENTINEL,
454 num == (b1 & TAG_NUMBER_MASK) as UInt,
455 ;
456 }
457 }
458}
459
460proof fn lemma_tag_fmt_unambiguous(tag: Tag)
461 requires
462 tag_fmt().consistent(tag),
463 tag_number_wf(tag.number),
464 ensures
465 (tag_fmt().mapper.0)((tag_fmt().mapper.1)(tag)) == tag,
466{
467 let num = tag_num_to_uint(tag.number);
468 if num < TAG_LONG_FORM_SENTINEL as UInt {
469 let low = num as u8;
470 lemma_first_byte_from_parts_roundtrip(tag.class, tag.constructed, low);
471 assert(low & TAG_NUMBER_MASK == low) by (bit_vector)
472 requires
473 low == num as u8,
474 num < TAG_LONG_FORM_SENTINEL as UInt,
475 ;
476 } else {
477 lemma_first_byte_from_parts_roundtrip(tag.class, tag.constructed, TAG_LONG_FORM_SENTINEL);
478 }
479}
480
481proof fn lemma_tag_wf_implies_tag_fmt_consistent(tag: Tag)
482 requires
483 tag_number_wf(tag.number),
484 ensures
485 tag_fmt().consistent(tag),
486{
487 let num = tag_num_to_uint(tag.number);
488 assert(TAG_LONG_FORM_SENTINEL & TAG_NUMBER_MASK == TAG_LONG_FORM_SENTINEL) by (bit_vector);
489 if num < TAG_LONG_FORM_SENTINEL as UInt {
490 let low = num as u8;
491 lemma_first_byte_from_parts_roundtrip(tag.class, tag.constructed, low);
492 assert(low & TAG_NUMBER_MASK == low) by (bit_vector)
493 requires
494 low == num as u8,
495 num < TAG_LONG_FORM_SENTINEL as UInt,
496 ;
497 } else {
498 lemma_first_byte_from_parts_roundtrip(tag.class, tag.constructed, TAG_LONG_FORM_SENTINEL);
499 lemma_base128_fmt_consistent::<true>(num);
500 }
501}
502
503pub broadcast proof fn lemma_tag_wf_implies_tag_consistent(tag: Tag)
506 requires
507 tag_number_wf(tag.number),
508 ensures
509 #[trigger] super::TagFmt.consistent(tag),
510{
511}
512
513pub(crate) broadcast proof fn lemma_tag_fmt_byte_len_bound(tag: Tag)
514 ensures
515 #[trigger] super::TagFmt.byte_len(tag) <= TAG_FMT_MAX_BYTE_LEN,
516{
517 let num = tag_num_to_uint(tag.number);
518 lemma_to_base128_len_bounds();
519 lemma_base128_fmt_byte_len::<true>(num);
520}
521
522mod derived_specs {
523 use super::*;
524 use super::super::TagFmt;
525
526 impl SpecParser for TagFmt {
527 type PVal = Tag;
528
529 open(crate) spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
530 tag_fmt().spec_parse(ibuf)
531 }
532 }
533
534 impl Consistency for TagFmt {
535 type Val = Tag;
536
537 open(crate) spec fn consistent(&self, v: Self::Val) -> bool {
538 tag_number_wf(v.number)
539 }
540 }
541
542 impl SpecSerializerDps for TagFmt {
543 type SValue = Tag;
544
545 open(crate) spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
546 tag_fmt().spec_serialize_dps(v, obuf)
547 }
548 }
549
550 impl SpecSerializer for TagFmt {
551 type SVal = Tag;
552
553 open(crate) spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
554 tag_fmt().spec_serialize(v)
555 }
556 }
557
558 impl SpecByteLen for TagFmt {
559 type T = Tag;
560
561 open(crate) spec fn byte_len(&self, v: Self::T) -> nat {
562 tag_fmt().byte_len(v)
563 }
564 }
565
566}
567
568mod derived_proofs {
569 use super::*;
570 use super::super::TagFmt;
571
572 impl SafeParser for TagFmt {
573 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
574 tag_fmt().lemma_parse_safe(ibuf);
575 }
576 }
577
578 impl Productive for TagFmt {
579 proof fn lemma_productive(&self, s: Seq<u8>) {
580 tag_fmt().lemma_productive(s);
581 }
582 }
583
584 impl SoundParser for TagFmt {
585 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
586 lemma_tag_fmt_sound_nonmal_inv();
587 tag_fmt().lemma_parse_sound_consumption(ibuf);
588 }
589
590 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
591 lemma_tag_fmt_sound_nonmal_inv();
592 tag_fmt().lemma_parse_sound_value(ibuf);
593 }
594 }
595
596 impl NonTailFmt for TagFmt {
597 proof fn lemma_serialize_dps_prepend(&self, v: Self::SValue, obuf: Seq<u8>) {
598 tag_fmt().lemma_serialize_dps_prepend(v, obuf);
599 }
600
601 proof fn lemma_serialize_dps_len(&self, v: Self::SValue, obuf: Seq<u8>) {
602 tag_fmt().lemma_serialize_dps_len(v, obuf);
603 }
604 }
605
606 impl GoodSerializer for TagFmt {
607 proof fn lemma_serialize_len(&self, v: Self::SVal) {
608 tag_fmt().lemma_serialize_len(v);
609 }
610 }
611
612 impl SPRoundTripDps for TagFmt {
613 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
614 lemma_tag_wf_implies_tag_fmt_consistent(v);
615 lemma_tag_fmt_unambiguous(v);
616 tag_fmt().inner.theorem_serialize_dps_parse_roundtrip(tag_fmt().mapper.1(v), obuf);
617 }
618 }
619
620 impl NoLookAhead for TagFmt {
621 proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>) {
622 tag_fmt().lemma_no_lookahead(i1, i2);
623 }
624 }
625
626 impl NonMalleable for TagFmt {
627 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
628 lemma_tag_fmt_sound_nonmal_inv();
629 tag_fmt().lemma_parse_non_malleable(buf1, buf2);
630 }
631 }
632
633 impl EquivSerializersGeneral for TagFmt {
634 proof fn lemma_serialize_equiv(&self, v: Self::SVal, obuf: Seq<u8>) {
635 tag_fmt().lemma_serialize_equiv(v, obuf);
636 }
637 }
638
639 impl EquivSerializers for TagFmt {
640 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
641 tag_fmt().lemma_serialize_equiv_on_empty(v);
642 }
643 }
644
645}
646
647impl Parser<&[u8]> for super::TagFmt {
648 type PT = Tag;
649
650 fn parse(&self, ibuf: &&[u8]) -> PResult<Self::PT> {
651 broadcast use crate::core::spec::SafeParser::lemma_parse_safe;
652 broadcast use crate::core::spec::SoundParser::lemma_parse_sound_value;
653
654 let _ = ibuf.len();
655
656 let (n1, b1): (usize, u8) = U8.parse(ibuf)?;
657 let rest = ibuf.skip(n1);
658
659 let (n2, num) = if b1 & TAG_NUMBER_MASK == TAG_LONG_FORM_SENTINEL {
660 let (n2, num) = Base128Fmt::<true>.parse(&rest)?;
661 if num < TAG_LONG_FORM_SENTINEL as UInt {
662 return Err(ParseError::non_canonical());
663 }
664 (n2, num)
665 } else {
666 (0, (b1 & TAG_NUMBER_MASK) as UInt)
667 };
668
669 let class = match b1 & TAG_CLASS_MASK {
670 0b0000_0000u8 => Class::Universal,
671 0b0100_0000u8 => Class::Application,
672 0b1000_0000u8 => Class::ContextSpecific,
673 _ => Class::Private,
674 };
675 let constructed = b1 & TAG_CONSTRUCTED_MASK != 0;
676 let number = match num {
677 0 => TagNumber::EOC,
678 1 => TagNumber::Boolean,
679 2 => TagNumber::Integer,
680 3 => TagNumber::BitString,
681 4 => TagNumber::OctetString,
682 5 => TagNumber::Null,
683 6 => TagNumber::ObjectIdentifier,
684 9 => TagNumber::Real,
685 10 => TagNumber::Enumerated,
686 12 => TagNumber::Utf8String,
687 13 => TagNumber::RelativeOid,
688 16 => TagNumber::Sequence,
689 17 => TagNumber::Set,
690 18 => TagNumber::NumericString,
691 19 => TagNumber::PrintableString,
692 20 => TagNumber::TeletexString,
693 21 => TagNumber::VideotexString,
694 22 => TagNumber::Ia5String,
695 23 => TagNumber::UtcTime,
696 24 => TagNumber::GeneralizedTime,
697 26 => TagNumber::VisibleString,
698 27 => TagNumber::GeneralString,
699 28 => TagNumber::UniversalString,
700 30 => TagNumber::BmpString,
701 other => TagNumber::Other { tag_num: other },
702 };
703
704 Ok((n1 + n2, Tag { class, constructed, number }))
705 }
706}
707
708impl<Output: OutputBuf> Serializer<Output, Tag> for super::TagFmt {
709 fn serialize_into(&self, v: &Tag, obuf: &mut Output) {
710 broadcast use crate::core::exec::output::outbuf_lemmas;
711
712 let num = tag_number_value(v.number);
713
714 let class_bits = match v.class {
715 Class::Universal => 0b0000_0000u8,
716 Class::Application => 0b0100_0000u8,
717 Class::ContextSpecific => 0b1000_0000u8,
718 Class::Private => 0b1100_0000u8,
719 };
720 let constructed_bit = if v.constructed {
721 TAG_CONSTRUCTED_MASK
722 } else {
723 0u8
724 };
725 proof {
726 lemma_tag_wf_implies_tag_fmt_consistent(*v);
727 }
728 if num < TAG_LONG_FORM_SENTINEL as UInt {
729 let low = num as u8;
730 let b1 = class_bits | constructed_bit | (low & TAG_NUMBER_MASK);
731 U8.serialize_into(&b1, obuf);
732 } else {
733 let b1 = class_bits | constructed_bit | TAG_LONG_FORM_SENTINEL & TAG_NUMBER_MASK;
734 U8.serialize_into(&b1, obuf);
735 Base128Fmt::<true>.serialize_into(&num, obuf);
736 }
737 }
738}
739
740impl Prepare<Tag> for super::TagFmt {
741 fn prepare(&self, v: &Tag) -> Result<usize, PreSerializeError> {
742 if let TagNumber::Other { tag_num } = v.number {
743 if matches!(tag_num, 0 | 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21
744 | 22 | 23 | 24 | 26 | 27 | 28 | 30) {
745 return Err(PreSerializeError::custom("Invalid tag number"));
746 }
747 }
748 let num = tag_number_value(v.number);
749
750 proof {
751 lemma_to_base128_len_bounds();
752 lemma_base128_fmt_byte_len::<true>(num);
753 }
754 let nbytes = Base128Fmt::<true>.length(&num);
755 if nbytes > BASE128_MAX_BYTES {
756 return Err(PreSerializeError::length_too_large());
757 }
758 proof {
759 assert(tag_number_wf(v.deep_view().number));
760 lemma_tag_wf_implies_tag_fmt_consistent(v.deep_view());
761 }
762
763 if num < TAG_LONG_FORM_SENTINEL as UInt {
764 Ok(1)
765 } else {
766 Ok(1 + nbytes)
767 }
768 }
769}
770
771impl ByteLen<Tag> for super::TagFmt {
772 fn length(&self, v: &Tag) -> usize {
773 let num = tag_number_value(v.number);
774
775 proof {
776 lemma_to_base128_len_bounds();
777 lemma_base128_fmt_byte_len::<true>(num);
778 lemma_first_byte_from_parts_roundtrip(v.class, v.constructed, TAG_LONG_FORM_SENTINEL);
779 assert(TAG_LONG_FORM_SENTINEL & TAG_NUMBER_MASK == TAG_LONG_FORM_SENTINEL)
780 by (bit_vector);
781 }
782 let nbytes = Base128Fmt::<true>.length(&num);
783
784 if num < TAG_LONG_FORM_SENTINEL as UInt {
785 1
786 } else {
787 1 + nbytes
788 }
789 }
790}
791
792impl super::TagFmt {
793 pub const EOC: Tag = Tag {
794 class: Class::Universal,
795 constructed: false,
796 number: TagNumber::EOC,
797 };
798
799 pub const BOOLEAN: Tag = Tag {
800 class: Class::Universal,
801 constructed: false,
802 number: TagNumber::Boolean,
803 };
804
805 pub const INTEGER: Tag = Tag {
806 class: Class::Universal,
807 constructed: false,
808 number: TagNumber::Integer,
809 };
810
811 pub const NULL: Tag = Tag {
812 class: Class::Universal,
813 constructed: false,
814 number: TagNumber::Null,
815 };
816
817 pub const OBJECT_IDENTIFIER: Tag = Tag {
818 class: Class::Universal,
819 constructed: false,
820 number: TagNumber::ObjectIdentifier,
821 };
822
823 pub const REAL: Tag = Tag {
824 class: Class::Universal,
825 constructed: false,
826 number: TagNumber::Real,
827 };
828
829 pub const ENUMERATED: Tag = Tag {
830 class: Class::Universal,
831 constructed: false,
832 number: TagNumber::Enumerated,
833 };
834
835 pub const RELATIVE_OID: Tag = Tag {
836 class: Class::Universal,
837 constructed: false,
838 number: TagNumber::RelativeOid,
839 };
840
841 pub const BIT_STRING: Tag = Tag {
842 class: Class::Universal,
843 constructed: false,
844 number: TagNumber::BitString,
845 };
846
847 pub const OCTET_STRING: Tag = Tag {
848 class: Class::Universal,
849 constructed: false,
850 number: TagNumber::OctetString,
851 };
852
853 pub const UTF8_STRING: Tag = Tag {
854 class: Class::Universal,
855 constructed: false,
856 number: TagNumber::Utf8String,
857 };
858
859 pub const NUMERIC_STRING: Tag = Tag {
860 class: Class::Universal,
861 constructed: false,
862 number: TagNumber::NumericString,
863 };
864
865 pub const PRINTABLE_STRING: Tag = Tag {
866 class: Class::Universal,
867 constructed: false,
868 number: TagNumber::PrintableString,
869 };
870
871 pub const TELETEX_STRING: Tag = Tag {
872 class: Class::Universal,
873 constructed: false,
874 number: TagNumber::TeletexString,
875 };
876
877 pub const VIDEOTEX_STRING: Tag = Tag {
878 class: Class::Universal,
879 constructed: false,
880 number: TagNumber::VideotexString,
881 };
882
883 pub const IA5_STRING: Tag = Tag {
884 class: Class::Universal,
885 constructed: false,
886 number: TagNumber::Ia5String,
887 };
888
889 pub const UTC_TIME: Tag = Tag {
890 class: Class::Universal,
891 constructed: false,
892 number: TagNumber::UtcTime,
893 };
894
895 pub const GENERALIZED_TIME: Tag = Tag {
896 class: Class::Universal,
897 constructed: false,
898 number: TagNumber::GeneralizedTime,
899 };
900
901 pub const VISIBLE_STRING: Tag = Tag {
902 class: Class::Universal,
903 constructed: false,
904 number: TagNumber::VisibleString,
905 };
906
907 pub const GENERAL_STRING: Tag = Tag {
908 class: Class::Universal,
909 constructed: false,
910 number: TagNumber::GeneralString,
911 };
912
913 pub const UNIVERSAL_STRING: Tag = Tag {
914 class: Class::Universal,
915 constructed: false,
916 number: TagNumber::UniversalString,
917 };
918
919 pub const BMP_STRING: Tag = Tag {
920 class: Class::Universal,
921 constructed: false,
922 number: TagNumber::BmpString,
923 };
924
925 pub const BIT_STRING_CONSTRUCTED: Tag = Tag {
926 class: Class::Universal,
927 constructed: true,
928 number: TagNumber::BitString,
929 };
930
931 pub const OCTET_STRING_CONSTRUCTED: Tag = Tag {
932 class: Class::Universal,
933 constructed: true,
934 number: TagNumber::OctetString,
935 };
936
937 pub const UTF8_STRING_CONSTRUCTED: Tag = Tag {
938 class: Class::Universal,
939 constructed: true,
940 number: TagNumber::Utf8String,
941 };
942
943 pub const NUMERIC_STRING_CONSTRUCTED: Tag = Tag {
944 class: Class::Universal,
945 constructed: true,
946 number: TagNumber::NumericString,
947 };
948
949 pub const PRINTABLE_STRING_CONSTRUCTED: Tag = Tag {
950 class: Class::Universal,
951 constructed: true,
952 number: TagNumber::PrintableString,
953 };
954
955 pub const TELETEX_STRING_CONSTRUCTED: Tag = Tag {
956 class: Class::Universal,
957 constructed: true,
958 number: TagNumber::TeletexString,
959 };
960
961 pub const VIDEOTEX_STRING_CONSTRUCTED: Tag = Tag {
962 class: Class::Universal,
963 constructed: true,
964 number: TagNumber::VideotexString,
965 };
966
967 pub const IA5_STRING_CONSTRUCTED: Tag = Tag {
968 class: Class::Universal,
969 constructed: true,
970 number: TagNumber::Ia5String,
971 };
972
973 pub const UTC_TIME_CONSTRUCTED: Tag = Tag {
974 class: Class::Universal,
975 constructed: true,
976 number: TagNumber::UtcTime,
977 };
978
979 pub const GENERALIZED_TIME_CONSTRUCTED: Tag = Tag {
980 class: Class::Universal,
981 constructed: true,
982 number: TagNumber::GeneralizedTime,
983 };
984
985 pub const VISIBLE_STRING_CONSTRUCTED: Tag = Tag {
986 class: Class::Universal,
987 constructed: true,
988 number: TagNumber::VisibleString,
989 };
990
991 pub const GENERAL_STRING_CONSTRUCTED: Tag = Tag {
992 class: Class::Universal,
993 constructed: true,
994 number: TagNumber::GeneralString,
995 };
996
997 pub const UNIVERSAL_STRING_CONSTRUCTED: Tag = Tag {
998 class: Class::Universal,
999 constructed: true,
1000 number: TagNumber::UniversalString,
1001 };
1002
1003 pub const BMP_STRING_CONSTRUCTED: Tag = Tag {
1004 class: Class::Universal,
1005 constructed: true,
1006 number: TagNumber::BmpString,
1007 };
1008
1009 pub const SEQUENCE: Tag = Tag {
1010 class: Class::Universal,
1011 constructed: true,
1012 number: TagNumber::Sequence,
1013 };
1014
1015 pub const SET: Tag = Tag { class: Class::Universal, constructed: true, number: TagNumber::Set };
1016}
1017
1018use crate::combinators::Const;
1019
1020pub broadcast proof fn lemma_const_tag_fmt_exec_inv(fmt: Const<super::TagFmt, Tag>)
1021 ensures
1022 #![all_triggers]
1023 <_ as Parser<&[u8]>>::exec_inv(&fmt),
1024 <_ as Prepare<Tag>>::exec_inv(&fmt),
1025{
1026 crate::core::exec::bridge_lemmas::lemma_const_parser_exec_inv::<&[u8], _, _>(&fmt);
1027 crate::core::exec::bridge_lemmas::lemma_const_prepare_exec_inv::<_, _>(&fmt);
1028}
1029
1030} verus! {
1036
1037#[cfg(feature = "alloc")]
1038fn test_exec_const_fmt(buf: &&[u8]) -> PResult<u16> {
1039 use crate::combinators::U16Be;
1040 let const_u16_fmt = Const(U16Be, 0x1234u16);
1041 let (n, v) = const_u16_fmt.parse(buf)?;
1042 if let Ok(len) = const_u16_fmt.prepare(&v) {
1043 let mut obuf = vec![0; len];
1044 const_u16_fmt.serialize(&v, &mut obuf);
1045 proof {
1046 const_u16_fmt.theorem_parse_serialize_roundtrip(buf@);
1047 assert(obuf@ == buf@.take(n as int));
1048 }
1049 }
1050 Err(ParseError::custom("Test function, not meant to succeed"))
1051}
1052
1053#[cfg(feature = "alloc")]
1054fn test_exec_tag_fmt(buf: &&[u8]) -> PResult<Tag> {
1055 broadcast use lemma_const_tag_fmt_exec_inv;
1056
1057 let asn_bool_tag_fmt = Const(super::TagFmt, super::TagFmt::BOOLEAN);
1058 let (n, tag) = asn_bool_tag_fmt.parse(buf)?;
1059 if let Ok(len) = asn_bool_tag_fmt.prepare(&tag) {
1060 let mut obuf = vec![0; len];
1061 asn_bool_tag_fmt.serialize(&tag, &mut obuf);
1062
1063 proof {
1064 asn_bool_tag_fmt.theorem_parse_serialize_roundtrip(buf@);
1065 assert(obuf@ == buf@.take(n as int));
1066 }
1067 }
1068 Err(ParseError::custom("Test function, not meant to succeed"))
1069}
1070
1071} #[cfg(not(verus_keep_ghost))]
1077unsafe impl Structural for TagNumber {}
1078#[cfg(not(verus_keep_ghost))]
1079unsafe impl Structural for Class {}
1080#[cfg(not(verus_keep_ghost))]
1081unsafe impl Structural for Tag {}