1use super::leb128::*;
3use crate::combinators::disjoint::disjointness_lemmas;
4use crate::core::exec::output::*;
5use crate::core::exec::parser::*;
6use crate::{
7 combinators::mapped::spec::*,
8 combinators::*,
9 core::{exec::*, proof::*, spec::*},
10};
11#[cfg(feature = "alloc")]
12use alloc::{vec, vec::Vec};
13use input::InputBuf;
14use vstd::arithmetic::power::*;
15use vstd::calc;
16use vstd::prelude::*;
17
18verus! {
19
20pub open spec fn nat_from_base128(bytes: Seq<u8>) -> nat
22 decreases bytes.len(),
23{
24 if bytes.len() == 0 {
25 0
26 } else {
27 nat_from_base128(bytes.drop_last()) * 128 + (bytes.last() % 128) as nat
28 }
29}
30
31pub open spec fn nat_to_base128(n: nat) -> Seq<u8>
33 decreases n,
34{
35 if n < 128 {
36 seq![n as u8]
37 } else {
38 nat_to_base128((n / 128) as nat).push((n % 128) as u8)
39 }
40}
41
42pub proof fn lemma_from_base128_push(bytes: Seq<u8>, b: u8)
43 ensures
44 nat_from_base128(bytes.push(b)) == nat_from_base128(bytes) * 128 + (b % 128) as nat,
45{
46 assert(bytes.push(b).drop_last() == bytes);
47}
48
49pub proof fn lemma_pow128_succ(exp: nat)
50 ensures
51 pow(128, exp + 1) == pow(128, exp) * 128,
52{
53 lemma_pow_adds(128, exp, 1);
54 lemma_pow1(128);
55}
56
57pub proof fn lemma_from_base128_upper_bound(bytes: Seq<u8>)
58 ensures
59 nat_from_base128(bytes) < pow(128, bytes.len()),
60 decreases bytes.len(),
61{
62 if bytes.len() == 0 {
63 lemma_pow0(128);
64 } else {
65 let prefix = bytes.drop_last();
66 lemma_from_base128_upper_bound(prefix);
67 lemma_pow128_succ(prefix.len());
68 }
69}
70
71pub proof fn lemma_nat_from_base128_bounds(bytes: Seq<u8>)
72 ensures
73 bytes.len() <= 4 ==> nat_from_base128(bytes) <= u32::MAX,
74 bytes.len() <= 9 ==> nat_from_base128(bytes) <= u64::MAX,
75{
76 lemma_from_base128_upper_bound(bytes);
77 reveal_with_fuel(pow, 10);
78}
79
80pub proof fn lemma_to_base128_props(n: nat)
81 ensures
82 nat_to_base128(n).len() > 0,
83 n > 0 ==> nat_to_base128(n)[0] != 0,
84 n > 0 ==> pow(128, (nat_to_base128(n).len() - 1) as nat) <= n,
85 forall|i: int| 0 <= i < nat_to_base128(n).len() ==> #[trigger] nat_to_base128(n)[i] < 128,
86 decreases n,
87{
88 if n < 128 {
89 lemma_pow0(128);
90 } else {
91 let q = (n / 128) as nat;
92 lemma_to_base128_props(q);
93 lemma_pow128_succ((nat_to_base128(q).len() - 1) as nat);
94 assert(pow(128, (nat_to_base128(q).len() - 1) as nat) * 128 <= q * 128) by (nonlinear_arith)
95 requires
96 pow(128, (nat_to_base128(q).len() - 1) as nat) <= q,
97 ;
98 }
99}
100
101pub proof fn lemma_to_base128_len_bound(n: nat, max_len: nat)
102 requires
103 0 < max_len,
104 n < pow(128, max_len),
105 ensures
106 nat_to_base128(n).len() <= max_len,
107{
108 if n == 0 {
109 } else {
110 lemma_to_base128_props(n);
111 lemma_pow_strictly_increases_converse(128, (nat_to_base128(n).len() - 1) as nat, max_len);
112 }
113}
114
115pub proof fn lemma_to_base128_len_bounds()
116 ensures
117 forall|n: u32| #[trigger] nat_to_base128(n as nat).len() <= 5,
118 forall|n: u64| #[trigger] nat_to_base128(n as nat).len() <= 10,
119{
120 reveal_with_fuel(pow, 11);
121 assert forall|n: u32| #[trigger] nat_to_base128(n as nat).len() <= 5 by {
122 lemma_to_base128_len_bound(n as nat, 5);
123 }
124 assert forall|n: u64| #[trigger] nat_to_base128(n as nat).len() <= 10 by {
125 lemma_to_base128_len_bound(n as nat, 10);
126 }
127}
128
129pub proof fn lemma_to_from_base128_roundtrip(n: nat)
130 ensures
131 nat_from_base128(nat_to_base128(n)) == n,
132 decreases n,
133{
134 if n < 128 {
135 reveal_with_fuel(nat_from_base128, 2);
136 } else {
137 let q = (n / 128) as nat;
138 let r = (n % 128) as nat;
139 lemma_to_from_base128_roundtrip(q);
140 lemma_from_base128_push(nat_to_base128(q), r as u8);
141 }
142}
143
144pub proof fn lemma_from_to_base128_roundtrip(bytes: Seq<u8>)
145 requires
146 bytes.len() > 0,
147 bytes.len() > 1 ==> bytes[0] != 0,
148 forall|i: int| 0 <= i < bytes.len() ==> bytes[i] < 128,
149 ensures
150 nat_to_base128(nat_from_base128(bytes)) == bytes,
151 decreases bytes.len(),
152{
153 if bytes.len() == 1 {
154 reveal_with_fuel(nat_from_base128, 2);
155 assert(bytes == seq![bytes[0]]);
156 } else {
157 let prefix = bytes.drop_last();
158 lemma_from_to_base128_roundtrip(prefix);
159 }
160}
161
162pub const CONTINUATION_MASK: u8 = 0b1000_0000;
163
164pub const PAYLOAD_MASK: u8 = 0b0111_1111;
165
166pub const BASE128_MAX_BYTES: usize = 9;
171
172pub type UInt = u64;
173
174pub type Base128Fmt__<const MINIMAL: bool> = Mapped<
175 Refined<
176 Repeat<Refined<U8, PredFnSpec<u8>>, Refined<U8, PredFnSpec<u8>>>,
177 PredFnSpec<(Seq<u8>, u8)>,
178 >,
179 FnSpecMapper<(Seq<u8>, u8), UInt>,
180>;
181
182pub open spec fn base128_fmt<const MINIMAL: bool>() -> Base128Fmt__<MINIMAL> {
183 Mapped {
184 inner: Refined(
185 Repeat(
186 Refined(U8, |b: u8| b & CONTINUATION_MASK != 0),
187 Refined(U8, |b: u8| b & CONTINUATION_MASK == 0),
188 ),
189 |pair: (Seq<u8>, u8)|
190 {
191 let (cont_bytes, term_byte) = pair;
194 &&& cont_bytes.len() <= BASE128_MAX_BYTES - 1
195 &&& MINIMAL ==> (cont_bytes.len() > 0 ==> cont_bytes[0] & PAYLOAD_MASK != 0)
196 },
197 ),
198 mapper: (
199 |pair: (Seq<u8>, u8)|
200 {
201 let (cont_bytes, term_byte) = pair;
202 let bytes = cont_bytes.push(term_byte);
203 nat_from_base128(bytes) as UInt
204 },
205 |n: UInt|
206 {
207 let bytes = nat_to_base128(n as nat);
208 let cont_bytes = bytes.drop_last().map_values(|b: u8| b | CONTINUATION_MASK);
209 let term_byte = bytes.last();
210 (cont_bytes, term_byte)
211 },
212 ),
213 }
214}
215
216proof fn lemma_nat_from_base128_modulo(bytes: Seq<u8>)
217 ensures
218 nat_from_base128(bytes) == nat_from_base128(bytes.map_values(|b: u8| (b % 128) as u8)),
219 decreases bytes.len(),
220{
221 if bytes.len() == 0 {
222 } else {
223 let prefix = bytes.drop_last();
224 lemma_nat_from_base128_modulo(prefix);
225 assert(bytes.map_values(|b: u8| (b % 128) as u8).drop_last() == prefix.map_values(
226 |b: u8| (b % 128) as u8,
227 ));
228 }
229}
230
231broadcast proof fn lemma_mask_modulo(b: u8)
232 by (bit_vector)
233 ensures
234 #[trigger] (b & PAYLOAD_MASK) == (b % 128) as u8,
235{
236}
237
238pub proof fn lemma_base128_fmt_sound_nonmal_inv()
239 ensures
240 base128_fmt::<true>().sound_inv(),
241 base128_fmt::<true>().nonmal_inv(),
242{
243 reveal(<Star<_> as Consistency>::consistent);
244 let fmt = base128_fmt::<true>();
245 assert forall|pair| fmt.inner.consistent(pair) implies (fmt.mapper.1)((fmt.mapper.0)(pair))
246 == pair by {
247 let (cont_bytes, term_byte) = pair;
248 let bytes = cont_bytes.push(term_byte);
249 assert(bytes.len() <= BASE128_MAX_BYTES);
250 lemma_nat_from_base128_bounds(bytes);
251
252 broadcast use lemma_mask_modulo;
253
254 let payload_bytes = bytes.map_values(|b: u8| (b % 128) as u8);
255 let n = nat_from_base128(bytes);
256 lemma_from_to_base128_roundtrip(payload_bytes); lemma_nat_from_base128_modulo(bytes); let encoded_bytes = nat_to_base128(n);
261 assert(encoded_bytes == payload_bytes);
262
263 assert(term_byte & PAYLOAD_MASK == term_byte) by (bit_vector)
264 requires
265 term_byte & CONTINUATION_MASK == 0,
266 ;
267 assert(encoded_bytes.last() == term_byte);
268 assert forall|i: int|
269 0 <= i < cont_bytes.len() implies encoded_bytes.drop_last().map_values(
270 |b: u8| b | CONTINUATION_MASK,
271 )[i] == cont_bytes[i] by {
272 let b_orig = cont_bytes[i];
273 assert(b_orig & CONTINUATION_MASK != 0);
274 assert(((b_orig & PAYLOAD_MASK) | 128) == b_orig) by (bit_vector)
275 requires
276 b_orig & CONTINUATION_MASK != 0,
277 ;
278 }
279 assert(encoded_bytes.drop_last().map_values(|b: u8| b | CONTINUATION_MASK) =~= cont_bytes);
280 }
281}
282
283pub proof fn lemma_base128_fmt_unambiguous<const MINIMAL: bool>()
284 ensures
285 base128_fmt::<MINIMAL>().unambiguous(),
286{
287 broadcast use disjointness_lemmas;
288
289 let fmt = base128_fmt::<MINIMAL>();
290 assert forall|o: UInt| #[trigger] (fmt.mapper.0)((fmt.mapper.1)(o)) == o by {
292 let bytes = nat_to_base128(o as nat);
293 let cont_bytes = bytes.drop_last().map_values(|b: u8| b | CONTINUATION_MASK);
294 let term_byte = bytes.last();
295 let bytes2 = cont_bytes.push(term_byte);
296
297 lemma_to_from_base128_roundtrip(o as nat); lemma_nat_from_base128_modulo(bytes);
300 lemma_nat_from_base128_modulo(bytes2);
301 let m1 = bytes2.map_values(|b: u8| (b % 128) as u8);
302 let m2 = bytes.map_values(|b: u8| (b % 128) as u8);
303 assert(forall|b: u8| ((b | 128) % 128) as u8 == b % 128) by (bit_vector);
305 assert(m1 == m2);
306
307 }
308}
309
310proof fn lemma_uint_shr7_is_div128(v: u64)
311 by (bit_vector)
312 ensures
313 (v >> 7usize) as nat == v as nat / 128,
314{
315}
316
317proof fn lemma_uint_low7_is_mod128(v: u64)
318 by (bit_vector)
319 ensures
320 (v & PAYLOAD_MASK as u64) as nat == v as nat % 128,
321{
322}
323
324proof fn lemma_uint64_shl7_or_is_base128(v: u64, b: u8)
325 by (bit_vector)
326 ensures
327 (((v << 7usize) | (b & 0x7fu8) as u64) as nat) == (v as nat * 128 + (b % 128) as nat) % (
328 0x1_0000_0000_0000_0000nat),
329{
330}
331
332pub(crate) proof fn lemma_base128_fmt_consistent<const MINIMAL: bool>(v: UInt)
333 requires
334 nat_to_base128(v as nat).len() <= BASE128_MAX_BYTES,
335 ensures
336 base128_fmt::<MINIMAL>().consistent(v),
337{
338 reveal(<Star<_> as Consistency>::consistent);
339 lemma_to_base128_props(v as nat);
340
341 assert(forall|byte: u8| #![auto] (byte | CONTINUATION_MASK) & CONTINUATION_MASK != 0)
342 by (bit_vector);
343 assert(forall|byte: u8| #![auto] byte < CONTINUATION_MASK ==> byte & CONTINUATION_MASK == 0)
344 by (bit_vector);
345 assert(forall|byte: u8|
346 #![auto]
347 byte < CONTINUATION_MASK ==> (byte | CONTINUATION_MASK) & PAYLOAD_MASK == byte)
348 by (bit_vector);
349}
350
351pub proof fn lemma_base128_fmt_byte_len<const MINIMAL: bool>(v: UInt)
352 ensures
353 base128_fmt::<MINIMAL>().byte_len(v) == nat_to_base128(v as nat).len(),
354{
355 let bytes = nat_to_base128(v as nat);
356 let cont_bytes = bytes.drop_last().map_values(|b: u8| b | CONTINUATION_MASK);
357 lemma_star_byte_len_seq_u8(cont_bytes);
358}
359
360pub(crate) proof fn lemma_base128_fmt_consistent_byte_len_bound<const MINIMAL: bool>(v: UInt)
362 requires
363 Base128Fmt::<MINIMAL>.consistent(v),
364 ensures
365 Base128Fmt::<MINIMAL>.byte_len(v) <= BASE128_MAX_BYTES,
366{
367 lemma_base128_fmt_byte_len::<MINIMAL>(v);
368}
369
370proof fn lemma_star_serialize_seq_u8(vs: Seq<u8>)
371 ensures
372 Star(Refined(U8, |b: u8| b & CONTINUATION_MASK != 0)).spec_serialize(vs) == vs,
373 decreases vs.len(),
374{
375 reveal(<Star<_> as SpecSerializer>::spec_serialize);
376 if vs.len() > 0 {
377 let prefix = vs.drop_last();
378 lemma_star_serialize_seq_u8(prefix);
379 }
380}
381
382proof fn lemma_star_byte_len_seq_u8(vs: Seq<u8>)
383 ensures
384 Star(Refined(U8, |b: u8| b & CONTINUATION_MASK != 0)).byte_len(vs) == vs.len(),
385 decreases vs.len(),
386{
387 reveal(<Star<_> as SpecByteLen>::byte_len);
388 if vs.len() == 0 {
389 } else {
390 let prefix = vs.drop_last();
391 lemma_star_byte_len_seq_u8(prefix);
392 }
393}
394
395proof fn lemma_star_parse_rec_from_scan(ibuf: Seq<u8>, n: int)
396 requires
397 0 < n <= ibuf.len(),
398 ibuf[n - 1] & CONTINUATION_MASK == 0,
399 forall|i: int| #![auto] 0 <= i < n - 1 ==> ibuf[i] & CONTINUATION_MASK != 0,
400 ensures
401 Star(Refined(U8, |b: u8| b & CONTINUATION_MASK != 0)).parse_rec(ibuf) == (
402 n - 1,
403 ibuf.take(n - 1),
404 ),
405 decreases n,
406{
407 if n > 1 {
408 lemma_star_parse_rec_from_scan(ibuf.skip(1), (n - 1) as int);
409 }
410}
411
412#[verifier::loop_isolation(false)]
413fn scan_base128_bytes<'a, const MINIMAL: bool>(ibuf: &&'a [u8]) -> (out: PResult<&'a [u8]>)
414 ensures
415 out matches Ok((n, bytes)) ==> {
416 let scanned = bytes.deep_view();
417 &&& 0 < n <= BASE128_MAX_BYTES
418 &&& n <= ibuf@.len()
419 &&& scanned == ibuf@.take(n as int)
420 &&& base128_fmt::<MINIMAL>().inner.spec_parse(ibuf@) == Some(
421 (n as int, (scanned.drop_last(), scanned.last())),
422 )
423 },
424 out is Err ==> base128_fmt::<MINIMAL>().inner.spec_parse(ibuf@) is None,
425{
426 let ghost fmt = base128_fmt::<MINIMAL>();
427 let ghost star = Star(Refined(U8, |b: u8| b & CONTINUATION_MASK != 0));
428
429 let mut i = 0usize;
430 while i < ibuf.len()
431 invariant
432 i <= BASE128_MAX_BYTES,
433 i <= ibuf@.len(),
434 forall|j: int| #![auto] 0 <= j < i as int ==> ibuf@[j] & CONTINUATION_MASK != 0,
435 decreases ibuf@.len() - i,
436 {
437 reveal(<Star<_> as SpecParser>::spec_parse);
438
439 if i == BASE128_MAX_BYTES {
440 proof {
441 if fmt.inner.spec_parse(ibuf@) is Some {
442 fmt.inner.lemma_parse_safe(ibuf@);
443 let (n, (cont_bytes, term_byte)) = fmt.inner.spec_parse(ibuf@)->0;
444 star.lemma_parse_sound_consumption(ibuf@);
445 lemma_star_byte_len_seq_u8(cont_bytes);
446 assert(term_byte == ibuf@[n - 1]);
447 assert(term_byte & CONTINUATION_MASK == 0);
448 assert(term_byte & CONTINUATION_MASK != 0);
449 }
450 }
451 return Err(ParseError::overflow());
452 }
453 let b = ibuf[i];
454 i += 1;
455 if b & CONTINUATION_MASK == 0 {
456 let bytes = ibuf.take(i);
457 if MINIMAL && i > 1 && (bytes[0] & PAYLOAD_MASK == 0) {
458 return Err(ParseError::non_canonical());
459 }
460 proof {
461 let scanned = bytes.deep_view();
462 let (cont_bytes, term_byte) = (scanned.drop_last(), scanned.last());
463 lemma_star_parse_rec_from_scan(ibuf@, i as int);
464 assert(star.parse_rec(ibuf@) == (i - 1, cont_bytes));
465 assert(fmt.inner.spec_parse(ibuf@) == Some((i as int, (cont_bytes, term_byte))));
466 }
467 return Ok((i, bytes));
468 }
469 }
470 proof {
471 if fmt.spec_parse(ibuf@) is Some {
472 fmt.inner.lemma_parse_safe(ibuf@);
473 let (n, (cont_bytes, term_byte)) = fmt.inner.spec_parse(ibuf@)->0;
474 star.lemma_parse_sound_consumption(ibuf@);
475 lemma_star_byte_len_seq_u8(cont_bytes);
476 assert(term_byte == ibuf@[n - 1]);
477 assert(term_byte & CONTINUATION_MASK == 0);
478 assert(term_byte & CONTINUATION_MASK != 0);
479 }
480 }
481 Err(ParseError::unexpected_eof())
482}
483
484pub fn uint_from_base128(bytes: &[u8]) -> (result: UInt)
485 requires
486 bytes.len() <= BASE128_MAX_BYTES,
487 ensures
488 result as nat == nat_from_base128(bytes.deep_view()),
489{
490 let n = bytes.len();
491 let mut acc: UInt = 0;
492 for i in 0..n
493 invariant
494 n == bytes.len(),
495 n <= BASE128_MAX_BYTES,
496 acc == nat_from_base128(bytes@.take(i as int)),
497 {
498 let b = bytes[i];
499 proof {
500 let prefix = bytes@.take(i as int);
501 let current = prefix.push(b);
502 assert(bytes@.take(i as int + 1) == current);
503 assert(current.drop_last() == prefix);
504 lemma_nat_from_base128_bounds(current);
505 lemma_uint64_shl7_or_is_base128(acc, b);
506 }
507 acc = (acc << 7usize) | ((b & PAYLOAD_MASK) as UInt);
508 }
509 assert(bytes@.take(n as int) == bytes.deep_view());
510 acc
511}
512
513#[cfg(feature = "alloc")]
514pub fn uint_to_base128(v: UInt) -> (buf: Vec<u8>)
515 ensures
516 buf@ == nat_to_base128(v as nat),
517 decreases v,
518{
519 if v < 128 {
520 vec![v as u8]
521 } else {
522 proof {
523 lemma_uint_shr7_is_div128(v);
524 lemma_uint_low7_is_mod128(v);
525 }
526 let mut buf = uint_to_base128(v >> 7);
527 buf.push((v & PAYLOAD_MASK as u64) as u8);
528 buf
529 }
530}
531
532#[verifier::loop_isolation(false)]
534pub fn uint_to_base128_in_place(v: UInt, obuf: &mut [u8])
535 requires
536 old(obuf)@.len() == nat_to_base128(v as nat).len(),
537 ensures
538 final(obuf)@ == nat_to_base128(v as nat),
539{
540 let len = obuf.len();
541
542 let ghost target = nat_to_base128(v as nat);
543 proof {
544 lemma_to_from_base128_roundtrip(v as nat);
545 lemma_to_base128_props(v as nat);
546 assert(target.take(len as int) == target);
547 }
548 let mut pos = len;
549 let mut current = v;
550
551 while pos > 0
554 invariant
555 len == obuf.len(),
556 pos <= len,
557 current as nat == nat_from_base128(target.take(pos as int)),
558 obuf@.skip(pos as int) == target.skip(pos as int),
559 decreases pos,
560 {
561 let ghost old_buf = obuf@;
562 let ghost old_current = current;
563
564 pos -= 1;
565 let byte = (current & PAYLOAD_MASK as UInt) as u8;
566 obuf[pos] = byte;
567 current = current >> 7;
568 proof {
569 lemma_uint_shr7_is_div128(old_current);
570 lemma_uint_low7_is_mod128(old_current);
571 assert(target[pos as int] < 128);
572 assert(target.take(pos as int + 1).drop_last() == target.take(pos as int));
573 assert(obuf@.skip(pos as int) == seq![byte] + old_buf.skip(pos as int + 1));
574 }
575 }
576}
577
578pub fn uint_to_base128_len(v: UInt) -> (len: usize)
579 ensures
580 len == nat_to_base128(v as nat).len(),
581{
582 let mut cur = v;
583 let mut len: usize = 1;
584 while cur >= 128
585 invariant
586 len + nat_to_base128(cur as nat).len() == nat_to_base128(v as nat).len() + 1,
587 decreases cur,
588 {
589 proof {
590 lemma_uint_shr7_is_div128(cur);
591 lemma_to_base128_len_bounds();
592 }
593 cur >>= 7;
594 len += 1;
595 }
596 len
597}
598
599#[derive(Clone, Copy)]
600pub struct Base128Fmt<const MINIMAL: bool = true>;
601
602mod derived_specs {
603 use super::*;
604
605 impl<const MINIMAL: bool> SpecParser for Base128Fmt<MINIMAL> {
606 type PVal = UInt;
607
608 open(crate) spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
609 base128_fmt::<MINIMAL>().spec_parse(ibuf)
610 }
611 }
612
613 impl<const MINIMAL: bool> Consistency for Base128Fmt<MINIMAL> {
614 type Val = UInt;
615
616 open(crate) spec fn consistent(&self, v: Self::Val) -> bool {
617 base128_fmt::<MINIMAL>().consistent(v)
618 }
619 }
620
621 impl<const MINIMAL: bool> SpecSerializerDps for Base128Fmt<MINIMAL> {
622 type SValue = UInt;
623
624 open(crate) spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
625 base128_fmt::<MINIMAL>().spec_serialize_dps(v, obuf)
626 }
627 }
628
629 impl<const MINIMAL: bool> SpecSerializer for Base128Fmt<MINIMAL> {
630 type SVal = UInt;
631
632 open(crate) spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
633 base128_fmt::<MINIMAL>().spec_serialize(v)
634 }
635 }
636
637 impl<const MINIMAL: bool> SpecByteLen for Base128Fmt<MINIMAL> {
638 type T = UInt;
639
640 open(crate) spec fn byte_len(&self, v: Self::T) -> nat {
641 base128_fmt::<MINIMAL>().byte_len(v)
642 }
643 }
644
645}
646
647mod derived_proofs {
648 use super::*;
649
650 impl<const MINIMAL: bool> SafeParser for Base128Fmt<MINIMAL> {
651 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
652 base128_fmt::<MINIMAL>().lemma_parse_safe(ibuf);
653 }
654 }
655
656 impl<const MINIMAL: bool> Productive for Base128Fmt<MINIMAL> {
657 proof fn lemma_productive(&self, s: Seq<u8>) {
658 base128_fmt::<MINIMAL>().lemma_productive(s);
659 }
660 }
661
662 impl SoundParser for Base128Fmt<true> {
663 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
664 lemma_base128_fmt_sound_nonmal_inv();
665 base128_fmt::<true>().lemma_parse_sound_consumption(ibuf);
666 }
667
668 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
669 lemma_base128_fmt_sound_nonmal_inv();
670 base128_fmt::<true>().lemma_parse_sound_value(ibuf);
671 }
672 }
673
674 impl<const MINIMAL: bool> NonTailFmt for Base128Fmt<MINIMAL> {
675 proof fn lemma_serialize_dps_prepend(&self, v: Self::SValue, obuf: Seq<u8>) {
676 base128_fmt::<MINIMAL>().lemma_serialize_dps_prepend(v, obuf);
677 }
678
679 proof fn lemma_serialize_dps_len(&self, v: Self::SValue, obuf: Seq<u8>) {
680 base128_fmt::<MINIMAL>().lemma_serialize_dps_len(v, obuf);
681 }
682 }
683
684 impl<const MINIMAL: bool> GoodSerializer for Base128Fmt<MINIMAL> {
685 proof fn lemma_serialize_len(&self, v: Self::SVal) {
686 base128_fmt::<MINIMAL>().lemma_serialize_len(v);
687 }
688 }
689
690 impl<const MINIMAL: bool> SPRoundTripDps for Base128Fmt<MINIMAL> {
691 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
692 lemma_base128_fmt_unambiguous::<MINIMAL>();
693 base128_fmt::<MINIMAL>().theorem_serialize_dps_parse_roundtrip(v, obuf);
694 }
695 }
696
697 impl<const MINIMAL: bool> NoLookAhead for Base128Fmt<MINIMAL> {
698 proof fn lemma_no_lookahead(&self, i1: Seq<u8>, i2: Seq<u8>) {
699 broadcast use disjointness_lemmas;
700
701 base128_fmt::<MINIMAL>().lemma_no_lookahead(i1, i2);
702 }
703 }
704
705 impl NonMalleable for Base128Fmt<true> {
706 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
707 lemma_base128_fmt_sound_nonmal_inv();
708 base128_fmt::<true>().lemma_parse_non_malleable(buf1, buf2);
709 }
710 }
711
712 impl<const MINIMAL: bool> EquivSerializersGeneral for Base128Fmt<MINIMAL> {
713 proof fn lemma_serialize_equiv(&self, v: Self::SVal, obuf: Seq<u8>) {
714 base128_fmt::<MINIMAL>().lemma_serialize_equiv(v, obuf);
715 }
716 }
717
718 impl<const MINIMAL: bool> EquivSerializers for Base128Fmt<MINIMAL> {
719 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
720 base128_fmt::<MINIMAL>().lemma_serialize_equiv_on_empty(v);
721 }
722 }
723
724}
725
726impl<const MINIMAL: bool> Parser<&[u8]> for Base128Fmt<MINIMAL> {
727 type PT = UInt;
728
729 fn parse(&self, ibuf: &&[u8]) -> PResult<Self::PT> {
730 let (n, bytes) = scan_base128_bytes::<MINIMAL>(ibuf)?;
731 proof {
732 let (_, (cont_bytes, term_byte)) = base128_fmt::<MINIMAL>().inner.spec_parse(ibuf@)->0;
733 assert(cont_bytes.push(term_byte) == bytes.deep_view());
734 }
735 let value = uint_from_base128(bytes);
736 Ok((n, value))
737 }
738}
739
740impl<Output: OutputBuf, const MINIMAL: bool> Serializer<Output, UInt> for Base128Fmt<MINIMAL> {
741 #[verifier::loop_isolation(false)]
742 fn serialize_into(&self, v: &UInt, obuf: &mut Output) {
743 broadcast use crate::core::exec::output::outbuf_lemmas;
744
745 let num_bytes = uint_to_base128_len(*v);
746 let mut bytes = [0u8;BASE128_MAX_BYTES + 1];
747 let (encoded, _) = bytes.split_at_mut(num_bytes);
748 uint_to_base128_in_place(*v, encoded);
749
750 proof {
751 assert(bytes@.take(num_bytes as int) == nat_to_base128(*v as nat));
752 lemma_base128_fmt_byte_len::<MINIMAL>(*v);
753 }
754 let ghost cont_bytes = bytes@.take(num_bytes as int).drop_last().map_values(
755 |b: u8| b | CONTINUATION_MASK,
756 );
757 proof {
758 old(obuf).lemma_same_destination_reflexive();
759 }
760 for i in 0..num_bytes - 1
761 invariant
762 cont_bytes.len() == num_bytes - 1,
763 obuf@ == old(obuf)@ + cont_bytes.take(i as int),
764 forall|n| old(obuf).fits(i as nat + n) <==> #[trigger] obuf.fits(n),
765 old(obuf).same_destination(obuf),
766 forall|j: int|
767 #![auto]
768 0 <= j < cont_bytes.len() ==> cont_bytes[j] == bytes@.take(
769 num_bytes as int,
770 ).drop_last()[j] | CONTINUATION_MASK,
771 {
772 broadcast use crate::core::exec::output::outbuf_lemmas;
773
774 let b = bytes[i];
775 obuf.write_byte((b | CONTINUATION_MASK) as u8);
776 }
777 obuf.write_byte(bytes[num_bytes - 1]);
778 proof {
779 lemma_star_serialize_seq_u8(cont_bytes);
780 }
781 }
782}
783
784impl<const MINIMAL: bool> ByteLen<UInt> for Base128Fmt<MINIMAL> {
785 fn length(&self, v: &UInt) -> (len: usize) {
786 let len = uint_to_base128_len(*v);
787 proof {
788 lemma_base128_fmt_byte_len::<MINIMAL>(*v);
789 }
790 len
791 }
792}
793
794impl<const MINIMAL: bool> Prepare<UInt> for Base128Fmt<MINIMAL> {
795 fn prepare(&self, v: &UInt) -> (checked: Result<usize, PreSerializeError>) {
796 let len = uint_to_base128_len(*v);
797 if len <= BASE128_MAX_BYTES {
798 proof {
799 lemma_base128_fmt_byte_len::<MINIMAL>(*v);
800 lemma_base128_fmt_consistent::<MINIMAL>(*v);
801 }
802 Ok(len)
803 } else {
804 Err(PreSerializeError::length_too_large())
805 }
806 }
807}
808
809} #[cfg(all(test, feature = "alloc"))]
811mod tests {
812 use super::*;
813 use crate::core::exec::serializer::PreSerializeErrorKind;
814 use crate::core::exec::{ByteLen, ParseErrorKind, Parser, Prepare, SerializerExt};
815
816 #[test]
817 fn base128_minimal_roundtrip_boundaries() {
818 let fmt = Base128Fmt::<true>;
819
820 let cases: &[(u64, &[u8])] = &[
821 (0, &[0x00]),
822 (1, &[0x01]),
823 (127, &[0x7f]),
824 (128, &[0x81, 0x00]),
825 (16383, &[0xff, 0x7f]),
826 ];
827
828 for &(value, expected) in cases {
829 let mut out = vec![0; fmt.prepare(&value).unwrap()];
830 fmt.serialize(&value, &mut out);
831 assert_eq!(out, expected);
832
833 let mut stack_out = [0u8; 2];
834 fmt.serialize(&value, &mut stack_out[..expected.len()]);
835 assert_eq!(&stack_out[..expected.len()], expected);
836
837 let parsed = fmt.parse(&&out[..]);
838 assert_eq!(parsed, Ok((expected.len(), value)));
839
840 let prepared = fmt.prepare(&value);
841 assert_eq!(prepared, Ok(expected.len()));
842 assert_eq!(fmt.length(&value), expected.len());
843 }
844 }
845
846 #[test]
847 fn uint_to_base128_in_place_matches_vec_encoding() {
848 for value in [0, 1, 0x7f, 0x80, 0x3fff, 0x4000, u64::MAX] {
849 let expected = uint_to_base128(value);
850 let len = uint_to_base128_len(value);
851 let mut actual = [0u8; BASE128_MAX_BYTES + 1];
852
853 uint_to_base128_in_place(value, &mut actual[..len]);
854
855 assert_eq!(&actual[..len], expected.as_slice());
856 }
857 }
858
859 #[test]
860 fn base128_minimal_rejects_non_canonical_zero() {
861 let input = [0x80, 0x00];
862
863 let err = Base128Fmt::<true>.parse(&&input[..]).unwrap_err();
864 assert_eq!(err.kind, ParseErrorKind::NonCanonical);
865
866 let parsed = Base128Fmt::<false>.parse(&&input[..]);
867 assert_eq!(parsed, Ok((2, 0)));
868 }
869
870 #[test]
871 fn base128_distinguishes_unexpected_eof_from_overflow() {
872 let eof = [0x80];
873 let eof_err = Base128Fmt::<true>.parse(&&eof[..]).unwrap_err();
874 assert_eq!(eof_err.kind, ParseErrorKind::UnexpectedEof);
875
876 let overflow = [0x80; BASE128_MAX_BYTES + 1];
877 let overflow_err = Base128Fmt::<true>.parse(&&overflow[..]).unwrap_err();
878 assert_eq!(overflow_err.kind, ParseErrorKind::Overflow);
879 }
880
881 #[test]
882 fn base128_prepare_rejects_values_needing_ten_bytes() {
883 let fmt = Base128Fmt::<true>;
884 let max_supported = (1u64 << 63) - 1;
885 let too_large = 1u64 << 63;
886
887 let mut out = vec![0; fmt.prepare(&max_supported).unwrap()];
888 fmt.serialize(&max_supported, &mut out);
889 assert_eq!(out.len(), BASE128_MAX_BYTES);
890 assert_eq!(fmt.prepare(&max_supported), Ok(BASE128_MAX_BYTES));
891 assert_eq!(fmt.length(&max_supported), BASE128_MAX_BYTES);
892
893 let len = fmt.length(&too_large);
894 assert_eq!(len, BASE128_MAX_BYTES + 1);
895
896 let err = fmt.prepare(&too_large).unwrap_err();
897 assert_eq!(err.kind, PreSerializeErrorKind::LengthTooLarge);
898 }
899}