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