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