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