1use crate::core::exec::input::{InputBuf, InputSlice};
3use crate::core::exec::output::*;
4use crate::core::exec::{
5 parser::{PResult, Parser},
6 serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
7 ParseError,
8};
9use crate::primitives::base256::*;
10use crate::{
11 combinators::{
12 mapped::spec::{FnSpecMapper, LosslessMapper, LossyMapper, SpecMapper},
13 I16Be, Mapped, Refined, Tail, I8,
14 },
15 core::{proof::*, spec::*},
16};
17#[cfg(feature = "alloc")]
18use alloc::vec::Vec;
19use vstd::arithmetic::mul::*;
20use vstd::arithmetic::power::*;
21use vstd::arithmetic::power2::*;
22use vstd::assert_seqs_equal;
23use vstd::bits::*;
24use vstd::prelude::*;
25
26verus! {
27
28pub type IntegerInnerFmt = Mapped<Refined<Tail, PredFnSpec<Seq<u8>>>, FnSpecMapper<Seq<u8>, int>>;
29
30pub open spec fn integer_fmt() -> IntegerInnerFmt {
31 Mapped {
32 inner: Refined(Tail, |bytes: Seq<u8>| integer_bytes_wf(bytes)),
33 mapper: (|bytes: Seq<u8>| int_from_be_bytes(bytes), |o: int| int_to_be_bytes(o)),
34 }
35}
36
37pub open spec fn sign_bit_set(b: u8) -> bool {
38 0x80u8 <= b
39}
40
41pub open spec fn invert_byte(b: u8) -> u8 {
42 !b
43}
44
45pub open spec fn invert_bytes(bytes: Seq<u8>) -> Seq<u8> {
46 bytes.map_values(|b: u8| invert_byte(b))
47}
48
49pub open spec fn integer_bytes_minimal(bytes: Seq<u8>) -> bool {
57 bytes.len() > 1 ==> {
58 &&& !(bytes[0] == 0x00u8 && !sign_bit_set(bytes[1]))
59 &&& !(bytes[0] == 0xFFu8 && sign_bit_set(bytes[1]))
60 }
61}
62
63pub open spec fn integer_bytes_wf(bytes: Seq<u8>) -> bool {
64 &&& bytes.len() > 0
66 &&& integer_bytes_minimal(bytes)
67}
68
69pub open spec fn int_from_be_bytes(bytes: Seq<u8>) -> int {
70 let unsigned = nat_from_be_bytes(bytes);
71 if sign_bit_set(bytes[0]) {
72 unsigned as int - pow(256, bytes.len()) as int
73 } else {
74 unsigned as int
75 }
76}
77
78pub open spec fn nonnegative_int_to_bytes(n: nat) -> Seq<u8> {
79 let body = nat_to_be_bytes(n);
80 if sign_bit_set(body[0]) {
81 seq![0x00u8] + body
82 } else {
83 body
84 }
85}
86
87pub open spec fn negative_int_to_bytes(n: nat) -> Seq<u8> {
88 let body = invert_bytes(nat_to_be_bytes(n));
89 if sign_bit_set(body[0]) {
90 body
91 } else {
92 seq![0xFFu8] + body
93 }
94}
95
96pub open spec fn int_to_be_bytes(v: int) -> Seq<u8> {
97 if v >= 0 {
98 nonnegative_int_to_bytes(v as nat)
99 } else {
100 negative_int_to_bytes((-1 - v) as nat)
101 }
102}
103
104pub proof fn lemma_invert_byte_props(b: u8)
105 ensures
106 invert_byte(b) as nat + b as nat == 0xFF,
107 invert_byte(invert_byte(b)) == b,
108 sign_bit_set(invert_byte(b)) <==> !sign_bit_set(b),
109{
110 assert(invert_byte(b) == (0xFFu8 - b)) by (bit_vector);
111 assert(invert_byte(b) as nat + b as nat == 0xFF);
112 assert(invert_byte(invert_byte(b)) == b) by (bit_vector);
113 assert(sign_bit_set(invert_byte(b)) <==> !sign_bit_set(b));
114}
115
116pub proof fn lemma_invert_bytes_involutive(bytes: Seq<u8>)
117 ensures
118 invert_bytes(invert_bytes(bytes)) == bytes,
119{
120 assert_seqs_equal!(invert_bytes(invert_bytes(bytes)) == bytes, i => {
121 lemma_invert_byte_props(bytes[i]);
122 });
123}
124
125pub proof fn lemma_from_be_bytes_invert(bytes: Seq<u8>)
126 ensures
127 nat_from_be_bytes(invert_bytes(bytes)) + nat_from_be_bytes(bytes) + 1 == pow(
128 256,
129 bytes.len(),
130 ),
131 decreases bytes.len(),
132{
133 if bytes.len() == 0 {
134 lemma_pow0(256);
135 } else {
136 let prefix = bytes.drop_last();
137 let last = bytes.last();
138 lemma_from_be_bytes_invert(prefix);
139 prefix.lemma_push_map_commute(|x: u8| invert_byte(x), last);
140 lemma_from_be_bytes_push(invert_bytes(prefix), invert_byte(last));
141 lemma_invert_byte_props(last);
142 lemma_pow256_succ(prefix.len());
143 assert(bytes == prefix.push(last));
144 }
145}
146
147pub proof fn lemma_integer_from_to_bytes(i: Seq<u8>)
148 requires
149 integer_bytes_wf(i),
150 ensures
151 int_to_be_bytes(int_from_be_bytes(i)) == i,
152{
153 if sign_bit_set(i[0]) {
154 let c = invert_bytes(i);
155 lemma_invert_bytes_involutive(i);
156 lemma_from_be_bytes_invert(i);
157 assert((-1 - int_from_be_bytes(i)) as nat == nat_from_be_bytes(invert_bytes(i)));
158 if i.len() > 1 && i[0] == 0xFFu8 {
159 let body = i.drop_first();
160 let c_body = c.drop_first();
161 assert(!sign_bit_set(body[0]));
162 lemma_invert_byte_props(body[0]);
163 lemma_from_be_bytes_prepend(c_body, 0x00u8);
164 lemma_from_to_be_bytes_roundtrip(c_body);
165 lemma_invert_bytes_involutive(body);
166 let first = i[0];
167 assert(first == 0xFFu8);
168 assert(invert_byte(0xFFu8) == 0x00u8) by (bit_vector);
169 assert_seqs_equal!(c == seq![0x00u8] + c_body);
170 assert(i == seq![0xFFu8] + body);
171 } else {
172 if c.len() > 1 {
173 lemma_invert_byte_props(i[0]);
174 assert(c[0] != 0x00u8);
175 }
176 lemma_from_to_be_bytes_roundtrip(c);
177 }
178 lemma_from_be_bytes_upper_bound(i);
179 assert(int_from_be_bytes(i) < 0);
180 assert(int_to_be_bytes(int_from_be_bytes(i)) == i);
181 } else {
182 if i.len() == 1 {
183 lemma_from_be_bytes_singleton(i[0]);
184 assert(i == seq![i[0]]);
185 } else if i[0] == 0x00u8 {
186 let body = i.drop_first();
187 assert(sign_bit_set(body[0]));
188 lemma_from_be_bytes_prepend(body, 0x00u8);
189 lemma_from_to_be_bytes_roundtrip(body);
190 assert(i == seq![0x00u8] + body);
191 } else {
192 lemma_from_to_be_bytes_roundtrip(i);
193 }
194 }
195}
196
197pub proof fn lemma_integer_to_from_bytes(o: int)
198 ensures
199 int_from_be_bytes(int_to_be_bytes(o)) == o,
200 integer_bytes_wf(int_to_be_bytes(o)),
201{
202 if o >= 0 {
203 let n = o as nat;
204 let body = nat_to_be_bytes(n);
205 lemma_to_from_be_bytes_roundtrip(n);
206 if sign_bit_set(body[0]) {
207 lemma_from_be_bytes_prepend(body, 0x00u8);
208 }
209 lemma_to_be_bytes_props(n);
210 } else {
211 let n = (-1 - o) as nat;
212 let unsigned = nat_to_be_bytes(n);
213 let body = invert_bytes(unsigned);
214 lemma_to_from_be_bytes_roundtrip(n);
215 lemma_from_be_bytes_invert(unsigned);
216 if !sign_bit_set(body[0]) {
217 lemma_from_be_bytes_prepend(body, 0xFFu8);
218 lemma_pow256_succ(unsigned.len());
219 }
220 lemma_to_be_bytes_props(n);
221 lemma_invert_byte_props(nat_to_be_bytes(n)[0]);
222 }
223}
224
225pub proof fn lemma_integer_fmt_sound_nonmal_inv()
226 ensures
227 integer_fmt().sound_inv(),
228 integer_fmt().nonmal_inv(),
229{
230 assert forall|v: Seq<u8>| #[trigger] integer_fmt().inner.consistent(v) implies (
231 integer_fmt().mapper.1)((integer_fmt().mapper.0)(v)) == v by {
232 lemma_integer_from_to_bytes(v);
233 }
234}
235
236pub proof fn lemma_integer_fmt_unambiguous()
237 ensures
238 integer_fmt().unambiguous(),
239{
240 assert forall|o: int| #[trigger] integer_fmt().consistent(o) implies (integer_fmt().mapper.0)(
241 (integer_fmt().mapper.1)(o),
242 ) == o by {
243 lemma_integer_to_from_bytes(o);
244 }
245}
246
247#[derive(Copy, Clone)]
248pub struct BigInt<'a> {
249 pub(crate) raw: &'a [u8],
250}
251
252proof fn lemma_large_nonnegative_integer(bytes: Seq<u8>)
253 requires
254 bytes.len() > 8,
255 !sign_bit_set(bytes[0]),
256 bytes[0] == 0 ==> sign_bit_set(bytes[1]),
257 ensures
258 nat_from_be_bytes(bytes) > i64::MAX as int,
259{
260 broadcast use lemma_pow_increases;
261
262 reveal_with_fuel(pow, 9);
263 if bytes[0] != 0 {
264 lemma_from_be_bytes_lower_bound(bytes);
265 lemma_pow_increases(256, 8, (bytes.len() - 1) as nat);
266 } else {
267 let rest = bytes.drop_first();
268 let tail = rest.drop_first();
269 assert(bytes == seq![bytes[0]] + rest);
270 assert(rest == seq![rest[0]] + tail);
271 lemma_from_be_bytes_prepend(rest, 0);
272 lemma_from_be_bytes_prepend(tail, rest[0]);
273 lemma_pow_increases(256, 7, tail.len());
274 let first_int: int = rest[0] as int;
275 let power: int = pow(256, tail.len());
276 lemma_mul_inequality(128, first_int, power);
277 }
278}
279
280pub(crate) proof fn lemma_large_integer_outside_i64(bytes: Seq<u8>)
281 requires
282 bytes.len() > 8,
283 integer_bytes_wf(bytes),
284 ensures
285 sign_bit_set(bytes[0]) ==> int_from_be_bytes(bytes) < i64::MIN as int,
286 !sign_bit_set(bytes[0]) ==> int_from_be_bytes(bytes) > i64::MAX as int,
287{
288 if sign_bit_set(bytes[0]) {
289 let inverted = invert_bytes(bytes);
290 lemma_invert_byte_props(bytes[0]);
291 if inverted[0] == 0 {
292 let first = bytes[0];
293 lemma_invert_byte_props(first);
294 lemma_invert_byte_props(bytes[1]);
295 }
296 lemma_large_nonnegative_integer(inverted);
297 lemma_from_be_bytes_invert(bytes);
298 } else {
299 lemma_large_nonnegative_integer(bytes);
300 }
301}
302
303impl<'a> BigInt<'a> {
304 pub open(crate) spec fn view(&self) -> Seq<u8> {
305 self.raw.deep_view()
306 }
307
308 #[verifier::type_invariant]
309 pub(crate) open(crate) spec fn wf(&self) -> bool {
310 integer_bytes_wf(self.view()) && self.view().len() > 8
311 }
312
313 fn new(raw: &'a [u8]) -> (res: Self)
314 requires
315 integer_bytes_wf(raw.deep_view()),
316 raw.len() > 8,
317 ensures
318 res.view() == raw.deep_view(),
319 {
320 BigInt { raw }
321 }
322
323 pub fn as_slice(&self) -> (res: &'a [u8])
324 ensures
325 res.deep_view() == self.view(),
326 {
327 self.raw
328 }
329
330 pub fn is_negative(&self) -> (negative: bool)
335 ensures
336 negative ==> int_from_be_bytes(self.view()) < i64::MIN as int,
337 !negative ==> int_from_be_bytes(self.view()) > i64::MAX as int,
338 {
339 proof {
340 use_type_invariant(self);
341 lemma_large_integer_outside_i64(self.view());
342 }
343 self.raw[0] >= 0x80
344 }
345}
346
347pub(crate) proof fn lemma_integer_small_view(value: i64)
348 ensures
349 (Integer::Small { v: value }).deep_view() == value as int,
350{
351}
352
353pub(crate) proof fn lemma_integer_big_view(raw: BigInt<'_>)
354 ensures
355 (Integer::Big { raw }).deep_view() == int_from_be_bytes(raw.view()),
356{
357}
358
359#[derive(Copy, Clone)]
360pub enum Integer<'a> {
361 Small { v: i64 },
362 Big { raw: BigInt<'a> },
363}
364
365impl<'a> DeepView for Integer<'a> {
366 type V = int;
367
368 closed spec fn deep_view(&self) -> Self::V {
369 match *self {
370 Integer::Small { v } => v as int,
371 Integer::Big { raw } => int_from_be_bytes(raw.view()),
372 }
373 }
374}
375
376impl<'a> Integer<'a> {
377 pub const fn from_i64(v: i64) -> Self {
379 Integer::Small { v }
380 }
381
382 pub fn as_i64(&self) -> (value: Option<i64>)
384 ensures
385 value matches Some(v) ==> self.deep_view() == v as int,
386 {
387 match *self {
388 Integer::Small { v } => Some(v),
389 Integer::Big { .. } => None,
390 }
391 }
392
393 pub fn in_i64_range<const HAS_MIN: bool, const MIN: i64, const HAS_MAX: bool, const MAX: i64>(
395 &self,
396 ) -> (ok: bool)
397 ensures
398 ok == ({
399 &&& HAS_MIN ==> MIN as int <= self.deep_view()
400 &&& HAS_MAX ==> self.deep_view() <= MAX as int
401 }),
402 {
403 match *self {
404 Integer::Small { v } => { (!HAS_MIN || MIN <= v) && (!HAS_MAX || v <= MAX) },
405 Integer::Big { raw } => {
406 let negative = raw.is_negative();
407 (!HAS_MIN || !negative) && (!HAS_MAX || negative)
408 },
409 }
410 }
411}
412
413#[derive(Clone, Copy)]
417pub struct Integer8Fmt;
418
419#[derive(Clone, Copy)]
424pub struct Integer16Fmt;
425
426#[verifier::allow_in_spec]
427pub fn fits_i8(v: i16) -> bool
428 returns
429 i8::MIN <= v <= i8::MAX,
430{
431 i8::MIN as i16 <= v && v <= i8::MAX as i16
432}
433
434pub(crate) broadcast proof fn lemma_integer8_fmt_byte_len(value: i8)
435 ensures
436 #[trigger] Integer8Fmt.byte_len(value) == 1,
437{
438}
439
440pub(crate) broadcast proof fn lemma_integer16_fmt_byte_len_bound(value: i16)
441 ensures
442 #[trigger] Integer16Fmt.byte_len(value) <= 2,
443{
444}
445
446mod derived_specs {
447 use super::*;
448 use super::super::IntegerFmt;
449
450 impl SpecParser for IntegerFmt {
451 type PVal = int;
452
453 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
454 integer_fmt().spec_parse(ibuf)
455 }
456 }
457
458 impl Consistency for IntegerFmt {
459 type Val = int;
460
461 open spec fn consistent(&self, v: Self::Val) -> bool {
462 integer_fmt().consistent(v)
463 }
464 }
465
466 impl SpecSerializerDps for IntegerFmt {
467 type SValue = int;
468
469 open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
470 integer_fmt().spec_serialize_dps(v, obuf)
471 }
472 }
473
474 impl SpecSerializer for IntegerFmt {
475 type SVal = int;
476
477 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
478 integer_fmt().spec_serialize(v)
479 }
480 }
481
482 impl SpecByteLen for IntegerFmt {
483 type T = int;
484
485 open spec fn byte_len(&self, v: Self::T) -> nat {
486 integer_fmt().byte_len(v)
487 }
488 }
489
490 impl SpecParser for Integer8Fmt {
491 type PVal = i8;
492
493 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
494 if ibuf.len() == 1 {
495 I8.spec_parse(ibuf)
496 } else {
497 None
498 }
499 }
500 }
501
502 impl Consistency for Integer8Fmt {
503 type Val = i8;
504
505 open spec fn consistent(&self, v: Self::Val) -> bool {
506 true
507 }
508 }
509
510 impl SpecSerializerDps for Integer8Fmt {
511 type SValue = i8;
512
513 open spec fn spec_serialize_dps(&self, v: Self::SValue, _obuf: Seq<u8>) -> Seq<u8> {
514 I8.spec_serialize(v)
515 }
516 }
517
518 impl SpecSerializer for Integer8Fmt {
519 type SVal = i8;
520
521 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
522 I8.spec_serialize(v)
523 }
524 }
525
526 impl SpecByteLen for Integer8Fmt {
527 type T = i8;
528
529 open spec fn byte_len(&self, v: Self::T) -> nat {
530 I8.byte_len(v)
531 }
532 }
533
534 impl ValueByteLen for Integer8Fmt {
535 open spec fn value_byte_len(v: Self::T) -> nat {
536 I8.byte_len(v)
537 }
538
539 proof fn lemma_value_len_matches_byte_len(&self, v: Self::T) {
540 }
541 }
542
543 impl SpecParser for Integer16Fmt {
544 type PVal = i16;
545
546 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
547 if ibuf.len() == 1 {
548 let (_, v) = I8.spec_parse(ibuf)->0;
549 Some((1, v as i16))
550 } else if ibuf.len() == 2 {
551 match I16Be.spec_parse(ibuf) {
552 Some((_, v)) if !fits_i8(v) => Some((2, v)),
553 _ => None,
554 }
555 } else {
556 None
557 }
558 }
559 }
560
561 impl Consistency for Integer16Fmt {
562 type Val = i16;
563
564 open spec fn consistent(&self, v: Self::Val) -> bool {
565 true
566 }
567 }
568
569 impl SpecSerializerDps for Integer16Fmt {
570 type SValue = i16;
571
572 open spec fn spec_serialize_dps(&self, v: Self::SValue, _obuf: Seq<u8>) -> Seq<u8> {
573 if fits_i8(v) {
574 I8.spec_serialize(v as i8)
575 } else {
576 I16Be.spec_serialize(v)
577 }
578 }
579 }
580
581 impl SpecSerializer for Integer16Fmt {
582 type SVal = i16;
583
584 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
585 if fits_i8(v) {
586 I8.spec_serialize(v as i8)
587 } else {
588 I16Be.spec_serialize(v)
589 }
590 }
591 }
592
593 impl SpecByteLen for Integer16Fmt {
594 type T = i16;
595
596 open spec fn byte_len(&self, v: Self::T) -> nat {
597 if fits_i8(v) {
598 I8.byte_len(v as i8)
599 } else {
600 I16Be.byte_len(v)
601 }
602 }
603 }
604
605}
606
607mod derived_proofs {
608 use super::*;
609 use super::super::IntegerFmt;
610
611 impl SafeParser for IntegerFmt {
612 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
613 integer_fmt().lemma_parse_safe(ibuf);
614 }
615 }
616
617 impl Productive for IntegerFmt {
618 proof fn lemma_productive(&self, s: Seq<u8>) {
619 if let Some((n, _)) = integer_fmt().spec_parse(s) {
620 assert(n > 0);
621 }
622 }
623 }
624
625 impl SoundParser for IntegerFmt {
626 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
627 lemma_integer_fmt_sound_nonmal_inv();
628 integer_fmt().lemma_parse_sound_consumption(ibuf);
629 }
630
631 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
632 lemma_integer_fmt_sound_nonmal_inv();
633 integer_fmt().lemma_parse_sound_value(ibuf);
634 }
635 }
636
637 impl GoodSerializer for IntegerFmt {
638 proof fn lemma_serialize_len(&self, v: Self::SVal) {
639 integer_fmt().lemma_serialize_len(v);
640 }
641 }
642
643 impl SPRoundTripDps for IntegerFmt {
644 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
645 lemma_integer_fmt_sound_nonmal_inv();
646 lemma_integer_fmt_unambiguous();
647 integer_fmt().theorem_serialize_dps_parse_roundtrip(v, obuf);
648 }
649 }
650
651 impl NonMalleable for IntegerFmt {
652 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
653 lemma_integer_fmt_sound_nonmal_inv();
654 integer_fmt().lemma_parse_non_malleable(buf1, buf2);
655 }
656 }
657
658 impl EquivSerializers for IntegerFmt {
659 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
660 integer_fmt().lemma_serialize_equiv_on_empty(v);
661 }
662 }
663
664 impl SafeParser for Integer8Fmt {
665 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
666 if ibuf.len() == 1 {
667 I8.lemma_parse_safe(ibuf);
668 }
669 }
670 }
671
672 impl Productive for Integer8Fmt {
673 proof fn lemma_productive(&self, s: Seq<u8>) {
674 if s.len() == 1 {
675 I8.lemma_productive(s);
676 }
677 }
678 }
679
680 impl SoundParser for Integer8Fmt {
681 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
682 if ibuf.len() == 1 {
683 I8.lemma_parse_sound_consumption(ibuf);
684 }
685 }
686
687 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
688 if ibuf.len() == 1 {
689 I8.lemma_parse_sound_value(ibuf);
690 }
691 }
692 }
693
694 impl GoodSerializer for Integer8Fmt {
695 proof fn lemma_serialize_len(&self, v: Self::SVal) {
696 I8.lemma_serialize_len(v);
697 }
698 }
699
700 impl SPRoundTripDps for Integer8Fmt {
701 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
702 I8.theorem_serialize_dps_parse_roundtrip(v, Seq::empty());
703 }
704 }
705
706 impl NonMalleable for Integer8Fmt {
707 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
708 if buf1.len() == 1 && buf2.len() == 1 {
709 I8.lemma_parse_non_malleable(buf1, buf2);
710 }
711 }
712 }
713
714 impl EquivSerializers for Integer8Fmt {
715 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
716 I8.lemma_serialize_equiv_on_empty(v);
717 }
718 }
719
720 impl SafeParser for Integer16Fmt {
721 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
722 if ibuf.len() == 1 {
723 I8.lemma_parse_safe(ibuf);
724 } else if ibuf.len() == 2 {
725 I16Be.lemma_parse_safe(ibuf);
726 }
727 }
728 }
729
730 impl Productive for Integer16Fmt {
731 proof fn lemma_productive(&self, s: Seq<u8>) {
732 if s.len() == 1 {
733 I8.lemma_productive(s);
734 } else if s.len() == 2 {
735 I16Be.lemma_productive(s);
736 }
737 }
738 }
739
740 impl SoundParser for Integer16Fmt {
741 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
742 if ibuf.len() == 1 {
743 I8.lemma_parse_sound_consumption(ibuf);
744 } else if ibuf.len() == 2 {
745 I16Be.lemma_parse_sound_consumption(ibuf);
746 }
747 }
748
749 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
750 if ibuf.len() == 1 {
751 I8.lemma_parse_sound_value(ibuf);
752 } else if ibuf.len() == 2 {
753 I16Be.lemma_parse_sound_value(ibuf);
754 }
755 }
756 }
757
758 impl GoodSerializer for Integer16Fmt {
759 proof fn lemma_serialize_len(&self, v: Self::SVal) {
760 if fits_i8(v) {
761 I8.lemma_serialize_len(v as i8);
762 } else {
763 I16Be.lemma_serialize_len(v);
764 }
765 }
766 }
767
768 impl SPRoundTripDps for Integer16Fmt {
769 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
770 if fits_i8(v) {
771 I8.theorem_serialize_dps_parse_roundtrip(v as i8, Seq::empty());
772 } else {
773 I16Be.theorem_serialize_dps_parse_roundtrip(v, Seq::empty());
774 }
775 }
776 }
777
778 impl NonMalleable for Integer16Fmt {
779 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
780 if buf1.len() == 1 && buf2.len() == 1 {
781 I8.lemma_parse_non_malleable(buf1, buf2);
782 } else if buf1.len() == 2 && buf2.len() == 2 {
783 I16Be.lemma_parse_non_malleable(buf1, buf2);
784 }
785 }
786 }
787
788 impl EquivSerializers for Integer16Fmt {
789 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
790 if fits_i8(v) {
791 I8.lemma_serialize_equiv_on_empty(v as i8);
792 } else {
793 I16Be.lemma_serialize_equiv_on_empty(v);
794 }
795 }
796 }
797
798}
799
800impl<'i> Parser<&'i [u8]> for super::IntegerFmt {
801 type PT = Integer<'i>;
802
803 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
804 let (n, bytes) = Tail.parse(ibuf)?;
805 if bytes.len() == 0 {
806 return Err(ParseError::custom("Empty integer"));
807 }
808 if bytes.len() > 1 {
809 let b0 = bytes[0];
810 let b1 = bytes[1];
811 if b0 == 0x00 && b1 < 0x80 {
812 return Err(ParseError::custom("Non-minimal integer"));
813 }
814 if b0 == 0xFF && b1 >= 0x80 {
815 return Err(ParseError::custom("Non-minimal integer"));
816 }
817 }
818 if bytes.len() <= 8 {
819 Ok((n, Integer::Small { v: i64_from_be_bytes(bytes) }))
820 } else {
821 Ok((n, Integer::Big { raw: BigInt::new(bytes) }))
822 }
823 }
824}
825
826impl<'i> Parser<&'i [u8]> for Integer8Fmt {
827 type PT = i8;
828
829 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
830 if ibuf.len() == 1 {
831 I8.parse(ibuf)
832 } else {
833 Err(ParseError::custom("Integer out of range for i8"))
834 }
835 }
836}
837
838impl<'i> Parser<&'i [u8]> for Integer16Fmt {
839 type PT = i16;
840
841 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
842 if ibuf.len() == 1 {
843 let (n, v) = I8.parse(ibuf)?;
844 Ok((n, v as i16))
845 } else if ibuf.len() == 2 {
846 let (n, v) = I16Be.parse(ibuf)?;
847 if fits_i8(v) {
848 Err(ParseError::non_canonical())
849 } else {
850 Ok((n, v))
851 }
852 } else {
853 Err(ParseError::custom("Integer out of range for i16"))
854 }
855 }
856}
857
858impl<Output: OutputBuf> Serializer<Output, i8> for Integer8Fmt {
859 fn serialize_into(&self, v: &i8, obuf: &mut Output) {
860 I8.serialize_into(v, obuf);
861 }
862}
863
864impl Prepare<i8> for Integer8Fmt {
865 fn prepare(&self, v: &i8) -> Result<usize, PreSerializeError> {
866 I8.prepare(v)
867 }
868}
869
870impl ByteLen<i8> for Integer8Fmt {
871 fn length(&self, v: &i8) -> usize {
872 I8.length(v)
873 }
874}
875
876impl<Output: OutputBuf> Serializer<Output, i16> for Integer16Fmt {
877 fn serialize_into(&self, v: &i16, obuf: &mut Output) {
878 if fits_i8(*v) {
879 I8.serialize_into(&(*v as i8), obuf);
880 } else {
881 I16Be.serialize_into(v, obuf);
882 }
883 }
884}
885
886impl Prepare<i16> for Integer16Fmt {
887 fn prepare(&self, v: &i16) -> Result<usize, PreSerializeError> {
888 if fits_i8(*v) {
889 I8.prepare(&(*v as i8))
890 } else {
891 I16Be.prepare(v)
892 }
893 }
894}
895
896impl ByteLen<i16> for Integer16Fmt {
897 fn length(&self, v: &i16) -> usize {
898 if fits_i8(*v) {
899 I8.length(&(*v as i8))
900 } else {
901 I16Be.length(v)
902 }
903 }
904}
905
906impl<Output: OutputBuf, 'i> Serializer<Output, Integer<'i>> for super::IntegerFmt {
907 fn serialize_into(&self, v: &Integer<'i>, obuf: &mut Output) {
908 match v {
909 Integer::Small { v } => {
910 let len = i64_to_be_bytes_len(*v);
911 let mut bytes = [0u8;size_of::<i64>() + 1];
912 let (encoded, _) = bytes.split_at_mut(len);
913 i64_to_be_bytes_in_place(*v, encoded);
914 Tail.serialize_into(&bytes[0..len], obuf);
915 },
916 Integer::Big { raw } => {
917 let bytes = raw.as_slice();
918 proof {
919 use_type_invariant(raw);
920 lemma_integer_fmt_sound_nonmal_inv();
921 lemma_integer_from_to_bytes(bytes.deep_view());
922 }
923 Tail.serialize_into(&bytes, obuf);
924 },
925 }
926 }
927}
928
929impl<'i> Prepare<Integer<'i>> for super::IntegerFmt {
930 fn prepare(&self, v: &Integer<'i>) -> Result<usize, PreSerializeError> {
931 match v {
932 Integer::Small { v } => {
933 let len = i64_to_be_bytes_len(*v);
934 proof {
935 lemma_integer_to_from_bytes(*v as int);
936 }
937 Ok(len)
938 },
939 Integer::Big { raw } => {
940 let bytes = raw.as_slice();
941 proof {
942 use_type_invariant(raw);
943 lemma_integer_fmt_sound_nonmal_inv();
944 lemma_integer_from_to_bytes(bytes.deep_view());
945 }
946 Tail.prepare(&bytes)
947 },
948 }
949 }
950}
951
952impl<'i> ByteLen<Integer<'i>> for super::IntegerFmt {
953 fn length(&self, v: &Integer<'i>) -> usize {
954 match v {
955 Integer::Small { v } => { i64_to_be_bytes_len(*v) },
956 Integer::Big { raw } => {
957 let bytes = raw.as_slice();
958 proof {
959 use_type_invariant(raw);
960 lemma_integer_fmt_sound_nonmal_inv();
961 lemma_integer_from_to_bytes(bytes.deep_view());
962 }
963 Tail.length(&bytes)
964 },
965 }
966 }
967}
968
969broadcast proof fn lemma_u64_as_i64(u: u64)
970 by (bit_vector)
971 ensures
972 u < 0x8000000000000000 ==> #[trigger] (u as i64) as int == u as int,
973 u >= 0x8000000000000000 ==> #[trigger] (u as i64) as int == u as int - 0x10000000000000000,
974{
975}
976
977pub fn i64_from_be_bytes(bytes: &[u8]) -> (r: i64)
979 requires
980 usize::BITS == 64,
981 1 <= bytes.len() <= 8,
982 ensures
983 r as int == int_from_be_bytes(bytes.deep_view()),
984{
985 broadcast use {lemma_pow_multiplies, lemma_pow2, lemma_pow_increases};
986 broadcast use lemma_from_be_bytes_upper_bound;
987 broadcast use lemma_u64_as_i64;
988
989 let n = bytes.len();
990 let u = u64_from_be_bytes(bytes);
991
992 let ghost s = bytes.deep_view();
993 let ghost (first, rest) = (s.first(), s.drop_first());
994 let ghost pw = pow(256, (n - 1) as nat);
995 let ghost nfb_rest = nat_from_be_bytes(rest);
996 proof {
997 assert(s == seq![first] + rest);
998 lemma_from_be_bytes_prepend(rest, first);
999 assert(nat_from_be_bytes(s) == first * pw + nfb_rest);
1001 reveal_with_fuel(pow, 9);
1002 }
1003 if bytes[0] >= 0x80 {
1004 if n == 8 {
1006 proof {
1007 assert(first * pw + nfb_rest >= 0x8000000000000000) by (nonlinear_arith)
1009 requires
1010 first >= 0x80,
1011 pw == 0x100000000000000,
1012 ;
1013 }
1014 u as i64
1016 } else { let shift: u64 = 8 * (n as u64);
1018 proof {
1019 assert(pow(2, 8) == 256) by (compute_only);
1021 lemma_u64_shl_is_mul(1u64, shift);
1022 }
1023 let sub: u64 = 1u64 << shift;
1024 (u as i64) - (sub as i64)
1027 }
1028 } else {
1029 proof {
1031 assert(nat_from_be_bytes(s) < 0x8000000000000000) by (nonlinear_arith)
1033 requires
1034 nat_from_be_bytes(s) == first as nat * pw + nfb_rest,
1035 nfb_rest < pw,
1036 first < 0x80,
1037 pw <= 0x100000000000000,
1038 ;
1039 }
1040 u as i64
1041 }
1042}
1043
1044#[cfg(feature = "alloc")]
1049pub fn i64_to_be_bytes(v: i64) -> (buf: Vec<u8>)
1050 requires
1051 usize::BITS == 64,
1052 ensures
1053 buf@ == int_to_be_bytes(v as int),
1054{
1055 if v >= 0 {
1056 let mut body = u64_to_be_bytes(v as u64);
1057 if body[0] >= 0x80 { body.insert(0, 0x00u8);
1059 body
1060 } else { body
1062 }
1063 } else {
1064 let m: u64 = (-1 - v) as u64;
1065 let mut body = u64_to_be_bytes(m);
1066 let ghost orig = body@;
1068 invert_bytes_in_place(&mut body);
1069 if body[0] >= 0x80 { body
1071 } else { body.insert(0, 0xFFu8);
1073 body
1074 }
1075 }
1076}
1077
1078pub fn i64_to_be_bytes_len(v: i64) -> (len: usize)
1080 requires
1081 usize::BITS == 64,
1082 ensures
1083 len == int_to_be_bytes(v as int).len(),
1084 len <= size_of::<i64>() + 1,
1085{
1086 let magnitude = if v >= 0 {
1087 v as u64
1088 } else {
1089 (-1 - v) as u64
1090 };
1091 let body_len = u64_to_be_bytes_len(magnitude);
1092 let first = u64_to_be_bytes_first(magnitude);
1093 proof {
1094 lemma_usize_to_be_bytes_len_bound(magnitude as usize);
1095 assert(body_len <= 8);
1096 if v >= 0 {
1097 assert(magnitude as nat == v as int);
1098 } else {
1099 assert(-1i64 - v >= 0);
1100 assert(magnitude as int == (-1i64 - v) as int);
1101 assert((-1i64 - v) as int == -1 - v as int);
1102 lemma_invert_byte_props(first);
1103 }
1104 }
1105 if first >= 0x80 {
1106 body_len + 1
1107 } else {
1108 body_len
1109 }
1110}
1111
1112fn invert_bytes_in_place(obuf: &mut [u8])
1114 ensures
1115 final(obuf)@ == invert_bytes(old(obuf)@),
1116{
1117 let n = obuf.len();
1118 for i in 0..n
1119 invariant
1120 n == obuf.len(),
1121 forall|k: int| 0 <= k < i ==> #[trigger] obuf@[k] == invert_byte(old(obuf)@[k]),
1122 forall|k: int| i <= k < n ==> #[trigger] obuf@[k] == old(obuf)@[k],
1123 {
1124 obuf[i] = !obuf[i];
1125 }
1126 assert(obuf@ =~= invert_bytes(old(obuf)@));
1127}
1128
1129pub fn i64_to_be_bytes_in_place(v: i64, obuf: &mut [u8])
1131 requires
1132 usize::BITS == 64,
1133 old(obuf)@.len() == int_to_be_bytes(v as int).len(),
1134 ensures
1135 final(obuf)@ == int_to_be_bytes(v as int),
1136{
1137 let magnitude = if v >= 0 {
1138 v as u64
1139 } else {
1140 (-1 - v) as u64
1141 };
1142 let first = u64_to_be_bytes_first(magnitude);
1143 proof {
1144 if v < 0 {
1145 lemma_invert_byte_props(first);
1146 }
1147 }
1148 if first >= 0x80 {
1149 let (sign, body) = obuf.split_at_mut(1);
1150 if v >= 0 {
1151 sign[0] = 0x00u8;
1152 } else {
1153 sign[0] = 0xFFu8;
1154 }
1155 usize_to_be_bytes_in_place(magnitude as usize, body);
1156 if v < 0 {
1157 invert_bytes_in_place(body);
1158 }
1159 } else {
1160 usize_to_be_bytes_in_place(magnitude as usize, obuf);
1161 if v < 0 {
1162 invert_bytes_in_place(obuf);
1163 }
1164 }
1165}
1166
1167} #[cfg(test)]
1169mod tests {
1170 use super::{Integer16Fmt, Integer8Fmt};
1171 use crate::core::exec::{Parser, Prepare, SerializerExt};
1172
1173 #[test]
1174 fn integer8_boundaries_and_noncanonical_lengths() {
1175 for (bytes, expected) in [(&[0x80u8][..], -128i8), (&[0x7fu8][..], 127i8)] {
1176 let (_, value) = Integer8Fmt.parse(&bytes).unwrap();
1177 assert_eq!(value, expected);
1178 }
1179
1180 let two_bytes = &[0x00u8, 0x7f][..];
1181 assert!(Integer8Fmt.parse(&two_bytes).is_err());
1182 }
1183
1184 #[test]
1185 fn integer16_uses_minimal_one_or_two_octets() {
1186 for (value, expected) in [
1187 (-32768i16, &[0x80u8, 0x00][..]),
1188 (-129i16, &[0xffu8, 0x7f][..]),
1189 (-128i16, &[0x80u8][..]),
1190 (127i16, &[0x7fu8][..]),
1191 (128i16, &[0x00u8, 0x80][..]),
1192 (32767i16, &[0x7fu8, 0xff][..]),
1193 ] {
1194 let mut encoded = vec![0; Integer16Fmt.prepare(&value).unwrap()];
1195 Integer16Fmt.serialize(&value, &mut encoded);
1196 assert_eq!(encoded, expected);
1197
1198 let (_, decoded) = Integer16Fmt.parse(&expected).unwrap();
1199 assert_eq!(decoded, value);
1200 }
1201
1202 for bytes in [&[0x00u8, 0x7f][..], &[0xffu8, 0x80][..]] {
1203 assert!(Integer16Fmt.parse(&bytes).is_err());
1204 }
1205 }
1206
1207 #[test]
1208 fn test_integer8_equivalence_with_general_integer() {
1209 use super::Integer;
1210 use crate::asn1::IntegerFmt;
1211
1212 for v in -128..=127 {
1213 let mut enc8 = vec![0; Integer8Fmt.prepare(&v).unwrap()];
1215 Integer8Fmt.serialize(&v, &mut enc8);
1216
1217 let val = Integer::Small { v: v as i64 };
1219 let mut enc_gen = vec![0; IntegerFmt.prepare(&val).unwrap()];
1220 IntegerFmt.serialize(&val, &mut enc_gen);
1221
1222 assert_eq!(enc8, enc_gen, "Mismatch serialization at {}", v);
1223
1224 let enc8_slice = enc8.as_slice();
1226 let (_, dec8) = Integer8Fmt.parse(&enc8_slice).unwrap();
1227 assert_eq!(dec8, v);
1228
1229 let (_, dec_gen) = IntegerFmt.parse(&enc8_slice).unwrap();
1231 match dec_gen {
1232 Integer::Small { v: val_i64 } => {
1233 assert_eq!(val_i64, v as i64);
1234 }
1235 _ => panic!("Expected Small for {}", v),
1236 }
1237 }
1238 }
1239
1240 #[test]
1241 fn test_integer16_equivalence_with_general_integer() {
1242 use super::Integer;
1243 use crate::asn1::IntegerFmt;
1244
1245 for v in -32768..=32767 {
1246 let mut enc16 = vec![0; Integer16Fmt.prepare(&v).unwrap()];
1248 Integer16Fmt.serialize(&v, &mut enc16);
1249
1250 let val = Integer::Small { v: v as i64 };
1252 let mut enc_gen = vec![0; IntegerFmt.prepare(&val).unwrap()];
1253 IntegerFmt.serialize(&val, &mut enc_gen);
1254
1255 assert_eq!(enc16, enc_gen, "Mismatch serialization at {}", v);
1256
1257 let enc16_slice = enc16.as_slice();
1259 let (_, dec16) = Integer16Fmt.parse(&enc16_slice).unwrap();
1260 assert_eq!(dec16, v);
1261
1262 let (_, dec_gen) = IntegerFmt.parse(&enc16_slice).unwrap();
1264 match dec_gen {
1265 Integer::Small { v: val_i64 } => {
1266 assert_eq!(val_i64, v as i64);
1267 }
1268 _ => panic!("Expected Small for {}", v),
1269 }
1270 }
1271 }
1272}