1use super::super::calc_macro::*;
15#[allow(unused_imports)]
16use super::super::prelude::*;
17
18verus! {
19
20#[verifier::inline]
21pub open spec fn rust_div(a: int, b: int) -> int
22 recommends
23 b != 0,
24{
25 if a == 0 {
26 0
27 } else if a > 0 {
28 a / b
29 } else {
30 -((-a) / b)
31 }
32}
33
34#[verifier::inline]
35pub open spec fn rust_rem(a: int, b: int) -> int
36 recommends
37 b != 0,
38{
39 if a == 0 {
40 0
41 } else if a > 0 {
42 a % b
43 } else {
44 -((-a) % b)
45 }
46}
47
48#[allow(unused_imports)]
49#[cfg(verus_keep_ghost)]
50use super::super::arithmetic::internals::div_internals::{
51 div_recursive,
52 lemma_div_induction_auto,
53 div_auto,
54 div_pos,
55 lemma_div_auto,
56};
57use super::super::arithmetic::internals::div_internals_nonlinear as DivINL;
58#[cfg(verus_keep_ghost)]
59use super::super::arithmetic::internals::mod_internals::{
60 lemma_div_add_denominator,
61 lemma_mod_auto,
62 mod_recursive,
63};
64use super::super::arithmetic::internals::mod_internals_nonlinear as ModINL;
65#[cfg(verus_keep_ghost)]
66use super::internals::mul_internals::{
67 group_mul_properties_internal,
68 lemma_mul_induction,
69 lemma_mul_induction_auto,
70};
71#[cfg(verus_keep_ghost)]
72use super::super::arithmetic::internals::general_internals::{is_le};
73#[cfg(verus_keep_ghost)]
74use super::super::math::{add as add1, sub as sub1, div as div1};
75use super::super::arithmetic::mul::*;
76
77pub broadcast proof fn lemma_div_is_div_recursive(x: int, d: int)
84 requires
85 0 < d,
86 ensures
87 div_recursive(x, d) == #[trigger] (x / d),
88{
89 reveal(div_recursive);
90 reveal(div_pos);
91 lemma_div_induction_auto(d, x, |u: int| div_recursive(u, d) == u / d);
92}
93
94pub proof fn lemma_div_by_self(d: int)
97 requires
98 d != 0,
99 ensures
100 d / d == 1,
101{
102 DivINL::lemma_div_by_self(d);
103}
104
105pub proof fn lemma_div_of0(d: int)
107 requires
108 d != 0,
109 ensures
110 0 as int / d == 0,
111{
112 DivINL::lemma_div_of0(d);
113}
114
115pub proof fn lemma_div_basics(x: int)
119 ensures
120 x != 0 as int ==> 0 as int / x == 0,
121 x / 1 == x,
122 x != 0 ==> x / x == 1,
123{
124 if (x != 0) {
125 lemma_div_by_self(x);
126 lemma_div_of0(x);
127 }
128}
129
130pub broadcast proof fn lemma_div_basics_1(x: int)
132 ensures
133 x != 0 as int ==> #[trigger] (0int / x) == 0,
134{
135 lemma_div_basics(x);
136}
137
138pub broadcast proof fn lemma_div_basics_2(x: int)
140 ensures
141 #[trigger] (x / 1) == x,
142{
143 lemma_div_basics(x);
144}
145
146pub broadcast proof fn lemma_div_basics_3(x: int)
148 ensures
149 x != 0 ==> #[trigger] (x / x) == 1,
150{
151 lemma_div_basics(x);
152}
153
154pub broadcast proof fn lemma_div_basics_4(x: int, y: int)
156 ensures
157 x >= 0 && y > 0 ==> #[trigger] (x / y) >= 0,
158{
159}
160
161pub broadcast proof fn lemma_div_basics_5(x: int, y: int)
164 ensures
165 x >= 0 && y > 0 ==> #[trigger] (x / y) <= x,
166{
167 assert forall|x: int, y: int| x >= 0 && y > 0 implies 0 <= #[trigger] (x / y) <= x by {
168 lemma_div_pos_is_pos(x, y);
169 lemma_div_is_ordered_by_denominator(x, 1, y);
170 };
171}
172
173pub broadcast group group_div_basics {
174 lemma_div_basics_1,
175 lemma_div_basics_2,
176 lemma_div_basics_3,
177 lemma_div_basics_4,
178 lemma_div_basics_5,
179}
180
181pub broadcast proof fn lemma_small_div_converse(x: int, d: int)
185 ensures
186 0 <= x && 0 < d && #[trigger] (x / d) == 0 ==> x < d,
187{
188 assert forall|x: int, d: int| 0 <= x && 0 < d && #[trigger] (x / d) == 0 implies x < d by {
189 lemma_div_induction_auto(d, x, |u: int| 0 <= u && 0 < d && u / d == 0 ==> u < d);
190 }
191}
192
193pub proof fn lemma_div_non_zero(x: int, d: int)
197 requires
198 x >= d > 0,
199 ensures
200 #[trigger] (x / d) > 0,
201{
202 broadcast use lemma_div_pos_is_pos;
203
204 if x / d == 0 {
205 broadcast use lemma_small_div_converse;
206
207 }
208}
209
210pub broadcast proof fn lemma_div_is_ordered_by_denominator(x: int, y: int, z: int)
216 requires
217 0 <= x,
218 1 <= y <= z,
219 ensures
220 #[trigger] (x / y) >= #[trigger] (x / z),
221 decreases x,
222{
223 reveal(div_recursive);
224 reveal(div_pos);
225 broadcast use lemma_div_is_div_recursive;
226
227 assert(forall|u: int, d: int|
228 #![trigger div_recursive(u, d)]
229 #![trigger div1(u, d)]
230 d > 0 ==> div_recursive(u, d) == div1(u, d));
231 if (x < z) {
232 lemma_div_is_ordered(0, x, y);
233 } else {
234 lemma_div_is_ordered(x - z, x - y, y);
235 lemma_div_is_ordered_by_denominator(x - z, y, z);
236 }
237}
238
239pub broadcast proof fn lemma_div_is_strictly_smaller(x: int, d: int)
242 requires
243 0 < x,
244 1 < d,
245 ensures
246 #[trigger] (x / d) < x,
247 decreases x,
248{
249 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
250}
251
252pub broadcast proof fn lemma_dividing_sums(a: int, b: int, d: int, r: int)
255 requires
256 0 < d,
257 r == a % d + b % d - (a + b) % d,
258 ensures
259 #![trigger (d * ((a + b) / d) - r), (d * (a / d) + d * (b / d))]
260 d * ((a + b) / d) - r == d * (a / d) + d * (b / d),
261{
262 ModINL::lemma_fundamental_div_mod(a + b, d);
263 ModINL::lemma_fundamental_div_mod(a, d);
264 ModINL::lemma_fundamental_div_mod(b, d);
265}
266
267pub broadcast proof fn lemma_div_pos_is_pos(x: int, d: int)
271 requires
272 0 <= x,
273 0 < d,
274 ensures
275 0 <= #[trigger] (x / d),
276{
277 lemma_div_auto(d);
278 assert(div_auto(d));
279 let f = |u: int| 0 <= u ==> u / d >= 0;
280 assert forall|i: int| #[trigger] is_le(0, i) && f(i) implies f(i + d) by {
281 assert(i / d >= 0);
282 };
283 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d >= 0);
284}
285
286pub broadcast proof fn lemma_div_plus_one(x: int, d: int)
290 requires
291 0 < d,
292 ensures
293 #![trigger (1 + x / d), ((d + x) / d)]
294 1 + x / d == (d + x) / d,
295{
296 lemma_div_auto(d);
297}
298
299pub broadcast proof fn lemma_div_minus_one(x: int, d: int)
303 requires
304 0 < d,
305 ensures
306 #![trigger (-1 + x / d), ((-d + x) / d)]
307 -1 + x / d == (-d + x) / d,
308{
309 lemma_div_auto(d);
310}
311
312pub proof fn lemma_basic_div_specific_divisor(d: int)
315 requires
316 0 < d,
317 ensures
318 forall|x: int| 0 <= x < d ==> #[trigger] (x / d) == 0,
319{
320 lemma_div_auto(d);
321}
322
323pub broadcast proof fn lemma_basic_div(x: int, d: int)
326 requires
327 0 <= x < d,
328 ensures
329 #[trigger] (x / d) == 0,
330{
331 lemma_basic_div_specific_divisor(d);
332}
333
334pub broadcast proof fn lemma_div_is_ordered(x: int, y: int, z: int)
338 requires
339 x <= y,
340 0 < z,
341 ensures
342 #[trigger] (x / z) <= #[trigger] (y / z),
343{
344 lemma_div_auto(z);
345 let f = |xy: int| xy <= 0 ==> (xy + y) / z <= y / z;
346 assert forall|i: int| #[trigger] is_le(i + 1, z) && f(i) implies f(i - z) by {
347 if (i - z <= 0) {
348 assert(f(i));
349 assert(i <= 0 ==> (i + y) / z <= y / z);
350 if (i > 0) {
351 assert(z > 0);
352 assert(i <= z);
353 assert(((i + y) - z) / z <= y / z);
354 } else {
355 assert((i + y) / z <= y / z);
356 }
357 assert((i - z + y) / z <= y / z);
358 }
359 };
360 lemma_div_induction_auto(z, x - y, |xy: int| xy <= 0 ==> (xy + y) / z <= y / z);
361}
362
363pub broadcast proof fn lemma_div_decreases(x: int, d: int)
366 requires
367 0 < x,
368 1 < d,
369 ensures
370 #[trigger] (x / d) < x,
371{
372 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
373}
374
375pub broadcast proof fn lemma_div_nonincreasing(x: int, d: int)
379 requires
380 0 <= x,
381 0 < d,
382 ensures
383 #[trigger] (x / d) <= x,
384{
385 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d <= u);
386}
387
388pub proof fn lemma_small_mod(x: nat, m: nat)
392 requires
393 x < m,
394 0 < m,
395 ensures
396 x % m == x,
397{
398 ModINL::lemma_small_mod(x, m);
399}
400
401pub broadcast proof fn lemma_breakdown(x: int, y: int, z: int)
406 requires
407 0 <= x,
408 0 < y,
409 0 < z,
410 ensures
411 #![trigger y * z, x % (y * z), y * ((x / y) % z) + x % y]
412 0 < y * z,
413 (x % (y * z)) == y * ((x / y) % z) + x % y,
414{
415 broadcast use lemma_mul_strictly_positive;
416
417 lemma_div_pos_is_pos(x, y);
418 calc! {
419 (<)
420 (y * (x / y)) % (y * z) + (x % y) % (y * z); (<=) {
421 lemma_part_bound1(x, y, z);
422 }
423 y * (z - 1) + (x % y) % (y * z); (<) {
424 lemma_part_bound2(x, y, z);
425 }
426 y * (z - 1) + y; (==) {
427 broadcast use group_mul_basics;
428
429 }
430 y * (z - 1) + y * 1; (==) {
431 broadcast use group_mul_is_distributive;
432
433 }
434 y * (z - 1 + 1); (==) {}
435 y * z;
436 }
437 calc! {
438 (==)
439 x % (y * z); {
440 ModINL::lemma_fundamental_div_mod(x, y);
441 }
442 (y * (x / y) + x % y) % (y * z); {
443 broadcast use group_mod_properties;
444
445 assert(0 <= x % y);
446 lemma_mul_nonnegative(y, x / y);
447 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
448 lemma_mod_adds(y * (x / y), x % y, y * z);
449 }
450 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
451 broadcast use {group_mod_properties, lemma_mul_is_commutative};
452
453 lemma_mul_increases(z, y);
454 assert((x % y) < y && y <= (y * z));
457 lemma_small_mod((x % y) as nat, (y * z) as nat);
458 assert((x % y) % (y * z) == x % y);
459 }
460 (y * (x / y)) % (y * z) + x % y; {
461 lemma_truncate_middle(x / y, y, z);
462 }
463 y * ((x / y) % z) + x % y;
464 }
465}
466
467pub broadcast proof fn lemma_remainder_upper(x: int, d: int)
471 requires
472 0 <= x,
473 0 < d,
474 ensures
475 #![trigger (x - d), (x / d * d)]
476 x - d < x / d * d,
477{
478 broadcast use group_mul_properties_internal;
479
480 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u - d < u / d * d);
481}
482
483pub broadcast proof fn lemma_remainder_lower(x: int, d: int)
487 requires
488 0 <= x,
489 0 < d,
490 ensures
491 x >= #[trigger] (x / d * d),
492{
493 broadcast use group_mul_properties_internal;
494
495 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u >= u / d * d);
496}
497
498pub broadcast proof fn lemma_remainder(x: int, d: int)
503 requires
504 0 <= x,
505 0 < d,
506 ensures
507 0 <= #[trigger] (x - (x / d * d)) < d,
508{
509 broadcast use group_mul_properties_internal;
510
511 lemma_div_induction_auto(d, x, |u: int| 0 <= u - u / d * d < d);
512}
513
514pub broadcast proof fn lemma_fundamental_div_mod(x: int, d: int)
518 requires
519 d != 0,
520 ensures
521 x == #[trigger] (d * (x / d) + (x % d)),
522{
523 assert(x == d * (x / d) + (x % d)) by {
524 ModINL::lemma_fundamental_div_mod(x, d);
525 }
526}
527
528pub broadcast proof fn lemma_div_denominator(x: int, c: int, d: int)
531 requires
532 0 <= x,
533 0 < c,
534 0 < d,
535 ensures
536 c * d != 0,
537 #[trigger] ((x / c) / d) == x / (c * d),
538{
539 lemma_mul_strictly_positive(c, d);
540 let r = x % (c as int * d as int);
541 lemma_div_pos_is_pos(r, c as int);
542 if (r / c as int >= d) {
543 ModINL::lemma_fundamental_div_mod(r, c as int);
544 lemma_mul_inequality(d as int, r / c as int, c as int);
545 lemma_mul_is_commutative(d, c);
546 }
547 assert(r / (c as int) < d);
548 lemma_fundamental_div_mod_converse(r / c, d, 0, r / c);
549 assert((r / c as int) % d as int == r / c as int);
550 lemma_fundamental_div_mod(r, c);
551 assert(c * (r / c) + r % c == r);
552 assert(c * ((r / c as int) % d as int) + r % c as int == r);
553 let k = x / (c as int * d as int);
554 lemma_fundamental_div_mod(x, c * d);
555 assert(x == (c * d) * (x / (c * d)) + x % (c * d));
556 assert(r == x - (c * d) * (x / (c * d)));
557 assert(r == x - (c * d) * k);
558 calc! {
559 (==)
560 c * ((x / c) % d) + x % c; {
561 broadcast use lemma_mul_is_commutative;
562
563 lemma_mod_multiples_vanish(-k, x / c, d);
564 }
565 c * ((x / c + (-k) * d) % d) + x % c; {
566 lemma_hoist_over_denominator(x, (-k) * d, c as nat);
567 }
568 c * (((x + (((-k) * d) * c)) / c) % d) + x % c; {
569 lemma_mul_is_associative(-k, d, c);
570 }
571 c * (((x + ((-k) * (d * c))) / c) % d) + x % c; {
572 lemma_mul_unary_negation(k, d * c);
573 }
574 c * (((x + (-(k * (d * c)))) / c) % d) + x % c; {
575 lemma_mul_is_associative(k, d, c);
576 }
577 c * (((x + (-(k * d * c))) / c) % d) + x % c; {}
578 c * (((x - k * d * c) / c) % d) + x % c; {
579 broadcast use {lemma_mul_is_associative, lemma_mul_is_commutative};
580
581 }
582 c * ((r / c) % d) + x % c; {}
583 c * (r / c) + x % c; {
584 lemma_fundamental_div_mod(r, c);
585 assert(r == c * (r / c) + r % c);
586 lemma_mod_mod(x, c, d);
587 assert(r % c == x % c);
588 }
589 r; {
590 broadcast use {group_mod_properties, lemma_mod_is_mod_recursive};
591
592 }
593 r % (c * d); {}
594 (x - (c * d) * k) % (c * d); {
595 lemma_mul_unary_negation(c * d, k);
596 }
597 (x + (c * d) * (-k)) % (c * d); {
598 lemma_mod_multiples_vanish(-k, x, c * d);
599 }
600 x % (c * d);
601 }
602 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d) ==> x - r == c * (x / c) - c
603 * ((x / c) % d)) by {
604 lemma_fundamental_div_mod(x, c);
605 };
606 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d));
607 assert(x - r == c * (x / c) - c * ((x / c) % d));
608 assert((x / c) / d == x / (c * d)) by {
609 lemma_fundamental_div_mod(x / c, d);
610 assert(d * ((x / c) / d) == x / c - ((x / c) % d));
611 lemma_fundamental_div_mod(x, c * d);
612 assert(x == (c * d) * (x / (c * d)) + (x % (c * d)));
613 lemma_mul_is_distributive_sub(c, x / c, (x / c) % d);
614 assert(c * (d * ((x / c) / d)) == c * (x / c) - c * ((x / c) % d));
615 lemma_mul_is_associative(c, d, (x / c) / d);
616 assert((c * d) * ((x / c) / d) == c * (x / c) - c * ((x / c) % d));
617 assert((c * d) * ((x / c) / d) == x - r);
618 assert((c * d) * ((x / c) / d) == (c * d) * (x / (c * d)));
619 lemma_mul_equality_converse(c * d, (x / c) / d, x / (c * d));
620 }
621 assert(c * d != 0) by {
622 assert(0 < c * d);
623 }
624 assert(c * d != 0); }
626
627pub broadcast proof fn lemma_mul_hoist_inequality(x: int, y: int, z: int)
631 requires
632 0 <= x,
633 0 < z,
634 ensures
635 #![trigger (x * (y / z)), ((x * y) / z)]
636 x * (y / z) <= (x * y) / z,
637{
638 calc! {
639 (==)
640 (x * y) / z; (==) {
641 lemma_fundamental_div_mod(y, z);
642 }
643 (x * (z * (y / z) + y % z)) / z; (==) {
644 broadcast use group_mul_is_distributive;
645
646 }
647 (x * (z * (y / z)) + x * (y % z)) / z;
648 }
649 assert((x * (z * (y / z)) + x * (y % z)) / z >= x * (y / z)) by {
650 broadcast use {group_mod_properties, lemma_mul_is_associative, lemma_mul_is_commutative};
651
652 lemma_mul_nonnegative(x, y % z);
653 lemma_div_is_ordered(x * (z * (y / z)), x * (z * (y / z)) + x * (y % z), z);
654 lemma_div_multiples_vanish(x * (y / z), z);
655 };
656}
657
658pub broadcast proof fn lemma_indistinguishable_quotients(a: int, b: int, d: int)
666 requires
667 0 < d,
668 0 <= a - a % d <= b < a + d - a % d,
669 ensures
670 #![trigger (a / d), (b / d)]
671 a / d == b / d,
672{
673 lemma_div_induction_auto(
674 d,
675 a - b,
676 |ab: int|
677 {
678 let u = ab + b;
679 0 <= u - u % d <= b < u + d - u % d ==> u / d == b / d
680 },
681 );
682}
683
684pub proof fn lemma_truncate_middle(x: int, b: int, c: int)
688 requires
689 0 <= x,
690 0 < b,
691 0 < c,
692 ensures
693 #![trigger (b * (x % c))]
694 0 < b * c,
695 (b * x) % (b * c) == b * (x % c),
696{
697 broadcast use {lemma_mul_strictly_positive, lemma_mul_nonnegative};
698
699 calc! {
700 (==)
701 b * x; {
702 ModINL::lemma_fundamental_div_mod(b * x, b * c);
703 }
704 (b * c) * ((b * x) / (b * c)) + (b * x) % (b * c); {
705 lemma_div_denominator(b * x, b, c);
706 }
707 (b * c) * (((b * x) / b) / c) + (b * x) % (b * c); {
708 broadcast use lemma_mul_is_commutative;
709
710 lemma_div_by_multiple(x, b);
711 }
712 (b * c) * (x / c) + (b * x) % (b * c);
713 }
714 assert(b * x == (b * c) * (x / c) + b * (x % c)) by {
715 ModINL::lemma_fundamental_div_mod(x, c);
716 broadcast use {group_mul_is_distributive, lemma_mul_is_associative};
717
718 };
719}
720
721pub broadcast proof fn lemma_div_multiples_vanish_quotient(x: int, a: int, d: int)
725 requires
726 0 < x,
727 0 <= a,
728 0 < d,
729 ensures
730 #![trigger a / d, x * a, x * d]
731 0 < x * d,
732 a / d == (x * a) / (x * d),
733{
734 lemma_mul_strictly_positive(x, d);
735 calc! {
736 (==)
737 (x * a) / (x * d); {
738 lemma_mul_nonnegative(x, a);
739 lemma_div_denominator(x * a, x, d);
740 }
741 ((x * a) / x) / d; {
742 lemma_div_multiples_vanish(a, x);
743 }
744 a / d;
745 }
746}
747
748#[verifier::spinoff_prover]
751pub broadcast proof fn lemma_round_down(a: int, r: int, d: int)
752 requires
753 0 < d,
754 a % d == 0,
755 0 <= r < d,
756 ensures
757 #![trigger (d * ((a + r) / d))]
758 a == d * ((a + r) / d),
759{
760 broadcast use group_mul_properties_internal;
761
762 lemma_div_induction_auto(d, a, |u: int| u % d == 0 ==> u == d * ((u + r) / d));
763}
764
765pub broadcast proof fn lemma_div_multiples_vanish_fancy(x: int, b: int, d: int)
767 requires
768 0 < d,
769 0 <= b < d,
770 ensures
771 #![trigger (d * x + b) / d]
772 (d * x + b) / d == x,
773{
774 let f = |u: int| (d * u + b) / d == u;
775 assert(f(0)) by {
776 lemma_div_auto(d);
777 }
778 assert forall|i: int| i >= 0 && #[trigger] f(i) implies #[trigger] f(add1(i, 1)) by {
779 assert(d * (i + 1) + b == d * i + b + d) by {
780 assert(d * (i + 1) == d * i + d) by {
781 lemma_mul_is_distributive_add(d, i, 1);
782 lemma_mul_basics(d);
783 }
784 }
785 super::internals::div_internals::lemma_div_basics(d);
786 }
787 assert forall|i: int| i <= 0 && #[trigger] f(i) implies #[trigger] f(sub1(i, 1)) by {
788 assert(d * (i - 1) + b == d * i + b - d) by {
789 assert(d * (i - 1) == d * i - d) by {
790 lemma_mul_is_distributive_sub(d, i, 1);
791 lemma_mul_basics(d);
792 }
793 }
794 super::internals::div_internals::lemma_div_basics(d);
795 }
796 broadcast use group_mul_properties_internal;
797
798 lemma_mul_induction(f);
799 assert(f(x));
800}
801
802pub broadcast proof fn lemma_div_multiples_vanish(x: int, d: int)
806 requires
807 0 < d,
808 ensures
809 #![trigger (d * x) / d]
810 (d * x) / d == x,
811{
812 lemma_div_multiples_vanish_fancy(x, 0, d);
813}
814
815pub broadcast proof fn lemma_div_by_multiple(b: int, d: int)
819 requires
820 0 <= b,
821 0 < d,
822 ensures
823 #![trigger ((b * d) / d)]
824 (b * d) / d == b,
825{
826 lemma_div_multiples_vanish(b, d);
827 broadcast use group_mul_properties_internal;
828
829}
830
831pub broadcast proof fn lemma_div_by_multiple_is_strongly_ordered(x: int, y: int, m: int, z: int)
835 requires
836 x < y,
837 y == m * z,
838 0 < z,
839 ensures
840 #![trigger x / z, m * z, y / z]
841 x / z < y / z,
842{
843 lemma_mod_multiples_basic(m, z);
844 lemma_div_induction_auto(
845 z,
846 y - x,
847 |yx: int|
848 {
849 let u = yx + x;
850 x < u && u % z == 0 ==> x / z < u / z
851 },
852 );
853}
854
855pub broadcast proof fn lemma_multiply_divide_le(a: int, b: int, c: int)
860 requires
861 0 < b,
862 a <= b * c,
863 ensures
864 #![trigger a / b, b * c]
865 a / b <= c,
866{
867 lemma_mod_multiples_basic(c, b);
868 let f = |i: int| 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b;
869 lemma_div_induction_auto(b, b * c - a, f);
870 lemma_div_multiples_vanish(c, b);
871}
872
873pub broadcast proof fn lemma_multiply_divide_lt(a: int, b: int, c: int)
877 requires
878 0 < b,
879 a < b * c,
880 ensures
881 #![trigger a / b, b * c]
882 a / b < c,
883{
884 assert(((b * c - a) + a) % b == 0 ==> a / b < ((b * c - a) + a) / b) by {
885 let f = |i: int| 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b;
886 lemma_div_induction_auto(b, b * c - a, f);
887 }
888 assert(b * c == c * b) by {
889 lemma_mul_is_commutative(b, c);
890 }
891 assert((b * c) % b == 0) by {
892 lemma_mod_multiples_basic(c, b);
893 }
894 assert((b * c) / b == c) by {
895 lemma_div_multiples_vanish(c, b);
896 }
897}
898
899pub broadcast proof fn lemma_hoist_over_denominator(x: int, j: int, d: nat)
903 requires
904 0 < d,
905 ensures
906 #![trigger x / d as int + j]
907 x / d as int + j == (x + j * d) / d as int,
908{
909 let dd = d as int;
910 let q = x / dd;
911 let r = x % dd;
912 assert(x == dd * q + r) by {
913 lemma_fundamental_div_mod(x, dd);
914 }
915 assert(j * dd == dd * j) by {
916 lemma_mul_is_commutative(j, dd);
917 }
918 assert(x + j * dd == dd * (q + j) + r) by {
919 lemma_mul_is_distributive_add(dd, q, j);
920 }
921 assert((x + j * dd) / dd == q + j) by {
922 lemma_fundamental_div_mod_converse(x + j * d, dd, q + j, r);
923 }
924}
925
926pub broadcast proof fn lemma_part_bound1(a: int, b: int, c: int)
930 requires
931 0 <= a,
932 0 < b,
933 0 < c,
934 ensures
935 #![trigger (b * (a / b) % (b * c))]
936 0 < b * c,
937 (b * (a / b) % (b * c)) <= b * (c - 1),
938{
939 lemma_mul_strictly_positive(b, a / b);
940 lemma_mul_strictly_positive(b, c);
941 lemma_mul_strictly_positive(b, c - 1);
942 calc! {
943 (==)
944 b * (a / b) % (b * c); {
945 ModINL::lemma_fundamental_div_mod(b * (a / b), b * c);
946 }
947 b * (a / b) - (b * c) * ((b * (a / b)) / (b * c)); {
948 broadcast use lemma_mul_is_associative;
949
950 }
951 b * (a / b) - b * (c * ((b * (a / b)) / (b * c))); {
952 broadcast use group_mul_is_distributive;
953
954 }
955 b * ((a / b) - (c * ((b * (a / b)) / (b * c))));
956 }
957 assert(b * (a / b) % (b * c) <= b * (c - 1)) by {
958 broadcast use {lemma_mul_is_commutative, lemma_mul_inequality};
959
960 };
961}
962
963pub broadcast proof fn lemma_mod_is_mod_recursive(x: int, m: int)
971 requires
972 m > 0,
973 ensures
974 mod_recursive(x, m) == #[trigger] (x % m),
975 decreases
976 (if x < 0 {
977 -x + m
978 } else {
979 x
980 }),
981{
982 reveal(mod_recursive);
983 if x < 0 {
984 calc! {
985 (==)
986 mod_recursive(x, m); {}
987 mod_recursive(x + m, m); {
988 lemma_mod_is_mod_recursive(x + m, m);
989 }
990 (x + m) % m; {
991 lemma_add_mod_noop(x, m, m);
992 }
993 ((x % m) + (m % m)) % m; {
994 broadcast use {lemma_mod_self_0, lemma_mod_twice};
995
996 }
997 (x % m) % m; {
998 broadcast use {lemma_mod_self_0, lemma_mod_twice};
999
1000 }
1001 x % m;
1002 }
1003 } else if x < m {
1004 lemma_small_mod(x as nat, m as nat);
1005 } else {
1006 calc! {
1007 (==)
1008 mod_recursive(x, m); {}
1009 mod_recursive(x - m, m); {
1010 lemma_mod_is_mod_recursive(x - m, m);
1011 }
1012 (x - m) % m; {
1013 lemma_sub_mod_noop(x, m, m);
1014 }
1015 ((x % m) - (m % m)) % m; {
1016 broadcast use {lemma_mod_self_0, lemma_mod_twice};
1017
1018 }
1019 (x % m) % m; {
1020 broadcast use {lemma_mod_self_0, lemma_mod_twice};
1021
1022 }
1023 x % m;
1024 }
1025 }
1026}
1027
1028pub broadcast proof fn lemma_mod_self_0(m: int)
1030 requires
1031 m > 0,
1032 ensures
1033 #[trigger] (m % m) == 0,
1034{
1035 lemma_mod_auto(m);
1036}
1037
1038pub broadcast proof fn lemma_mod_twice(x: int, m: int)
1040 requires
1041 m > 0,
1042 ensures
1043 #[trigger] ((x % m) % m) == x % m,
1044{
1045 lemma_mod_auto(m);
1046}
1047
1048pub broadcast group group_mod_basics {
1049 lemma_mod_self_0,
1050 lemma_mod_twice,
1051}
1052
1053pub broadcast proof fn lemma_mod_division_less_than_divisor(x: int, m: int)
1055 requires
1056 m > 0,
1057 ensures
1058 0 <= #[trigger] (x % m) < m,
1059{
1060 lemma_mod_auto(m);
1061}
1062
1063pub broadcast group group_mod_properties {
1064 group_mod_basics,
1065 lemma_mod_division_less_than_divisor,
1066}
1067
1068pub broadcast proof fn lemma_mod_decreases(x: nat, m: nat)
1071 requires
1072 0 < m,
1073 ensures
1074 #[trigger] (x % m) <= x,
1075{
1076 lemma_mod_auto(m as int);
1077}
1078
1079pub broadcast proof fn lemma_mod_is_zero(x: nat, m: nat)
1081 requires
1082 x > 0 && m > 0,
1083 #[trigger] (x % m) == 0,
1084 ensures
1085 x >= m,
1086{
1087 if (x < m) {
1088 lemma_small_mod(x, m);
1089 }
1090}
1091
1092#[verifier::spinoff_prover]
1095pub broadcast proof fn lemma_mod_multiples_basic(x: int, m: int)
1096 requires
1097 m > 0,
1098 ensures
1099 #[trigger] ((x * m) % m) == 0,
1100{
1101 lemma_mod_auto(m);
1102 broadcast use group_mul_properties_internal;
1103
1104 let f = |u: int| (u * m) % m == 0;
1105 lemma_mul_induction(f);
1106 assert(f(x));
1107}
1108
1109pub broadcast proof fn lemma_mod_add_multiples_vanish(b: int, m: int)
1112 requires
1113 0 < m,
1114 ensures
1115 (m + b) % m == #[trigger] (b % m),
1116{
1117 lemma_mod_auto(m);
1118}
1119
1120pub broadcast proof fn lemma_mod_sub_multiples_vanish(b: int, m: int)
1123 requires
1124 0 < m,
1125 ensures
1126 (-m + b) % m == #[trigger] (b % m),
1127{
1128 lemma_mod_auto(m);
1129}
1130
1131#[verifier::spinoff_prover]
1134pub broadcast proof fn lemma_mod_multiples_vanish(a: int, b: int, m: int)
1135 requires
1136 0 < m,
1137 ensures
1138 #[trigger] ((m * a + b) % m) == b % m,
1139 decreases
1140 (if a > 0 {
1141 a
1142 } else {
1143 -a
1144 }),
1145{
1146 lemma_mod_auto(m);
1147 broadcast use group_mul_properties_internal;
1148
1149 let f = |u: int| (m * u + b) % m == b % m;
1150 lemma_mul_induction(f);
1151 assert(f(a));
1152}
1153
1154pub broadcast proof fn lemma_mod_subtraction(x: nat, s: nat, d: nat)
1159 requires
1160 0 < d,
1161 0 <= s <= x % d,
1162 ensures
1163 #![trigger ((x - s) % d as int)]
1164 x % d - s % d == (x - s) % d as int,
1165{
1166 lemma_mod_auto(d as int);
1167}
1168
1169pub broadcast proof fn lemma_add_mod_noop(x: int, y: int, m: int)
1173 requires
1174 0 < m,
1175 ensures
1176 #![trigger (x + y) % m]
1177 ((x % m) + (y % m)) % m == (x + y) % m,
1178{
1179 lemma_mod_auto(m);
1180}
1181
1182pub broadcast proof fn lemma_add_mod_noop_right(x: int, y: int, m: int)
1186 requires
1187 0 < m,
1188 ensures
1189 #![trigger (x + y) % m]
1190 (x + (y % m)) % m == (x + y) % m,
1191{
1192 lemma_mod_auto(m);
1193}
1194
1195pub broadcast proof fn lemma_sub_mod_noop(x: int, y: int, m: int)
1199 requires
1200 0 < m,
1201 ensures
1202 #![trigger (x - y) % m]
1203 ((x % m) - (y % m)) % m == (x - y) % m,
1204{
1205 lemma_mod_auto(m);
1206}
1207
1208pub broadcast proof fn lemma_sub_mod_noop_right(x: int, y: int, m: int)
1212 requires
1213 0 < m,
1214 ensures
1215 #![trigger ((x - y) % m)]
1216 (x - (y % m)) % m == (x - y) % m,
1217{
1218 lemma_mod_auto(m);
1219}
1220
1221pub broadcast proof fn lemma_mod_adds(a: int, b: int, d: int)
1225 requires
1226 0 < d,
1227 ensures
1228 #![trigger ((a + b) % d)]
1229 a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d),
1230 (a % d + b % d) < d ==> a % d + b % d == (a + b) % d,
1231{
1232 broadcast use group_mul_properties_internal;
1233
1234 lemma_div_auto(d);
1235}
1236
1237#[verifier::spinoff_prover]
1241pub proof fn lemma_mod_neg_neg(x: int, d: int)
1242 requires
1243 0 < d,
1244 ensures
1245 x % d == (x * (1 - d)) % d,
1246{
1247 broadcast use group_mul_properties_internal;
1248
1249 assert((x - x * d) % d == x % d) by {
1250 let f = |i: int| (x - i * d) % d == x % d;
1251 assert(f(0) && (forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, 1))) && (
1252 forall|i: int| i <= 0 && #[trigger] f(i) ==> #[trigger] f(sub1(i, 1)))) by {
1253 lemma_mod_auto(d);
1254 };
1255 lemma_mul_induction(f);
1256 assert(f(x));
1257 }
1258
1259}
1260
1261proof fn lemma_fundamental_div_mod_converse_helper_1(u: int, d: int, r: int)
1264 requires
1265 d != 0,
1266 0 <= r < d,
1267 ensures
1268 u == (u * d + r) / d,
1269 decreases
1270 if u >= 0 {
1271 u
1272 } else {
1273 -u
1274 },
1275{
1276 if u < 0 {
1277 lemma_fundamental_div_mod_converse_helper_1(u + 1, d, r);
1278 lemma_div_add_denominator(d, u * d + r);
1279 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1280 assert(u == (u * d + r) / d);
1281 } else if u == 0 {
1282 DivINL::lemma_small_div();
1283 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1284 assert(u == (u * d + r) / d);
1285 } else {
1286 lemma_fundamental_div_mod_converse_helper_1(u - 1, d, r);
1287 lemma_div_add_denominator(d, (u - 1) * d + r);
1288 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1289 assert(u * d + r == (u - 1) * d + r + d);
1290 assert(u == (u * d + r) / d);
1291 }
1292}
1293
1294proof fn lemma_fundamental_div_mod_converse_helper_2(u: int, d: int, r: int)
1297 requires
1298 d != 0,
1299 0 <= r < d,
1300 ensures
1301 r == (u * d + r) % d,
1302 decreases
1303 if u >= 0 {
1304 u
1305 } else {
1306 -u
1307 },
1308{
1309 if u < 0 {
1310 lemma_fundamental_div_mod_converse_helper_2(u + 1, d, r);
1311 lemma_mod_add_multiples_vanish(u * d + r, d);
1312 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1313 assert(u * d == (u + 1) * d + (-1) * d);
1314 assert(u * d + r == (u + 1) * d + r - d);
1315 assert(r == (u * d + r) % d);
1316 } else if u == 0 {
1317 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1318 if d > 0 {
1319 lemma_small_mod(r as nat, d as nat);
1320 } else {
1321 lemma_small_mod(r as nat, (-d) as nat);
1322 }
1323 assert(r == (u * d + r) % d);
1324 } else {
1325 lemma_fundamental_div_mod_converse_helper_2(u - 1, d, r);
1326 lemma_mod_add_multiples_vanish((u - 1) * d + r, d);
1327 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1328 assert(u * d + r == (u - 1) * d + r + d);
1329 assert(r == (u * d + r) % d);
1330 }
1331}
1332
1333pub broadcast proof fn lemma_fundamental_div_mod_converse_mod(x: int, d: int, q: int, r: int)
1337 requires
1338 d != 0,
1339 0 <= r < d,
1340 x == #[trigger] (q * d + r),
1341 ensures
1342 r == #[trigger] (x % d),
1343{
1344 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1345 assert(q == (q * d + r) / d);
1346 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1347}
1348
1349pub broadcast proof fn lemma_fundamental_div_mod_converse_div(x: int, d: int, q: int, r: int)
1353 requires
1354 d != 0,
1355 0 <= r < d,
1356 x == #[trigger] (q * d + r),
1357 ensures
1358 q == #[trigger] (x / d),
1359{
1360 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1361 assert(q == (q * d + r) / d);
1362 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1363}
1364
1365pub proof fn lemma_fundamental_div_mod_converse(x: int, d: int, q: int, r: int)
1369 requires
1370 d != 0,
1371 0 <= r < d,
1372 x == q * d + r,
1373 ensures
1374 r == x % d,
1375 q == x / d,
1376{
1377 lemma_fundamental_div_mod_converse_mod(x, d, q, r);
1378 lemma_fundamental_div_mod_converse_div(x, d, q, r);
1379}
1380
1381pub broadcast group group_fundamental_div_mod_converse {
1382 lemma_fundamental_div_mod_converse_mod,
1383 lemma_fundamental_div_mod_converse_div,
1384}
1385
1386pub broadcast proof fn lemma_mod_pos_bound(x: int, m: int)
1389 requires
1390 0 <= x,
1391 0 < m,
1392 ensures
1393 0 <= #[trigger] (x % m) < m,
1394{
1395 lemma_mod_auto(m);
1396}
1397
1398pub broadcast proof fn lemma_mod_bound(x: int, m: int)
1401 requires
1402 0 < m,
1403 ensures
1404 0 <= #[trigger] (x % m) < m,
1405{
1406 ModINL::lemma_mod_range(x, m);
1407}
1408
1409pub broadcast proof fn lemma_mul_mod_noop_left(x: int, y: int, m: int)
1412 requires
1413 0 < m,
1414 ensures
1415 (x % m) * y % m == #[trigger] (x * y % m),
1416{
1417 lemma_mod_auto(m);
1418 lemma_mul_induction_auto(y, |u: int| (x % m) * u % m == x * u % m);
1419}
1420
1421pub broadcast proof fn lemma_mul_mod_noop_right(x: int, y: int, m: int)
1424 requires
1425 0 < m,
1426 ensures
1427 x * (y % m) % m == #[trigger] ((x * y) % m),
1428{
1429 lemma_mod_auto(m);
1430 lemma_mul_induction_auto(x, |u: int| u * (y % m) % m == (u * y) % m);
1431}
1432
1433pub broadcast proof fn lemma_mul_mod_noop_general(x: int, y: int, m: int)
1437 requires
1438 0 < m,
1439 ensures
1440 ((x % m) * y) % m == (x * y) % m,
1441 (x * (y % m)) % m == (x * y) % m,
1442 ((x % m) * (y % m)) % m == #[trigger] ((x * y) % m),
1443{
1444 lemma_mul_mod_noop_left(x, y, m);
1445 lemma_mul_mod_noop_right(x, y, m);
1446 lemma_mul_mod_noop_right(x % m, y, m);
1447}
1448
1449pub broadcast proof fn lemma_mul_mod_noop(x: int, y: int, m: int)
1453 requires
1454 0 < m,
1455 ensures
1456 (x % m) * (y % m) % m == #[trigger] ((x * y) % m),
1457{
1458 lemma_mul_mod_noop_general(x, y, m);
1459}
1460
1461pub broadcast proof fn lemma_mod_equivalence(x: int, y: int, m: int)
1469 requires
1470 0 < m,
1471 ensures
1472 #![trigger (x - y) % m]
1473 x % m == y % m <==> (x - y) % m == 0,
1474{
1475 lemma_mod_auto(m);
1476}
1477
1478pub open spec fn is_mod_equivalent(x: int, y: int, m: int) -> bool
1481 recommends
1482 m > 0,
1483{
1484 x % m == y % m <==> (x - y) % m == 0
1485}
1486
1487pub broadcast proof fn lemma_mod_mul_equivalent(x: int, y: int, z: int, m: int)
1490 requires
1491 m > 0,
1492 is_mod_equivalent(x, y, m),
1493 ensures
1494 #[trigger] is_mod_equivalent(x * z, y * z, m),
1495{
1496 lemma_mul_mod_noop_left(x, z, m);
1497 lemma_mul_mod_noop_left(y, z, m);
1498 lemma_mod_equivalence(x, y, m);
1499 lemma_mod_equivalence(x * z, y * z, m);
1500}
1501
1502pub broadcast proof fn lemma_mod_ordering(x: int, k: int, d: int)
1506 requires
1507 1 < d,
1508 0 < k,
1509 ensures
1510 0 < d * k,
1511 x % d <= #[trigger] (x % (d * k)),
1512{
1513 lemma_mul_strictly_increases(d, k);
1514 calc! {
1515 (==)
1516 x % d + d * (x / d); {
1517 lemma_fundamental_div_mod(x, d);
1518 }
1519 x; {
1520 lemma_fundamental_div_mod(x, d * k);
1521 }
1522 x % (d * k) + (d * k) * (x / (d * k)); {
1523 broadcast use lemma_mul_is_associative;
1524
1525 }
1526 x % (d * k) + d * (k * (x / (d * k)));
1527 }
1528 calc! {
1529 (==)
1530 x % d; {
1531 broadcast use group_mod_properties;
1532
1533 }
1534 (x % d) % d; {
1535 lemma_mod_multiples_vanish(x / d - k * (x / (d * k)), x % d, d);
1536 }
1537 (x % d + d * (x / d - k * (x / (d * k)))) % d; {
1538 broadcast use lemma_mul_is_distributive_sub;
1539
1540 }
1541 (x % d + d * (x / d) - d * (k * (x / (d * k)))) % d; {}
1542 (x % (d * k)) % d;
1543 }
1544 assert((x % (d * k)) % d <= x % (d * k)) by {
1545 broadcast use group_mod_properties;
1546
1547 lemma_mod_decreases((x % (d * k)) as nat, d as nat);
1548 };
1549}
1550
1551pub broadcast proof fn lemma_mod_mod(x: int, a: int, b: int)
1555 requires
1556 0 < a,
1557 0 < b,
1558 ensures
1559 #![trigger (x % (a * b)) % a, x % a]
1560 0 < a * b,
1561 (x % (a * b)) % a == x % a,
1562{
1563 broadcast use lemma_mul_strictly_positive;
1564
1565 calc! {
1566 (==)
1567 x; {
1568 lemma_fundamental_div_mod(x, a * b);
1569 }
1570 (a * b) * (x / (a * b)) + x % (a * b); {
1571 broadcast use lemma_mul_is_associative;
1572
1573 }
1574 a * (b * (x / (a * b))) + x % (a * b); {
1575 lemma_fundamental_div_mod(x % (a * b), a);
1576 }
1577 a * (b * (x / (a * b))) + a * (x % (a * b) / a) + (x % (a * b)) % a; {
1578 broadcast use group_mul_is_distributive;
1579
1580 }
1581 a * (b * (x / (a * b)) + x % (a * b) / a) + (x % (a * b)) % a;
1582 }
1583 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1584
1585 lemma_fundamental_div_mod_converse(
1586 x,
1587 a,
1588 b * (x / (a * b)) + x % (a * b) / a,
1589 (x % (a * b)) % a,
1590 );
1591}
1592
1593pub broadcast proof fn lemma_part_bound2(x: int, y: int, z: int)
1595 requires
1596 0 <= x,
1597 0 < y,
1598 0 < z,
1599 ensures
1600 y * z > 0,
1601 #[trigger] (x % y) % #[trigger] (y * z) < y,
1602{
1603 broadcast use {
1604 lemma_mul_strictly_positive,
1605 group_mod_properties,
1606 lemma_mul_is_commutative,
1607 lemma_mul_increases,
1608 };
1609
1610 assert(x % y < y);
1611 assert(y <= y * z);
1612 assert(0 <= x % y < y * z);
1613 lemma_small_mod((x % y) as nat, (y * z) as nat);
1614 assert((x % y) % (y * z) == x % y);
1615}
1616
1617pub broadcast proof fn lemma_mod_breakdown(x: int, y: int, z: int)
1620 requires
1621 0 <= x,
1622 0 < y,
1623 0 < z,
1624 ensures
1625 #![trigger x % (y * z)]
1626 y * z > 0,
1627 x % (y * z) == y * ((x / y) % z) + x % y,
1628{
1629 broadcast use lemma_mul_strictly_positive;
1630
1631 lemma_div_pos_is_pos(x, y);
1632 assert(0 <= x / y);
1633 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z) by {
1634 lemma_part_bound1(x, y, z);
1635 lemma_part_bound2(x, y, z);
1636 broadcast use {group_mul_basics, group_mul_is_distributive};
1637
1638 };
1639 calc! {
1640 (==)
1641 x % (y * z); {
1642 lemma_fundamental_div_mod(x, y);
1643 }
1644 (y * (x / y) + x % y) % (y * z); {
1645 broadcast use group_mod_properties;
1646
1647 assert(0 <= x % y);
1648 lemma_mul_nonnegative(y, x / y);
1649 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
1650 lemma_mod_adds(y * (x / y), x % y, y * z);
1651 }
1652 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
1653 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1654
1655 lemma_mul_increases(z, y);
1656 assert(x % y < y && y <= y * z);
1657 lemma_small_mod((x % y) as nat, (y * z) as nat);
1658 assert((x % y) % (y * z) == x % y);
1659 }
1660 (y * (x / y)) % (y * z) + x % y; {
1661 lemma_truncate_middle(x / y, y, z);
1662 }
1663 y * ((x / y) % z) + x % y;
1664 }
1665}
1666
1667}