1use crate::vstd::arithmetic::div_mod::*;
5use crate::vstd::arithmetic::mul::*;
6use crate::vstd::arithmetic::power::*;
7use crate::vstd::arithmetic::power2::*;
8use crate::vstd::calc_macro::*;
9use crate::vstd::group_vstd_default;
10use crate::vstd::layout;
11use crate::vstd::prelude::*;
12use core::marker::PhantomData;
13
14verus! {
15
16broadcast use group_vstd_default;
17
18pub trait Base {
20 spec fn base() -> nat;
21
22 proof fn base_min()
23 ensures
24 Self::base() > 1,
25 ;
26}
27
28pub open spec fn base_upper_bound_excl<B: Base>(len: nat) -> int {
32 pow(B::base() as int, len)
33}
34
35pub trait BasePow2: Base {
37 spec fn bits() -> nat;
38
39 proof fn bits_to_base()
40 ensures
41 Self::bits() > 1,
42 Self::base() == pow2(Self::bits()),
43 ;
44}
45
46pub trait CompatibleSmallerBaseFor<BIG: BasePow2>: BasePow2 {
48 proof fn compatible()
49 ensures
50 BIG::bits() > Self::bits() && BIG::bits() % Self::bits() == 0,
51 ;
52}
53
54pub enum Endian {
56 Little,
57 Big,
58}
59
60pub uninterp spec fn endianness() -> Endian;
63
64#[verifier::ext_equal]
68pub struct EndianNat<B: Base> {
69 pub endian: Endian,
70 pub digits: Seq<int>,
71 pub phantom: core::marker::PhantomData<B>,
72}
73
74impl<B: Base> EndianNat<B> {
75 pub open spec fn in_bounds(s: Seq<int>) -> bool {
77 forall|i| 0 <= i < s.len() ==> 0 <= #[trigger] s[i] < B::base()
78 }
79
80 pub open spec fn wf(self) -> bool {
82 Self::in_bounds(self.digits)
83 }
84
85 pub open spec fn new(endian: Endian, digits: Seq<int>) -> Self
87 recommends
88 Self::in_bounds(digits),
89 {
90 EndianNat { endian, digits, phantom: PhantomData }
91 }
92
93 pub open spec fn new_default(digits: Seq<int>) -> Self
95 recommends
96 Self::in_bounds(digits),
97 {
98 EndianNat { endian: endianness(), digits, phantom: PhantomData }
99 }
100
101 pub open spec fn len(self) -> nat {
103 self.digits.len()
104 }
105
106 pub open spec fn index(self, i: int) -> int
108 recommends
109 0 <= i < self.digits.len(),
110 {
111 self.digits[i]
112 }
113
114 #[verifier::inline]
115 pub open spec fn spec_index(self, i: int) -> int
116 recommends
117 0 <= i < self.digits.len(),
118 {
119 self.index(i)
120 }
121
122 pub open spec fn first(self) -> nat
124 recommends
125 self.digits.len() > 0,
126 {
127 self.digits.first() as nat
128 }
129
130 pub open spec fn last(self) -> nat
132 recommends
133 self.digits.len() > 0,
134 {
135 self.digits.last() as nat
136 }
137
138 pub open spec fn least(self) -> nat
140 recommends
141 self.digits.len() > 0,
142 {
143 match self.endian {
144 Endian::Little => self.first(),
145 Endian::Big => self.last(),
146 }
147 }
148
149 pub open spec fn most(self) -> nat
151 recommends
152 self.digits.len() > 0,
153 {
154 match self.endian {
155 Endian::Little => self.last(),
156 Endian::Big => self.first(),
157 }
158 }
159
160 pub open spec fn skip(self, n: nat) -> Self
162 recommends
163 0 <= n <= self.digits.len(),
164 {
165 EndianNat { endian: self.endian, digits: self.digits.skip(n as int), phantom: self.phantom }
166 }
167
168 pub open spec fn take(self, n: nat) -> Self
170 recommends
171 0 <= n <= self.digits.len(),
172 {
173 EndianNat { endian: self.endian, digits: self.digits[..n], phantom: self.phantom }
174 }
175
176 #[verifier::inline]
177 pub open spec fn spec_index_range_from<N: Integer>(self, n: N) -> Self
178 recommends
179 0 <= n as int <= self.digits.len(),
180 {
181 self.skip(n as nat)
182 }
183
184 #[verifier::inline]
185 pub open spec fn spec_index_range_to<N: Integer>(self, n: N) -> Self
186 recommends
187 0 <= n as int <= self.digits.len(),
188 {
189 self.take(n as nat)
190 }
191
192 pub open spec fn skip_least(self, n: nat) -> Self
194 recommends
195 0 <= n <= self.digits.len(),
196 {
197 match self.endian {
198 Endian::Little => self[n..],
199 Endian::Big => self[..self.len() - n],
200 }
201 }
202
203 pub open spec fn skip_most(self, n: nat) -> Self
205 recommends
206 0 <= n <= self.digits.len(),
207 {
208 match self.endian {
209 Endian::Little => self[..self.len() - n],
210 Endian::Big => self[n..],
211 }
212 }
213
214 pub open spec fn take_least(self, n: nat) -> Self
216 recommends
217 0 <= n <= self.digits.len(),
218 {
219 match self.endian {
220 Endian::Little => self[..n],
221 Endian::Big => self[self.len() - n..],
222 }
223 }
224
225 pub open spec fn take_most(self, n: nat) -> Self
227 recommends
228 0 <= n <= self.digits.len(),
229 {
230 match self.endian {
231 Endian::Little => self[self.len() - n..],
232 Endian::Big => self[..n],
233 }
234 }
235
236 pub open spec fn drop_first(self) -> Self
238 recommends
239 self.len() > 0,
240 {
241 EndianNat { endian: self.endian, digits: self.digits.drop_first(), phantom: self.phantom }
242 }
243
244 pub open spec fn drop_last(self) -> Self
246 recommends
247 self.len() > 0,
248 {
249 EndianNat { endian: self.endian, digits: self.digits.drop_last(), phantom: self.phantom }
250 }
251
252 pub open spec fn drop_least(self) -> Self
254 recommends
255 self.len() > 0,
256 {
257 match self.endian {
258 Endian::Little => self.drop_first(),
259 Endian::Big => self.drop_last(),
260 }
261 }
262
263 pub open spec fn drop_most(self) -> Self
265 recommends
266 self.len() > 0,
267 {
268 match self.endian {
269 Endian::Little => self.drop_last(),
270 Endian::Big => self.drop_first(),
271 }
272 }
273
274 pub open spec fn append(self, other: Self) -> Self
276 recommends
277 self.endian == other.endian,
278 {
279 EndianNat::new(self.endian, self.digits + other.digits)
280 }
281
282 pub open spec fn append_least(self, other: Self) -> Self
285 recommends
286 self.endian == other.endian,
287 {
288 match self.endian {
289 Endian::Little => other.append(self),
290 Endian::Big => self.append(other),
291 }
292 }
293
294 pub open spec fn append_most(self, other: Self) -> Self
297 recommends
298 self.endian == other.endian,
299 {
300 match self.endian {
301 Endian::Little => self.append(other),
302 Endian::Big => other.append(self),
303 }
304 }
305
306 pub open spec fn push_first(self, n: int) -> Self
308 recommends
309 n < B::base(),
310 {
311 EndianNat { endian: self.endian, digits: seq![n].add(self.digits), phantom: self.phantom }
312 }
313
314 pub open spec fn push_last(self, n: int) -> Self
316 recommends
317 n < B::base(),
318 {
319 EndianNat { endian: self.endian, digits: self.digits.push(n), phantom: self.phantom }
320 }
321
322 pub open spec fn push_least(self, n: int) -> Self
324 recommends
325 n < B::base(),
326 {
327 match self.endian {
328 Endian::Little => self.push_first(n),
329 Endian::Big => self.push_last(n),
330 }
331 }
332
333 pub open spec fn push_most(self, n: int) -> Self
335 recommends
336 n < B::base(),
337 {
338 match self.endian {
339 Endian::Little => self.push_last(n),
340 Endian::Big => self.push_first(n),
341 }
342 }
343
344 #[verifier::opaque]
346 pub open spec fn to_nat(self) -> nat
347 decreases self.len(),
348 {
349 if self.len() == 0 {
350 0
351 } else {
352 self.drop_least().to_nat() * B::base() + self.least()
353 }
354 }
355
356 pub broadcast proof fn to_nat_properties(self)
357 requires
358 self.wf(),
359 ensures
360 #[trigger] self.to_nat() < base_upper_bound_excl::<B>(self.len()),
361 decreases self.len(),
362 {
363 reveal(EndianNat::to_nat);
364 reveal(pow);
365 if self.len() == 0 {
366 } else {
367 self.drop_least().to_nat_properties();
368
369 calc! {
370 (<)
371 self.to_nat(); (==) {}
372 self.drop_least().to_nat() * B::base() + self.least(); (<) {}
373 self.drop_least().to_nat() * B::base() + B::base(); (<=) {
374 broadcast use lemma_mul_inequality, lemma_mul_is_distributive_sub_other_way;
375
376 assert((base_upper_bound_excl::<B>((self.len() - 1) as nat) - 1)
377 * B::base() as nat == (base_upper_bound_excl::<B>((self.len() - 1) as nat)
378 * B::base() - B::base()) as nat);
379 }
380 (base_upper_bound_excl::<B>((self.len() - 1) as nat) * B::base() - B::base()
381 + B::base()) as nat; (==) {
382 broadcast use lemma_pow1;
383
384 }
385 (base_upper_bound_excl::<B>((self.len() - 1) as nat) * pow(
386 B::base() as int,
387 1,
388 )) as nat; (==) {
389 broadcast use lemma_pow_sub_add_cancel;
390
391 }
392 base_upper_bound_excl::<B>(self.len()) as nat;
393 }
394 }
395 }
396
397 pub proof fn to_nat_append_least(endian: Self, other: Self)
398 requires
399 endian.wf(),
400 other.wf(),
401 endian.endian == other.endian,
402 ensures
403 endian.append_least(other).to_nat() == (endian.to_nat() * base_upper_bound_excl::<B>(
404 other.len(),
405 )) + other.to_nat(),
406 decreases other.len(),
407 {
408 reveal(EndianNat::to_nat);
409 reveal(pow);
410 if other.len() == 0 {
411 } else {
412 let least = other.least();
413 let rest = other.drop_least();
414 Self::to_nat_append_least(endian, rest);
415 assert(endian.append_least(other).drop_least() =~= endian.append_least(rest));
416 assert(endian.to_nat() * base_upper_bound_excl::<B>(rest.len()) * B::base()
417 == endian.to_nat() * base_upper_bound_excl::<B>(rest.len() + 1)) by {
418 broadcast use lemma_pow1;
419
420 assert(B::base() == pow(B::base() as int, 1));
421 broadcast use lemma_pow_adds;
422
423 assert(pow(B::base() as int, rest.len() + 1) == pow(B::base() as int, rest.len())
424 * pow(B::base() as int, 1));
425 assert(endian.to_nat() * base_upper_bound_excl::<B>(rest.len()) * B::base()
426 == endian.to_nat() * base_upper_bound_excl::<B>(rest.len() + 1))
427 by (nonlinear_arith)
428 requires
429 base_upper_bound_excl::<B>(rest.len()) * B::base()
430 == base_upper_bound_excl::<B>(rest.len() + 1),
431 ;
432 }
433 assert(endian.append_least(other).to_nat() == (endian.to_nat()
434 * base_upper_bound_excl::<B>(other.len())) + other.to_nat()) by (nonlinear_arith)
435 requires
436 endian.append_least(other).to_nat() == endian.append_least(rest).to_nat()
437 * B::base() + least,
438 other.to_nat() == rest.to_nat() * B::base() + least,
439 endian.append_least(rest).to_nat() == (endian.to_nat()
440 * base_upper_bound_excl::<B>(rest.len())) + rest.to_nat(),
441 endian.to_nat() * base_upper_bound_excl::<B>(rest.len()) * B::base()
442 == endian.to_nat() * base_upper_bound_excl::<B>(rest.len() + 1),
443 other.len() == rest.len() + 1,
444 ;
445 }
446 }
447
448 pub open spec fn from_nat(n: nat, len: nat) -> Self
451 recommends
452 n < base_upper_bound_excl::<B>(len),
453 decreases len,
454 {
455 if len == 0 {
456 EndianNat { digits: Seq::empty(), endian: endianness(), phantom: PhantomData }
457 } else {
458 let least = (n % B::base()) as int;
459 let rest = n / B::base();
460 let rest_endian = Self::from_nat(rest, (len - 1) as nat);
461 rest_endian.push_least(least)
462 }
463 }
464
465 proof fn base_upper_bound_excl_len(n: nat, len: nat)
466 requires
467 n < base_upper_bound_excl::<B>(len),
468 0 < len,
469 ensures
470 n / B::base() < base_upper_bound_excl::<B>((len - 1) as nat),
471 {
472 reveal(pow);
473 assert(n / B::base() < base_upper_bound_excl::<B>((len - 1) as nat)) by (nonlinear_arith)
474 requires
475 n < B::base() * base_upper_bound_excl::<B>((len - 1) as nat),
476 B::base() > 0,
477 ;
478 }
479
480 pub broadcast proof fn from_nat_properties(n: nat, len: nat)
481 requires
482 n < base_upper_bound_excl::<B>(len),
483 ensures
484 #![trigger Self::from_nat(n, len)]
485 Self::from_nat(n, len).len() == len,
486 Self::from_nat(n, len).endian == endianness(),
487 Self::from_nat(n, len).wf(),
488 decreases len,
489 {
490 if len == 0 {
491 } else {
492 Self::base_upper_bound_excl_len(n, len);
493 let endian_nat = Self::from_nat(n, len);
494 let least = endian_nat.least();
495 Self::from_nat_properties(n / B::base(), (len - 1) as nat);
496 B::base_min();
497 assert(least < B::base()) by (nonlinear_arith)
498 requires
499 B::base() > 0,
500 least == (n % B::base()),
501 ;
502 }
503 }
504
505 pub broadcast proof fn from_nat_to_nat(n: nat, len: nat)
511 requires
512 n < base_upper_bound_excl::<B>(len),
513 ensures
514 #[trigger] Self::from_nat(n, len).to_nat() == n,
515 decreases Self::from_nat(n, len).len(),
516 {
517 reveal(pow);
518 reveal(EndianNat::to_nat);
519 if Self::from_nat(n, len).len() == 0 {
520 } else {
521 B::base_min();
522 let endian_nat = Self::from_nat(n, len);
523 let least = endian_nat.least();
524 let rest = endian_nat.drop_least();
525 assert(rest =~= Self::from_nat(n / B::base(), (len - 1) as nat));
526 Self::base_upper_bound_excl_len(n, len);
527 Self::from_nat_to_nat(n / B::base(), (len - 1) as nat);
528 assert((n % B::base()) + (n / B::base()) * B::base() == n) by (nonlinear_arith)
529 requires
530 B::base() > 0,
531 ;
532 }
533 }
534
535 pub broadcast proof fn to_nat_from_nat(endian_nat: Self)
540 requires
541 endian_nat.wf(),
542 endian_nat.endian == endianness(),
543 ensures
544 #[trigger] Self::from_nat(endian_nat.to_nat(), endian_nat.len()) == endian_nat,
545 decreases endian_nat.len(),
546 {
547 reveal(pow);
548 reveal(EndianNat::to_nat);
549 if endian_nat.len() == 0 {
550 } else {
551 let n = endian_nat.to_nat();
552 let least = endian_nat.least();
553 let rest = endian_nat.drop_least();
554 Self::to_nat_from_nat(rest);
555 assert(least == n % B::base() && rest.to_nat() == n / B::base()) by {
556 assert(n == rest.to_nat() * B::base() + least);
557 assert(least < B::base());
558 lemma_fundamental_div_mod_converse(
559 n as int,
560 B::base() as int,
561 rest.to_nat() as int,
562 least as int,
563 );
564 }
565 }
566 }
567
568 pub broadcast proof fn to_nat_injective(n1: Self, n2: Self)
569 requires
570 n1.wf(),
571 n2.wf(),
572 n1.endian == endianness(),
573 n2.endian == endianness(),
574 n1.len() == n2.len(),
575 #[trigger] n1.to_nat() == #[trigger] n2.to_nat(),
576 ensures
577 n1 == n2,
578 {
579 broadcast use EndianNat::to_nat_from_nat;
580
581 assert(Self::from_nat(n1.to_nat(), n1.len()) == n1);
582 assert(Self::from_nat(n2.to_nat(), n2.len()) == n2);
583 }
584
585 pub broadcast proof fn from_nat_injective(n1: nat, len1: nat, n2: nat, len2: nat)
586 requires
587 n1 < base_upper_bound_excl::<B>(len1),
588 n2 < base_upper_bound_excl::<B>(len2),
589 #[trigger] Self::from_nat(n1, len1) == #[trigger] Self::from_nat(n2, len2),
590 ensures
591 n1 == n2,
592 {
593 broadcast use EndianNat::from_nat_to_nat;
594
595 assert(Self::from_nat(n1, len1).to_nat() == n1);
596 assert(Self::from_nat(n2, len2).to_nat() == n2);
597 }
598
599 #[verifier::opaque]
601 pub open spec fn to_nat_most(self) -> nat
602 decreases self.len(),
603 {
604 if self.len() == 0 {
605 0
606 } else {
607 (self.drop_most().to_nat_most() + self.most() * pow(
608 B::base() as int,
609 (self.len() - 1) as nat,
610 )) as nat
611 }
612 }
613
614 pub broadcast proof fn to_nat_eq_to_nat_most(self)
619 requires
620 self.wf(),
621 ensures
622 #[trigger] self.to_nat() == #[trigger] self.to_nat_most(),
623 decreases self.len(),
624 {
625 reveal(EndianNat::to_nat);
626 reveal(EndianNat::to_nat_most);
627 if self.len() == 0 {
628 } else {
629 if self.drop_most().len() == 0 {
630 calc! {
631 (==)
632 self.to_nat_most(); {
633 assert(self.drop_most().to_nat_most() == 0);
634 assert(self.to_nat_most() == (self.most() * pow(
635 B::base() as int,
636 (self.len() - 1) as nat,
637 )) as nat);
638 }
639 (self.most() * pow(B::base() as int, (self.len() - 1) as nat)) as nat; {
640 reveal(pow);
641 assert((self.most() * pow(B::base() as int, (self.len() - 1) as nat))
642 == self.most()) by (nonlinear_arith)
643 requires
644 pow(B::base() as int, (self.len() - 1) as nat) == 1,
645 self.most() >= 0,
646 ;
647 }
648 self.most(); {}
649 self.least(); {
650 assert(self.drop_least().to_nat() == 0);
651 assert(0 * B::base() == 0);
652 }
653 self.to_nat();
654 };
655 } else {
656 calc! {
657 (==)
658 self.to_nat_most() as int; {}
659 ((self.drop_most().to_nat_most() + self.most() * pow(
660 B::base() as int,
661 (self.len() - 1) as nat,
662 )) as nat) as int; {
663 assert(self.most() >= 0);
664 assert(self.len() > 1);
665 lemma_pow_positive(B::base() as int, (self.len() - 1) as nat);
666 assert(pow(B::base() as int, (self.len() - 1) as nat) >= 0);
667 }
668 self.drop_most().to_nat_most() + self.most() * pow(
669 B::base() as int,
670 (self.len() - 1) as nat,
671 ); {
672 self.drop_most().to_nat_eq_to_nat_most();
673 }
674 self.drop_most().to_nat() + self.most() * pow(
675 B::base() as int,
676 (self.len() - 1) as nat,
677 ); {}
678 self.drop_most().drop_least().to_nat() * B::base() + self.drop_most().least()
679 + self.most() * pow(B::base() as int, (self.len() - 1) as nat); {
680 self.drop_most().drop_least().to_nat_eq_to_nat_most();
681 }
682 self.drop_most().drop_least().to_nat_most() * B::base()
683 + self.drop_most().least() + self.most() * pow(
684 B::base() as int,
685 (self.len() - 1) as nat,
686 ); {
687 assert(self.drop_most().drop_least() == self.drop_least().drop_most());
688 }
689 self.drop_least().drop_most().to_nat_most() * B::base() + self.least()
690 + self.most() * pow(B::base() as int, (self.len() - 1) as nat); {
691 assert(self.most() * pow(B::base() as int, (self.len() - 2) as nat)
692 * B::base() == self.most() * (pow(
693 B::base() as int,
694 (self.len() - 2) as nat,
695 ) * B::base())) by {
696 broadcast use crate::vstd::arithmetic::mul::lemma_mul_is_associative;
697
698 }
699 assert(pow(B::base() as int, (self.len() - 1) as nat) == pow(
700 B::base() as int,
701 (self.len() - 2) as nat,
702 ) * B::base()) by {
703 assert(B::base() == pow(B::base() as int, 1)) by {
704 lemma_pow1(B::base() as int);
705 }
706 lemma_pow_adds(B::base() as int, (self.len() - 2) as nat, 1);
707 }
708 }
709 self.drop_least().drop_most().to_nat_most() * B::base() + (self.most() * pow(
710 B::base() as int,
711 (self.len() - 2) as nat,
712 )) * B::base() + self.least(); {
713 lemma_mul_is_distributive_add_other_way(
714 B::base() as int,
715 self.drop_least().drop_most().to_nat_most() as int,
716 self.most() * pow(B::base() as int, (self.len() - 2) as nat),
717 );
718 }
719 (self.drop_least().drop_most().to_nat_most() + self.most() * pow(
720 B::base() as int,
721 (self.len() - 2) as nat,
722 )) * B::base() + self.least(); {
723 assert((self.drop_least().drop_most().to_nat_most() + self.most() * pow(
724 B::base() as int,
725 (self.len() - 2) as nat,
726 )) == self.drop_least().to_nat_most()) by {
727 lemma_pow_positive(B::base() as int, (self.len() - 2) as nat);
728 };
729 }
730 (self.drop_least().to_nat_most() * B::base() + self.least()) as int; {
731 self.drop_least().to_nat_eq_to_nat_most();
732 }
733 self.to_nat() as int;
734 }
735 }
736 }
737 }
738}
739
740impl<B: Base> EndianNat<B> {
744 pub open spec fn exp<BIG>() -> nat where BIG: BasePow2, B: CompatibleSmallerBaseFor<BIG> {
750 BIG::bits() / B::bits()
751 }
752
753 pub broadcast proof fn exp_properties<BIG>() where
754 BIG: BasePow2,
755 B: CompatibleSmallerBaseFor<BIG>,
756
757 ensures
758 #![trigger Self::exp()]
759 base_upper_bound_excl::<B>(Self::exp()) == BIG::base(),
760 Self::exp() > 0,
761 {
762 broadcast use crate::vstd::arithmetic::div_mod::group_div_basics;
763
764 assert(forall|x| x != 0 ==> #[trigger] (0int / x) == 0);
765 broadcast use crate::vstd::arithmetic::power::lemma_pow_multiplies;
766
767 B::bits_to_base();
768
769 calc! {
770 (==)
771 BIG::bits(); {
772 crate::vstd::arithmetic::div_mod::lemma_fundamental_div_mod(
773 BIG::bits() as int,
774 B::bits() as int,
775 );
776 }
777 B::bits() * (BIG::bits() / B::bits()) + (BIG::bits() % B::bits()); {
778 B::compatible();
779 }
780 B::bits() * (BIG::bits() / B::bits()); {}
781 B::bits() * Self::exp();
782 }
783 calc! {
784 (==)
785 base_upper_bound_excl::<B>(Self::exp()); {
786 crate::vstd::arithmetic::power::lemma_pow_multiplies(2, B::bits(), Self::exp());
787 crate::vstd::arithmetic::power2::lemma_pow2(B::bits());
788 }
789 pow(2, B::bits() * Self::exp()) as int; {}
790 pow(2, BIG::bits()) as int; {
791 crate::vstd::arithmetic::power2::lemma_pow2(BIG::bits());
792 }
793 pow2(BIG::bits()) as int; {
794 BIG::bits_to_base();
795 }
796 BIG::base() as int;
797 }
798
799 B::compatible();
800 assert((BIG::bits() / B::bits()) != 0);
801 BIG::bits_to_base();
802
803 }
804
805 pub open spec fn from_big<BIG>(n: EndianNat<BIG>) -> Self where
808 BIG: BasePow2,
809 B: CompatibleSmallerBaseFor<BIG>,
810
811 decreases n.len(),
812 {
813 if n.len() == 0 {
814 EndianNat::new(n.endian, Seq::empty())
815 } else {
816 Self::from_big(n.drop_least()).append_least(EndianNat::from_nat(n.least(), Self::exp()))
817 }
818 }
819
820 pub broadcast proof fn from_big_properties<BIG>(n: EndianNat<BIG>) where
821 BIG: BasePow2,
822 B: CompatibleSmallerBaseFor<BIG>,
823
824 requires
825 n.wf(),
826 n.endian == endianness(),
827 ensures
828 #![trigger Self::from_big(n)]
829 Self::from_big(n).wf(),
830 Self::from_big(n).endian == endianness(),
831 Self::from_big(n).len() == n.len() * Self::exp(),
832 Self::from_big(n).to_nat() == n.to_nat(),
833 decreases n.len(),
834 {
835 reveal(EndianNat::to_nat);
836 broadcast use EndianNat::exp_properties;
837
838 if n.len() == 0 {
839 } else {
840 let least = n.least();
841 let rest = n.drop_least();
842 Self::from_big_properties(rest);
843 Self::from_nat_properties(least, Self::exp());
844 assert(Self::from_big(n).len() == n.len() * Self::exp()) by (nonlinear_arith)
845 requires
846 Self::from_big(n).len() == (n.len() - 1) * Self::exp() + Self::exp(),
847 ;
848 let small_least = EndianNat::from_nat(least, Self::exp());
849 let small_rest = Self::from_big(rest);
850 Self::to_nat_append_least(small_rest, small_least);
851 Self::from_nat_to_nat(least, Self::exp());
852 }
853 }
854
855 #[verifier::opaque]
858 pub open spec fn to_big<BIG>(n: EndianNat<B>) -> EndianNat<BIG> where
859 BIG: BasePow2,
860 B: CompatibleSmallerBaseFor<BIG>,
861
862 recommends
863 n.len() % Self::exp() == 0,
864 decreases n.len(),
865 when n.len() % Self::exp() == 0
866 via Self::to_big_decreases
867 {
868 if n.len() == 0 {
869 EndianNat::new(n.endian, Seq::empty())
870 } else {
871 Self::to_big(n.skip_least(Self::exp())).append_least(
872 EndianNat::new(n.endian, seq![n.take_least(Self::exp()).to_nat() as int]),
873 )
874 }
875 }
876
877 #[via_fn]
878 proof fn to_big_decreases<BIG>(n: EndianNat<B>) where
879 BIG: BasePow2,
880 B: CompatibleSmallerBaseFor<BIG>,
881 {
882 broadcast use EndianNat::exp_properties;
883
884 if n.len() != 0 {
885 assert(Self::exp() <= n.len()) by {
886 broadcast use crate::vstd::arithmetic::div_mod::lemma_mod_is_zero;
887
888 }
889 assert(n.skip_least(Self::exp()).len() < n.len());
890 }
891 }
892
893 pub broadcast proof fn to_big_properties<BIG>(n: EndianNat<B>) where
894 BIG: BasePow2,
895 B: CompatibleSmallerBaseFor<BIG>,
896
897 requires
898 n.wf(),
899 n.endian == endianness(),
900 n.len() % Self::exp() == 0,
901 ensures
902 #![trigger Self::to_big(n)]
903 Self::to_big(n).wf(),
904 Self::to_big(n).endian == endianness(),
905 Self::to_big(n).len() == n.len() / Self::exp(),
906 Self::to_big(n).to_nat() == n.to_nat(),
907 decreases n.len(),
908 {
909 reveal(EndianNat::to_big);
910 reveal(EndianNat::to_nat);
911 broadcast use EndianNat::exp_properties;
912
913 if n.len() == 0 {
914 } else {
915 let least = n.take_least(Self::exp());
916 let rest = n.skip_least(Self::exp());
917 assert(n.len() >= Self::exp()) by (nonlinear_arith)
918 requires
919 n.len() % Self::exp() == 0,
920 Self::exp() > 0,
921 n.len() > 0,
922 ;
923 assert(rest.len() % Self::exp() == 0) by {
924 lemma_mod_multiples_vanish(-1 as int, n.len() as int, Self::exp() as int);
925 assert(n.len() % Self::exp() == 0);
926 assert(rest.len() == n.len() - Self::exp() == -1 * Self::exp() + n.len());
927 }
928 Self::to_big_properties(rest);
929 Self::to_nat_properties(least);
930 let big_least = EndianNat::<BIG>::new(n.endian, seq![least.to_nat() as int]);
931 let big_rest = Self::to_big(rest);
932 assert(Self::to_big(n).to_nat() == n.to_nat()) by {
933 assert(big_rest.append_least(big_least).to_nat() == (big_rest.to_nat()
934 * base_upper_bound_excl::<BIG>(big_least.len())) + big_least.to_nat()) by {
935 EndianNat::<BIG>::to_nat_append_least(big_rest, big_least);
936 }
937 assert(big_least.to_nat() == least.to_nat()) by {
938 assert(big_least.drop_least().to_nat() * BIG::base() + big_least.least()
939 == least.to_nat()) by {
940 assert(big_least.least() == least.to_nat());
941 assert(big_least.drop_least().to_nat() == 0);
942 lemma_mul_basics(BIG::base() as int);
943 }
944 }
945 assert(n.to_nat() == (rest.to_nat() * base_upper_bound_excl::<B>(Self::exp()))
946 + least.to_nat()) by {
947 assert(n =~= rest.append_least(least));
948 EndianNat::<B>::to_nat_append_least(rest, least);
949 }
950 assert(base_upper_bound_excl::<B>(Self::exp()) == base_upper_bound_excl::<BIG>(
951 big_least.len(),
952 )) by {
953 broadcast use lemma_pow1;
954
955 }
956 }
957 assert(Self::to_big(n).len() == n.len() / Self::exp()) by {
958 assert(big_rest.len() == rest.len() / Self::exp());
959 assert(Self::to_big(n).len() == big_rest.len() + 1);
960 assert(n.len() == rest.len() + Self::exp());
961 assert(Self::exp() > 0);
962 lemma_div_plus_one(rest.len() as int, Self::exp() as int);
963 }
964 }
965
966 }
967
968 pub broadcast proof fn to_big_from_big<BIG>(n: EndianNat<B>) where
973 BIG: BasePow2,
974 B: CompatibleSmallerBaseFor<BIG>,
975
976 requires
977 n.wf(),
978 n.endian == endianness(),
979 n.len() % Self::exp() == 0,
980 ensures
981 #[trigger] Self::from_big(Self::to_big(n)) == n,
982 decreases n.len(),
983 {
984 reveal(EndianNat::to_big);
985 broadcast use EndianNat::exp_properties;
986
987 if n.len() == 0 {
988 } else {
989 let least = n.take_least(Self::exp());
990 let rest = n.skip_least(Self::exp());
991 assert(n.len() >= Self::exp()) by (nonlinear_arith)
992 requires
993 n.len() % Self::exp() == 0,
994 Self::exp() > 0,
995 n.len() > 0,
996 ;
997 lemma_mod_sub_multiples_vanish(n.len() as int, Self::exp() as int);
1000 assert(rest.len() % Self::exp() == 0);
1001 Self::to_big_from_big(rest);
1002 let big = Self::to_big(n);
1003 assert(big =~= Self::to_big(rest).append_least(
1004 EndianNat::new(n.endian, seq![least.to_nat() as int]),
1005 ));
1006 let big_least = big.least();
1007 let big_rest = big.drop_least();
1008 assert(big_rest =~= Self::to_big(rest));
1009 assert(Self::from_big(big_rest) == rest);
1010 Self::to_nat_from_nat(least);
1011 assert(EndianNat::<B>::from_nat(big_least, Self::exp()) == least);
1012 }
1013 }
1014
1015 #[verifier::spinoff_prover]
1020 #[verifier::rlimit(20)]
1021 pub broadcast proof fn from_big_to_big<BIG>(n: EndianNat<BIG>) where
1022 BIG: BasePow2,
1023 B: CompatibleSmallerBaseFor<BIG>,
1024
1025 requires
1026 n.wf(),
1027 n.endian == endianness(),
1028 ensures
1029 #[trigger] Self::to_big(Self::from_big(n)) == n,
1030 decreases n.len(),
1031 {
1032 reveal(EndianNat::to_big);
1033 reveal(EndianNat::to_nat);
1034 broadcast use EndianNat::exp_properties;
1035
1036 if n.len() == 0 {
1037 Self::from_big_properties(n);
1038 let small = Self::from_big(n);
1039 assert(small.len() % Self::exp() == 0) by (nonlinear_arith)
1040 requires
1041 small.len() == 0,
1042 Self::exp() > 0,
1043 ;
1044 Self::to_big_properties(small);
1045 assert(Self::to_big(Self::from_big(n)).digits == n.digits);
1046 assert(Self::to_big(Self::from_big(n)).endian == n.endian);
1047 } else {
1048 let least = n.least();
1049 let rest = n.drop_least();
1050 Self::from_big_to_big(rest);
1051 Self::from_big_properties(rest);
1052
1053 let small = Self::from_big(n);
1054 let small_least = small.take_least(Self::exp());
1055 let small_rest = small.skip_least(Self::exp());
1056 Self::from_nat_properties(least, Self::exp());
1057 let from_nat_least = EndianNat::<B>::from_nat(least, Self::exp());
1058 assert(small_least =~= from_nat_least);
1059 EndianNat::<B>::from_nat_to_nat(least, Self::exp());
1060
1061 assert(small_rest =~= Self::from_big(rest));
1062 lemma_mod_multiples_basic(rest.len() as int, Self::exp() as int);
1064 assert(small_rest.len() % Self::exp() == 0);
1065
1066 Self::from_big_properties(n);
1067 lemma_mod_multiples_basic(n.len() as int, Self::exp() as int);
1070 assert(small.len() % Self::exp() == 0);
1071 }
1072 }
1073
1074 pub broadcast proof fn to_big_injective<BIG>(n1: EndianNat<B>, n2: EndianNat<B>) where
1075 BIG: BasePow2,
1076 B: CompatibleSmallerBaseFor<BIG>,
1077
1078 requires
1079 n1.wf(),
1080 n2.wf(),
1081 n1.endian == endianness(),
1082 n2.endian == endianness(),
1083 n1.len() % Self::exp() == 0,
1084 n2.len() % Self::exp() == 0,
1085 #[trigger] Self::to_big(n1) == #[trigger] Self::to_big(n2),
1086 ensures
1087 n1 == n2,
1088 {
1089 broadcast use EndianNat::to_big_from_big;
1090
1091 assert(Self::from_big(Self::to_big(n1)) == n1);
1092 assert(Self::from_big(Self::to_big(n2)) == n2);
1093 }
1094
1095 pub broadcast proof fn from_big_injective<BIG>(n1: EndianNat<BIG>, n2: EndianNat<BIG>) where
1096 BIG: BasePow2,
1097 B: CompatibleSmallerBaseFor<BIG>,
1098
1099 requires
1100 n1.wf(),
1101 n2.wf(),
1102 n1.endian == endianness(),
1103 n2.endian == endianness(),
1104 #[trigger] Self::from_big(n1) == #[trigger] Self::from_big(n2),
1105 ensures
1106 n1 == n2,
1107 {
1108 broadcast use EndianNat::from_big_to_big;
1109
1110 assert(Self::to_big(Self::from_big(n1)) == n1);
1111 assert(Self::to_big(Self::from_big(n2)) == n2);
1112 }
1113
1114 #[verifier::spinoff_prover]
1115 pub proof fn to_big_single<BIG>(x: EndianNat<B>) where
1116 BIG: BasePow2,
1117 B: CompatibleSmallerBaseFor<BIG>,
1118
1119 requires
1120 x.len() == Self::exp(),
1121 x.len() > 0,
1122 ensures
1123 Self::to_big(x).len() == 1,
1124 Self::to_big(x)[0] == x.to_nat(),
1125 {
1126 broadcast use EndianNat::exp_properties;
1127
1128 reveal(EndianNat::to_big);
1129 crate::vstd::arithmetic::div_mod::lemma_mod_self_0(Self::exp() as int);
1130 crate::vstd::arithmetic::div_mod::lemma_small_mod(0, Self::exp());
1131 assert(x.len() % Self::exp() == 0);
1132 assert(x.skip_least(Self::exp()).len() == 0);
1133 assert(x.skip_least(Self::exp()).len() % Self::exp() == 0);
1134 assert(x =~= x.take_least(Self::exp()));
1135 assert(Self::to_big(x) == Self::to_big(x.skip_least(Self::exp())).append_least(
1136 EndianNat::new(x.endian, seq![x.take_least(Self::exp()).to_nat() as int]),
1137 ));
1138 }
1139}
1140
1141pub open spec fn to_big_from_digits<BIG, B>(n: Seq<B>) -> EndianNat<BIG> where
1145 BIG: BasePow2,
1146 B: CompatibleSmallerBaseFor<BIG> + Integer,
1147 {
1148 EndianNat::<B>::to_big::<BIG>(EndianNat::<B>::new(endianness(), n.map(|i, d| d as int)))
1149}
1150
1151impl Base for u8 {
1154 open spec fn base() -> nat {
1155 u8::MAX as nat + 1
1156 }
1157
1158 proof fn base_min() {
1159 }
1160}
1161
1162impl Base for u64 {
1163 open spec fn base() -> nat {
1164 u64::MAX as nat + 1
1165 }
1166
1167 proof fn base_min() {
1168 }
1169}
1170
1171impl Base for usize {
1172 open spec fn base() -> nat {
1173 usize::MAX as nat + 1
1174 }
1175
1176 proof fn base_min() {
1177 }
1178}
1179
1180impl BasePow2 for u8 {
1181 open spec fn bits() -> nat {
1182 8
1183 }
1184
1185 proof fn bits_to_base() {
1186 crate::vstd::arithmetic::power2::lemma2_to64();
1187 }
1188}
1189
1190impl BasePow2 for u64 {
1191 open spec fn bits() -> nat {
1192 64
1193 }
1194
1195 proof fn bits_to_base() {
1196 crate::vstd::arithmetic::power2::lemma2_to64();
1197 }
1198}
1199
1200impl BasePow2 for usize {
1201 open spec fn bits() -> nat {
1202 usize::BITS as nat
1203 }
1204
1205 proof fn bits_to_base() {
1206 crate::vstd::arithmetic::power2::lemma2_to64();
1207 }
1208}
1209
1210impl CompatibleSmallerBaseFor<u64> for u8 {
1211 proof fn compatible() {
1212 }
1213}
1214
1215impl CompatibleSmallerBaseFor<usize> for u8 {
1216 proof fn compatible() {
1217 }
1218}
1219
1220pub broadcast group group_endian_nat_axioms {
1221 EndianNat::from_nat_properties,
1222 EndianNat::to_nat_properties,
1223 EndianNat::from_nat_to_nat,
1224 EndianNat::to_nat_from_nat,
1225 EndianNat::to_nat_injective,
1226 EndianNat::from_nat_injective,
1227 EndianNat::to_nat_eq_to_nat_most,
1228 EndianNat::exp_properties,
1229 EndianNat::to_big_properties,
1230 EndianNat::from_big_properties,
1231 EndianNat::from_big_to_big,
1232 EndianNat::to_big_from_big,
1233 EndianNat::to_big_injective,
1234 EndianNat::from_big_injective,
1235}
1236
1237}