1use crate::core::exec::input::{InputBuf, InputSlice};
3use crate::core::exec::output::*;
4use crate::core::exec::{
5 parser::{PResult, Parser},
6 serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
7 ParseError,
8};
9use crate::{
10 combinators::{
11 mapped::spec::{LosslessMapper, LossyMapper, SpecMapper},
12 Mapped, Refined, Tail,
13 },
14 core::{proof::*, spec::*},
15};
16use vstd::assert_seqs_equal;
17use vstd::prelude::*;
18use OutputBuf;
19
20use super::datetime::*;
21
22verus! {
23
24#[verifier::ext_equal]
28pub struct GeneralizedTimeSpec {
29 pub datetime: DateTime,
30 pub precision: TimePrecision,
31 pub fraction: Seq<u8>,
32 pub zone: TimeZone,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub struct GeneralizedTime<'a> {
37 pub datetime: DateTime,
38 pub precision: TimePrecision,
39 pub fraction: &'a [u8],
40 pub zone: TimeZone,
41}
42
43impl<'a> DeepView for GeneralizedTime<'a> {
44 type V = GeneralizedTimeSpec;
45
46 closed spec fn deep_view(&self) -> Self::V {
47 GeneralizedTimeSpec {
48 datetime: self.datetime,
49 precision: self.precision,
50 fraction: self.fraction@,
51 zone: self.zone,
52 }
53 }
54}
55
56impl GeneralizedTimeSpec {
57 pub open spec fn wf(&self) -> bool {
60 &&& datetime_wf(self.datetime)
61 &&& self.datetime.year <= 9999
62 &&& digits(self.fraction, 0, self.fraction.len() as int)
63 &&& (self.precision == TimePrecision::Hour || self.precision == TimePrecision::Minute
64 || self.precision == TimePrecision::Second)
65 &&& (self.precision != TimePrecision::Hour || (self.datetime.minute == 0
66 && self.datetime.second == 0))
67 &&& (self.precision != TimePrecision::Minute || self.datetime.second == 0)
68 }
69
70 pub open spec fn der_wf(&self) -> bool {
75 &&& self.wf()
76 &&& self.zone == TimeZone::Utc
77 &&& self.precision == TimePrecision::Second
78 &&& (self.fraction.len() == 0 || self.fraction.last() != 0x30)
79 }
80}
81
82impl<'a> GeneralizedTime<'a> {
83 pub fn new(
84 datetime: DateTime,
85 precision: TimePrecision,
86 fraction: &'a [u8],
87 zone: TimeZone,
88 ) -> (value: Self)
89 requires
90 (GeneralizedTimeSpec { datetime, precision, fraction: fraction@, zone }).wf(),
91 ensures
92 value.deep_view() == (GeneralizedTimeSpec {
93 datetime,
94 precision,
95 fraction: fraction@,
96 zone,
97 }),
98 {
99 GeneralizedTime { datetime, precision, fraction, zone }
100 }
101
102 pub fn fraction(&self) -> (fraction: &'a [u8])
103 ensures
104 fraction.deep_view() == self.deep_view().fraction,
105 {
106 self.fraction
107 }
108}
109
110pub open spec fn generalized_fields_wf(bytes: Seq<u8>, main_end: usize) -> bool {
112 &&& (main_end == 10 || main_end == 12 || main_end == 14)
113 &&& digits(bytes, 0, main_end as int)
114 &&& datetime_wf(
115 DateTime {
116 year: decimal4(bytes, 0),
117 month: decimal2(bytes, 4),
118 day: decimal2(bytes, 6),
119 hour: decimal2(bytes, 8),
120 minute: if main_end >= 12 {
121 decimal2(bytes, 10)
122 } else {
123 0
124 },
125 second: if main_end == 14 {
126 decimal2(bytes, 12)
127 } else {
128 0
129 },
130 },
131 )
132}
133
134pub fn generalized_fields_valid(bytes: &[u8], main_end: usize) -> bool
136 requires
137 main_end <= bytes.len(),
138 returns
139 generalized_fields_wf(bytes@, main_end),
140{
141 if main_end != 10 && main_end != 12 && main_end != 14 {
142 return false;
143 }
144 if !is_digits(bytes, 0, main_end) {
145 return false;
146 }
147 let value = DateTime {
148 year: decimal_4(bytes, 0),
149 month: decimal_2(bytes, 4),
150 day: decimal_2(bytes, 6),
151 hour: decimal_2(bytes, 8),
152 minute: if main_end >= 12 {
153 decimal_2(bytes, 10)
154 } else {
155 0
156 },
157 second: if main_end == 14 {
158 decimal_2(bytes, 12)
159 } else {
160 0
161 },
162 };
163 datetime_wf(value)
164}
165
166pub open spec fn generalized_fraction_wf<const DER: bool>(
172 bytes: Seq<u8>,
173 main_end: usize,
174 zone_start: usize,
175) -> bool {
176 if zone_start == main_end {
177 true
178 } else {
179 &&& main_end + 1 < zone_start
180 &&& (bytes[main_end as int] == 0x2e || (!DER && bytes[main_end as int] == 0x2c))
181 &&& digits(bytes, main_end as int + 1, zone_start as int)
182 &&& (!DER || bytes[zone_start as int - 1] != 0x30)
183 }
184}
185
186pub fn generalized_fraction_valid<const DER: bool>(
188 bytes: &[u8],
189 main_end: usize,
190 zone_start: usize,
191) -> bool
192 requires
193 main_end <= zone_start <= bytes.len(),
194 returns
195 generalized_fraction_wf::<DER>(bytes@, main_end, zone_start),
196{
197 if zone_start == main_end {
198 return true;
199 }
200 if main_end + 1 >= zone_start {
201 return false;
202 }
203 if bytes[main_end] != 0x2e && (DER || bytes[main_end] != 0x2c) {
204 return false;
205 }
206 is_digits(bytes, main_end + 1, zone_start) && (!DER || bytes[zone_start - 1] != 0x30)
207}
208
209pub open spec fn generalized_zone_wf<const DER: bool>(bytes: Seq<u8>, zone_start: usize) -> bool {
213 if DER {
214 zone_start + 1 == bytes.len() && bytes[zone_start as int] == 0x5a
215 } else {
216 ||| zone_start == bytes.len()
217 ||| zone_start + 1 == bytes.len() && bytes[zone_start as int] == 0x5a
218 ||| zone_start + 3 == bytes.len() && (bytes[zone_start as int] == 0x2b
219 || bytes[zone_start as int] == 0x2d) && digits(
220 bytes,
221 zone_start as int + 1,
222 zone_start as int + 3,
223 ) && decimal2(bytes, (zone_start as int + 1) as usize) <= 23
224 ||| zone_start + 5 == bytes.len() && (bytes[zone_start as int] == 0x2b
225 || bytes[zone_start as int] == 0x2d) && digits(
226 bytes,
227 zone_start as int + 1,
228 zone_start as int + 5,
229 ) && decimal2(bytes, (zone_start as int + 1) as usize) <= 23 && decimal2(
230 bytes,
231 (zone_start as int + 3) as usize,
232 ) <= 59
233 }
234}
235
236pub fn generalized_zone_valid<const DER: bool>(bytes: &[u8], zone_start: usize) -> bool
238 requires
239 zone_start <= bytes.len(),
240 returns
241 generalized_zone_wf::<DER>(bytes@, zone_start),
242{
243 if DER {
244 return bytes.len() - zone_start == 1 && bytes[zone_start] == 0x5a;
245 }
246 if zone_start == bytes.len() {
247 return true;
248 }
249 if bytes.len() - zone_start == 1 {
250 return bytes[zone_start] == 0x5a;
251 }
252 if bytes[zone_start] != 0x2b && bytes[zone_start] != 0x2d {
253 return false;
254 }
255 if bytes.len() - zone_start == 3 {
256 return is_digits(bytes, zone_start + 1, zone_start + 3) && decimal_2(bytes, zone_start + 1)
257 <= 23;
258 }
259 bytes.len() - zone_start == 5 && is_digits(bytes, zone_start + 1, zone_start + 5) && decimal_2(
260 bytes,
261 zone_start + 1,
262 ) <= 23 && decimal_2(bytes, zone_start + 3) <= 59
263}
264
265pub open spec fn generalized_candidate_wf<const DER: bool>(
266 bytes: Seq<u8>,
267 main_end: usize,
268 zone_start: usize,
269) -> bool {
270 &&& main_end <= zone_start <= bytes.len()
271 &&& generalized_fields_wf(bytes, main_end)
272 &&& generalized_fraction_wf::<DER>(bytes, main_end, zone_start)
273 &&& generalized_zone_wf::<DER>(bytes, zone_start)
274}
275
276pub fn generalized_candidate_valid<const DER: bool>(
278 bytes: &[u8],
279 main_end: usize,
280 zone_start: usize,
281) -> bool
282 requires
283 zone_start <= bytes.len(),
284 returns
285 generalized_candidate_wf::<DER>(bytes@, main_end, zone_start),
286{
287 main_end <= zone_start && generalized_fields_valid(bytes, main_end)
288 && generalized_fraction_valid::<DER>(bytes, main_end, zone_start)
289 && generalized_zone_valid::<DER>(bytes, zone_start)
290}
291
292pub open spec fn generalized_time_bytes_wf<const DER: bool>(bytes: Seq<u8>) -> bool {
296 let zone_start = generalized_zone_start(bytes);
297 if DER {
298 generalized_candidate_wf::<true>(bytes, 14, zone_start)
299 } else {
300 ||| generalized_candidate_wf::<false>(bytes, 10, zone_start)
301 ||| generalized_candidate_wf::<false>(bytes, 12, zone_start)
302 ||| generalized_candidate_wf::<false>(bytes, 14, zone_start)
303 }
304}
305
306pub fn generalized_time_bytes_valid<const DER: bool>(bytes: &[u8]) -> bool
308 returns
309 generalized_time_bytes_wf::<DER>(bytes@),
310{
311 let zone_start = generalized_zonestart(bytes);
312 if DER {
313 generalized_candidate_valid::<true>(bytes, 14, zone_start)
314 } else {
315 generalized_candidate_valid::<false>(bytes, 10, zone_start)
316 || generalized_candidate_valid::<false>(bytes, 12, zone_start)
317 || generalized_candidate_valid::<false>(bytes, 14, zone_start)
318 }
319}
320
321pub open spec fn generalized_zone_start(bytes: Seq<u8>) -> usize {
324 let len = bytes.len();
325 if len > 0 && bytes[len - 1] == 0x5a {
326 (len - 1) as usize
327 } else if len >= 3 && (bytes[len - 3] == 0x2b || bytes[len - 3] == 0x2d) {
328 (len - 3) as usize
329 } else if len >= 5 && (bytes[len - 5] == 0x2b || bytes[len - 5] == 0x2d) {
330 (len - 5) as usize
331 } else {
332 len as usize
333 }
334}
335
336pub fn generalized_zonestart(bytes: &[u8]) -> (zone_start: usize)
338 ensures
339 zone_start <= bytes.len(),
340 returns
341 generalized_zone_start(bytes@),
342{
343 let len = bytes.len();
344 if len > 0 && bytes[len - 1] == 0x5a {
345 len - 1
346 } else if len >= 3 && (bytes[len - 3] == 0x2b || bytes[len - 3] == 0x2d) {
347 len - 3
348 } else if len >= 5 && (bytes[len - 5] == 0x2b || bytes[len - 5] == 0x2d) {
349 len - 5
350 } else {
351 len
352 }
353}
354
355pub open spec fn generalized_main_end(bytes: Seq<u8>, zone_start: usize) -> usize {
357 if generalized_candidate_wf::<false>(bytes, 10, zone_start) {
358 10
359 } else if generalized_candidate_wf::<false>(bytes, 12, zone_start) {
360 12
361 } else {
362 14
363 }
364}
365
366pub fn generalized_mainend(bytes: &[u8], zone_start: usize) -> usize
368 requires
369 generalized_time_bytes_wf::<false>(bytes@),
370 zone_start == generalized_zone_start(bytes@),
371 returns
372 generalized_main_end(bytes@, zone_start),
373{
374 if generalized_candidate_valid::<false>(bytes, 10, zone_start) {
375 10
376 } else if generalized_candidate_valid::<false>(bytes, 12, zone_start) {
377 12
378 } else {
379 14
380 }
381}
382
383pub open spec fn generalized_time_value(bytes: Seq<u8>) -> Option<GeneralizedTimeSpec> {
386 let zone_start = generalized_zone_start(bytes);
387 let main_end = generalized_main_end(bytes, zone_start);
388 let local = DateTime {
389 year: decimal4(bytes, 0),
390 month: decimal2(bytes, 4),
391 day: decimal2(bytes, 6),
392 hour: decimal2(bytes, 8),
393 minute: if main_end >= 12 {
394 decimal2(bytes, 10)
395 } else {
396 0
397 },
398 second: if main_end == 14 {
399 decimal2(bytes, 12)
400 } else {
401 0
402 },
403 };
404 let precision = if main_end == 10 {
405 TimePrecision::Hour
406 } else if main_end == 12 {
407 TimePrecision::Minute
408 } else {
409 TimePrecision::Second
410 };
411 let fraction = if main_end == zone_start {
412 Seq::empty()
413 } else {
414 bytes[main_end + 1..zone_start]
415 };
416 if zone_start == bytes.len() || bytes[zone_start as int] == 0x5a {
417 Some(
418 GeneralizedTimeSpec {
419 datetime: local,
420 precision,
421 fraction,
422 zone: if zone_start == bytes.len() {
423 TimeZone::Local
424 } else {
425 TimeZone::Utc
426 },
427 },
428 )
429 } else {
430 let offset_minute = if bytes.len() - zone_start == 5 {
431 decimal2(bytes, (zone_start as int + 3) as usize)
432 } else {
433 0
434 };
435 match normalize_offset(
436 local,
437 bytes[zone_start as int] == 0x2b,
438 decimal2(bytes, (zone_start as int + 1) as usize),
439 offset_minute,
440 ) {
441 Some(datetime) => Some(
442 GeneralizedTimeSpec { datetime, precision, fraction, zone: TimeZone::Utc },
443 ),
444 None => None,
445 }
446 }
447}
448
449#[verifier::rlimit(20)]
452pub fn generalized_timevalue<'a>(bytes: &'a [u8]) -> (res: Option<GeneralizedTime<'a>>)
453 requires
454 generalized_time_bytes_wf::<false>(bytes@),
455 ensures
456 res.deep_view() == generalized_time_value(bytes@),
457{
458 let zone_start = generalized_zonestart(bytes);
459 let main_end = generalized_mainend(bytes, zone_start);
460 let local = DateTime {
461 year: decimal_4(bytes, 0),
462 month: decimal_2(bytes, 4),
463 day: decimal_2(bytes, 6),
464 hour: decimal_2(bytes, 8),
465 minute: if main_end >= 12 {
466 decimal_2(bytes, 10)
467 } else {
468 0
469 },
470 second: if main_end == 14 {
471 decimal_2(bytes, 12)
472 } else {
473 0
474 },
475 };
476 let precision = if main_end == 10 {
477 TimePrecision::Hour
478 } else if main_end == 12 {
479 TimePrecision::Minute
480 } else {
481 TimePrecision::Second
482 };
483 let fraction = if main_end == zone_start {
484 &bytes[main_end..main_end]
485 } else {
486 &bytes[main_end + 1..zone_start]
487 };
488 if zone_start == bytes.len() || bytes[zone_start] == 0x5a {
489 Some(
490 GeneralizedTime {
491 datetime: local,
492 precision,
493 fraction,
494 zone: if zone_start == bytes.len() {
495 TimeZone::Local
496 } else {
497 TimeZone::Utc
498 },
499 },
500 )
501 } else {
502 let offset_minute = if bytes.len() - zone_start == 5 {
503 decimal_2(bytes, zone_start + 3)
504 } else {
505 0
506 };
507 match normalize_offset(
508 local,
509 bytes[zone_start] == 0x2b,
510 decimal_2(bytes, zone_start + 1),
511 offset_minute,
512 ) {
513 Some(datetime) => Some(
514 GeneralizedTime { datetime, precision, fraction, zone: TimeZone::Utc },
515 ),
516 None => None,
517 }
518 }
519}
520
521pub open spec fn generalized_time_wf<const DER: bool>(bytes: Seq<u8>) -> bool {
523 &&& generalized_time_bytes_wf::<DER>(bytes)
524 &&& generalized_time_value(bytes) matches Some(value) ==> value.wf()
525 &&& generalized_time_value(bytes).is_some()
526 &&& bytes.len() <= usize::MAX
527}
528
529pub fn generalized_time_valid<const DER: bool>(bytes: &[u8]) -> bool
531 returns
532 generalized_time_wf::<DER>(bytes@),
533{
534 assert(bytes@.len() == bytes.len());
535 assert(bytes@.len() <= usize::MAX);
536 if !generalized_time_bytes_valid::<DER>(bytes) {
537 return false;
538 }
539 match generalized_timevalue(bytes) {
540 Some(value) => generalized_value_wf::<false>(&value),
541 None => false,
542 }
543}
544
545pub open spec fn generalized_time_prefix(value: GeneralizedTimeSpec) -> Seq<u8> {
546 decimal4_bytes(value.datetime.year)@ + decimal2_bytes(value.datetime.month)@ + decimal2_bytes(
547 value.datetime.day,
548 )@ + decimal2_bytes(value.datetime.hour)@ + if value.precision == TimePrecision::Hour {
549 Seq::empty()
550 } else {
551 decimal2_bytes(value.datetime.minute)@ + if value.precision == TimePrecision::Second {
552 decimal2_bytes(value.datetime.second)@
553 } else {
554 Seq::empty()
555 }
556 }
557}
558
559pub open spec fn generalized_time_fraction(value: GeneralizedTimeSpec) -> Seq<u8> {
560 if value.fraction.len() == 0 {
561 Seq::empty()
562 } else {
563 seq![0x2eu8] + value.fraction
564 }
565}
566
567pub open spec fn generalized_time_suffix(value: GeneralizedTimeSpec) -> Seq<u8> {
568 if value.zone == TimeZone::Utc {
569 seq![0x5au8]
570 } else {
571 Seq::empty()
572 }
573}
574
575pub open spec fn generalized_time_bytes(value: GeneralizedTimeSpec) -> Seq<u8> {
576 generalized_time_prefix(value) + generalized_time_fraction(value) + generalized_time_suffix(
577 value,
578 )
579}
580
581pub(crate) fn generalized_time_der_prefix_bytes<'a>(value: &GeneralizedTime<'a>) -> (bytes:
582 [u8; 14])
583 requires
584 value.deep_view().der_wf(),
585 ensures
586 bytes@ == generalized_time_prefix(value.deep_view()),
587{
588 let year = decimal4_bytes(value.datetime.year);
589 let month = decimal2_bytes(value.datetime.month);
590 let day = decimal2_bytes(value.datetime.day);
591 let hour = decimal2_bytes(value.datetime.hour);
592 let minute = decimal2_bytes(value.datetime.minute);
593 let second = decimal2_bytes(value.datetime.second);
594 [
595 year[0],
596 year[1],
597 year[2],
598 year[3],
599 month[0],
600 month[1],
601 day[0],
602 day[1],
603 hour[0],
604 hour[1],
605 minute[0],
606 minute[1],
607 second[0],
608 second[1],
609 ]
610}
611
612pub fn generalized_time_to_bytes<'a, Output: OutputBuf>(
614 value: &GeneralizedTime<'a>,
615 obuf: &mut Output,
616)
617 requires
618 value.deep_view().wf(),
619 old(obuf).fits(generalized_time_bytes(value.deep_view()).len()),
620 ensures
621 final(obuf)@ == old(obuf)@ + generalized_time_bytes(value.deep_view()),
622 forall|n|
623 old(obuf).fits(generalized_time_bytes(value.deep_view()).len() + n)
624 <==> final(obuf).fits(n),
625 old(obuf).same_destination(final(obuf)),
626{
627 broadcast use crate::core::exec::output::outbuf_lemmas;
628
629 let year = decimal4_bytes(value.datetime.year);
630 let month = decimal2_bytes(value.datetime.month);
631 let day = decimal2_bytes(value.datetime.day);
632 let hour = decimal2_bytes(value.datetime.hour);
633 obuf.write_bytes(&year);
634 obuf.write_bytes(&month);
635 obuf.write_bytes(&day);
636 obuf.write_bytes(&hour);
637 if value.precision != TimePrecision::Hour {
638 let minute = decimal2_bytes(value.datetime.minute);
639 obuf.write_bytes(&minute);
640 if value.precision == TimePrecision::Second {
641 let second = decimal2_bytes(value.datetime.second);
642 obuf.write_bytes(&second);
643 }
644 }
645 if value.fraction.len() > 0 {
646 obuf.write_byte(0x2e);
647 obuf.write_bytes(value.fraction);
648 }
649 if value.zone == TimeZone::Utc {
650 obuf.write_byte(0x5a);
651 }
652}
653
654#[verifier::allow_in_spec]
656pub fn generalized_value_wf<'a, const DER: bool>(value: &GeneralizedTime<'a>) -> bool
657 returns
658 if DER {
659 value.deep_view().der_wf()
660 } else {
661 value.deep_view().wf()
662 },
663{
664 let base = datetime_wf(value.datetime) && value.datetime.year <= 9999 && is_digits(
665 value.fraction,
666 0,
667 value.fraction.len(),
668 ) && (value.precision == TimePrecision::Hour || value.precision == TimePrecision::Minute
669 || value.precision == TimePrecision::Second) && (value.precision != TimePrecision::Hour || (
670 value.datetime.minute == 0 && value.datetime.second == 0)) && (value.precision
671 != TimePrecision::Minute || value.datetime.second == 0);
672 base && (!DER || (value.zone == TimeZone::Utc && value.precision == TimePrecision::Second && (
673 value.fraction.len() == 0 || value.fraction[value.fraction.len() - 1] != 0x30)))
674}
675
676pub open spec fn generalized_time_len(value: GeneralizedTimeSpec) -> nat {
677 10 as nat + if value.precision == TimePrecision::Hour {
678 0 as nat
679 } else {
680 2 as nat
681 } + if value.precision == TimePrecision::Second {
682 2 as nat
683 } else {
684 0 as nat
685 } + if value.fraction.len() == 0 {
686 0 as nat
687 } else {
688 1 + value.fraction.len()
689 } + if value.zone == TimeZone::Utc {
690 1 as nat
691 } else {
692 0 as nat
693 }
694}
695
696spec fn generalized_time_main_end(value: GeneralizedTimeSpec) -> usize {
697 if value.precision == TimePrecision::Hour {
698 10
699 } else if value.precision == TimePrecision::Minute {
700 12
701 } else {
702 14
703 }
704}
705
706spec fn generalized_time_zone_start(value: GeneralizedTimeSpec) -> usize {
707 (generalized_time_main_end(value) + generalized_time_fraction(value).len()) as usize
708}
709
710#[verifier::rlimit(20)]
712proof fn lemma_generalized_time_encoded_prefix(value: GeneralizedTimeSpec)
713 requires
714 value.wf(),
715 generalized_time_len(value) <= usize::MAX,
716 ensures
717 generalized_time_prefix(value).len() == generalized_time_main_end(value),
718 generalized_fields_wf(generalized_time_bytes(value), generalized_time_main_end(value)),
719 decimal4(generalized_time_bytes(value), 0) == value.datetime.year,
720 decimal2(generalized_time_bytes(value), 4) == value.datetime.month,
721 decimal2(generalized_time_bytes(value), 6) == value.datetime.day,
722 decimal2(generalized_time_bytes(value), 8) == value.datetime.hour,
723 value.precision != TimePrecision::Hour ==> decimal2(generalized_time_bytes(value), 10)
724 == value.datetime.minute,
725 value.precision == TimePrecision::Second ==> decimal2(generalized_time_bytes(value), 12)
726 == value.datetime.second,
727{
728 lemma_decimal4_roundtrip(value.datetime.year);
729 lemma_decimal2_roundtrip(value.datetime.month);
730 lemma_decimal2_roundtrip(value.datetime.day);
731 lemma_decimal2_roundtrip(value.datetime.hour);
732 lemma_decimal2_roundtrip(value.datetime.minute);
733 lemma_decimal2_roundtrip(value.datetime.second);
734}
735
736#[verifier::rlimit(20)]
737proof fn lemma_generalized_time_encoded_fraction<const DER: bool>(value: GeneralizedTimeSpec)
738 requires
739 if DER {
740 value.der_wf()
741 } else {
742 value.wf()
743 },
744 generalized_time_len(value) <= usize::MAX,
745 ensures
746 generalized_fraction_wf::<DER>(
747 generalized_time_bytes(value),
748 generalized_time_main_end(value),
749 generalized_time_zone_start(value),
750 ),
751 if generalized_time_main_end(value) == generalized_time_zone_start(value) {
752 value.fraction.len() == 0
753 } else {
754 generalized_time_bytes(value)[generalized_time_main_end(value)
755 + 1..generalized_time_zone_start(value)] == value.fraction
756 },
757{
758 let prefix = generalized_time_prefix(value);
759 let fraction = generalized_time_fraction(value);
760 let suffix = generalized_time_suffix(value);
761 let bytes = prefix + fraction + suffix;
762 let main_end = generalized_time_main_end(value);
763 let zone_start: usize = (main_end + fraction.len()) as usize;
764
765 if value.fraction.len() == 0 {
766 } else {
767 assert(fraction == seq![0x2eu8] + value.fraction);
768 assert_seqs_equal!(bytes[main_end + 1.. zone_start] == value.fraction, i => {
769 assert(bytes[main_end as int + 1 + i] == fraction[1 + i]);
770 assert(fraction[1 + i] == value.fraction[i]);
771 });
772 assert(digits(bytes, main_end as int + 1, zone_start as int)) by {
773 assert forall|i: int| main_end <= i < zone_start - 1 implies ascii_digit(
774 #[trigger] bytes[i + 1],
775 ) by {
776 assert(bytes[i + 1] == value.fraction[i - main_end]);
777 }
778 }
779 assert(generalized_fraction_wf::<DER>(bytes, main_end, zone_start));
780 }
781}
782
783#[verifier::rlimit(20)]
784proof fn lemma_generalized_time_encoded_zone<const DER: bool>(value: GeneralizedTimeSpec)
785 requires
786 if DER {
787 value.der_wf()
788 } else {
789 value.wf()
790 },
791 generalized_time_len(value) <= usize::MAX,
792 ensures
793 generalized_zone_start(generalized_time_bytes(value)) == generalized_time_zone_start(value),
794 generalized_zone_wf::<DER>(
795 generalized_time_bytes(value),
796 generalized_time_zone_start(value),
797 ),
798 (generalized_time_zone_start(value) == generalized_time_bytes(value).len()) <==> value.zone
799 == TimeZone::Local,
800 value.zone == TimeZone::Utc ==> generalized_time_bytes(value)[generalized_time_zone_start(
801 value,
802 ) as int] == 0x5a,
803{
804}
805
806#[verifier::rlimit(20)]
807proof fn lemma_generalized_time_encoded_layout<const DER: bool>(value: GeneralizedTimeSpec)
808 requires
809 if DER {
810 value.der_wf()
811 } else {
812 value.wf()
813 },
814 generalized_time_len(value) <= usize::MAX,
815 ensures
816 generalized_time_bytes_wf::<DER>(generalized_time_bytes(value)),
817 generalized_main_end(generalized_time_bytes(value), generalized_time_zone_start(value))
818 == generalized_time_main_end(value),
819{
820 lemma_generalized_time_encoded_prefix(value);
821 lemma_generalized_time_encoded_fraction::<DER>(value);
822 lemma_generalized_time_encoded_zone::<DER>(value);
823}
824
825#[verifier::rlimit(20)]
826pub proof fn lemma_generalized_time_encode_roundtrip<const DER: bool>(value: GeneralizedTimeSpec)
827 requires
828 if DER {
829 value.der_wf()
830 } else {
831 value.wf()
832 },
833 generalized_time_len(value) <= usize::MAX,
834 ensures
835 generalized_time_wf::<DER>(generalized_time_bytes(value)),
836 generalized_time_value(generalized_time_bytes(value)) == Some(value),
837 generalized_time_bytes(value).len() == generalized_time_len(value),
838{
839 lemma_generalized_time_encoded_layout::<DER>(value);
840 lemma_generalized_time_encoded_prefix(value);
841 lemma_generalized_time_encoded_fraction::<DER>(value);
842 lemma_generalized_time_encoded_zone::<DER>(value);
843}
844
845#[verifier::rlimit(100)]
846pub proof fn lemma_der_generalized_time_canonical(bytes: Seq<u8>)
847 requires
848 generalized_time_wf::<true>(bytes),
849 ensures
850 generalized_time_bytes(generalized_time_value(bytes).unwrap()) == bytes,
851{
852 lemma_decimal4_canonical(bytes, 0);
853 lemma_decimal2_canonical(bytes, 4);
854 lemma_decimal2_canonical(bytes, 6);
855 lemma_decimal2_canonical(bytes, 8);
856 lemma_decimal2_canonical(bytes, 10);
857 lemma_decimal2_canonical(bytes, 12);
858}
859
860mod derived_specs {
861 use super::*;
862
863 impl<const DER: bool> SpecParser for super::super::GeneralizedTimeFmt<DER> {
864 type PVal = GeneralizedTimeSpec;
865
866 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
867 if generalized_time_wf::<DER>(ibuf) {
868 Some((ibuf.len() as int, generalized_time_value(ibuf).unwrap()))
869 } else {
870 None
871 }
872 }
873 }
874
875 impl<const DER: bool> Consistency for super::super::GeneralizedTimeFmt<DER> {
876 type Val = GeneralizedTimeSpec;
877
878 open spec fn consistent(&self, value: Self::Val) -> bool {
879 (if DER {
880 value.der_wf()
881 } else {
882 value.wf()
883 }) && generalized_time_len(value) <= usize::MAX
884 }
885 }
886
887 impl<const DER: bool> SpecSerializerDps for super::super::GeneralizedTimeFmt<DER> {
888 type SValue = GeneralizedTimeSpec;
889
890 open spec fn spec_serialize_dps(&self, value: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
891 generalized_time_bytes(value)
892 }
893 }
894
895 impl<const DER: bool> SpecSerializer for super::super::GeneralizedTimeFmt<DER> {
896 type SVal = GeneralizedTimeSpec;
897
898 open spec fn spec_serialize(&self, value: Self::SVal) -> Seq<u8> {
899 generalized_time_bytes(value)
900 }
901 }
902
903 impl<const DER: bool> SpecByteLen for super::super::GeneralizedTimeFmt<DER> {
904 type T = GeneralizedTimeSpec;
905
906 open spec fn byte_len(&self, value: Self::T) -> nat {
907 generalized_time_len(value)
908 }
909 }
910
911}
912
913pub(crate) proof fn lemma_der_generalized_time_model(value: GeneralizedTimeSpec)
914 requires
915 super::GeneralizedTimeFmt::<true>.consistent(value),
916 ensures
917 value.der_wf(),
918 super::GeneralizedTimeFmt::<true>.spec_serialize(value) == generalized_time_prefix(value)
919 + generalized_time_fraction(value) + generalized_time_suffix(value),
920 super::GeneralizedTimeFmt::<true>.spec_serialize(value).len()
921 == super::GeneralizedTimeFmt::<true>.byte_len(value),
922 super::GeneralizedTimeFmt::<true>.spec_serialize(value).len() <= usize::MAX,
923 generalized_time_prefix(value).len() == 14,
924 generalized_time_suffix(value) == seq![0x5au8],
925{
926}
927
928pub(crate) proof fn lemma_der_generalized_time_layout(value: GeneralizedTimeSpec, pos: usize)
929 requires
930 super::GeneralizedTimeFmt::<true>.consistent(value),
931 ensures
932 super::GeneralizedTimeFmt::<true>.spec_serialize(value).len() == if value.fraction.len()
933 == 0 {
934 15
935 } else {
936 value.fraction.len() + 16
937 },
938 pos < super::GeneralizedTimeFmt::<true>.spec_serialize(value).len() ==> {
939 super::GeneralizedTimeFmt::<true>.spec_serialize(value)[pos as int] == if pos < 14 {
940 generalized_time_prefix(value)[pos as int]
941 } else if value.fraction.len() == 0 {
942 0x5au8
943 } else if pos == 14 {
944 0x2eu8
945 } else if (pos as nat) < value.fraction.len() + 15 {
946 value.fraction[pos as int - 15]
947 } else {
948 0x5au8
949 }
950 },
951{
952 lemma_der_generalized_time_model(value);
953}
954
955mod derived_proofs {
956 use super::*;
957
958 impl<const DER: bool> SafeParser for super::super::GeneralizedTimeFmt<DER> {
959 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
960 }
961 }
962
963 impl<const DER: bool> Productive for super::super::GeneralizedTimeFmt<DER> {
964 proof fn lemma_productive(&self, ibuf: Seq<u8>) {
965 if let Some((n, _)) = self.spec_parse(ibuf) {
966 assert(n == ibuf.len());
967 assert(n >= 10);
968 }
969 }
970 }
971
972 impl<const DER: bool> GoodSerializer for super::super::GeneralizedTimeFmt<DER> {
973 proof fn lemma_serialize_len(&self, value: Self::SVal) {
974 }
975 }
976
977 impl<const DER: bool> EquivSerializers for super::super::GeneralizedTimeFmt<DER> {
978 proof fn lemma_serialize_equiv_on_empty(&self, value: Self::SVal) {
979 }
980 }
981
982 impl<const DER: bool> SPRoundTripDps for super::super::GeneralizedTimeFmt<DER> {
983 proof fn theorem_serialize_dps_parse_roundtrip(&self, value: Self::T, obuf: Seq<u8>) {
984 lemma_generalized_time_encode_roundtrip::<DER>(value);
985 }
986 }
987
988 impl SoundParser for super::super::GeneralizedTimeFmt<true> {
989 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
990 if let Some((n, value)) = self.spec_parse(ibuf) {
991 lemma_der_generalized_time_canonical(ibuf);
992 assert(generalized_time_bytes(value) == ibuf);
993 }
994 }
995
996 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
997 if let Some((_, value)) = self.spec_parse(ibuf) {
998 assert(self.consistent(value));
999 }
1000 }
1001 }
1002
1003 impl NonMalleable for super::super::GeneralizedTimeFmt<true> {
1004 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
1005 if let (Some((n1, value1)), Some((n2, value2))) = (
1006 self.spec_parse(buf1),
1007 self.spec_parse(buf2),
1008 ) {
1009 lemma_der_generalized_time_canonical(buf1);
1010 lemma_der_generalized_time_canonical(buf2);
1011 if value1 == value2 {
1012 assert(buf1 == generalized_time_bytes(value1));
1013 assert(buf2 == generalized_time_bytes(value2));
1014 assert(buf1[0..n1] == buf1);
1015 assert(buf2[0..n2] == buf2);
1016 }
1017 }
1018 }
1019 }
1020
1021}
1022
1023impl<'i, const DER: bool> Parser<&'i [u8]> for super::GeneralizedTimeFmt<DER> {
1024 type PT = GeneralizedTime<'i>;
1025
1026 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
1027 let (n, bytes) = Tail.parse(ibuf)?;
1028 assert(bytes@ == bytes.deep_view());
1029 if !generalized_time_valid::<DER>(bytes) {
1030 return Err(ParseError::custom("Invalid GeneralizedTime"));
1031 }
1032 match generalized_timevalue(bytes) {
1033 Some(value) => Ok((n, value)),
1034 None => Err(ParseError::custom("GeneralizedTime offset out of range")),
1035 }
1036 }
1037}
1038
1039impl<Output: OutputBuf, 'i, const DER: bool> Serializer<
1040 Output,
1041 GeneralizedTime<'i>,
1042> for super::GeneralizedTimeFmt<DER> {
1043 fn serialize_into(&self, value: &GeneralizedTime<'i>, obuf: &mut Output) {
1044 generalized_time_to_bytes(value, obuf);
1045 }
1046}
1047
1048impl<'i, const DER: bool> Prepare<GeneralizedTime<'i>> for super::GeneralizedTimeFmt<DER> {
1049 fn prepare(&self, value: &GeneralizedTime<'i>) -> Result<usize, PreSerializeError> {
1050 if !generalized_value_wf::<DER>(value) {
1051 return Err(PreSerializeError::custom("Invalid GeneralizedTime value"));
1052 }
1053 if value.fraction.len() > usize::MAX - 16 {
1054 return Err(PreSerializeError::length_too_large());
1055 }
1056 Ok(
1057 10 + if value.precision == TimePrecision::Hour {
1058 0
1059 } else {
1060 2
1061 } + if value.precision == TimePrecision::Second {
1062 2
1063 } else {
1064 0
1065 } + if value.fraction.len() == 0 {
1066 0
1067 } else {
1068 1 + value.fraction.len()
1069 } + if value.zone == TimeZone::Utc {
1070 1
1071 } else {
1072 0
1073 },
1074 )
1075 }
1076}
1077
1078impl<'i, const DER: bool> ByteLen<GeneralizedTime<'i>> for super::GeneralizedTimeFmt<DER> {
1079 fn length(&self, value: &GeneralizedTime<'i>) -> usize {
1080 10 + if value.precision == TimePrecision::Hour {
1081 0
1082 } else {
1083 2
1084 } + if value.precision == TimePrecision::Second {
1085 2
1086 } else {
1087 0
1088 } + if value.fraction.len() == 0 {
1089 0
1090 } else {
1091 1 + value.fraction.len()
1092 } + if value.zone == TimeZone::Utc {
1093 1
1094 } else {
1095 0
1096 }
1097 }
1098}
1099
1100}