1use super::spec::*;
3use crate::core::{proof::*, spec::*};
4use vstd::prelude::*;
5
6verus! {
7
8pub open spec fn sp_roundtrip_dps<T>(
10 parser: ParserFnSpec<T>,
11 consistent: PredFnSpec<T>,
12 byte_len: ByteLenFnSpec<T>,
13 serializer_dps: SerializerDPSFnSpec<T>,
14) -> bool {
15 forall|v: T, obuf: Seq<u8>|
16 consistent(v) ==> #[trigger] parser(serializer_dps(v, obuf)) == Some(
17 (byte_len(v) as int, v),
18 )
19}
20
21pub open spec fn no_lookahead_parser<T>(parser: ParserFnSpec<T>) -> bool {
23 forall|i1: Seq<u8>, i2: Seq<u8>|
24 (#[trigger] parser(i1) matches Some((n, v)) ==> 0 <= n <= i2.len() ==> i2.take(n)
25 == i1.take(n) ==> #[trigger] parser(i2) == Some((n, v)))
26}
27
28pub open spec fn parser_pair_some<T>(
29 parser: ParserFnSpec<T>,
30 buf1: Seq<u8>,
31 buf2: Seq<u8>,
32) -> Option<((int, T), (int, T))> {
33 match parser(buf1) {
34 Some((n1, v1)) => match parser(buf2) {
35 Some((n2, v2)) => Some(((n1, v1), (n2, v2))),
36 None => None,
37 },
38 None => None,
39 }
40}
41
42pub open spec fn non_malleable_parser<T>(parser: ParserFnSpec<T>) -> bool {
44 forall|buf1: Seq<u8>, buf2: Seq<u8>| #[trigger]
45 parser_pair_some(parser, buf1, buf2) matches Some(((n1, v1), (n2, v2))) ==> v1 == v2
46 ==> buf1.take(n1) == buf2.take(n2)
47}
48
49impl<SpecP, Cnstcy, Blen> NonMalleable for ParserSpecs<SpecP, Cnstcy, Blen> where
50 Blen: SpecByteLen,
51 SpecP: SpecParser<PVal = Blen::T>,
52 Cnstcy: Consistency<Val = Blen::T>,
53 {
54 open spec fn nonmal_inv(&self) -> bool {
55 let (p, _, _) = *self;
56 let p_fn = |ibuf| p.spec_parse(ibuf);
57 non_malleable_parser(p_fn)
58 }
59
60 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
61 let (p, _, _) = *self;
62 let p_fn = |ibuf| p.spec_parse(ibuf);
63 if let Some((n1, v1)) = self.spec_parse(buf1) {
64 if let Some((n2, v2)) = self.spec_parse(buf2) {
65 if v1 == v2 {
66 assert(self.nonmal_inv());
67 assert(parser_pair_some(p_fn, buf1, buf2) == Some(((n1, v1), (n2, v2))));
68 assert(non_malleable_parser(p_fn));
69 assert(buf1.take(n1) == buf2.take(n2));
70 }
71 }
72 }
73 }
74}
75
76impl<T> NonMalleable for BundledSpecs<T> {
77 open spec fn nonmal_inv(&self) -> bool {
78 parser_specs(*self).nonmal_inv()
79 }
80
81 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
82 parser_specs(*self).lemma_parse_non_malleable(buf1, buf2);
83 }
84}
85
86impl<T> SPRoundTripDps for BundledSpecs<T> {
87 open spec fn unambiguous(&self) -> bool {
88 let (c, b, p, _, s_dps) = *self;
89 sp_roundtrip_dps(p, c, b, s_dps)
90 }
91
92 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
93 let (c, b, p, _, s_dps) = *self;
94 assert(sp_roundtrip_dps(p, c, b, s_dps));
95 assert(c(v));
96 assert(p(s_dps(v, obuf)) == Some(((b)(v) as int, v)));
97 }
98}
99
100impl<T> NoLookAhead for BundledSpecs<T> {
101 open spec fn no_lookahead_inv(&self) -> bool {
102 let (_, _, p, _, _) = *self;
103 no_lookahead_parser(p)
104 }
105
106 proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>) {
107 let (_, _, p, _, _) = *self;
108 if let Some((n, v)) = self.spec_parse(i1) {
109 if 0 <= n <= i2.len() {
110 if i2.take(n) == i1.take(n) {
111 assert(no_lookahead_parser(p));
112 assert(p(i1) == Some((n, v)));
113 assert(p(i2) == Some((n, v)));
114 }
115 }
116 }
117 }
118}
119
120impl<T> EquivSerializersGeneral for BundledSpecs<T> {
121 open spec fn equiv_general_inv(&self) -> bool {
122 let (_, _, _, s, s_dps) = *self;
123 forall|v: T, obuf: Seq<u8>| #[trigger] (s_dps)(v, obuf) == (s)(v) + obuf
124 }
125
126 proof fn lemma_serialize_equiv(&self, v: Self::SVal, obuf: Seq<u8>) {
127 let (_, _, _, s, s_dps) = *self;
128 assert((s_dps)(v, obuf) == (s)(v) + obuf);
129 }
130}
131
132impl<T> EquivSerializers for BundledSpecs<T> {
133 open spec fn equiv_inv(&self) -> bool {
134 let (_, _, _, s, s_dps) = *self;
135 forall|v: T| #[trigger] (s_dps)(v, seq![]) == (s)(v) + seq![]
136 }
137
138 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
139 let (_, _, _, s, s_dps) = *self;
140 assert((s_dps)(v, seq![]) == (s)(v) + seq![]);
141 }
142}
143
144pub trait NonMalleableRecBody: SafeParserRecBody + SoundParserRecBody where
146 Self::Body: NonMalleable + SoundParser,
147 {
148 proof fn lemma_body_nonmal_inv_preservation(
149 &self,
150 param: Self::Param,
151 rec: ParamRecSpecs<Self::Param, Self::T>,
152 )
153 requires
154 forall|p: Self::Param| #![trigger rec(p)] rec(p).safe_inv(),
155 forall|p: Self::Param| #![trigger rec(p)] rec(p).sound_inv(),
156 forall|p: Self::Param| #![trigger rec(p)] rec(p).nonmal_inv(),
157 ensures
158 self.spec_body(param, rec).nonmal_inv(),
159 ;
160}
161
162pub trait SPRoundTripDpsRecBody: NonTailFmtRecBody where Self::Body: SPRoundTripDps + NonTailFmt {
165 proof fn lemma_body_sp_roundtrip_dps_inv_preservation(
166 &self,
167 param: Self::Param,
168 rec: ParamRecSpecs<Self::Param, Self::T>,
169 )
170 requires
171 forall|p: Self::Param| #![trigger rec(p)] rec(p).unambiguous(),
172 forall|p: Self::Param| #![trigger rec(p)] rec(p).serialize_dps_inv(),
173 ensures
174 self.spec_body(param, rec).unambiguous(),
175 ;
176}
177
178pub trait NoLookAheadRecBody: SafeParserRecBody where Self::Body: NoLookAhead {
180 proof fn lemma_body_no_lookahead_inv_preservation(
181 &self,
182 param: Self::Param,
183 rec: ParamRecSpecs<Self::Param, Self::T>,
184 )
185 requires
186 forall|p: Self::Param| #![trigger rec(p)] rec(p).no_lookahead_inv(),
187 ensures
188 self.spec_body(param, rec).no_lookahead_inv(),
189 ;
190}
191
192pub trait EquivSerializersGeneralRecBody: SpecRecBody where Self::Body: EquivSerializersGeneral {
194 proof fn lemma_s_body_equiv_general_inv_preservation(
195 &self,
196 param: Self::Param,
197 rec: ParamRecSpecs<Self::Param, Self::T>,
198 )
199 requires
200 forall|p: Self::Param| #![trigger rec(p)] rec(p).equiv_general_inv(),
201 ensures
202 self.spec_body(param, rec).equiv_general_inv(),
203 ;
204}
205
206pub trait StrictRecBody: SpecRecBody where Self::Body: StrictCombinator {
210 #[verusfmt::skip]
211 proof fn lemma_body_all_inv_preservation(
212 &self,
213 param: Self::Param,
214 rec: ParamRecSpecs<Self::Param, Self::T>,
215 )
216 ensures
217 (forall|p: Self::Param| #![trigger rec(p)] rec(p).safe_inv())
218 ==> self.spec_body(param, rec).safe_inv(),
219
220 (forall|p: Self::Param| #![trigger rec(p)] rec(p).productive_inv())
221 ==> self.spec_body(param, rec).productive_inv(),
222
223 (forall|p: Self::Param| #![trigger rec(p)] rec(p).sound_inv())
224 ==> self.spec_body(param, rec).sound_inv(),
225
226 (forall|p: Self::Param| #![trigger rec(p)] rec(p).safe_inv())
227 && (forall|p: Self::Param| #![trigger rec(p)] rec(p).sound_inv())
228 && (forall|p: Self::Param| #![trigger rec(p)] rec(p).nonmal_inv())
229 ==> self.spec_body(param, rec).nonmal_inv(),
230
231 (forall|p: Self::Param| #![trigger rec(p)] rec(p).serialize_inv())
232 ==> self.spec_body(param, rec).serialize_inv(),
233
234 (forall|p: Self::Param| #![trigger rec(p)] rec(p).serialize_dps_inv())
235 ==> self.spec_body(param, rec).serialize_dps_inv(),
236
237 (forall|p: Self::Param| #![trigger rec(p)] rec(p).unambiguous())
238 && (forall| p: Self::Param| #![trigger rec(p)] rec(p).serialize_dps_inv())
239 ==> self.spec_body(param, rec).unambiguous(),
240
241 (forall|p: Self::Param| #![trigger rec(p)] rec(p).equiv_general_inv())
242 ==> self.spec_body(param, rec).equiv_general_inv(),
243 ;
244}
245
246impl<Body: StrictRecBody> SafeParserRecBody for Body where Body::Body: StrictCombinator {
247 proof fn lemma_body_safe_inv_preservation(
248 &self,
249 param: Self::Param,
250 rec: ParamRecSpecs<Self::Param, Self::T>,
251 ) {
252 self.lemma_body_all_inv_preservation(param, rec);
253 assert(self.spec_body(param, rec).safe_inv());
254 }
255}
256
257impl<Body: StrictRecBody> ProductiveRecBody for Body where Body::Body: StrictCombinator {
258 proof fn lemma_body_productive_inv_preservation(
259 &self,
260 param: Self::Param,
261 rec: ParamRecSpecs<Self::Param, Self::T>,
262 ) {
263 self.lemma_body_all_inv_preservation(param, rec);
264 assert(self.spec_body(param, rec).productive_inv());
265 }
266}
267
268impl<Body: StrictRecBody> SoundParserRecBody for Body where Body::Body: StrictCombinator {
269 proof fn lemma_body_sound_inv_preservation(
270 &self,
271 param: Self::Param,
272 rec: ParamRecSpecs<Self::Param, Self::T>,
273 ) {
274 self.lemma_body_all_inv_preservation(param, rec);
275 assert(self.spec_body(param, rec).sound_inv());
276 }
277}
278
279impl<Body: StrictRecBody> NonMalleableRecBody for Body where Body::Body: StrictCombinator {
280 proof fn lemma_body_nonmal_inv_preservation(
281 &self,
282 param: Self::Param,
283 rec: ParamRecSpecs<Self::Param, Self::T>,
284 ) {
285 self.lemma_body_all_inv_preservation(param, rec);
286 assert(self.spec_body(param, rec).nonmal_inv());
287 }
288}
289
290impl<Body: StrictRecBody> GoodSerializerRecBody for Body where Body::Body: StrictCombinator {
291 proof fn lemma_s_body_serialize_inv_preservation(
292 &self,
293 param: Self::Param,
294 rec: ParamRecSpecs<Self::Param, Self::T>,
295 ) {
296 self.lemma_body_all_inv_preservation(param, rec);
297 assert(self.spec_body(param, rec).serialize_inv());
298 }
299}
300
301impl<Body: StrictRecBody> NonTailFmtRecBody for Body where Body::Body: StrictCombinator {
302 proof fn lemma_s_body_dps_serialize_dps_inv_preservation(
303 &self,
304 param: Self::Param,
305 rec: ParamRecSpecs<Self::Param, Self::T>,
306 ) {
307 self.lemma_body_all_inv_preservation(param, rec);
308 assert(self.spec_body(param, rec).serialize_dps_inv());
309 }
310}
311
312impl<Body: StrictRecBody> SPRoundTripDpsRecBody for Body where Body::Body: StrictCombinator {
313 proof fn lemma_body_sp_roundtrip_dps_inv_preservation(
314 &self,
315 param: Self::Param,
316 rec: ParamRecSpecs<Self::Param, Self::T>,
317 ) {
318 self.lemma_body_all_inv_preservation(param, rec);
319 assert(self.spec_body(param, rec).unambiguous());
320 }
321}
322
323impl<Body: StrictRecBody> EquivSerializersGeneralRecBody for Body where
324 Body::Body: StrictCombinator,
325 {
326 proof fn lemma_s_body_equiv_general_inv_preservation(
327 &self,
328 param: Self::Param,
329 rec: ParamRecSpecs<Self::Param, Self::T>,
330 ) {
331 self.lemma_body_all_inv_preservation(param, rec);
332 assert(self.spec_body(param, rec).equiv_general_inv());
333 }
334}
335
336impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
337 Body: NonMalleableRecBody,
338 Body::Body: NonMalleable + SoundParser,
339 Param: DeepView<V = Body::Param>,
340 {
341 #[verusfmt::skip]
343 proof fn non_malleable_by_induction(
344 &self,
345 gas: nat,
346 param: Body::Param,
347 buf1: Seq<u8>,
348 buf2: Seq<u8>,
349 n1: int,
350 n2: int,
351 v1: Body::T,
352 v2: Body::T,
353 )
354 ensures
355 Self::spec_parse_gas(&self.0, gas, param, buf1) == Some((n1, v1)) ==>
356 Self::spec_parse_gas(&self.0, gas, param, buf2) == Some((n2, v2)) ==>
357 v1 == v2 ==> buf1.take(n1) == buf2.take(n2),
358 decreases gas,
359 {
360 if !(Self::spec_parse_gas(&self.0, gas, param, buf1) == Some((n1, v1))) {
361 return ;
362 }
363 if !(Self::spec_parse_gas(&self.0, gas, param, buf2) == Some((n2, v2))) {
364 return ;
365 }
366 if !(v1 == v2) {
367 return ;
368 }
369
370 let callback = Self::specs_callback(&self.0, gas);
371 let callback_p = callback(param).2;
372 let callback_c = callback(param).0;
373 let callback_b = callback(param).1;
374
375 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
376 callback(p).2(rem) matches Some((nn, _vv)) ==> 0 <= nn <= rem.len() by {
377 if let Some((nn, vv)) = callback(p).2(rem) {
378 self.safe_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
379 }
380 }
381
382 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
383 callback(p).2(rem) matches Some((nn, vv)) ==> {
384 &&& callback(p).0(vv)
385 &&& callback(p).1(vv) == nn
386 } by {
387 if let Some((nn, vv)) = callback(p).2(rem) {
388 self.sound_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
389 }
390 }
391
392 assert forall|p: Body::Param, rem1: Seq<u8>, rem2: Seq<u8>| #[trigger]
393 parser_pair_some(callback(p).2, rem1, rem2) matches Some(((nn1, vv1), (nn2, vv2)))
394 ==> vv1 == vv2 ==> rem1.take(nn1) == rem2.take(nn2) by {
395 if let Some(((nn1, vv1), (nn2, vv2))) = parser_pair_some(callback(p).2, rem1, rem2) {
396 if vv1 == vv2 {
397 self.non_malleable_by_induction((gas - 1) as nat, p, rem1, rem2, nn1, nn2, vv1, vv2);
398 }
399 }
400 }
401
402 assert forall|p: Body::Param| #[trigger] callback(p).safe_inv() by {
403 assert(callback(p).safe_inv());
404 }
405 assert forall|p: Body::Param| #[trigger] callback(p).sound_inv() by {
406 assert(callback(p).sound_inv());
407 }
408 assert forall|p: Body::Param| #[trigger] callback(p).nonmal_inv() by {
409 let p_fn = |ibuf: Seq<u8>| callback(p).2.spec_parse(ibuf);
410 assert(p_fn == callback(p).2);
411 assert(callback(p).nonmal_inv());
412 }
413
414 self.0.lemma_body_safe_inv_preservation(param, callback);
415 self.0.lemma_body_nonmal_inv_preservation(param, callback);
416 let body = self.0.spec_body(param, callback);
417
418 body.lemma_parse_non_malleable(buf1, buf2);
419
420 assert(Self::spec_parse_gas(&self.0, gas, param, buf1) == body.spec_parse(buf1));
421 assert(Self::spec_parse_gas(&self.0, gas, param, buf2) == body.spec_parse(buf2));
422 }
423}
424
425impl<const LIMIT: usize, Body, Param> NonMalleable for super::FixWith<LIMIT, Body, Param> where
426 Body: NonMalleableRecBody,
427 Body::Body: NonMalleable + SafeParser + SoundParser,
428 Param: DeepView<V = Body::Param>,
429 {
430 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
431 if let Some((n1, v1)) = self.spec_parse(buf1) {
432 if let Some((n2, v2)) = self.spec_parse(buf2) {
433 if v1 == v2 {
434 self.non_malleable_by_induction(
435 LIMIT as nat,
436 self.1.deep_view(),
437 buf1,
438 buf2,
439 n1,
440 n2,
441 v1,
442 v2,
443 );
444 }
445 }
446 }
447 }
448}
449
450impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
451 Body: SPRoundTripDpsRecBody + NonTailFmtRecBody,
452 Body::Body: SPRoundTripDps + NonTailFmt,
453 Param: DeepView<V = Body::Param>,
454 {
455 proof fn sp_roundtrip_dps_by_induction(
456 &self,
457 gas: nat,
458 param: Body::Param,
459 v: Body::T,
460 obuf: Seq<u8>,
461 )
462 requires
463 Self::consistent_gas(&self.0, gas, param, v),
464 ensures
465 Self::spec_parse_gas(
466 &self.0,
467 gas,
468 param,
469 Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf),
470 ) == Some((Self::byte_len_gas(&self.0, gas, param, v) as int, v)),
471 decreases gas,
472 {
473 let callback = Self::specs_callback(&self.0, gas);
474
475 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>|
476 (callback(p).0(vv)) implies #[trigger] callback(p).2(callback(p).4(vv, buf)) == Some(
477 (callback(p).1(vv) as int, vv),
478 ) by {
479 if callback(p).0(vv) {
480 self.sp_roundtrip_dps_by_induction((gas - 1) as nat, p, vv, buf);
481 }
482 }
483
484 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>| #[trigger]
485 callback(p).4(vv, buf).len() - buf.len() == callback(p).1(vv) by {
486 if gas > 0 {
487 self.nontail_dps_by_induction((gas - 1) as nat, p, vv, buf);
488 } else {
489 assert(callback(p).4(vv, buf) == buf);
490 assert(callback(p).1(vv) == 0);
491 }
492 }
493
494 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>|
495 exists|new_buf: Seq<u8>| (#[trigger] callback(p).4(vv, buf)) == new_buf + buf by {
496 if gas > 0 {
497 self.nontail_dps_by_induction((gas - 1) as nat, p, vv, buf);
498 let witness = choose|w: Seq<u8>|
499 Self::spec_serialize_dps_gas(&self.0, (gas - 1) as nat, p, vv, buf) == w + buf;
500 assert(callback(p).4(vv, buf) == witness + buf);
501 } else {
502 assert(callback(p).4(vv, buf) == Seq::<u8>::empty() + buf);
503 }
504 }
505
506 assert forall|p: Body::Param| #[trigger] callback(p).unambiguous() by {
507 assert(callback(p).unambiguous());
508 }
509 assert forall|p: Body::Param| #[trigger] callback(p).serialize_dps_inv() by {
510 assert(callback(p).serialize_dps_inv());
511 }
512
513 self.0.lemma_body_sp_roundtrip_dps_inv_preservation(param, callback);
514 let body = self.0.spec_body(param, callback);
515
516 assert(Self::consistent_gas(&self.0, gas, param, v) == body.consistent(v));
517
518 body.theorem_serialize_dps_parse_roundtrip(v, obuf);
519
520 assert(Self::spec_parse_gas(
521 &self.0,
522 gas,
523 param,
524 Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf),
525 ) == body.spec_parse(body.spec_serialize_dps(v, obuf)));
526 assert(Self::byte_len_gas(&self.0, gas, param, v) == body.byte_len(v));
527 }
528}
529
530impl<const LIMIT: usize, Body, Param> SPRoundTripDps for super::FixWith<LIMIT, Body, Param> where
531 Body: SPRoundTripDpsRecBody + NonTailFmtRecBody,
532 Body::Body: SPRoundTripDps + NonTailFmt,
533 Param: DeepView<V = Body::Param>,
534 {
535 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
536 self.sp_roundtrip_dps_by_induction(LIMIT as nat, self.1.deep_view(), v, obuf);
537 }
538}
539
540impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
541 Body: EquivSerializersGeneralRecBody,
542 Body::Body: EquivSerializersGeneral,
543 Param: DeepView<V = Body::Param>,
544 {
545 proof fn equiv_serializers_general_by_induction(
546 &self,
547 gas: nat,
548 param: Body::Param,
549 v: Body::T,
550 obuf: Seq<u8>,
551 )
552 ensures
553 Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf) == Self::spec_serialize_gas(
554 &self.0,
555 gas,
556 param,
557 v,
558 ) + obuf,
559 decreases gas,
560 {
561 let callback = Self::specs_callback(&self.0, gas);
562
563 assert forall|p: Body::Param, vv: Body::T, buf: Seq<u8>| #[trigger]
564 callback(p).4(vv, buf) == callback(p).3(vv) + buf by {
565 if gas > 0 {
566 self.equiv_serializers_general_by_induction((gas - 1) as nat, p, vv, buf);
567 } else {
568 assert(callback(p).4(vv, buf) == buf);
569 assert(callback(p).3(vv) == Seq::<u8>::empty());
570 assert(callback(p).4(vv, buf) == callback(p).3(vv) + buf);
571 }
572 }
573
574 assert forall|p: Body::Param| #[trigger] callback(p).equiv_general_inv() by {
575 assert(callback(p).equiv_general_inv());
576 }
577 self.0.lemma_s_body_equiv_general_inv_preservation(param, callback);
578 let body = self.0.spec_body(param, callback);
579
580 body.lemma_serialize_equiv(v, obuf);
581
582 assert(Self::spec_serialize_dps_gas(&self.0, gas, param, v, obuf)
583 == body.spec_serialize_dps(v, obuf));
584 assert(Self::spec_serialize_gas(&self.0, gas, param, v) == body.spec_serialize(v));
585 }
586}
587
588impl<const LIMIT: usize, Body, Param> EquivSerializersGeneral for super::FixWith<
589 LIMIT,
590 Body,
591 Param,
592> where
593 Body: EquivSerializersGeneralRecBody,
594 Body::Body: EquivSerializersGeneral,
595 Param: DeepView<V = Body::Param>,
596 {
597 proof fn lemma_serialize_equiv(&self, v: Self::SVal, obuf: Seq<u8>) {
598 self.equiv_serializers_general_by_induction(LIMIT as nat, self.1.deep_view(), v, obuf);
599 }
600}
601
602impl<const LIMIT: usize, Body, Param> EquivSerializers for super::FixWith<LIMIT, Body, Param> where
603 Body: EquivSerializersGeneralRecBody,
604 Body::Body: EquivSerializersGeneral,
605 Param: DeepView<V = Body::Param>,
606 {
607 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
608 self.lemma_serialize_equiv(v, Seq::empty());
609 }
610}
611
612impl<const LIMIT: usize, Body, Param> super::FixWith<LIMIT, Body, Param> where
613 Body: NoLookAheadRecBody,
614 Body::Body: NoLookAhead,
615 Param: DeepView<V = Body::Param>,
616 {
617 proof fn no_lookahead_by_induction(
618 &self,
619 gas: nat,
620 param: Body::Param,
621 i1: Seq<u8>,
622 i2: Seq<u8>,
623 n: int,
624 v: Body::T,
625 )
626 requires
627 Self::spec_parse_gas(&self.0, gas, param, i1) == Some((n, v)),
628 0 <= n <= i2.len(),
629 i2.take(n) == i1.take(n),
630 ensures
631 Self::spec_parse_gas(&self.0, gas, param, i2) == Some((n, v)),
632 decreases gas,
633 {
634 let callback = Self::specs_callback(&self.0, gas);
635
636 assert forall|p: Body::Param, rem: Seq<u8>| #[trigger]
637 callback(p).2(rem) matches Some((nn, _vv)) ==> 0 <= nn <= rem.len() by {
638 if let Some((nn, vv)) = callback(p).2(rem) {
639 self.safe_parser_by_induction((gas - 1) as nat, p, rem, nn, vv);
640 }
641 }
642
643 assert forall|p: Body::Param, j1: Seq<u8>, j2: Seq<u8>|
644 (#[trigger] callback(p).2(j1) matches Some((nn, vv)) ==> 0 <= nn <= j2.len()
645 ==> j2.take(nn) == j1.take(nn) ==> #[trigger] callback(p).2(j2) == Some(
646 (nn, vv),
647 )) by {
648 if let Some((nn, vv)) = callback(p).2(j1) {
649 if 0 <= nn && nn <= j2.len() && j2.take(nn) == j1.take(nn) {
650 self.no_lookahead_by_induction((gas - 1) as nat, p, j1, j2, nn, vv);
651 }
652 }
653 }
654
655 assert forall|p: Body::Param| #[trigger] callback(p).safe_inv() by {
656 assert(callback(p).safe_inv());
657 }
658 assert forall|p: Body::Param| #[trigger] callback(p).no_lookahead_inv() by {
659 assert(callback(p).no_lookahead_inv());
660 }
661
662 self.0.lemma_body_safe_inv_preservation(param, callback);
663 self.0.lemma_body_no_lookahead_inv_preservation(param, callback);
664 let body = self.0.spec_body(param, callback);
665
666 assert(Self::spec_parse_gas(&self.0, gas, param, i1) == body.spec_parse(i1));
667 assert(Self::spec_parse_gas(&self.0, gas, param, i2) == body.spec_parse(i2));
668
669 body.lemma_no_lookahead(i1, i2);
670
671 assert(body.spec_parse(i1) == Some((n, v)));
672 assert(body.spec_parse(i2) == Some((n, v)));
673 }
674}
675
676impl<const LIMIT: usize, Body, Param> NoLookAhead for super::FixWith<LIMIT, Body, Param> where
677 Body: NoLookAheadRecBody,
678 Body::Body: NoLookAhead,
679 Param: DeepView<V = Body::Param>,
680 {
681 proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>) {
682 if let Some((n, v)) = self.spec_parse(i1) {
683 if 0 <= n <= i2.len() {
684 if i2.take(n) == i1.take(n) {
685 self.no_lookahead_by_induction(LIMIT as nat, self.1.deep_view(), i1, i2, n, v);
686 }
687 }
688 }
689 }
690}
691
692}