1use super::super::calc_macro::*;
15#[allow(unused_imports)]
16use super::super::prelude::*;
17
18verus! {
19
20#[allow(unused_imports)]
21#[cfg(verus_keep_ghost)]
22use super::super::arithmetic::internals::div_internals::{
23 div_recursive,
24 lemma_div_induction_auto,
25 div_auto,
26 div_pos,
27 lemma_div_auto,
28};
29use super::super::arithmetic::internals::div_internals_nonlinear as DivINL;
30#[cfg(verus_keep_ghost)]
31use super::super::arithmetic::internals::mod_internals::{
32 lemma_div_add_denominator,
33 lemma_mod_auto,
34 mod_recursive,
35};
36use super::super::arithmetic::internals::mod_internals_nonlinear as ModINL;
37#[cfg(verus_keep_ghost)]
38use super::internals::mul_internals::{
39 group_mul_properties_internal,
40 lemma_mul_induction,
41 lemma_mul_induction_auto,
42};
43#[cfg(verus_keep_ghost)]
44use super::super::arithmetic::internals::general_internals::{is_le};
45#[cfg(verus_keep_ghost)]
46use super::super::math::{add as add1, sub as sub1, div as div1};
47use super::super::arithmetic::mul::*;
48
49pub broadcast proof fn lemma_div_is_div_recursive(x: int, d: int)
56 requires
57 0 < d,
58 ensures
59 div_recursive(x, d) == #[trigger] (x / d),
60{
61 reveal(div_recursive);
62 reveal(div_pos);
63 lemma_div_induction_auto(d, x, |u: int| div_recursive(u, d) == u / d);
64}
65
66pub proof fn lemma_div_by_self(d: int)
69 requires
70 d != 0,
71 ensures
72 d / d == 1,
73{
74 DivINL::lemma_div_by_self(d);
75}
76
77pub proof fn lemma_div_of0(d: int)
79 requires
80 d != 0,
81 ensures
82 0 as int / d == 0,
83{
84 DivINL::lemma_div_of0(d);
85}
86
87pub proof fn lemma_div_basics(x: int)
91 ensures
92 x != 0 as int ==> 0 as int / x == 0,
93 x / 1 == x,
94 x != 0 ==> x / x == 1,
95{
96 if (x != 0) {
97 lemma_div_by_self(x);
98 lemma_div_of0(x);
99 }
100}
101
102pub broadcast proof fn lemma_div_basics_1(x: int)
104 ensures
105 x != 0 as int ==> #[trigger] (0int / x) == 0,
106{
107 lemma_div_basics(x);
108}
109
110pub broadcast proof fn lemma_div_basics_2(x: int)
112 ensures
113 #[trigger] (x / 1) == x,
114{
115 lemma_div_basics(x);
116}
117
118pub broadcast proof fn lemma_div_basics_3(x: int)
120 ensures
121 x != 0 ==> #[trigger] (x / x) == 1,
122{
123 lemma_div_basics(x);
124}
125
126pub broadcast proof fn lemma_div_basics_4(x: int, y: int)
128 ensures
129 x >= 0 && y > 0 ==> #[trigger] (x / y) >= 0,
130{
131}
132
133pub broadcast proof fn lemma_div_basics_5(x: int, y: int)
136 ensures
137 x >= 0 && y > 0 ==> #[trigger] (x / y) <= x,
138{
139 assert forall|x: int, y: int| x >= 0 && y > 0 implies 0 <= #[trigger] (x / y) <= x by {
140 lemma_div_pos_is_pos(x, y);
141 lemma_div_is_ordered_by_denominator(x, 1, y);
142 };
143}
144
145pub broadcast group group_div_basics {
146 lemma_div_basics_1,
147 lemma_div_basics_2,
148 lemma_div_basics_3,
149 lemma_div_basics_4,
150 lemma_div_basics_5,
151}
152
153pub broadcast proof fn lemma_small_div_converse(x: int, d: int)
157 ensures
158 0 <= x && 0 < d && #[trigger] (x / d) == 0 ==> x < d,
159{
160 assert forall|x: int, d: int| 0 <= x && 0 < d && #[trigger] (x / d) == 0 implies x < d by {
161 lemma_div_induction_auto(d, x, |u: int| 0 <= u && 0 < d && u / d == 0 ==> u < d);
162 }
163}
164
165pub proof fn lemma_div_non_zero(x: int, d: int)
169 requires
170 x >= d > 0,
171 ensures
172 #[trigger] (x / d) > 0,
173{
174 broadcast use lemma_div_pos_is_pos;
175
176 if x / d == 0 {
177 broadcast use lemma_small_div_converse;
178
179 }
180}
181
182pub broadcast proof fn lemma_div_is_ordered_by_denominator(x: int, y: int, z: int)
188 requires
189 0 <= x,
190 1 <= y <= z,
191 ensures
192 #[trigger] (x / y) >= #[trigger] (x / z),
193 decreases x,
194{
195 reveal(div_recursive);
196 reveal(div_pos);
197 broadcast use lemma_div_is_div_recursive;
198
199 assert(forall|u: int, d: int|
200 #![trigger div_recursive(u, d)]
201 #![trigger div1(u, d)]
202 d > 0 ==> div_recursive(u, d) == div1(u, d));
203 if (x < z) {
204 lemma_div_is_ordered(0, x, y);
205 } else {
206 lemma_div_is_ordered(x - z, x - y, y);
207 lemma_div_is_ordered_by_denominator(x - z, y, z);
208 }
209}
210
211pub broadcast proof fn lemma_div_is_strictly_smaller(x: int, d: int)
214 requires
215 0 < x,
216 1 < d,
217 ensures
218 #[trigger] (x / d) < x,
219 decreases x,
220{
221 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
222}
223
224pub broadcast proof fn lemma_dividing_sums(a: int, b: int, d: int, r: int)
227 requires
228 0 < d,
229 r == a % d + b % d - (a + b) % d,
230 ensures
231 #![trigger (d * ((a + b) / d) - r), (d * (a / d) + d * (b / d))]
232 d * ((a + b) / d) - r == d * (a / d) + d * (b / d),
233{
234 ModINL::lemma_fundamental_div_mod(a + b, d);
235 ModINL::lemma_fundamental_div_mod(a, d);
236 ModINL::lemma_fundamental_div_mod(b, d);
237}
238
239pub broadcast proof fn lemma_div_pos_is_pos(x: int, d: int)
243 requires
244 0 <= x,
245 0 < d,
246 ensures
247 0 <= #[trigger] (x / d),
248{
249 lemma_div_auto(d);
250 assert(div_auto(d));
251 let f = |u: int| 0 <= u ==> u / d >= 0;
252 assert forall|i: int| #[trigger] is_le(0, i) && f(i) implies f(i + d) by {
253 assert(i / d >= 0);
254 };
255 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d >= 0);
256}
257
258pub broadcast proof fn lemma_div_plus_one(x: int, d: int)
262 requires
263 0 < d,
264 ensures
265 #![trigger (1 + x / d), ((d + x) / d)]
266 1 + x / d == (d + x) / d,
267{
268 lemma_div_auto(d);
269}
270
271pub broadcast proof fn lemma_div_minus_one(x: int, d: int)
275 requires
276 0 < d,
277 ensures
278 #![trigger (-1 + x / d), ((-d + x) / d)]
279 -1 + x / d == (-d + x) / d,
280{
281 lemma_div_auto(d);
282}
283
284pub proof fn lemma_basic_div_specific_divisor(d: int)
287 requires
288 0 < d,
289 ensures
290 forall|x: int| 0 <= x < d ==> #[trigger] (x / d) == 0,
291{
292 lemma_div_auto(d);
293}
294
295pub broadcast proof fn lemma_basic_div(x: int, d: int)
298 requires
299 0 <= x < d,
300 ensures
301 #[trigger] (x / d) == 0,
302{
303 lemma_basic_div_specific_divisor(d);
304}
305
306pub broadcast proof fn lemma_div_is_ordered(x: int, y: int, z: int)
310 requires
311 x <= y,
312 0 < z,
313 ensures
314 #[trigger] (x / z) <= #[trigger] (y / z),
315{
316 lemma_div_auto(z);
317 let f = |xy: int| xy <= 0 ==> (xy + y) / z <= y / z;
318 assert forall|i: int| #[trigger] is_le(i + 1, z) && f(i) implies f(i - z) by {
319 if (i - z <= 0) {
320 assert(f(i));
321 assert(i <= 0 ==> (i + y) / z <= y / z);
322 if (i > 0) {
323 assert(z > 0);
324 assert(i <= z);
325 assert(((i + y) - z) / z <= y / z);
326 } else {
327 assert((i + y) / z <= y / z);
328 }
329 assert((i - z + y) / z <= y / z);
330 }
331 };
332 lemma_div_induction_auto(z, x - y, |xy: int| xy <= 0 ==> (xy + y) / z <= y / z);
333}
334
335pub broadcast proof fn lemma_div_decreases(x: int, d: int)
338 requires
339 0 < x,
340 1 < d,
341 ensures
342 #[trigger] (x / d) < x,
343{
344 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
345}
346
347pub broadcast proof fn lemma_div_nonincreasing(x: int, d: int)
351 requires
352 0 <= x,
353 0 < d,
354 ensures
355 #[trigger] (x / d) <= x,
356{
357 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d <= u);
358}
359
360pub proof fn lemma_small_mod(x: nat, m: nat)
364 requires
365 x < m,
366 0 < m,
367 ensures
368 x % m == x,
369{
370 ModINL::lemma_small_mod(x, m);
371}
372
373pub broadcast proof fn lemma_breakdown(x: int, y: int, z: int)
378 requires
379 0 <= x,
380 0 < y,
381 0 < z,
382 ensures
383 #![trigger y * z, x % (y * z), y * ((x / y) % z) + x % y]
384 0 < y * z,
385 (x % (y * z)) == y * ((x / y) % z) + x % y,
386{
387 broadcast use lemma_mul_strictly_positive;
388
389 lemma_div_pos_is_pos(x, y);
390 calc! {
391 (<)
392 (y * (x / y)) % (y * z) + (x % y) % (y * z); (<=) {
393 lemma_part_bound1(x, y, z);
394 }
395 y * (z - 1) + (x % y) % (y * z); (<) {
396 lemma_part_bound2(x, y, z);
397 }
398 y * (z - 1) + y; (==) {
399 broadcast use group_mul_basics;
400
401 }
402 y * (z - 1) + y * 1; (==) {
403 broadcast use group_mul_is_distributive;
404
405 }
406 y * (z - 1 + 1); (==) {}
407 y * z;
408 }
409 calc! {
410 (==)
411 x % (y * z); {
412 ModINL::lemma_fundamental_div_mod(x, y);
413 }
414 (y * (x / y) + x % y) % (y * z); {
415 broadcast use group_mod_properties;
416
417 assert(0 <= x % y);
418 lemma_mul_nonnegative(y, x / y);
419 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
420 lemma_mod_adds(y * (x / y), x % y, y * z);
421 }
422 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
423 broadcast use {group_mod_properties, lemma_mul_is_commutative};
424
425 lemma_mul_increases(z, y);
426 assert((x % y) < y && y <= (y * z));
429 lemma_small_mod((x % y) as nat, (y * z) as nat);
430 assert((x % y) % (y * z) == x % y);
431 }
432 (y * (x / y)) % (y * z) + x % y; {
433 lemma_truncate_middle(x / y, y, z);
434 }
435 y * ((x / y) % z) + x % y;
436 }
437}
438
439pub broadcast proof fn lemma_remainder_upper(x: int, d: int)
443 requires
444 0 <= x,
445 0 < d,
446 ensures
447 #![trigger (x - d), (x / d * d)]
448 x - d < x / d * d,
449{
450 broadcast use group_mul_properties_internal;
451
452 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u - d < u / d * d);
453}
454
455pub broadcast proof fn lemma_remainder_lower(x: int, d: int)
459 requires
460 0 <= x,
461 0 < d,
462 ensures
463 x >= #[trigger] (x / d * d),
464{
465 broadcast use group_mul_properties_internal;
466
467 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u >= u / d * d);
468}
469
470pub broadcast proof fn lemma_remainder(x: int, d: int)
475 requires
476 0 <= x,
477 0 < d,
478 ensures
479 0 <= #[trigger] (x - (x / d * d)) < d,
480{
481 broadcast use group_mul_properties_internal;
482
483 lemma_div_induction_auto(d, x, |u: int| 0 <= u - u / d * d < d);
484}
485
486pub broadcast proof fn lemma_fundamental_div_mod(x: int, d: int)
490 requires
491 d != 0,
492 ensures
493 x == #[trigger] (d * (x / d) + (x % d)),
494{
495 assert(x == d * (x / d) + (x % d)) by {
496 ModINL::lemma_fundamental_div_mod(x, d);
497 }
498}
499
500pub broadcast proof fn lemma_div_denominator(x: int, c: int, d: int)
503 requires
504 0 <= x,
505 0 < c,
506 0 < d,
507 ensures
508 c * d != 0,
509 #[trigger] ((x / c) / d) == x / (c * d),
510{
511 lemma_mul_strictly_positive(c, d);
512 let r = x % (c as int * d as int);
513 lemma_div_pos_is_pos(r, c as int);
514 if (r / c as int >= d) {
515 ModINL::lemma_fundamental_div_mod(r, c as int);
516 lemma_mul_inequality(d as int, r / c as int, c as int);
517 lemma_mul_is_commutative(d, c);
518 }
519 assert(r / (c as int) < d);
520 lemma_fundamental_div_mod_converse(r / c, d, 0, r / c);
521 assert((r / c as int) % d as int == r / c as int);
522 lemma_fundamental_div_mod(r, c);
523 assert(c * (r / c) + r % c == r);
524 assert(c * ((r / c as int) % d as int) + r % c as int == r);
525 let k = x / (c as int * d as int);
526 lemma_fundamental_div_mod(x, c * d);
527 assert(x == (c * d) * (x / (c * d)) + x % (c * d));
528 assert(r == x - (c * d) * (x / (c * d)));
529 assert(r == x - (c * d) * k);
530 calc! {
531 (==)
532 c * ((x / c) % d) + x % c; {
533 broadcast use lemma_mul_is_commutative;
534
535 lemma_mod_multiples_vanish(-k, x / c, d);
536 }
537 c * ((x / c + (-k) * d) % d) + x % c; {
538 lemma_hoist_over_denominator(x, (-k) * d, c as nat);
539 }
540 c * (((x + (((-k) * d) * c)) / c) % d) + x % c; {
541 lemma_mul_is_associative(-k, d, c);
542 }
543 c * (((x + ((-k) * (d * c))) / c) % d) + x % c; {
544 lemma_mul_unary_negation(k, d * c);
545 }
546 c * (((x + (-(k * (d * c)))) / c) % d) + x % c; {
547 lemma_mul_is_associative(k, d, c);
548 }
549 c * (((x + (-(k * d * c))) / c) % d) + x % c; {}
550 c * (((x - k * d * c) / c) % d) + x % c; {
551 broadcast use {lemma_mul_is_associative, lemma_mul_is_commutative};
552
553 }
554 c * ((r / c) % d) + x % c; {}
555 c * (r / c) + x % c; {
556 lemma_fundamental_div_mod(r, c);
557 assert(r == c * (r / c) + r % c);
558 lemma_mod_mod(x, c, d);
559 assert(r % c == x % c);
560 }
561 r; {
562 broadcast use {group_mod_properties, lemma_mod_is_mod_recursive};
563
564 }
565 r % (c * d); {}
566 (x - (c * d) * k) % (c * d); {
567 lemma_mul_unary_negation(c * d, k);
568 }
569 (x + (c * d) * (-k)) % (c * d); {
570 lemma_mod_multiples_vanish(-k, x, c * d);
571 }
572 x % (c * d);
573 }
574 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d) ==> x - r == c * (x / c) - c
575 * ((x / c) % d)) by {
576 lemma_fundamental_div_mod(x, c);
577 };
578 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d));
579 assert(x - r == c * (x / c) - c * ((x / c) % d));
580 assert((x / c) / d == x / (c * d)) by {
581 lemma_fundamental_div_mod(x / c, d);
582 assert(d * ((x / c) / d) == x / c - ((x / c) % d));
583 lemma_fundamental_div_mod(x, c * d);
584 assert(x == (c * d) * (x / (c * d)) + (x % (c * d)));
585 lemma_mul_is_distributive_sub(c, x / c, (x / c) % d);
586 assert(c * (d * ((x / c) / d)) == c * (x / c) - c * ((x / c) % d));
587 lemma_mul_is_associative(c, d, (x / c) / d);
588 assert((c * d) * ((x / c) / d) == c * (x / c) - c * ((x / c) % d));
589 assert((c * d) * ((x / c) / d) == x - r);
590 assert((c * d) * ((x / c) / d) == (c * d) * (x / (c * d)));
591 lemma_mul_equality_converse(c * d, (x / c) / d, x / (c * d));
592 }
593 assert(c * d != 0) by {
594 assert(0 < c * d);
595 }
596 assert(c * d != 0); }
598
599pub broadcast proof fn lemma_mul_hoist_inequality(x: int, y: int, z: int)
603 requires
604 0 <= x,
605 0 < z,
606 ensures
607 #![trigger (x * (y / z)), ((x * y) / z)]
608 x * (y / z) <= (x * y) / z,
609{
610 calc! {
611 (==)
612 (x * y) / z; (==) {
613 lemma_fundamental_div_mod(y, z);
614 }
615 (x * (z * (y / z) + y % z)) / z; (==) {
616 broadcast use group_mul_is_distributive;
617
618 }
619 (x * (z * (y / z)) + x * (y % z)) / z;
620 }
621 assert((x * (z * (y / z)) + x * (y % z)) / z >= x * (y / z)) by {
622 broadcast use {group_mod_properties, lemma_mul_is_associative, lemma_mul_is_commutative};
623
624 lemma_mul_nonnegative(x, y % z);
625 lemma_div_is_ordered(x * (z * (y / z)), x * (z * (y / z)) + x * (y % z), z);
626 lemma_div_multiples_vanish(x * (y / z), z);
627 };
628}
629
630pub broadcast proof fn lemma_indistinguishable_quotients(a: int, b: int, d: int)
638 requires
639 0 < d,
640 0 <= a - a % d <= b < a + d - a % d,
641 ensures
642 #![trigger (a / d), (b / d)]
643 a / d == b / d,
644{
645 lemma_div_induction_auto(
646 d,
647 a - b,
648 |ab: int|
649 {
650 let u = ab + b;
651 0 <= u - u % d <= b < u + d - u % d ==> u / d == b / d
652 },
653 );
654}
655
656pub proof fn lemma_truncate_middle(x: int, b: int, c: int)
660 requires
661 0 <= x,
662 0 < b,
663 0 < c,
664 ensures
665 #![trigger (b * (x % c))]
666 0 < b * c,
667 (b * x) % (b * c) == b * (x % c),
668{
669 broadcast use {lemma_mul_strictly_positive, lemma_mul_nonnegative};
670
671 calc! {
672 (==)
673 b * x; {
674 ModINL::lemma_fundamental_div_mod(b * x, b * c);
675 }
676 (b * c) * ((b * x) / (b * c)) + (b * x) % (b * c); {
677 lemma_div_denominator(b * x, b, c);
678 }
679 (b * c) * (((b * x) / b) / c) + (b * x) % (b * c); {
680 broadcast use lemma_mul_is_commutative;
681
682 lemma_div_by_multiple(x, b);
683 }
684 (b * c) * (x / c) + (b * x) % (b * c);
685 }
686 assert(b * x == (b * c) * (x / c) + b * (x % c)) by {
687 ModINL::lemma_fundamental_div_mod(x, c);
688 broadcast use {group_mul_is_distributive, lemma_mul_is_associative};
689
690 };
691}
692
693pub broadcast proof fn lemma_div_multiples_vanish_quotient(x: int, a: int, d: int)
697 requires
698 0 < x,
699 0 <= a,
700 0 < d,
701 ensures
702 #![trigger a / d, x * a, x * d]
703 0 < x * d,
704 a / d == (x * a) / (x * d),
705{
706 lemma_mul_strictly_positive(x, d);
707 calc! {
708 (==)
709 (x * a) / (x * d); {
710 lemma_mul_nonnegative(x, a);
711 lemma_div_denominator(x * a, x, d);
712 }
713 ((x * a) / x) / d; {
714 lemma_div_multiples_vanish(a, x);
715 }
716 a / d;
717 }
718}
719
720pub broadcast proof fn lemma_round_down(a: int, r: int, d: int)
723 requires
724 0 < d,
725 a % d == 0,
726 0 <= r < d,
727 ensures
728 #![trigger (d * ((a + r) / d))]
729 a == d * ((a + r) / d),
730{
731 broadcast use group_mul_properties_internal;
732
733 lemma_div_induction_auto(d, a, |u: int| u % d == 0 ==> u == d * ((u + r) / d));
734}
735
736pub broadcast proof fn lemma_div_multiples_vanish_fancy(x: int, b: int, d: int)
738 requires
739 0 < d,
740 0 <= b < d,
741 ensures
742 #![trigger (d * x + b) / d]
743 (d * x + b) / d == x,
744{
745 let f = |u: int| (d * u + b) / d == u;
746 assert(f(0)) by {
747 lemma_div_auto(d);
748 }
749 assert forall|i: int| i >= 0 && #[trigger] f(i) implies #[trigger] f(add1(i, 1)) by {
750 assert(d * (i + 1) + b == d * i + b + d) by {
751 assert(d * (i + 1) == d * i + d) by {
752 lemma_mul_is_distributive_add(d, i, 1);
753 lemma_mul_basics(d);
754 }
755 }
756 super::internals::div_internals::lemma_div_basics(d);
757 }
758 assert forall|i: int| i <= 0 && #[trigger] f(i) implies #[trigger] f(sub1(i, 1)) by {
759 assert(d * (i - 1) + b == d * i + b - d) by {
760 assert(d * (i - 1) == d * i - d) by {
761 lemma_mul_is_distributive_sub(d, i, 1);
762 lemma_mul_basics(d);
763 }
764 }
765 super::internals::div_internals::lemma_div_basics(d);
766 }
767 broadcast use group_mul_properties_internal;
768
769 lemma_mul_induction(f);
770 assert(f(x));
771}
772
773pub broadcast proof fn lemma_div_multiples_vanish(x: int, d: int)
777 requires
778 0 < d,
779 ensures
780 #![trigger (d * x) / d]
781 (d * x) / d == x,
782{
783 lemma_div_multiples_vanish_fancy(x, 0, d);
784}
785
786pub broadcast proof fn lemma_div_by_multiple(b: int, d: int)
790 requires
791 0 <= b,
792 0 < d,
793 ensures
794 #![trigger ((b * d) / d)]
795 (b * d) / d == b,
796{
797 lemma_div_multiples_vanish(b, d);
798 broadcast use group_mul_properties_internal;
799
800}
801
802pub broadcast proof fn lemma_div_by_multiple_is_strongly_ordered(x: int, y: int, m: int, z: int)
806 requires
807 x < y,
808 y == m * z,
809 0 < z,
810 ensures
811 #![trigger x / z, m * z, y / z]
812 x / z < y / z,
813{
814 lemma_mod_multiples_basic(m, z);
815 lemma_div_induction_auto(
816 z,
817 y - x,
818 |yx: int|
819 {
820 let u = yx + x;
821 x < u && u % z == 0 ==> x / z < u / z
822 },
823 );
824}
825
826pub broadcast proof fn lemma_multiply_divide_le(a: int, b: int, c: int)
831 requires
832 0 < b,
833 a <= b * c,
834 ensures
835 #![trigger a / b, b * c]
836 a / b <= c,
837{
838 lemma_mod_multiples_basic(c, b);
839 let f = |i: int| 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b;
840 lemma_div_induction_auto(b, b * c - a, f);
841 lemma_div_multiples_vanish(c, b);
842}
843
844pub broadcast proof fn lemma_multiply_divide_lt(a: int, b: int, c: int)
848 requires
849 0 < b,
850 a < b * c,
851 ensures
852 #![trigger a / b, b * c]
853 a / b < c,
854{
855 assert(((b * c - a) + a) % b == 0 ==> a / b < ((b * c - a) + a) / b) by {
856 let f = |i: int| 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b;
857 lemma_div_induction_auto(b, b * c - a, f);
858 }
859 assert(b * c == c * b) by {
860 lemma_mul_is_commutative(b, c);
861 }
862 assert((b * c) % b == 0) by {
863 lemma_mod_multiples_basic(c, b);
864 }
865 assert((b * c) / b == c) by {
866 lemma_div_multiples_vanish(c, b);
867 }
868}
869
870pub broadcast proof fn lemma_hoist_over_denominator(x: int, j: int, d: nat)
874 requires
875 0 < d,
876 ensures
877 #![trigger x / d as int + j]
878 x / d as int + j == (x + j * d) / d as int,
879{
880 let dd = d as int;
881 let q = x / dd;
882 let r = x % dd;
883 assert(x == dd * q + r) by {
884 lemma_fundamental_div_mod(x, dd);
885 }
886 assert(j * dd == dd * j) by {
887 lemma_mul_is_commutative(j, dd);
888 }
889 assert(x + j * dd == dd * (q + j) + r) by {
890 lemma_mul_is_distributive_add(dd, q, j);
891 }
892 assert((x + j * dd) / dd == q + j) by {
893 lemma_fundamental_div_mod_converse(x + j * d, dd, q + j, r);
894 }
895}
896
897pub broadcast proof fn lemma_part_bound1(a: int, b: int, c: int)
901 requires
902 0 <= a,
903 0 < b,
904 0 < c,
905 ensures
906 #![trigger (b * (a / b) % (b * c))]
907 0 < b * c,
908 (b * (a / b) % (b * c)) <= b * (c - 1),
909{
910 lemma_mul_strictly_positive(b, a / b);
911 lemma_mul_strictly_positive(b, c);
912 lemma_mul_strictly_positive(b, c - 1);
913 calc! {
914 (==)
915 b * (a / b) % (b * c); {
916 ModINL::lemma_fundamental_div_mod(b * (a / b), b * c);
917 }
918 b * (a / b) - (b * c) * ((b * (a / b)) / (b * c)); {
919 broadcast use lemma_mul_is_associative;
920
921 }
922 b * (a / b) - b * (c * ((b * (a / b)) / (b * c))); {
923 broadcast use group_mul_is_distributive;
924
925 }
926 b * ((a / b) - (c * ((b * (a / b)) / (b * c))));
927 }
928 assert(b * (a / b) % (b * c) <= b * (c - 1)) by {
929 broadcast use {lemma_mul_is_commutative, lemma_mul_inequality};
930
931 };
932}
933
934pub broadcast proof fn lemma_mod_is_mod_recursive(x: int, m: int)
942 requires
943 m > 0,
944 ensures
945 mod_recursive(x, m) == #[trigger] (x % m),
946 decreases
947 (if x < 0 {
948 -x + m
949 } else {
950 x
951 }),
952{
953 reveal(mod_recursive);
954 if x < 0 {
955 calc! {
956 (==)
957 mod_recursive(x, m); {}
958 mod_recursive(x + m, m); {
959 lemma_mod_is_mod_recursive(x + m, m);
960 }
961 (x + m) % m; {
962 lemma_add_mod_noop(x, m, m);
963 }
964 ((x % m) + (m % m)) % m; {
965 broadcast use {lemma_mod_self_0, lemma_mod_twice};
966
967 }
968 (x % m) % m; {
969 broadcast use {lemma_mod_self_0, lemma_mod_twice};
970
971 }
972 x % m;
973 }
974 } else if x < m {
975 lemma_small_mod(x as nat, m as nat);
976 } else {
977 calc! {
978 (==)
979 mod_recursive(x, m); {}
980 mod_recursive(x - m, m); {
981 lemma_mod_is_mod_recursive(x - m, m);
982 }
983 (x - m) % m; {
984 lemma_sub_mod_noop(x, m, m);
985 }
986 ((x % m) - (m % m)) % m; {
987 broadcast use {lemma_mod_self_0, lemma_mod_twice};
988
989 }
990 (x % m) % m; {
991 broadcast use {lemma_mod_self_0, lemma_mod_twice};
992
993 }
994 x % m;
995 }
996 }
997}
998
999pub broadcast proof fn lemma_mod_self_0(m: int)
1001 requires
1002 m > 0,
1003 ensures
1004 #[trigger] (m % m) == 0,
1005{
1006 lemma_mod_auto(m);
1007}
1008
1009pub broadcast proof fn lemma_mod_twice(x: int, m: int)
1011 requires
1012 m > 0,
1013 ensures
1014 #[trigger] ((x % m) % m) == x % m,
1015{
1016 lemma_mod_auto(m);
1017}
1018
1019pub broadcast group group_mod_basics {
1020 lemma_mod_self_0,
1021 lemma_mod_twice,
1022}
1023
1024pub broadcast proof fn lemma_mod_division_less_than_divisor(x: int, m: int)
1026 requires
1027 m > 0,
1028 ensures
1029 0 <= #[trigger] (x % m) < m,
1030{
1031 lemma_mod_auto(m);
1032}
1033
1034pub broadcast group group_mod_properties {
1035 group_mod_basics,
1036 lemma_mod_division_less_than_divisor,
1037}
1038
1039pub broadcast proof fn lemma_mod_decreases(x: nat, m: nat)
1042 requires
1043 0 < m,
1044 ensures
1045 #[trigger] (x % m) <= x,
1046{
1047 lemma_mod_auto(m as int);
1048}
1049
1050pub broadcast proof fn lemma_mod_is_zero(x: nat, m: nat)
1052 requires
1053 x > 0 && m > 0,
1054 #[trigger] (x % m) == 0,
1055 ensures
1056 x >= m,
1057{
1058 if (x < m) {
1059 lemma_small_mod(x, m);
1060 }
1061}
1062
1063#[verifier::spinoff_prover]
1066pub broadcast proof fn lemma_mod_multiples_basic(x: int, m: int)
1067 requires
1068 m > 0,
1069 ensures
1070 #[trigger] ((x * m) % m) == 0,
1071{
1072 lemma_mod_auto(m);
1073 broadcast use group_mul_properties_internal;
1074
1075 let f = |u: int| (u * m) % m == 0;
1076 lemma_mul_induction(f);
1077 assert(f(x));
1078}
1079
1080pub broadcast proof fn lemma_mod_add_multiples_vanish(b: int, m: int)
1083 requires
1084 0 < m,
1085 ensures
1086 (m + b) % m == #[trigger] (b % m),
1087{
1088 lemma_mod_auto(m);
1089}
1090
1091pub broadcast proof fn lemma_mod_sub_multiples_vanish(b: int, m: int)
1094 requires
1095 0 < m,
1096 ensures
1097 (-m + b) % m == #[trigger] (b % m),
1098{
1099 lemma_mod_auto(m);
1100}
1101
1102#[verifier::spinoff_prover]
1105pub broadcast proof fn lemma_mod_multiples_vanish(a: int, b: int, m: int)
1106 requires
1107 0 < m,
1108 ensures
1109 #[trigger] ((m * a + b) % m) == b % m,
1110 decreases
1111 (if a > 0 {
1112 a
1113 } else {
1114 -a
1115 }),
1116{
1117 lemma_mod_auto(m);
1118 broadcast use group_mul_properties_internal;
1119
1120 let f = |u: int| (m * u + b) % m == b % m;
1121 lemma_mul_induction(f);
1122 assert(f(a));
1123}
1124
1125pub broadcast proof fn lemma_mod_subtraction(x: nat, s: nat, d: nat)
1130 requires
1131 0 < d,
1132 0 <= s <= x % d,
1133 ensures
1134 #![trigger ((x - s) % d as int)]
1135 x % d - s % d == (x - s) % d as int,
1136{
1137 lemma_mod_auto(d as int);
1138}
1139
1140pub broadcast proof fn lemma_add_mod_noop(x: int, y: int, m: int)
1144 requires
1145 0 < m,
1146 ensures
1147 #![trigger (x + y) % m]
1148 ((x % m) + (y % m)) % m == (x + y) % m,
1149{
1150 lemma_mod_auto(m);
1151}
1152
1153pub broadcast proof fn lemma_add_mod_noop_right(x: int, y: int, m: int)
1157 requires
1158 0 < m,
1159 ensures
1160 #![trigger (x + y) % m]
1161 (x + (y % m)) % m == (x + y) % m,
1162{
1163 lemma_mod_auto(m);
1164}
1165
1166pub broadcast proof fn lemma_sub_mod_noop(x: int, y: int, m: int)
1170 requires
1171 0 < m,
1172 ensures
1173 #![trigger (x - y) % m]
1174 ((x % m) - (y % m)) % m == (x - y) % m,
1175{
1176 lemma_mod_auto(m);
1177}
1178
1179pub broadcast proof fn lemma_sub_mod_noop_right(x: int, y: int, m: int)
1183 requires
1184 0 < m,
1185 ensures
1186 #![trigger ((x - y) % m)]
1187 (x - (y % m)) % m == (x - y) % m,
1188{
1189 lemma_mod_auto(m);
1190}
1191
1192pub broadcast proof fn lemma_mod_adds(a: int, b: int, d: int)
1196 requires
1197 0 < d,
1198 ensures
1199 #![trigger ((a + b) % d)]
1200 a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d),
1201 (a % d + b % d) < d ==> a % d + b % d == (a + b) % d,
1202{
1203 broadcast use group_mul_properties_internal;
1204
1205 lemma_div_auto(d);
1206}
1207
1208#[verifier::spinoff_prover]
1212pub proof fn lemma_mod_neg_neg(x: int, d: int)
1213 requires
1214 0 < d,
1215 ensures
1216 x % d == (x * (1 - d)) % d,
1217{
1218 broadcast use group_mul_properties_internal;
1219
1220 assert((x - x * d) % d == x % d) by {
1221 let f = |i: int| (x - i * d) % d == x % d;
1222 assert(f(0) && (forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, 1))) && (
1223 forall|i: int| i <= 0 && #[trigger] f(i) ==> #[trigger] f(sub1(i, 1)))) by {
1224 lemma_mod_auto(d);
1225 };
1226 lemma_mul_induction(f);
1227 assert(f(x));
1228 }
1229
1230}
1231
1232proof fn lemma_fundamental_div_mod_converse_helper_1(u: int, d: int, r: int)
1235 requires
1236 d != 0,
1237 0 <= r < d,
1238 ensures
1239 u == (u * d + r) / d,
1240 decreases
1241 if u >= 0 {
1242 u
1243 } else {
1244 -u
1245 },
1246{
1247 if u < 0 {
1248 lemma_fundamental_div_mod_converse_helper_1(u + 1, d, r);
1249 lemma_div_add_denominator(d, u * d + r);
1250 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1251 assert(u == (u * d + r) / d);
1252 } else if u == 0 {
1253 DivINL::lemma_small_div();
1254 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1255 assert(u == (u * d + r) / d);
1256 } else {
1257 lemma_fundamental_div_mod_converse_helper_1(u - 1, d, r);
1258 lemma_div_add_denominator(d, (u - 1) * d + r);
1259 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1260 assert(u * d + r == (u - 1) * d + r + d);
1261 assert(u == (u * d + r) / d);
1262 }
1263}
1264
1265proof fn lemma_fundamental_div_mod_converse_helper_2(u: int, d: int, r: int)
1268 requires
1269 d != 0,
1270 0 <= r < d,
1271 ensures
1272 r == (u * d + r) % d,
1273 decreases
1274 if u >= 0 {
1275 u
1276 } else {
1277 -u
1278 },
1279{
1280 if u < 0 {
1281 lemma_fundamental_div_mod_converse_helper_2(u + 1, d, r);
1282 lemma_mod_add_multiples_vanish(u * d + r, d);
1283 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1284 assert(u * d == (u + 1) * d + (-1) * d);
1285 assert(u * d + r == (u + 1) * d + r - d);
1286 assert(r == (u * d + r) % d);
1287 } else if u == 0 {
1288 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1289 if d > 0 {
1290 lemma_small_mod(r as nat, d as nat);
1291 } else {
1292 lemma_small_mod(r as nat, (-d) as nat);
1293 }
1294 assert(r == (u * d + r) % d);
1295 } else {
1296 lemma_fundamental_div_mod_converse_helper_2(u - 1, d, r);
1297 lemma_mod_add_multiples_vanish((u - 1) * d + r, d);
1298 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1299 assert(u * d + r == (u - 1) * d + r + d);
1300 assert(r == (u * d + r) % d);
1301 }
1302}
1303
1304pub broadcast proof fn lemma_fundamental_div_mod_converse_mod(x: int, d: int, q: int, r: int)
1308 requires
1309 d != 0,
1310 0 <= r < d,
1311 x == #[trigger] (q * d + r),
1312 ensures
1313 r == #[trigger] (x % d),
1314{
1315 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1316 assert(q == (q * d + r) / d);
1317 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1318}
1319
1320pub broadcast proof fn lemma_fundamental_div_mod_converse_div(x: int, d: int, q: int, r: int)
1324 requires
1325 d != 0,
1326 0 <= r < d,
1327 x == #[trigger] (q * d + r),
1328 ensures
1329 q == #[trigger] (x / d),
1330{
1331 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1332 assert(q == (q * d + r) / d);
1333 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1334}
1335
1336pub proof fn lemma_fundamental_div_mod_converse(x: int, d: int, q: int, r: int)
1340 requires
1341 d != 0,
1342 0 <= r < d,
1343 x == q * d + r,
1344 ensures
1345 r == x % d,
1346 q == x / d,
1347{
1348 lemma_fundamental_div_mod_converse_mod(x, d, q, r);
1349 lemma_fundamental_div_mod_converse_div(x, d, q, r);
1350}
1351
1352pub broadcast group group_fundamental_div_mod_converse {
1353 lemma_fundamental_div_mod_converse_mod,
1354 lemma_fundamental_div_mod_converse_div,
1355}
1356
1357pub broadcast proof fn lemma_mod_pos_bound(x: int, m: int)
1360 requires
1361 0 <= x,
1362 0 < m,
1363 ensures
1364 0 <= #[trigger] (x % m) < m,
1365{
1366 lemma_mod_auto(m);
1367}
1368
1369pub broadcast proof fn lemma_mod_bound(x: int, m: int)
1372 requires
1373 0 < m,
1374 ensures
1375 0 <= #[trigger] (x % m) < m,
1376{
1377 ModINL::lemma_mod_range(x, m);
1378}
1379
1380pub broadcast proof fn lemma_mul_mod_noop_left(x: int, y: int, m: int)
1383 requires
1384 0 < m,
1385 ensures
1386 (x % m) * y % m == #[trigger] (x * y % m),
1387{
1388 lemma_mod_auto(m);
1389 lemma_mul_induction_auto(y, |u: int| (x % m) * u % m == x * u % m);
1390}
1391
1392pub broadcast proof fn lemma_mul_mod_noop_right(x: int, y: int, m: int)
1395 requires
1396 0 < m,
1397 ensures
1398 x * (y % m) % m == #[trigger] ((x * y) % m),
1399{
1400 lemma_mod_auto(m);
1401 lemma_mul_induction_auto(x, |u: int| u * (y % m) % m == (u * y) % m);
1402}
1403
1404pub broadcast proof fn lemma_mul_mod_noop_general(x: int, y: int, m: int)
1408 requires
1409 0 < m,
1410 ensures
1411 ((x % m) * y) % m == (x * y) % m,
1412 (x * (y % m)) % m == (x * y) % m,
1413 ((x % m) * (y % m)) % m == #[trigger] ((x * y) % m),
1414{
1415 lemma_mul_mod_noop_left(x, y, m);
1416 lemma_mul_mod_noop_right(x, y, m);
1417 lemma_mul_mod_noop_right(x % m, y, m);
1418}
1419
1420pub broadcast proof fn lemma_mul_mod_noop(x: int, y: int, m: int)
1424 requires
1425 0 < m,
1426 ensures
1427 (x % m) * (y % m) % m == #[trigger] ((x * y) % m),
1428{
1429 lemma_mul_mod_noop_general(x, y, m);
1430}
1431
1432pub broadcast proof fn lemma_mod_equivalence(x: int, y: int, m: int)
1440 requires
1441 0 < m,
1442 ensures
1443 #![trigger (x - y) % m]
1444 x % m == y % m <==> (x - y) % m == 0,
1445{
1446 lemma_mod_auto(m);
1447}
1448
1449pub open spec fn is_mod_equivalent(x: int, y: int, m: int) -> bool
1452 recommends
1453 m > 0,
1454{
1455 x % m == y % m <==> (x - y) % m == 0
1456}
1457
1458pub broadcast proof fn lemma_mod_mul_equivalent(x: int, y: int, z: int, m: int)
1461 requires
1462 m > 0,
1463 is_mod_equivalent(x, y, m),
1464 ensures
1465 #[trigger] is_mod_equivalent(x * z, y * z, m),
1466{
1467 lemma_mul_mod_noop_left(x, z, m);
1468 lemma_mul_mod_noop_left(y, z, m);
1469 lemma_mod_equivalence(x, y, m);
1470 lemma_mod_equivalence(x * z, y * z, m);
1471}
1472
1473pub broadcast proof fn lemma_mod_ordering(x: int, k: int, d: int)
1477 requires
1478 1 < d,
1479 0 < k,
1480 ensures
1481 0 < d * k,
1482 x % d <= #[trigger] (x % (d * k)),
1483{
1484 lemma_mul_strictly_increases(d, k);
1485 calc! {
1486 (==)
1487 x % d + d * (x / d); {
1488 lemma_fundamental_div_mod(x, d);
1489 }
1490 x; {
1491 lemma_fundamental_div_mod(x, d * k);
1492 }
1493 x % (d * k) + (d * k) * (x / (d * k)); {
1494 broadcast use lemma_mul_is_associative;
1495
1496 }
1497 x % (d * k) + d * (k * (x / (d * k)));
1498 }
1499 calc! {
1500 (==)
1501 x % d; {
1502 broadcast use group_mod_properties;
1503
1504 }
1505 (x % d) % d; {
1506 lemma_mod_multiples_vanish(x / d - k * (x / (d * k)), x % d, d);
1507 }
1508 (x % d + d * (x / d - k * (x / (d * k)))) % d; {
1509 broadcast use lemma_mul_is_distributive_sub;
1510
1511 }
1512 (x % d + d * (x / d) - d * (k * (x / (d * k)))) % d; {}
1513 (x % (d * k)) % d;
1514 }
1515 assert((x % (d * k)) % d <= x % (d * k)) by {
1516 broadcast use group_mod_properties;
1517
1518 lemma_mod_decreases((x % (d * k)) as nat, d as nat);
1519 };
1520}
1521
1522pub broadcast proof fn lemma_mod_mod(x: int, a: int, b: int)
1526 requires
1527 0 < a,
1528 0 < b,
1529 ensures
1530 #![trigger (x % (a * b)) % a, x % a]
1531 0 < a * b,
1532 (x % (a * b)) % a == x % a,
1533{
1534 broadcast use lemma_mul_strictly_positive;
1535
1536 calc! {
1537 (==)
1538 x; {
1539 lemma_fundamental_div_mod(x, a * b);
1540 }
1541 (a * b) * (x / (a * b)) + x % (a * b); {
1542 broadcast use lemma_mul_is_associative;
1543
1544 }
1545 a * (b * (x / (a * b))) + x % (a * b); {
1546 lemma_fundamental_div_mod(x % (a * b), a);
1547 }
1548 a * (b * (x / (a * b))) + a * (x % (a * b) / a) + (x % (a * b)) % a; {
1549 broadcast use group_mul_is_distributive;
1550
1551 }
1552 a * (b * (x / (a * b)) + x % (a * b) / a) + (x % (a * b)) % a;
1553 }
1554 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1555
1556 lemma_fundamental_div_mod_converse(
1557 x,
1558 a,
1559 b * (x / (a * b)) + x % (a * b) / a,
1560 (x % (a * b)) % a,
1561 );
1562}
1563
1564pub broadcast proof fn lemma_part_bound2(x: int, y: int, z: int)
1566 requires
1567 0 <= x,
1568 0 < y,
1569 0 < z,
1570 ensures
1571 y * z > 0,
1572 #[trigger] (x % y) % #[trigger] (y * z) < y,
1573{
1574 broadcast use {
1575 lemma_mul_strictly_positive,
1576 group_mod_properties,
1577 lemma_mul_is_commutative,
1578 lemma_mul_increases,
1579 };
1580
1581 assert(x % y < y);
1582 assert(y <= y * z);
1583 assert(0 <= x % y < y * z);
1584 lemma_small_mod((x % y) as nat, (y * z) as nat);
1585 assert((x % y) % (y * z) == x % y);
1586}
1587
1588pub broadcast proof fn lemma_mod_breakdown(x: int, y: int, z: int)
1591 requires
1592 0 <= x,
1593 0 < y,
1594 0 < z,
1595 ensures
1596 #![trigger x % (y * z)]
1597 y * z > 0,
1598 x % (y * z) == y * ((x / y) % z) + x % y,
1599{
1600 broadcast use lemma_mul_strictly_positive;
1601
1602 lemma_div_pos_is_pos(x, y);
1603 assert(0 <= x / y);
1604 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z) by {
1605 lemma_part_bound1(x, y, z);
1606 lemma_part_bound2(x, y, z);
1607 broadcast use {group_mul_basics, group_mul_is_distributive};
1608
1609 };
1610 calc! {
1611 (==)
1612 x % (y * z); {
1613 lemma_fundamental_div_mod(x, y);
1614 }
1615 (y * (x / y) + x % y) % (y * z); {
1616 broadcast use group_mod_properties;
1617
1618 assert(0 <= x % y);
1619 lemma_mul_nonnegative(y, x / y);
1620 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
1621 lemma_mod_adds(y * (x / y), x % y, y * z);
1622 }
1623 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
1624 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1625
1626 lemma_mul_increases(z, y);
1627 assert(x % y < y && y <= y * z);
1628 lemma_small_mod((x % y) as nat, (y * z) as nat);
1629 assert((x % y) % (y * z) == x % y);
1630 }
1631 (y * (x / y)) % (y * z) + x % y; {
1632 lemma_truncate_middle(x / y, y, z);
1633 }
1634 y * ((x / y) % z) + x % y;
1635 }
1636}
1637
1638}