1use crate::core::{proof::*, spec::*};
3use vstd::prelude::*;
4
5verus! {
6
7pub type ParserSpecs<SpecP, Cnstcy, Blen> = (SpecP, Cnstcy, Blen);
9
10pub type ParserFnSpecs<T> = (ParserFnSpec<T>, PredFnSpec<T>, ByteLenFnSpec<T>);
11
12impl<SpecP, Cnstcy, Blen> SpecByteLen for ParserSpecs<SpecP, Cnstcy, Blen> where
13 Blen: SpecByteLen,
14 SpecP: SpecParser<PVal = Blen::T>,
15 Cnstcy: Consistency<Val = Blen::T>,
16 {
17 type T = Blen::T;
18
19 open spec fn byte_len(&self, v: Self::T) -> nat {
20 (self.2).byte_len(v)
21 }
22}
23
24impl<SpecP, Cnstcy, Blen> Consistency for ParserSpecs<SpecP, Cnstcy, Blen> where
25 Blen: SpecByteLen,
26 SpecP: SpecParser<PVal = Blen::T>,
27 Cnstcy: Consistency<Val = Blen::T>,
28 {
29 type Val = Blen::T;
30
31 open spec fn consistent(&self, v: Self::Val) -> bool {
32 (self.1).consistent(v)
33 }
34}
35
36impl<SpecP, Cnstcy, Blen> SpecParser for ParserSpecs<SpecP, Cnstcy, Blen> where
37 Blen: SpecByteLen,
38 SpecP: SpecParser<PVal = Blen::T>,
39 Cnstcy: Consistency<Val = Blen::T>,
40 {
41 type PVal = Blen::T;
42
43 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
44 (self.0).spec_parse(ibuf)
45 }
46}
47
48pub open spec fn safe_parser<T>(parser: ParserFnSpec<T>) -> bool {
50 forall|input: Seq<u8>| #[trigger] parser(input) matches Some((n, _)) ==> 0 <= n <= input.len()
51}
52
53pub type SerializerSpecs<SpecS, Blen> = (SpecS, Blen);
55
56pub type SerializerFnSpecs<T> = (SerializerFnSpec<T>, ByteLenFnSpec<T>);
57
58impl<SpecS, Blen> SpecByteLen for SerializerSpecs<SpecS, Blen> where
59 Blen: SpecByteLen,
60 SpecS: SpecSerializer<SVal = Blen::T>,
61 {
62 type T = Blen::T;
63
64 open spec fn byte_len(&self, v: Self::T) -> nat {
65 (self.1).byte_len(v)
66 }
67}
68
69impl<SpecS, Blen> SpecSerializer for SerializerSpecs<SpecS, Blen> where
70 Blen: SpecByteLen,
71 SpecS: SpecSerializer<SVal = Blen::T>,
72 {
73 type SVal = Blen::T;
74
75 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
76 (self.0).spec_serialize(v)
77 }
78}
79
80pub open spec fn non_tail_fmt_dps<T>(
82 serializer_dps: SerializerDPSFnSpec<T>,
83 byte_len: ByteLenFnSpec<T>,
84) -> bool {
85 &&& forall|v: T, obuf: Seq<u8>| #[trigger]
86 serializer_dps(v, obuf).len() - obuf.len() == byte_len(
87 v,
88 )
89 &&& forall|v: T, obuf: Seq<u8>| #[trigger]
91 serializer_dps(v, obuf) == (choose|w: Seq<u8>| serializer_dps(v, obuf) == w + obuf) + obuf
92}
93
94pub open spec fn good_serializer_fn<T>(
96 serializer: SerializerFnSpec<T>,
97 byte_len: ByteLenFnSpec<T>,
98) -> bool {
99 forall|v: T| #[trigger] serializer(v).len() == byte_len(v)
100}
101
102impl<SpecS, Blen> GoodSerializer for SerializerSpecs<SpecS, Blen> where
103 Blen: SpecByteLen,
104 SpecS: SpecSerializer<SVal = Blen::T>,
105 {
106 open spec fn serialize_inv(&self) -> bool {
107 let (s, b) = *self;
108 let (s_fn, b_fn) = (|v| s.spec_serialize(v), |v| b.byte_len(v));
109 good_serializer_fn(s_fn, b_fn)
110 }
111
112 proof fn lemma_serialize_len(&self, v: Self::SVal) {
113 let (s, b) = *self;
114 let (s_fn, b_fn) = (|v| s.spec_serialize(v), |v| b.byte_len(v));
115 assert(good_serializer_fn(s_fn, b_fn));
116 assert(s_fn(v).len() == b_fn(v));
117 }
118}
119
120impl<SpecP, Cnstcy, Blen> SafeParser for (SpecP, Cnstcy, Blen) where
121 Blen: SpecByteLen,
122 SpecP: SpecParser<PVal = Blen::T>,
123 Cnstcy: Consistency<Val = Blen::T>,
124 {
125 open spec fn safe_inv(&self) -> bool {
126 let (p, _, _) = *self;
127 let p_fn = |ibuf| p.spec_parse(ibuf);
128 safe_parser(p_fn)
129 }
130
131 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
132 let (p, _, _) = *self;
133 let p_fn = |i: Seq<u8>| p.spec_parse(i);
134 assert(self.safe_inv());
135 if let Some((n, v)) = self.spec_parse(ibuf) {
136 assert(safe_parser(p_fn));
137 assert(p_fn(ibuf) == Some((n, v)));
138 assert(0 <= n <= ibuf.len());
139 }
140 }
141}
142
143impl<SpecP, Cnstcy, Blen> SoundParser for (SpecP, Cnstcy, Blen) where
144 Blen: SpecByteLen,
145 SpecP: SpecParser<PVal = Blen::T>,
146 Cnstcy: Consistency<Val = Blen::T>,
147 {
148 open spec fn sound_inv(&self) -> bool {
149 let (p, c, b) = *self;
150 let (p_fn, c_fn, b_fn) = (
151 |ibuf| p.spec_parse(ibuf),
152 |v| c.consistent(v),
153 |v| b.byte_len(v),
154 );
155 sound_parser(p_fn, c_fn, b_fn)
156 }
157
158 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
159 let (p, c, b) = *self;
160 let (p_fn, c_fn, b_fn) = (
161 |i: Seq<u8>| p.spec_parse(i),
162 |v: Blen::T| c.consistent(v),
163 |v: Blen::T| b.byte_len(v),
164 );
165 assert(self.sound_inv());
166 if let Some((n, v)) = self.spec_parse(ibuf) {
167 assert(sound_parser(p_fn, c_fn, b_fn));
168 assert(p_fn(ibuf) == Some((n, v)));
169 assert(b_fn(v) == n);
170 }
171 }
172
173 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
174 let (p, c, b) = *self;
175 let (p_fn, c_fn, b_fn) = (
176 |i: Seq<u8>| p.spec_parse(i),
177 |v: Blen::T| c.consistent(v),
178 |v: Blen::T| b.byte_len(v),
179 );
180 assert(self.sound_inv());
181 if let Some((n, v)) = self.spec_parse(ibuf) {
182 assert(sound_parser(p_fn, c_fn, b_fn));
183 assert(p_fn(ibuf) == Some((n, v)));
184 assert(c_fn(v));
185 }
186 }
187}
188
189impl<SpecP, Cnstcy, Blen> Productive for (SpecP, Cnstcy, Blen) where
190 Blen: SpecByteLen,
191 SpecP: SpecParser<PVal = Blen::T>,
192 Cnstcy: Consistency<Val = Blen::T>,
193 {
194 open spec fn productive_inv(&self) -> bool {
195 let (p, _, _) = *self;
196 let p_fn = |ibuf| p.spec_parse(ibuf);
197 productive_parser(p_fn)
198 }
199
200 proof fn lemma_productive(&self, ibuf: Seq<u8>) {
201 let (p, _, _) = *self;
202 let p_fn = |i: Seq<u8>| p.spec_parse(i);
203 assert(self.productive_inv());
204 if let Some((n, v)) = self.spec_parse(ibuf) {
205 assert(productive_parser(p_fn));
206 assert(p_fn(ibuf) == Some((n, v)));
207 assert(n > 0);
208 }
209 }
210}
211
212pub open spec fn sound_parser<T>(
214 parser: ParserFnSpec<T>,
215 consistent: PredFnSpec<T>,
216 byte_len: ByteLenFnSpec<T>,
217) -> bool {
218 forall|input: Seq<u8>| #[trigger]
219 parser(input) matches Some((n, v)) ==> {
220 &&& consistent(v)
221 &&& byte_len(v) == n
222 }
223}
224
225pub open spec fn productive_parser<T>(parser: ParserFnSpec<T>) -> bool {
227 forall|input: Seq<u8>| #[trigger] parser(input) matches Some((n, _)) ==> n > 0
228}
229
230pub type BundledSpecs<T> = (
231 PredFnSpec<T>,
232 ByteLenFnSpec<T>,
233 ParserFnSpec<T>,
234 SerializerFnSpec<T>,
235 SerializerDPSFnSpec<T>,
236);
237
238pub type ParamRecSpecs<P, T> = spec_fn(P) -> BundledSpecs<T>;
239
240pub open spec fn parser_specs<T>(bundled: BundledSpecs<T>) -> ParserSpecs<
241 ParserFnSpec<T>,
242 PredFnSpec<T>,
243 ByteLenFnSpec<T>,
244> {
245 (bundled.2, bundled.0, bundled.1)
246}
247
248pub open spec fn serializer_specs<T>(bundled: BundledSpecs<T>) -> SerializerSpecs<
249 SerializerFnSpec<T>,
250 ByteLenFnSpec<T>,
251> {
252 (bundled.3, bundled.1)
253}
254
255impl<T> Consistency for BundledSpecs<T> {
256 type Val = T;
257
258 open spec fn consistent(&self, v: Self::Val) -> bool {
259 (self.0)(v)
260 }
261}
262
263impl<T> SpecByteLen for BundledSpecs<T> {
264 type T = T;
265
266 open spec fn byte_len(&self, v: Self::T) -> nat {
267 (self.1)(v)
268 }
269}
270
271impl<T> SpecParser for BundledSpecs<T> {
272 type PVal = T;
273
274 open spec fn spec_parse(&self, input: Seq<u8>) -> Option<(int, Self::PVal)> {
275 (self.2)(input)
276 }
277}
278
279impl<T> SpecSerializer for BundledSpecs<T> {
280 type SVal = T;
281
282 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
283 (self.3)(v)
284 }
285}
286
287impl<T> SpecSerializerDps for BundledSpecs<T> {
288 type SValue = T;
289
290 open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
291 (self.4)(v, obuf)
292 }
293}
294
295impl<T> SafeParser for BundledSpecs<T> {
296 open spec fn safe_inv(&self) -> bool {
297 parser_specs(*self).safe_inv()
298 }
299
300 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
301 parser_specs(*self).lemma_parse_safe(ibuf);
302 }
303}
304
305impl<T> SoundParser for BundledSpecs<T> {
306 open spec fn sound_inv(&self) -> bool {
307 parser_specs(*self).sound_inv()
308 }
309
310 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
311 parser_specs(*self).lemma_parse_sound_consumption(ibuf);
312 }
313
314 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
315 parser_specs(*self).lemma_parse_sound_value(ibuf);
316 }
317}
318
319impl<T> Productive for BundledSpecs<T> {
320 open spec fn productive_inv(&self) -> bool {
321 parser_specs(*self).productive_inv()
322 }
323
324 proof fn lemma_productive(&self, ibuf: Seq<u8>) {
325 parser_specs(*self).lemma_productive(ibuf);
326 }
327}
328
329impl<T> GoodSerializer for BundledSpecs<T> {
330 open spec fn serialize_inv(&self) -> bool {
331 serializer_specs(*self).serialize_inv()
332 }
333
334 proof fn lemma_serialize_len(&self, v: Self::SVal) {
335 serializer_specs(*self).lemma_serialize_len(v);
336 }
337}
338
339impl<T> NonTailFmt for BundledSpecs<T> {
340 open spec fn serialize_dps_inv(&self) -> bool {
341 let (_, b, _, _, s_dps) = *self;
342 non_tail_fmt_dps(s_dps, b)
343 }
344
345 proof fn lemma_serialize_dps_prepend(&self, v: Self::SValue, obuf: Seq<u8>) {
346 let (_, b, _, _, s_dps) = *self;
347 let witness = choose|w: Seq<u8>| (s_dps)(v, obuf) == w + obuf;
348 assert((s_dps)(v, obuf) == witness + obuf);
349 }
350
351 proof fn lemma_serialize_dps_len(&self, v: Self::SValue, obuf: Seq<u8>) {
352 let (_, b, _, _, s_dps) = *self;
353 assert((s_dps)(v, obuf).len() - obuf.len() == (b)(v));
354 }
355}
356
357pub trait SpecRecBody {
359 type Param;
360
361 type T;
362
363 type Body: SpecCombinator<T = Self::T>;
364
365 spec fn spec_body(
368 &self,
369 param: Self::Param,
370 rec: ParamRecSpecs<Self::Param, Self::T>,
371 ) -> Self::Body;
372}
373
374pub trait SafeParserRecBody: SpecRecBody where Self::Body: SafeParser {
376 proof fn lemma_body_safe_inv_preservation(
377 &self,
378 param: Self::Param,
379 rec: ParamRecSpecs<Self::Param, Self::T>,
380 )
381 requires
382 forall|p: Self::Param| #![trigger rec(p)] rec(p).safe_inv(),
383 ensures
384 self.spec_body(param, rec).safe_inv(),
385 ;
386}
387
388pub trait SoundParserRecBody: SpecRecBody where Self::Body: SoundParser {
390 proof fn lemma_body_sound_inv_preservation(
391 &self,
392 param: Self::Param,
393 rec: ParamRecSpecs<Self::Param, Self::T>,
394 )
395 requires
396 forall|p: Self::Param| #![trigger rec(p)] rec(p).sound_inv(),
397 ensures
398 self.spec_body(param, rec).sound_inv(),
399 ;
400}
401
402pub trait ProductiveRecBody: SafeParserRecBody where Self::Body: Productive {
404 proof fn lemma_body_productive_inv_preservation(
405 &self,
406 param: Self::Param,
407 rec: ParamRecSpecs<Self::Param, Self::T>,
408 )
409 requires
410 forall|p: Self::Param| #![trigger rec(p)] rec(p).safe_inv(),
411 forall|p: Self::Param| #![trigger rec(p)] rec(p).productive_inv(),
412 ensures
413 self.spec_body(param, rec).productive_inv(),
414 ;
415}
416
417pub trait GoodSerializerRecBody: SpecRecBody where Self::Body: GoodSerializer {
419 proof fn lemma_s_body_serialize_inv_preservation(
420 &self,
421 param: Self::Param,
422 rec: ParamRecSpecs<Self::Param, Self::T>,
423 )
424 requires
425 forall|p: Self::Param| #![trigger rec(p)] rec(p).serialize_inv(),
426 ensures
427 self.spec_body(param, rec).serialize_inv(),
428 ;
429}
430
431pub trait NonTailFmtRecBody: SpecRecBody where Self::Body: NonTailFmt {
433 proof fn lemma_s_body_dps_serialize_dps_inv_preservation(
434 &self,
435 param: Self::Param,
436 rec: ParamRecSpecs<Self::Param, Self::T>,
437 )
438 requires
439 forall|p: Self::Param| #![trigger rec(p)] rec(p).serialize_dps_inv(),
440 ensures
441 self.spec_body(param, rec).serialize_dps_inv(),
442 ;
443}
444
445impl<const LIMIT: usize, Body, Param> SpecByteLen for super::FixWith<LIMIT, Body, Param> where
446 Body: SpecRecBody,
447 Param: DeepView<V = Body::Param>,
448 {
449 type T = Body::T;
450
451 open spec fn byte_len(&self, v: Self::T) -> nat {
452 Self::byte_len_gas(&self.0, LIMIT as nat, self.1.deep_view(), v)
453 }
454}
455
456impl<const LIMIT: usize, Body, Param> Consistency for super::FixWith<LIMIT, Body, Param> where
457 Body: SpecRecBody,
458 Param: DeepView<V = Body::Param>,
459 {
460 type Val = Body::T;
461
462 open spec fn consistent(&self, v: Self::Val) -> bool {
463 Self::consistent_gas(&self.0, LIMIT as nat, self.1.deep_view(), v)
464 }
465}
466
467impl<const LIMIT: usize, Body, Param> SpecParser for super::FixWith<LIMIT, Body, Param> where
468 Body: SpecRecBody,
469 Param: DeepView<V = Body::Param>,
470 {
471 type PVal = Body::T;
472
473 open spec fn spec_parse(&self, input: Seq<u8>) -> Option<(int, Self::PVal)> {
474 Self::spec_parse_gas(&self.0, LIMIT as nat, self.1.deep_view(), input)
475 }
476}
477
478impl<const LIMIT: usize, Body, Param> SpecSerializer for super::FixWith<LIMIT, Body, Param> where
479 Body: SpecRecBody,
480 Param: DeepView<V = Body::Param>,
481 {
482 type SVal = Body::T;
483
484 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
485 Self::spec_serialize_gas(&self.0, LIMIT as nat, self.1.deep_view(), v)
486 }
487}
488
489impl<const LIMIT: usize, Body, Param> SpecSerializerDps for super::FixWith<
490 LIMIT,
491 Body,
492 Param,
493> where Body: SpecRecBody, Param: DeepView<V = Body::Param> {
494 type SValue = Body::T;
495
496 open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
497 Self::spec_serialize_dps_gas(&self.0, LIMIT as nat, self.1.deep_view(), v, obuf)
498 }
499}
500
501impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
502 Body: SpecRecBody,
503 Param: DeepView<V = Body::Param>,
504 {
505 pub open spec fn byte_len_gas(body: &Body, gas: nat, param: Body::Param, v: Body::T) -> nat
506 decreases gas, 2nat,
507 {
508 body.spec_body(param, Self::specs_callback(&body, gas)).byte_len(v)
509 }
510
511 pub open spec fn consistent_gas(body: &Body, gas: nat, param: Body::Param, v: Body::T) -> bool
512 decreases gas, 2nat,
513 {
514 body.spec_body(param, Self::specs_callback(&body, gas)).consistent(v)
515 }
516
517 pub open spec fn spec_parse_gas(
518 body: &Body,
519 gas: nat,
520 param: Body::Param,
521 input: Seq<u8>,
522 ) -> Option<(int, Body::T)>
523 decreases gas, 2nat,
524 {
525 body.spec_body(param, Self::specs_callback(&body, gas)).spec_parse(input)
526 }
527
528 pub open spec fn spec_serialize_gas(
529 body: &Body,
530 gas: nat,
531 param: Body::Param,
532 v: Body::T,
533 ) -> Seq<u8>
534 decreases gas, 2nat,
535 {
536 body.spec_body(param, Self::specs_callback(&body, gas)).spec_serialize(v)
537 }
538
539 pub open spec fn spec_serialize_dps_gas(
540 body: &Body,
541 gas: nat,
542 param: Body::Param,
543 v: Body::T,
544 obuf: Seq<u8>,
545 ) -> Seq<u8>
546 decreases gas, 2nat,
547 {
548 body.spec_body(param, Self::specs_callback(&body, gas)).spec_serialize_dps(v, obuf)
549 }
550
551 pub open spec fn spec_parse_callback(body: &Body, gas: nat, param: Body::Param) -> ParserFnSpec<
552 Body::T,
553 >
554 decreases gas, 0nat,
555 {
556 |ibuf: Seq<u8>|
557 if gas > 0 {
558 Self::spec_parse_gas(body, (gas - 1) as nat, param, ibuf)
559 } else {
560 None
561 }
562 }
563
564 pub open spec fn consistent_callback(body: &Body, gas: nat, param: Body::Param) -> PredFnSpec<
565 Body::T,
566 >
567 decreases gas, 0nat,
568 {
569 |vv: Body::T|
570 if gas > 0 {
571 Self::consistent_gas(body, (gas - 1) as nat, param, vv)
572 } else {
573 false
574 }
575 }
576
577 pub open spec fn byte_len_callback(body: &Body, gas: nat, param: Body::Param) -> ByteLenFnSpec<
578 Body::T,
579 >
580 decreases gas, 0nat,
581 {
582 |vv: Body::T|
583 if gas > 0 {
584 Self::byte_len_gas(body, (gas - 1) as nat, param, vv)
585 } else {
586 0
587 }
588 }
589
590 pub open spec fn spec_serialize_callback(
591 body: &Body,
592 gas: nat,
593 param: Body::Param,
594 ) -> SerializerFnSpec<Body::T>
595 decreases gas, 0nat,
596 {
597 |vv: Body::T|
598 if gas > 0 {
599 Self::spec_serialize_gas(body, (gas - 1) as nat, param, vv)
600 } else {
601 Seq::empty()
602 }
603 }
604
605 pub open spec fn spec_serialize_dps_callback(
606 body: &Body,
607 gas: nat,
608 param: Body::Param,
609 ) -> SerializerDPSFnSpec<Body::T>
610 decreases gas, 0nat,
611 {
612 |vv: Body::T, obuf: Seq<u8>|
613 if gas > 0 {
614 Self::spec_serialize_dps_gas(body, (gas - 1) as nat, param, vv, obuf)
615 } else {
616 obuf
617 }
618 }
619
620 pub open spec fn specs_callback(body: &Body, gas: nat) -> ParamRecSpecs<Body::Param, Body::T>
622 decreases gas, 1nat,
623 {
624 |param: Body::Param|
625 (
626 Self::consistent_callback(&body, gas, param),
627 Self::byte_len_callback(&body, gas, param),
628 Self::spec_parse_callback(&body, gas, param),
629 Self::spec_serialize_callback(&body, gas, param),
630 Self::spec_serialize_dps_callback(&body, gas, param),
631 )
632 }
633}
634
635impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
636 Body: SafeParserRecBody,
637 Body::Body: SafeParser,
638 Param: DeepView<V = Body::Param>,
639 {
640 pub proof fn lemma_specs_callback_safe_inv(&self, gas: nat, param: Body::Param)
641 ensures
642 Self::specs_callback(&self.0, gas)(param).safe_inv(),
643 decreases gas,
644 {
645 let callback = Self::specs_callback(&self.0, gas);
646
647 assert forall|p: Body::Param, input: Seq<u8>| #[trigger]
648 callback(p).2(input) matches Some((n, _v)) ==> 0 <= n <= input.len() by {
649 if let Some((n, v)) = callback(p).2(input) {
650 self.safe_parser_by_induction((gas - 1) as nat, p, input, n, v);
651 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, p, input) == Some((n, v)));
652 }
653 }
654
655 assert(callback(param).safe_inv());
656 }
657
658 pub(crate) proof fn safe_parser_by_induction(
660 &self,
661 gas: nat,
662 param: Body::Param,
663 input: Seq<u8>,
664 n: int,
665 v: Body::T,
666 )
667 ensures
668 Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v)) ==> 0 <= n
669 <= input.len(),
670 decreases gas,
671 {
672 if !(Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v))) {
673 return;
674 }
675 let callback = Self::specs_callback(&self.0, gas);
676 let callback_p = callback(param).2;
677
678 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
679 callback(p).2(rem) matches Some((nn, _vv)) ==> 0 <= nn <= rem.len() by {
680 if let Some((nn, vv)) = callback(p).2(rem) {
681 self.safe_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
682 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, p, rem) == Some((nn, vv)));
683 assert(0 <= nn <= rem.len());
684 }
685 }
686
687 assert forall|p: Body::Param| #[trigger] callback(p).safe_inv() by {
688 assert(safe_parser(callback(p).2));
689 }
690
691 self.0.lemma_body_safe_inv_preservation(param, callback);
692 let body = self.0.spec_body(param, callback);
693 body.lemma_parse_safe(input);
694
695 assert(Self::spec_parse_gas(&self.0, gas, param, input) == body.spec_parse(input));
696 }
697}
698
699impl<const LIMIT: usize, Body, Param> SafeParser for super::FixWith<LIMIT, Body, Param> where
700 Body: SafeParserRecBody,
701 Body::Body: SafeParser,
702 Param: DeepView<V = Body::Param>,
703 {
704 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
705 if let Some((n, v)) = self.spec_parse(ibuf) {
706 self.safe_parser_by_induction(LIMIT as nat, self.1.deep_view(), ibuf, n, v);
707 }
708 }
709}
710
711impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
712 Body: SoundParserRecBody,
713 Body::Body: SoundParser,
714 Param: DeepView<V = Body::Param>,
715 {
716 pub proof fn sound_parser_by_induction(
718 &self,
719 gas: nat,
720 param: Body::Param,
721 input: Seq<u8>,
722 n: int,
723 v: Body::T,
724 )
725 ensures
726 Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v)) ==> {
727 &&& Self::consistent_gas(&self.0, gas, param, v)
728 &&& Self::byte_len_gas(&self.0, gas, param, v) == n
729 },
730 decreases gas,
731 {
732 if !(Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v))) {
733 return;
734 }
735 let callback = Self::specs_callback(&self.0, gas);
736 let callback_p = callback(param).2;
737 let callback_c = callback(param).0;
738 let callback_b = callback(param).1;
739
740 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
741 callback(p).2(rem) matches Some((nn, vv)) ==> {
742 &&& callback(p).0(vv)
743 &&& callback(p).1(vv) == nn
744 } by {
745 if let Some((nn, vv)) = callback(p).2(rem) {
746 self.sound_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
747 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, p, rem) == Some((nn, vv)));
748 assert(Self::consistent_gas(&self.0, (gas - 1) as nat, p, vv) == callback(p).0(vv));
749 assert(Self::byte_len_gas(&self.0, (gas - 1) as nat, p, vv) == callback(p).1(vv));
750 assert(callback(p).0(vv));
751 assert(callback(p).1(vv) == nn);
752 }
753 }
754
755 assert forall|p: Body::Param| #[trigger] callback(p).sound_inv() by {
756 assert(sound_parser(callback(p).2, callback(p).0, callback(p).1));
757 }
758
759 self.0.lemma_body_sound_inv_preservation(param, callback);
760 let body = self.0.spec_body(param, callback);
761
762 body.lemma_parse_sound_consumption(input);
763 body.lemma_parse_sound_value(input);
764
765 assert(Self::spec_parse_gas(&self.0, gas, param, input) == body.spec_parse(input));
766 assert(Self::consistent_gas(&self.0, gas, param, v) == body.consistent(v));
767 assert(Self::byte_len_gas(&self.0, gas, param, v) == body.byte_len(v));
768 }
769}
770
771impl<const LIMIT: usize, Body, Param> SoundParser for super::FixWith<LIMIT, Body, Param> where
772 Body: SoundParserRecBody,
773 Body::Body: SoundParser,
774 Param: DeepView<V = Body::Param>,
775 {
776 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
777 if let Some((n, v)) = self.spec_parse(ibuf) {
778 self.sound_parser_by_induction(LIMIT as nat, self.1.deep_view(), ibuf, n, v);
779 }
780 }
781
782 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
783 if let Some((n, v)) = self.spec_parse(ibuf) {
784 self.sound_parser_by_induction(LIMIT as nat, self.1.deep_view(), ibuf, n, v);
785 }
786 }
787}
788
789impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
790 Body: ProductiveRecBody,
791 Body::Body: Productive,
792 Param: DeepView<V = Body::Param>,
793 {
794 pub proof fn lemma_specs_callback_productive_inv(&self, gas: nat, param: Body::Param)
796 ensures
797 Self::specs_callback(&self.0, gas)(param).productive_inv(),
798 decreases gas,
799 {
800 let callback = Self::specs_callback(&self.0, gas);
801
802 assert forall|input: Seq<u8>| #[trigger]
803 callback(param).2(input) matches Some((n, _v)) ==> n > 0 by {
804 if let Some((n, v)) = callback(param).2(input) {
805 self.productive_by_induction((gas - 1) as nat, param, input, n, v);
806 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, param, input) == Some(
807 (n, v),
808 ));
809 }
810 }
811
812 assert(callback(param).productive_inv());
813 }
814
815 pub(crate) proof fn productive_by_induction(
817 &self,
818 gas: nat,
819 param: Body::Param,
820 input: Seq<u8>,
821 n: int,
822 v: Body::T,
823 )
824 ensures
825 Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v)) ==> n > 0,
826 decreases gas,
827 {
828 if !(Self::spec_parse_gas(&self.0, gas, param, input) == Some((n, v))) {
829 return;
830 }
831 let callback = Self::specs_callback(&self.0, gas);
832
833 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
834 callback(p).2(rem) matches Some((nn, _vv)) ==> 0 <= nn <= rem.len() by {
835 if let Some((nn, vv)) = callback(p).2(rem) {
836 self.safe_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
837 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, p, rem) == Some((nn, vv)));
838 assert(0 <= nn <= rem.len());
839 }
840 }
841
842 assert forall|p: Body::Param| #[trigger] callback(p).safe_inv() by {
843 assert(safe_parser(callback(p).2));
844 }
845
846 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
847 callback(p).2(rem) matches Some((nn, _vv)) ==> nn > 0 by {
848 if let Some((nn, vv)) = callback(p).2(rem) {
849 self.productive_by_induction((gas - 1) as nat, p, rem, nn, vv);
850 assert(Self::spec_parse_gas(&self.0, (gas - 1) as nat, p, rem) == Some((nn, vv)));
851 assert(nn > 0);
852 }
853 }
854
855 assert forall|p: Body::Param| #[trigger] callback(p).productive_inv() by {
856 assert(productive_parser(callback(p).2));
857 }
858
859 self.0.lemma_body_safe_inv_preservation(param, callback);
860 self.0.lemma_body_productive_inv_preservation(param, callback);
861
862 let body = self.0.spec_body(param, callback);
863 body.lemma_parse_safe(input);
864 body.lemma_productive(input);
865
866 assert(Self::spec_parse_gas(&self.0, gas, param, input) == body.spec_parse(input));
867 }
868}
869
870impl<const LIMIT: usize, Body, Param> Productive for super::FixWith<LIMIT, Body, Param> where
871 Body: ProductiveRecBody,
872 Body::Body: Productive,
873 Param: DeepView<V = Body::Param>,
874 {
875 proof fn lemma_productive(&self, ibuf: Seq<u8>) {
876 if let Some((n, v)) = self.spec_parse(ibuf) {
877 self.productive_by_induction(LIMIT as nat, self.1.deep_view(), ibuf, n, v);
878 }
879 }
880}
881
882impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
883 Body: GoodSerializerRecBody,
884 Body::Body: GoodSerializer,
885 Param: DeepView<V = Body::Param>,
886 {
887 proof fn good_serializer_by_induction(&self, gas: nat, param: Body::Param, v: Body::T)
889 ensures
890 Self::spec_serialize_gas(&self.0, gas, param, v).len() == Self::byte_len_gas(
891 &self.0,
892 gas,
893 param,
894 v,
895 ),
896 decreases gas,
897 {
898 let callback = Self::specs_callback(&self.0, gas);
899
900 assert forall|p: Body::Param, vv: Body::T| #[trigger]
901 callback(p).3(vv).len() == callback(p).1(vv) by {
902 if gas > 0 {
903 self.good_serializer_by_induction((gas - 1) as nat, p, vv);
904 }
905 }
906
907 assert forall|p: Body::Param| #[trigger] callback(p).serialize_inv() by {
908 assert(good_serializer_fn(callback(p).3, callback(p).1));
909 }
910
911 self.0.lemma_s_body_serialize_inv_preservation(param, callback);
912 let body = self.0.spec_body(param, callback);
913
914 body.lemma_serialize_len(v);
915
916 assert(Self::spec_serialize_gas(&self.0, gas, param, v) == body.spec_serialize(v));
917 assert(Self::byte_len_gas(&self.0, gas, param, v) == body.byte_len(v));
918 }
919}
920
921impl<const LIMIT: usize, Body, Param> GoodSerializer for super::FixWith<LIMIT, Body, Param> where
922 Body: GoodSerializerRecBody,
923 Body::Body: GoodSerializer,
924 Param: DeepView<V = Body::Param>,
925 {
926 proof fn lemma_serialize_len(&self, v: Self::SVal) {
927 self.good_serializer_by_induction(LIMIT as nat, self.1.deep_view(), v);
928 }
929}
930
931impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
932 Body: NonTailFmtRecBody,
933 Body::Body: NonTailFmt,
934 Param: DeepView<V = Body::Param>,
935 {
936 pub(crate) proof fn nontail_dps_by_induction(
938 &self,
939 gas: nat,
940 param: Body::Param,
941 v: Body::T,
942 obuf: Seq<u8>,
943 )
944 ensures
945 exists|new_buf: Seq<u8>|
946 (#[trigger] Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf) == new_buf
947 + obuf),
948 Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf).len() - obuf.len()
949 == Self::byte_len_gas(&self.0, gas, param, v),
950 decreases gas, 1nat,
951 {
952 let callback = Self::specs_callback(&self.0, gas);
953
954 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>| #[trigger]
955 callback(p).4(vv, buf).len() - buf.len() == callback(p).1(vv) by {
956 if gas > 0 {
957 self.nontail_dps_by_induction((gas - 1) as nat, p, vv, buf);
958 }
959 }
960
961 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>|
962 exists|new_buf: Seq<u8>| (#[trigger] callback(p).4(vv, buf)) == new_buf + buf by {
963 if gas > 0 {
964 self.nontail_dps_by_induction((gas - 1) as nat, p, vv, buf);
965 let witness = choose|w: Seq<u8>|
966 Self::spec_serialize_dps_gas(&self.0, (gas - 1) as nat, p, vv, buf) == w + buf;
967 assert(callback(p).4(vv, buf) == witness + buf);
968 } else {
969 assert(callback(p).4(vv, buf) == Seq::<u8>::empty() + buf);
970 }
971 }
972
973 assert forall|p: Body::Param| #[trigger] callback(p).serialize_dps_inv() by {
974 assert(non_tail_fmt_dps(callback(p).4, callback(p).1));
975 }
976 self.0.lemma_s_body_dps_serialize_dps_inv_preservation(param, callback);
977 let body = self.0.spec_body(param, callback);
978
979 body.lemma_serialize_dps_prepend(v, obuf);
980 body.lemma_serialize_dps_len(v, obuf);
981
982 assert(Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf)
983 == body.spec_serialize_dps(v, obuf));
984 assert(Self::byte_len_gas(&self.0, gas, param, v) == body.byte_len(v));
985 }
986}
987
988impl<const LIMIT: usize, Body, Param> NonTailFmt for super::FixWith<LIMIT, Body, Param> where
989 Body: NonTailFmtRecBody,
990 Body::Body: NonTailFmt,
991 Param: DeepView<V = Body::Param>,
992 {
993 proof fn lemma_serialize_dps_prepend(&self, v: Self::SValue, obuf: Seq<u8>) {
994 self.nontail_dps_by_induction(LIMIT as nat, self.1.deep_view(), v, obuf);
995 }
996
997 proof fn lemma_serialize_dps_len(&self, v: Self::SValue, obuf: Seq<u8>) {
998 self.nontail_dps_by_induction(LIMIT as nat, self.1.deep_view(), v, obuf);
999 }
1000}
1001
1002}