1use super::ber::*;
9use super::modifiers::{DefaultedFmt, ImplicitlyTaggedFmt, Retaggable};
10#[cfg(verus_only)]
11use super::tag::tag_num_to_uint;
12use super::tag::{tag_num_from_uint, TagNumber};
13use super::{ASN1Fmt, AnyFmt, Class, Tag, TagFmt};
14use crate::combinators::mapped::spec::{BiMap, SpecMap, SpecMapper};
15use crate::combinators::{Alt, Choice, Const, Eof, Mapped, Named, Optional, Pair, Ref, Refined};
16use crate::core::{proof::*, spec::*};
17use vstd::prelude::*;
18
19verus! {
20
21#[verifier::ext_equal]
30pub ghost struct Asn1TagLeadMask {
31 pub universal: u64,
32 pub application: u64,
33 pub context_specific: u64,
34 pub private: u64,
35}
36
37#[verifier::ext_equal]
42pub ghost struct Asn1StartDomain {
43 pub accepts_empty: bool,
44 pub tags: Asn1TagLeadMask,
45}
46
47#[verifier::inline]
48pub open spec fn empty_tag_lead_mask() -> Asn1TagLeadMask {
49 Asn1TagLeadMask { universal: 0, application: 0, context_specific: 0, private: 0 }
50}
51
52#[verifier::inline]
54pub open spec fn asn1_start_mask(
55 accepts_empty: bool,
56 universal: u64,
57 application: u64,
58 context_specific: u64,
59 private: u64,
60) -> Asn1StartDomain {
61 Asn1StartDomain {
62 accepts_empty,
63 tags: Asn1TagLeadMask { universal, application, context_specific, private },
64 }
65}
66
67#[verifier::inline]
68pub open spec fn tag_lead_low(number: TagNumber) -> u64 {
69 let value = tag_num_to_uint(number);
70 if value < 31u64 {
71 value
72 } else {
73 31u64
74 }
75}
76
77#[verifier::inline]
78pub open spec fn tag_lead_index(tag: Tag) -> u64 {
79 let low = tag_lead_low(tag.number);
80 if tag.constructed {
81 low | 32u64
82 } else {
83 low
84 }
85}
86
87#[verifier::inline]
88pub open spec fn tag_lead_bit(tag: Tag) -> u64 {
89 1u64 << tag_lead_index(tag)
90}
91
92#[verifier::inline]
93pub open spec fn tag_lead_mask(tag: Tag) -> Asn1TagLeadMask {
94 let bit = tag_lead_bit(tag);
95 match tag.class {
96 Class::Universal => Asn1TagLeadMask {
97 universal: bit,
98 application: 0,
99 context_specific: 0,
100 private: 0,
101 },
102 Class::Application => Asn1TagLeadMask {
103 universal: 0,
104 application: bit,
105 context_specific: 0,
106 private: 0,
107 },
108 Class::ContextSpecific => Asn1TagLeadMask {
109 universal: 0,
110 application: 0,
111 context_specific: bit,
112 private: 0,
113 },
114 Class::Private => Asn1TagLeadMask {
115 universal: 0,
116 application: 0,
117 context_specific: 0,
118 private: bit,
119 },
120 }
121}
122
123#[verifier::inline]
124pub open spec fn tag_lead_masks_union(
125 left: Asn1TagLeadMask,
126 right: Asn1TagLeadMask,
127) -> Asn1TagLeadMask {
128 Asn1TagLeadMask {
129 universal: left.universal | right.universal,
130 application: left.application | right.application,
131 context_specific: left.context_specific | right.context_specific,
132 private: left.private | right.private,
133 }
134}
135
136pub open spec fn tag_lead_mask_contains(mask: Asn1TagLeadMask, tag: Tag) -> bool {
137 let bit = tag_lead_bit(tag);
138 match tag.class {
139 Class::Universal => mask.universal & bit != 0,
140 Class::Application => mask.application & bit != 0,
141 Class::ContextSpecific => mask.context_specific & bit != 0,
142 Class::Private => mask.private & bit != 0,
143 }
144}
145
146#[verifier::inline]
147pub open spec fn tag_lead_masks_disjoint(left: Asn1TagLeadMask, right: Asn1TagLeadMask) -> bool {
148 &&& left.universal & right.universal == 0
149 &&& left.application & right.application == 0
150 &&& left.context_specific & right.context_specific == 0
151 &&& left.private & right.private == 0
152}
153
154pub open spec fn asn1_start_exact(tag: Tag) -> Asn1StartDomain {
155 asn1_start_exact_uint(tag.class, tag.constructed, tag_num_to_uint(tag.number))
156}
157
158pub open spec fn asn1_start_exact_uint(
164 class: Class,
165 constructed: bool,
166 number: u64,
167) -> Asn1StartDomain {
168 let low = if number < 31u64 {
169 number
170 } else {
171 31u64
172 };
173 let index = if constructed {
174 low | 32u64
175 } else {
176 low
177 };
178 let bit = 1u64 << index;
179 Asn1StartDomain {
180 accepts_empty: false,
181 tags: match class {
182 Class::Universal => Asn1TagLeadMask {
183 universal: bit,
184 application: 0,
185 context_specific: 0,
186 private: 0,
187 },
188 Class::Application => Asn1TagLeadMask {
189 universal: 0,
190 application: bit,
191 context_specific: 0,
192 private: 0,
193 },
194 Class::ContextSpecific => Asn1TagLeadMask {
195 universal: 0,
196 application: 0,
197 context_specific: bit,
198 private: 0,
199 },
200 Class::Private => Asn1TagLeadMask {
201 universal: 0,
202 application: 0,
203 context_specific: 0,
204 private: bit,
205 },
206 },
207 }
208}
209
210pub proof fn lemma_asn1_start_exact_uint(class: Class, constructed: bool, number: u64)
212 ensures
213 asn1_start_exact(Tag { class, constructed, number: tag_num_from_uint(number) })
214 == asn1_start_exact_uint(class, constructed, number),
215{
216 lemma_tag_number_roundtrip(number);
217}
218
219pub open spec fn tag_leads_distinct_uint(
221 left_class: Class,
222 left_constructed: bool,
223 left_number: u64,
224 right_class: Class,
225 right_constructed: bool,
226 right_number: u64,
227) -> bool {
228 ||| left_class != right_class
229 ||| left_constructed != right_constructed
230 ||| (if left_number < 31u64 {
231 left_number
232 } else {
233 31u64
234 }) != (if right_number < 31u64 {
235 right_number
236 } else {
237 31u64
238 })
239}
240
241pub broadcast proof fn lemma_asn1_starts_disjoint_exact_uint(
243 left_class: Class,
244 left_constructed: bool,
245 left_number: u64,
246 right_class: Class,
247 right_constructed: bool,
248 right_number: u64,
249)
250 ensures
251 #[trigger] asn1_starts_disjoint(
252 asn1_start_exact_uint(left_class, left_constructed, left_number),
253 asn1_start_exact_uint(right_class, right_constructed, right_number),
254 ) <==> tag_leads_distinct_uint(
255 left_class,
256 left_constructed,
257 left_number,
258 right_class,
259 right_constructed,
260 right_number,
261 ),
262{
263 let left = Tag {
264 class: left_class,
265 constructed: left_constructed,
266 number: tag_num_from_uint(left_number),
267 };
268 let right = Tag {
269 class: right_class,
270 constructed: right_constructed,
271 number: tag_num_from_uint(right_number),
272 };
273 lemma_tag_number_roundtrip(left_number);
274 lemma_tag_number_roundtrip(right_number);
275 lemma_asn1_start_exact_uint(left_class, left_constructed, left_number);
276 lemma_asn1_start_exact_uint(right_class, right_constructed, right_number);
277 lemma_asn1_starts_disjoint_exact(left, right);
278}
279
280pub open spec fn asn1_start_identity(class: Class, number: TagNumber) -> Asn1StartDomain {
281 asn1_start_identity_uint(class, tag_num_to_uint(number))
282}
283
284#[verifier::inline]
286pub open spec fn asn1_start_identity_uint(class: Class, number: u64) -> Asn1StartDomain {
287 asn1_start_union(
288 asn1_start_exact_uint(class, false, number),
289 asn1_start_exact_uint(class, true, number),
290 )
291}
292
293pub proof fn lemma_asn1_start_identity_uint(class: Class, number: u64)
295 ensures
296 asn1_start_identity(class, tag_num_from_uint(number)) == asn1_start_identity_uint(
297 class,
298 number,
299 ),
300{
301 lemma_asn1_start_exact_uint(class, false, number);
302 lemma_asn1_start_exact_uint(class, true, number);
303}
304
305pub open spec fn asn1_start_any_non_eoc() -> Asn1StartDomain {
306 Asn1StartDomain {
307 accepts_empty: false,
308 tags: Asn1TagLeadMask {
309 universal: 0xffff_ffff_ffff_fffeu64,
310 application: 0xffff_ffff_ffff_ffffu64,
311 context_specific: 0xffff_ffff_ffff_ffffu64,
312 private: 0xffff_ffff_ffff_ffffu64,
313 },
314 }
315}
316
317pub open spec fn asn1_start_ber_boundary() -> Asn1StartDomain {
318 Asn1StartDomain { accepts_empty: true, tags: tag_lead_mask(TagFmt::EOC) }
319}
320
321pub open spec fn asn1_start_empty() -> Asn1StartDomain {
322 Asn1StartDomain { accepts_empty: true, tags: empty_tag_lead_mask() }
323}
324
325pub open spec fn asn1_start_union(
326 left: Asn1StartDomain,
327 right: Asn1StartDomain,
328) -> Asn1StartDomain {
329 Asn1StartDomain {
330 accepts_empty: left.accepts_empty || right.accepts_empty,
331 tags: tag_lead_masks_union(left.tags, right.tags),
332 }
333}
334
335pub open spec fn input_starts_with(input: Seq<u8>, domain: Asn1StartDomain) -> bool {
337 ||| input.len() == 0 && domain.accepts_empty
338 ||| match TagFmt.spec_parse(input) {
339 Some((_n, tag)) => tag_lead_mask_contains(domain.tags, tag),
340 None => false,
341 }
342}
343
344pub open spec fn asn1_starts_disjoint(left: Asn1StartDomain, right: Asn1StartDomain) -> bool {
346 &&& !(left.accepts_empty && right.accepts_empty)
347 &&& tag_lead_masks_disjoint(left.tags, right.tags)
348}
349
350pub open spec fn tag_leads_distinct(left: Tag, right: Tag) -> bool {
355 ||| left.class != right.class
356 ||| left.constructed != right.constructed
357 ||| tag_lead_low(left.number) != tag_lead_low(right.number)
358}
359
360pub broadcast proof fn lemma_tag_number_roundtrip(number: u64)
362 ensures
363 #[trigger] tag_num_to_uint(super::tag::uint_to_tag_num(number)) == number,
364 #[trigger] tag_num_to_uint(tag_num_from_uint(number)) == number,
365{
366}
367
368proof fn lemma_word_union_contains(left: u64, right: u64, bit: u64)
369 by (bit_vector)
370 requires
371 left & bit != 0 || right & bit != 0,
372 ensures
373 (left | right) & bit != 0,
374{
375}
376
377proof fn lemma_tag_lead_union_contains(left: Asn1TagLeadMask, right: Asn1TagLeadMask, tag: Tag)
378 requires
379 tag_lead_mask_contains(left, tag) || tag_lead_mask_contains(right, tag),
380 ensures
381 tag_lead_mask_contains(tag_lead_masks_union(left, right), tag),
382{
383 let bit = tag_lead_bit(tag);
384 match tag.class {
385 Class::Universal => lemma_word_union_contains(left.universal, right.universal, bit),
386 Class::Application => lemma_word_union_contains(left.application, right.application, bit),
387 Class::ContextSpecific => {
388 lemma_word_union_contains(left.context_specific, right.context_specific, bit)
389 },
390 Class::Private => lemma_word_union_contains(left.private, right.private, bit),
391 }
392}
393
394pub proof fn lemma_input_starts_with_union(
395 input: Seq<u8>,
396 left: Asn1StartDomain,
397 right: Asn1StartDomain,
398)
399 requires
400 input_starts_with(input, left) || input_starts_with(input, right),
401 ensures
402 input_starts_with(input, asn1_start_union(left, right)),
403{
404 if input.len() != 0 {
405 if let Some((_n, tag)) = TagFmt.spec_parse(input) {
406 lemma_tag_lead_union_contains(left.tags, right.tags, tag);
407 }
408 }
409}
410
411proof fn lemma_disjoint_words_cannot_contain_same_bit(left: u64, right: u64, bit_index: u64)
412 by (bit_vector)
413 requires
414 bit_index < 64,
415 left & right == 0,
416 left & (1u64 << bit_index) != 0,
417 right & (1u64 << bit_index) != 0,
418 ensures
419 false,
420{
421}
422
423proof fn lemma_single_bits_disjoint(left_index: u64, right_index: u64)
424 by (bit_vector)
425 requires
426 left_index < 64,
427 right_index < 64,
428 ensures
429 ((1u64 << left_index) & (1u64 << right_index) == 0) <==> left_index != right_index,
430{
431}
432
433proof fn lemma_tag_lead_low_bound(number: TagNumber)
434 ensures
435 tag_lead_low(number) < 32,
436{
437}
438
439proof fn lemma_tag_lead_index_bound(tag: Tag)
440 ensures
441 tag_lead_index(tag) < 64,
442{
443 let low = tag_lead_low(tag.number);
444 lemma_tag_lead_low_bound(tag.number);
445 assert((low | 32u64) < 64u64) by (bit_vector)
446 requires
447 low < 32,
448 ;
449}
450
451proof fn lemma_tag_lead_indices_distinct(left: Tag, right: Tag)
452 ensures
453 tag_lead_index(left) != tag_lead_index(right) <==> left.constructed != right.constructed
454 || tag_lead_low(left.number) != tag_lead_low(right.number),
455{
456 let left_low = tag_lead_low(left.number);
457 let right_low = tag_lead_low(right.number);
458 lemma_tag_lead_low_bound(left.number);
459 lemma_tag_lead_low_bound(right.number);
460 if left.constructed {
461 if right.constructed {
462 assert((left_low | 32u64) != (right_low | 32u64) <==> left_low != right_low)
463 by (bit_vector)
464 requires
465 left_low < 32,
466 right_low < 32,
467 ;
468 } else {
469 assert((left_low | 32u64) != right_low) by (bit_vector)
470 requires
471 left_low < 32,
472 right_low < 32,
473 ;
474 }
475 } else if right.constructed {
476 assert(left_low != (right_low | 32u64)) by (bit_vector)
477 requires
478 left_low < 32,
479 right_low < 32,
480 ;
481 }
482}
483
484proof fn lemma_exact_tag_lead_masks_disjoint(left: Tag, right: Tag)
485 ensures
486 tag_lead_masks_disjoint(tag_lead_mask(left), tag_lead_mask(right)) <==> left.class
487 != right.class || tag_lead_bit(left) & tag_lead_bit(right) == 0,
488{
489 let left_bit = tag_lead_bit(left);
490 let right_bit = tag_lead_bit(right);
491 assert(left_bit & 0u64 == 0) by (bit_vector);
492 assert(0u64 & right_bit == 0) by (bit_vector);
493 assert(0u64 & 0u64 == 0) by (bit_vector);
494}
495
496pub broadcast proof fn lemma_asn1_starts_disjoint_exact(left: Tag, right: Tag)
498 ensures
499 #[trigger] asn1_starts_disjoint(asn1_start_exact(left), asn1_start_exact(right))
500 <==> tag_leads_distinct(left, right),
501{
502 lemma_tag_lead_index_bound(left);
503 lemma_tag_lead_index_bound(right);
504 lemma_tag_lead_indices_distinct(left, right);
505 lemma_single_bits_disjoint(tag_lead_index(left), tag_lead_index(right));
506 lemma_exact_tag_lead_masks_disjoint(left, right);
507}
508
509proof fn lemma_tag_lead_mask_contains_self(tag: Tag)
510 ensures
511 tag_lead_mask_contains(tag_lead_mask(tag), tag),
512{
513 lemma_tag_lead_index_bound(tag);
514 let index = tag_lead_index(tag);
515 assert((1u64 << index) & (1u64 << index) != 0) by (bit_vector)
516 requires
517 index < 64,
518 ;
519}
520
521proof fn lemma_identity_mask_contains(class: Class, number: TagNumber, tag: Tag)
522 requires
523 tag.class == class,
524 tag.number == number,
525 ensures
526 tag_lead_mask_contains(asn1_start_identity(class, number).tags, tag),
527{
528 lemma_tag_lead_mask_contains_self(tag);
529 let primitive = Tag { class, constructed: false, number };
530 let constructed = Tag { class, constructed: true, number };
531 lemma_tag_lead_union_contains(tag_lead_mask(primitive), tag_lead_mask(constructed), tag);
532}
533
534proof fn lemma_exact_input_starts_with_bitmap(input: Seq<u8>, tag: Tag)
535 requires
536 exists|n: int| TagFmt.spec_parse(input) == Some((n, tag)),
537 ensures
538 input_starts_with(input, asn1_start_exact(tag)),
539{
540 lemma_tag_lead_mask_contains_self(tag);
541}
542
543proof fn lemma_identity_input_starts_with_bitmap(input: Seq<u8>, class: Class, number: TagNumber)
544 requires
545 exists|n: int, tag: Tag|
546 TagFmt.spec_parse(input) == Some((n, tag)) && tag.class == class && tag.number
547 == number,
548 ensures
549 input_starts_with(input, asn1_start_identity(class, number)),
550{
551 let parsed = choose|parsed: (int, Tag)|
552 #![auto]
553 TagFmt.spec_parse(input) == Some(parsed) && parsed.1.class == class && parsed.1.number
554 == number;
555 lemma_identity_mask_contains(class, number, parsed.1);
556}
557
558proof fn lemma_wf_zero_tag_number_is_eoc(number: TagNumber)
559 requires
560 super::tag::tag_number_wf(number),
561 tag_num_to_uint(number) == 0,
562 ensures
563 number == TagNumber::EOC,
564{
565}
566
567proof fn lemma_any_non_eoc_mask_contains(tag: Tag)
568 requires
569 super::tag::tag_number_wf(tag.number),
570 tag != TagFmt::EOC,
571 ensures
572 tag_lead_mask_contains(asn1_start_any_non_eoc().tags, tag),
573{
574 lemma_tag_lead_index_bound(tag);
575 let index = tag_lead_index(tag);
576 if tag.class == Class::Universal {
577 if index == 0 {
578 let number = tag_num_to_uint(tag.number);
579 let low = tag_lead_low(tag.number);
580 if tag.constructed {
581 assert(index == (low | 32u64));
582 assert((low | 32u64) != 0) by (bit_vector);
583 } else if number < 31u64 {
584 assert(low == number);
585 assert(index == number);
586 lemma_wf_zero_tag_number_is_eoc(tag.number);
587 assert(tag == TagFmt::EOC);
588 } else {
589 assert(low == 31u64);
590 assert(index == 31u64);
591 }
592 }
593 assert(0xffff_ffff_ffff_fffeu64 & (1u64 << index) != 0) by (bit_vector)
594 requires
595 index < 64,
596 index != 0,
597 ;
598 } else {
599 assert(0xffff_ffff_ffff_ffffu64 & (1u64 << index) != 0) by (bit_vector)
600 requires
601 index < 64,
602 ;
603 }
604}
605
606proof fn lemma_disjoint_masks_cannot_contain_same_tag(
607 left: Asn1TagLeadMask,
608 right: Asn1TagLeadMask,
609 tag: Tag,
610)
611 requires
612 tag_lead_masks_disjoint(left, right),
613 tag_lead_mask_contains(left, tag),
614 tag_lead_mask_contains(right, tag),
615 ensures
616 false,
617{
618 lemma_tag_lead_index_bound(tag);
619 let index = tag_lead_index(tag);
620 match tag.class {
621 Class::Universal => lemma_disjoint_words_cannot_contain_same_bit(
622 left.universal,
623 right.universal,
624 index,
625 ),
626 Class::Application => lemma_disjoint_words_cannot_contain_same_bit(
627 left.application,
628 right.application,
629 index,
630 ),
631 Class::ContextSpecific => lemma_disjoint_words_cannot_contain_same_bit(
632 left.context_specific,
633 right.context_specific,
634 index,
635 ),
636 Class::Private => lemma_disjoint_words_cannot_contain_same_bit(
637 left.private,
638 right.private,
639 index,
640 ),
641 }
642}
643
644proof fn lemma_disjoint_starts_cannot_both_hold(
645 input: Seq<u8>,
646 left: Asn1StartDomain,
647 right: Asn1StartDomain,
648)
649 requires
650 asn1_starts_disjoint(left, right),
651 input_starts_with(input, left),
652 input_starts_with(input, right),
653 ensures
654 false,
655{
656 if input.len() == 0 {
657 } else if let Some((_n, tag)) = TagFmt.spec_parse(input) {
658 lemma_disjoint_masks_cannot_contain_same_tag(left.tags, right.tags, tag);
659 }
660}
661
662pub trait HasAsn1Start: SpecParser {
664 spec fn asn1_start(&self) -> Asn1StartDomain;
665
666 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>)
667 ensures
668 self.spec_parse(input) is Some ==> input_starts_with(input, self.asn1_start()),
669 ;
670}
671
672impl HasAsn1Start for Const<TagFmt, Tag> {
674 #[verifier::inline]
675 open spec fn asn1_start(&self) -> Asn1StartDomain {
676 asn1_start_exact_uint(self.1.class, self.1.constructed, tag_num_to_uint(self.1.number))
677 }
678
679 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
680 if self.spec_parse(input) is Some {
681 lemma_exact_input_starts_with_bitmap(input, self.1);
682 }
683 }
684}
685
686impl<Content: SpecCombinator, const DER: bool> HasAsn1Start for ASN1Fmt<Content, DER> {
688 #[verifier::inline]
689 open spec fn asn1_start(&self) -> Asn1StartDomain {
690 asn1_start_exact_uint(self.0.class, self.0.constructed, tag_num_to_uint(self.0.number))
691 }
692
693 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
694 if self.spec_parse(input) is Some {
695 lemma_exact_input_starts_with_bitmap(input, self.0);
696 }
697 }
698}
699
700impl<Content: SpecCombinator> HasAsn1Start for BerSequenceFmt<Content> {
702 #[verifier::inline]
703 open spec fn asn1_start(&self) -> Asn1StartDomain {
704 asn1_start_exact_uint(self.0.class, self.0.constructed, tag_num_to_uint(self.0.number))
705 }
706
707 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
708 if self.spec_parse(input) is Some {
709 lemma_exact_input_starts_with_bitmap(input, self.0);
710 }
711 }
712}
713
714impl<Content: SpecCombinator> HasAsn1Start for BerSequenceOfFmt<Content> {
716 #[verifier::inline]
717 open spec fn asn1_start(&self) -> Asn1StartDomain {
718 asn1_start_exact_uint(self.0.class, self.0.constructed, tag_num_to_uint(self.0.number))
719 }
720
721 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
722 if self.spec_parse(input) is Some {
723 lemma_exact_input_starts_with_bitmap(input, self.0);
724 }
725 }
726}
727
728impl<const LIMIT: usize> HasAsn1Start for BerOctetStringFmt<LIMIT> {
730 #[verifier::inline]
731 open spec fn asn1_start(&self) -> Asn1StartDomain {
732 asn1_start_identity_uint(self.0.class, tag_num_to_uint(self.0.number))
733 }
734
735 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
736 if self.spec_parse(input) is Some {
737 lemma_identity_input_starts_with_bitmap(input, self.0.class, self.0.number);
738 }
739 }
740}
741
742impl<const LIMIT: usize> HasAsn1Start for BerBitStringFmt<LIMIT> {
744 #[verifier::inline]
745 open spec fn asn1_start(&self) -> Asn1StartDomain {
746 asn1_start_identity_uint(self.0.class, tag_num_to_uint(self.0.number))
747 }
748
749 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
750 if self.spec_parse(input) is Some {
751 lemma_identity_input_starts_with_bitmap(input, self.0.class, self.0.number);
752 }
753 }
754}
755
756impl<Content: SpecCombinator, const LIMIT: usize> HasAsn1Start for BerCharStringFmt<
759 Content,
760 LIMIT,
761> {
762 #[verifier::inline]
763 open spec fn asn1_start(&self) -> Asn1StartDomain {
764 asn1_start_identity_uint(self.0.class, tag_num_to_uint(self.0.number))
765 }
766
767 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
768 if self.spec_parse(input) is Some {
769 lemma_identity_input_starts_with_bitmap(input, self.0.class, self.0.number);
770 }
771 }
772}
773
774impl<const DER: bool> HasAsn1Start for AnyFmt<DER> {
776 #[verifier::inline]
777 open spec fn asn1_start(&self) -> Asn1StartDomain {
778 asn1_start_any_non_eoc()
779 }
780
781 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
782 if self.spec_parse(input) is Some {
783 let parsed = choose|parsed: (int, Tag)|
784 #![auto]
785 TagFmt.spec_parse(input) == Some(parsed) && parsed.1 != TagFmt::EOC;
786 TagFmt.lemma_parse_sound_value(input);
787 lemma_any_non_eoc_mask_contains(parsed.1);
788 }
789 }
790}
791
792impl<const LIMIT: usize> HasAsn1Start for BerAnyFmt<LIMIT> {
794 #[verifier::inline]
795 open spec fn asn1_start(&self) -> Asn1StartDomain {
796 asn1_start_any_non_eoc()
797 }
798
799 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
800 if self.spec_parse(input) is Some {
801 let parsed = choose|parsed: (int, Tag)|
802 #![auto]
803 TagFmt.spec_parse(input) == Some(parsed) && parsed.1 != TagFmt::EOC;
804 TagFmt.lemma_parse_sound_value(input);
805 lemma_any_non_eoc_mask_contains(parsed.1);
806 }
807 }
808}
809
810impl HasAsn1Start for BerEndFmt {
812 #[verifier::inline]
813 open spec fn asn1_start(&self) -> Asn1StartDomain {
814 asn1_start_ber_boundary()
815 }
816
817 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
818 if self.spec_parse(input) is Some && input.len() != 0 {
819 lemma_exact_input_starts_with_bitmap(input, TagFmt::EOC);
820 }
821 }
822}
823
824impl HasAsn1Start for Eof {
826 #[verifier::inline]
827 open spec fn asn1_start(&self) -> Asn1StartDomain {
828 asn1_start_empty()
829 }
830
831 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
832 }
833}
834
835impl<Inner: HasAsn1Start, Predicate: SpecPred<Inner::PVal>> HasAsn1Start for Refined<
837 Inner,
838 Predicate,
839> {
840 #[verifier::inline]
841 open spec fn asn1_start(&self) -> Asn1StartDomain {
842 self.0.asn1_start()
843 }
844
845 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
846 self.0.lemma_parse_implies_asn1_start(input);
847 }
848}
849
850impl<Inner, Mapper> HasAsn1Start for Mapped<Inner, Mapper> where
852 Inner: HasAsn1Start,
853 Mapper: SpecMapper<In = Inner::PVal>,
854 {
855 #[verifier::inline]
856 open spec fn asn1_start(&self) -> Asn1StartDomain {
857 self.inner.asn1_start()
858 }
859
860 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
861 self.inner.lemma_parse_implies_asn1_start(input);
862 }
863}
864
865impl<Inner, Mapper, Reverse> HasAsn1Start for Mapped<Inner, BiMap<Mapper, Reverse>> where
867 Inner: HasAsn1Start,
868 Mapper: SpecMap<Input = Inner::PVal>,
869 Reverse: SpecMap<Input = Mapper::Output, Output = Mapper::Input>,
870 {
871 #[verifier::inline]
872 open spec fn asn1_start(&self) -> Asn1StartDomain {
873 self.inner.asn1_start()
874 }
875
876 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
877 self.inner.lemma_parse_implies_asn1_start(input);
878 }
879}
880
881impl<Inner: HasAsn1Start> HasAsn1Start for Ref<Inner> {
883 #[verifier::inline]
884 open spec fn asn1_start(&self) -> Asn1StartDomain {
885 self.0.asn1_start()
886 }
887
888 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
889 self.0.lemma_parse_implies_asn1_start(input);
890 }
891}
892
893impl<Inner: HasAsn1Start> HasAsn1Start for Named<Inner> {
895 #[verifier::inline]
896 open spec fn asn1_start(&self) -> Asn1StartDomain {
897 self.1.asn1_start()
898 }
899
900 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
901 self.1.lemma_parse_implies_asn1_start(input);
902 }
903}
904
905impl<Format> HasAsn1Start for ImplicitlyTaggedFmt<Format> where Format: Retaggable + HasAsn1Start {
907 #[verifier::inline]
908 open spec fn asn1_start(&self) -> Asn1StartDomain {
909 self.1.spec_retagged(self.0).asn1_start()
910 }
911
912 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
913 self.1.spec_retagged(self.0).lemma_parse_implies_asn1_start(input);
914 }
915}
916
917impl<Left: HasAsn1Start, Right: SpecParser> HasAsn1Start for Pair<Left, Right> {
919 #[verifier::inline]
920 open spec fn asn1_start(&self) -> Asn1StartDomain {
921 self.0.asn1_start()
922 }
923
924 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
925 self.0.lemma_parse_implies_asn1_start(input);
926 }
927}
928
929impl<Field: HasAsn1Start, Rest: HasAsn1Start> HasAsn1Start for Optional<Field, Rest> {
931 #[verifier::inline]
932 open spec fn asn1_start(&self) -> Asn1StartDomain {
933 asn1_start_union(self.0.asn1_start(), self.1.asn1_start())
934 }
935
936 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
937 self.0.lemma_parse_implies_asn1_start(input);
938 self.1.lemma_parse_implies_asn1_start(input);
939 if self.spec_parse(input) is Some {
940 if self.0.spec_parse(input) is None {
941 assert(input.skip(0) == input);
942 }
943 lemma_input_starts_with_union(input, self.0.asn1_start(), self.1.asn1_start());
944 }
945 }
946}
947
948impl<Field, Rest, const DER: bool> HasAsn1Start for DefaultedFmt<
950 Field,
951 Field::PVal,
952 Rest,
953 DER,
954> where
955 Field: SpecByteLen + HasAsn1Start<PVal = Field::T>,
956 Rest: SpecByteLen + HasAsn1Start<PVal = Rest::T>,
957 {
958 #[verifier::inline]
959 open spec fn asn1_start(&self) -> Asn1StartDomain {
960 asn1_start_union(self.0.asn1_start(), self.2.asn1_start())
961 }
962
963 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
964 let fmt = super::modifiers::defaulted_fmt::<Field, Rest, DER>(self.0, self.1, self.2);
965 fmt.lemma_parse_implies_asn1_start(input);
966 }
967}
968
969impl<Left: HasAsn1Start, Right: HasAsn1Start> HasAsn1Start for Choice<Left, Right> {
971 #[verifier::inline]
972 open spec fn asn1_start(&self) -> Asn1StartDomain {
973 asn1_start_union(self.0.asn1_start(), self.1.asn1_start())
974 }
975
976 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
977 self.0.lemma_parse_implies_asn1_start(input);
978 self.1.lemma_parse_implies_asn1_start(input);
979 if self.spec_parse(input) is Some {
980 lemma_input_starts_with_union(input, self.0.asn1_start(), self.1.asn1_start());
981 }
982 }
983}
984
985impl<
987 const NONDETERMINISTIC: bool,
988 Left: HasAsn1Start,
989 Right: HasAsn1Start<PVal = Left::PVal>,
990> HasAsn1Start for Alt<Left, Right, NONDETERMINISTIC> {
991 #[verifier::inline]
992 open spec fn asn1_start(&self) -> Asn1StartDomain {
993 asn1_start_union(self.0.asn1_start(), self.1.asn1_start())
994 }
995
996 proof fn lemma_parse_implies_asn1_start(&self, input: Seq<u8>) {
997 self.0.lemma_parse_implies_asn1_start(input);
998 self.1.lemma_parse_implies_asn1_start(input);
999 if self.spec_parse(input) is Some {
1000 lemma_input_starts_with_union(input, self.0.asn1_start(), self.1.asn1_start());
1001 }
1002 }
1003}
1004
1005pub broadcast proof fn lemma_disjoint_asn1_starts<Left: HasAsn1Start, Right: HasAsn1Start>(
1010 left: Left,
1011 right: Right,
1012)
1013 requires
1014 asn1_starts_disjoint(left.asn1_start(), right.asn1_start()),
1015 ensures
1016 #[trigger] disjoint_domains(left, right),
1017{
1018 reveal(disjoint_domains);
1019 assert forall|input: Seq<u8>|
1020 left.spec_parse(input) is Some && right.spec_parse(input) is Some implies false by {
1021 left.lemma_parse_implies_asn1_start(input);
1022 right.lemma_parse_implies_asn1_start(input);
1023 lemma_disjoint_starts_cannot_both_hold(input, left.asn1_start(), right.asn1_start());
1024 }
1025}
1026
1027pub broadcast proof fn lemma_disjoint_defaulted<Parser, Field, Rest, const DER: bool>(
1033 parser: Parser,
1034 defaulted: DefaultedFmt<Field, Field::PVal, Rest, DER>,
1035) where
1036 Parser: SpecParser,
1037 Field: SpecByteLen + SpecParser<PVal = Field::T>,
1038 Rest: SpecByteLen + SpecParser<PVal = Rest::T>,
1039
1040 requires
1041 disjoint_domains(parser, defaulted.0),
1042 disjoint_domains(parser, defaulted.2),
1043 ensures
1044 #[trigger] disjoint_domains(parser, defaulted),
1045{
1046 reveal(disjoint_domains);
1047 broadcast use vstd::seq_lib::lemma_seq_skip_nothing;
1048
1049}
1050
1051pub broadcast group asn1_disjointness_lemmas {
1054 lemma_tag_number_roundtrip,
1055 lemma_asn1_starts_disjoint_exact,
1056 lemma_asn1_starts_disjoint_exact_uint,
1057 lemma_disjoint_asn1_starts,
1058 lemma_disjoint_defaulted,
1059}
1060
1061}