1use super::prelude::*;
3
4verus! {
5
6#[cfg(verus_keep_ghost)]
7use super::arithmetic::power::pow;
8#[cfg(verus_keep_ghost)]
9use super::arithmetic::power2::{
10 pow2,
11 lemma_pow2_unfold,
12 lemma_pow2_adds,
13 lemma_pow2_pos,
14 lemma2_to64,
15 lemma_pow2_strictly_increases,
16};
17#[cfg(verus_keep_ghost)]
18use super::arithmetic::div_mod::{
19 lemma_div_by_multiple,
20 lemma_div_denominator,
21 lemma_div_is_ordered,
22 lemma_mod_breakdown,
23 lemma_mod_multiples_vanish,
24 lemma_remainder_lower,
25};
26#[cfg(verus_keep_ghost)]
27use super::arithmetic::mul::{
28 lemma_mul_inequality,
29 lemma_mul_is_commutative,
30 lemma_mul_is_associative,
31};
32#[cfg(verus_keep_ghost)]
33use super::calc_macro::*;
34
35pub proof fn lemma_unsigned_int_max_is_pow2_minus_1()
37 ensures
38 (u8::MAX as nat) == pow2(u8::BITS as nat) - 1,
39 (u16::MAX as nat) == pow2(u16::BITS as nat) - 1,
40 (u32::MAX as nat) == pow2(u32::BITS as nat) - 1,
41 (u64::MAX as nat) == pow2(u64::BITS as nat) - 1,
42 (u128::MAX as nat) == pow2(u128::BITS as nat) - 1,
43{
44 assert(0x100 == pow2(8)) by (compute);
45 assert(0x1_0000 == pow2(16)) by (compute);
46 assert(0x1_0000_0000 == pow2(32)) by (compute);
47 assert(0x1_0000_0000_0000_0000 == pow2(64)) by (compute);
48 assert(0x1_0000_0000_0000_0000_0000_0000_0000_0000 == pow2(128)) by (compute);
49}
50
51} macro_rules! lemma_shr_is_div {
54 ($name:ident, $uN:ty) => {
55 #[cfg(verus_keep_ghost)]
56 verus! {
57 #[doc = "Proof that for x and n of type "]
58 #[doc = stringify!($uN)]
59 #[doc = ", shifting x right by n is equivalent to division of x by 2^n."]
60 pub broadcast proof fn $name(x: $uN, shift: $uN)
61 requires
62 0 <= shift < <$uN>::BITS,
63 ensures
64 #[trigger] (x >> shift) == x as nat / pow2(shift as nat),
65 decreases shift,
66 {
67 reveal(pow);
69 if shift == 0 {
70 assert(x >> 0 == x) by (bit_vector);
71 assert(pow2(0) == 1) by (compute_only);
72 } else if shift == 1 {
73 assert(x >> 1 == x / 2) by (bit_vector);
74 assert(pow2(1) == 2) by (compute_only);
75 } else if shift == 2 {
76 assert(x >> 2 == x / 4) by (bit_vector);
77 assert(pow2(2) == 4) by (compute_only);
78 } else if shift == 3 {
79 assert(x >> 3 == x / 8) by (bit_vector);
80 assert(pow2(3) == 8) by (compute_only);
81 } else {
82 assert(x >> shift == (x >> (sub(shift, 4) as $uN)) / 16) by (bit_vector)
83 requires
84 4 <= shift < <$uN>::BITS,
85 ;
86 calc!{ (==)
87 (x >> shift) as nat;
88 {}
89 ((x >> (sub(shift, 4) as $uN)) / 16) as nat;
90 { $name(x, (shift - 4) as $uN); }
91 (x as nat / pow2((shift - 4) as nat)) / 16;
92 {
93 lemma_pow2_pos((shift - 4) as nat);
94 lemma2_to64();
95 assert(pow2(4) == 16) by (compute_only);
96 lemma_div_denominator(x as int, pow2((shift - 4) as nat) as int, 16);
97 }
98 x as nat / (pow2((shift - 4) as nat) * pow2(4));
99 {
100 lemma_pow2_adds((shift - 4) as nat, 4);
101 }
102 x as nat / pow2(shift as nat);
103 }
104 }
105 }
106 }
107 };
108}
109
110lemma_shr_is_div!(lemma_u128_shr_is_div, u128);
111lemma_shr_is_div!(lemma_u64_shr_is_div, u64);
112lemma_shr_is_div!(lemma_u32_shr_is_div, u32);
113lemma_shr_is_div!(lemma_u16_shr_is_div, u16);
114lemma_shr_is_div!(lemma_u8_shr_is_div, u8);
115lemma_shr_is_div!(lemma_usize_shr_is_div, usize);
116
117macro_rules! lemma_pow2_no_overflow {
119 ($name:ident, $uN:ty) => {
120 #[cfg(verus_keep_ghost)]
121 verus! {
122 #[doc = "Proof that 2^n does not overflow "]
123 #[doc = stringify!($uN)]
124 #[doc = " for an exponent n."]
125 pub broadcast proof fn $name(n: nat)
126 requires
127 0 <= n < <$uN>::BITS,
128 ensures
129 0 < #[trigger] pow2(n) < <$uN>::MAX,
130 {
131 lemma_pow2_pos(n);
132 lemma_unsigned_int_max_is_pow2_minus_1();
133 lemma_pow2_unfold(<$uN>::BITS as nat);
134 if n < <$uN>::BITS - 1 {
135 lemma_pow2_strictly_increases(n, (<$uN>::BITS - 1) as nat);
136 }
137 }
138 }
139 };
140}
141
142lemma_pow2_no_overflow!(lemma_u128_pow2_no_overflow, u128);
143lemma_pow2_no_overflow!(lemma_u64_pow2_no_overflow, u64);
144lemma_pow2_no_overflow!(lemma_u32_pow2_no_overflow, u32);
145lemma_pow2_no_overflow!(lemma_u16_pow2_no_overflow, u16);
146lemma_pow2_no_overflow!(lemma_u8_pow2_no_overflow, u8);
147lemma_pow2_no_overflow!(lemma_usize_pow2_no_overflow, usize);
148
149macro_rules! lemma_shl_is_mul {
151 ($name:ident, $no_overflow:ident, $uN:ty) => {
152 #[cfg(verus_keep_ghost)]
153 verus! {
154 #[doc = "Proof that for x and n of type "]
155 #[doc = stringify!($uN)]
156 #[doc = ", shifting x left by n is equivalent to multiplication of x by 2^n (provided no overflow)."]
157 pub broadcast proof fn $name(x: $uN, shift: $uN)
158 requires
159 0 <= shift < <$uN>::BITS,
160 x * pow2(shift as nat) <= <$uN>::MAX,
161 ensures
162 #[trigger] (x << shift) == x * pow2(shift as nat),
163 decreases shift,
164 {
165 $no_overflow(shift as nat);
167 reveal(pow);
168 if shift == 0 {
169 assert(x << 0 == x) by (bit_vector);
170 assert(pow2(0) == 1) by (compute_only);
171 super::arithmetic::mul::lemma_mul_basics(x as int);
172 } else if shift == 1 {
173 assert(x << 1 == mul(x, 2)) by (bit_vector);
174 assert(pow2(1) == 2) by (compute_only);
175 } else if shift == 2 {
176 assert(x << 2 == mul(x, 4)) by (bit_vector);
177 assert(pow2(2) == 4) by (compute_only);
178 } else if shift == 3 {
179 assert(x << 3 == mul(x, 8)) by (bit_vector);
180 assert(pow2(3) == 8) by (compute_only);
181 } else {
182 assert(x << shift == mul(x << ((sub(shift, 4)) as $uN), 16)) by (bit_vector)
183 requires
184 4 <= shift < <$uN>::BITS,
185 ;
186 assert(pow2(4) == 16) by (compute_only);
187 assert((x << (sub(shift, 4) as $uN)) == x * pow2(sub(shift, 4) as nat)) by {
188 lemma_pow2_strictly_increases((shift - 4) as nat, shift as nat);
189 lemma_mul_inequality(
190 pow2((shift - 4) as nat) as int,
191 pow2(shift as nat) as int,
192 x as int,
193 );
194 lemma_mul_is_commutative(x as int, pow2((shift - 4) as nat) as int);
195 lemma_mul_is_commutative(x as int, pow2(shift as nat) as int);
196 $name(x, (shift - 4) as $uN);
197 }
198 calc!{ (==)
199 ((x << (sub(shift, 4) as $uN)) * 16);
200 {}
201 ((x * pow2(sub(shift, 4) as nat)) * 16);
202 {
203 lemma_mul_is_associative(x as int, pow2(sub(shift, 4) as nat) as int, 16);
204 }
205 x * ((pow2(sub(shift, 4) as nat)) * 16);
206 {
207 lemma_pow2_adds((shift - 4) as nat, 4);
208 }
209 x * pow2(shift as nat);
210 }
211 }
212 }
213 }
214 };
215}
216
217lemma_shl_is_mul!(lemma_u128_shl_is_mul, lemma_u128_pow2_no_overflow, u128);
218lemma_shl_is_mul!(lemma_u64_shl_is_mul, lemma_u64_pow2_no_overflow, u64);
219lemma_shl_is_mul!(lemma_u32_shl_is_mul, lemma_u32_pow2_no_overflow, u32);
220lemma_shl_is_mul!(lemma_u16_shl_is_mul, lemma_u16_pow2_no_overflow, u16);
221lemma_shl_is_mul!(lemma_u8_shl_is_mul, lemma_u8_pow2_no_overflow, u8);
222lemma_shl_is_mul!(lemma_usize_shl_is_mul, lemma_usize_pow2_no_overflow, usize);
223
224macro_rules! lemma_mul_pow2_le_max_iff_max_shr {
225 ($name:ident, $shr_is_div:ident, $uN:ty) => {
226 #[cfg(verus_keep_ghost)]
227 verus! {
228 #[doc = "Proof that for x, n and max of type "]
229 #[doc = stringify!($uN)]
230 #[doc = ", multiplication of x by 2^n is less than or equal to max if and only if x is less than or equal to shifting max right by n."]
231 pub proof fn $name(x: $uN, shift: $uN, max: $uN)
232 requires
233 0 <= shift < <$uN>::BITS,
234 ensures
235 x * pow2(shift as nat) <= max <==> x <= (max >> shift),
236 {
237 assert(max >> shift == max as nat / pow2(shift as nat)) by {
238 $shr_is_div(max, shift as $uN);
239 };
240
241 lemma_pow2_pos(shift as nat);
242
243 if x * pow2(shift as nat) <= max {
244 assert(x <= (max as nat) / pow2(shift as nat)) by {
245 lemma_div_is_ordered(x as int * pow2(shift as nat) as int, max as int, pow2(shift as nat) as int);
246 lemma_div_by_multiple(x as int, pow2(shift as nat) as int);
247 };
248 }
249 if x <= (max >> shift) {
250 assert(x * pow2(shift as nat) <= max as nat) by {
251 lemma_mul_inequality(x as int, max as int / pow2(shift as nat) as int, pow2(shift as nat) as int);
252 lemma_remainder_lower(max as int, pow2(shift as nat) as int);
253 lemma_mul_is_commutative(max as int / pow2(shift as nat) as int, pow2(shift as nat) as int);
254 };
255 }
256 }
257 }
258 };
259}
260
261lemma_mul_pow2_le_max_iff_max_shr!(
262 lemma_u128_mul_pow2_le_max_iff_max_shr,
263 lemma_u128_shr_is_div,
264 u128
265);
266lemma_mul_pow2_le_max_iff_max_shr!(
267 lemma_u64_mul_pow2_le_max_iff_max_shr,
268 lemma_u64_shr_is_div,
269 u64
270);
271lemma_mul_pow2_le_max_iff_max_shr!(
272 lemma_u32_mul_pow2_le_max_iff_max_shr,
273 lemma_u32_shr_is_div,
274 u32
275);
276lemma_mul_pow2_le_max_iff_max_shr!(
277 lemma_u16_mul_pow2_le_max_iff_max_shr,
278 lemma_u16_shr_is_div,
279 u16
280);
281lemma_mul_pow2_le_max_iff_max_shr!(lemma_u8_mul_pow2_le_max_iff_max_shr, lemma_u8_shr_is_div, u8);
282lemma_mul_pow2_le_max_iff_max_shr!(
283 lemma_usize_mul_pow2_le_max_iff_max_shr,
284 lemma_usize_shr_is_div,
285 usize
286);
287
288verus! {
289
290pub open spec fn low_bits_mask(n: nat) -> nat {
292 (pow2(n) - 1) as nat
293}
294
295pub broadcast proof fn lemma_low_bits_mask_unfold(n: nat)
297 requires
298 n > 0,
299 ensures
300 #[trigger] low_bits_mask(n) == 2 * low_bits_mask((n - 1) as nat) + 1,
301{
302 calc! {
303 (==)
304 low_bits_mask(n); {}
305 (pow2(n) - 1) as nat; {
306 lemma_pow2_unfold(n);
307 }
308 (2 * pow2((n - 1) as nat) - 1) as nat; {}
309 (2 * (pow2((n - 1) as nat) - 1) + 1) as nat; {
310 lemma_pow2_pos((n - 1) as nat);
311 }
312 (2 * low_bits_mask((n - 1) as nat) + 1) as nat;
313 }
314}
315
316pub broadcast proof fn lemma_low_bits_mask_is_odd(n: nat)
318 requires
319 n > 0,
320 ensures
321 #[trigger] (low_bits_mask(n) % 2) == 1,
322{
323 calc! {
324 (==)
325 low_bits_mask(n) % 2; {
326 lemma_low_bits_mask_unfold(n);
327 }
328 (2 * low_bits_mask((n - 1) as nat) + 1) % 2; {
329 lemma_mod_multiples_vanish(low_bits_mask((n - 1) as nat) as int, 1, 2);
330 }
331 1nat % 2;
332 }
333}
334
335pub broadcast proof fn lemma_low_bits_mask_div2(n: nat)
337 requires
338 n > 0,
339 ensures
340 #[trigger] (low_bits_mask(n) / 2) == low_bits_mask((n - 1) as nat),
341{
342 lemma_low_bits_mask_unfold(n);
343}
344
345pub proof fn lemma_low_bits_mask_values()
348 ensures
349 low_bits_mask(0) == 0x0,
350 low_bits_mask(1) == 0x1,
351 low_bits_mask(2) == 0x3,
352 low_bits_mask(3) == 0x7,
353 low_bits_mask(4) == 0xf,
354 low_bits_mask(5) == 0x1f,
355 low_bits_mask(6) == 0x3f,
356 low_bits_mask(7) == 0x7f,
357 low_bits_mask(8) == 0xff,
358 low_bits_mask(9) == 0x1ff,
359 low_bits_mask(10) == 0x3ff,
360 low_bits_mask(11) == 0x7ff,
361 low_bits_mask(12) == 0xfff,
362 low_bits_mask(13) == 0x1fff,
363 low_bits_mask(14) == 0x3fff,
364 low_bits_mask(15) == 0x7fff,
365 low_bits_mask(16) == 0xffff,
366 low_bits_mask(17) == 0x1ffff,
367 low_bits_mask(18) == 0x3ffff,
368 low_bits_mask(19) == 0x7ffff,
369 low_bits_mask(20) == 0xfffff,
370 low_bits_mask(21) == 0x1fffff,
371 low_bits_mask(22) == 0x3fffff,
372 low_bits_mask(23) == 0x7fffff,
373 low_bits_mask(24) == 0xffffff,
374 low_bits_mask(25) == 0x1ffffff,
375 low_bits_mask(26) == 0x3ffffff,
376 low_bits_mask(27) == 0x7ffffff,
377 low_bits_mask(28) == 0xfffffff,
378 low_bits_mask(29) == 0x1fffffff,
379 low_bits_mask(30) == 0x3fffffff,
380 low_bits_mask(31) == 0x7fffffff,
381 low_bits_mask(32) == 0xffffffff,
382 low_bits_mask(64) == 0xffffffffffffffff,
383{
384 #[verusfmt::skip]
385 assert(
386 low_bits_mask(0) == 0x0 &&
387 low_bits_mask(1) == 0x1 &&
388 low_bits_mask(2) == 0x3 &&
389 low_bits_mask(3) == 0x7 &&
390 low_bits_mask(4) == 0xf &&
391 low_bits_mask(5) == 0x1f &&
392 low_bits_mask(6) == 0x3f &&
393 low_bits_mask(7) == 0x7f &&
394 low_bits_mask(8) == 0xff &&
395 low_bits_mask(9) == 0x1ff &&
396 low_bits_mask(10) == 0x3ff &&
397 low_bits_mask(11) == 0x7ff &&
398 low_bits_mask(12) == 0xfff &&
399 low_bits_mask(13) == 0x1fff &&
400 low_bits_mask(14) == 0x3fff &&
401 low_bits_mask(15) == 0x7fff &&
402 low_bits_mask(16) == 0xffff &&
403 low_bits_mask(17) == 0x1ffff &&
404 low_bits_mask(18) == 0x3ffff &&
405 low_bits_mask(19) == 0x7ffff &&
406 low_bits_mask(20) == 0xfffff &&
407 low_bits_mask(21) == 0x1fffff &&
408 low_bits_mask(22) == 0x3fffff &&
409 low_bits_mask(23) == 0x7fffff &&
410 low_bits_mask(24) == 0xffffff &&
411 low_bits_mask(25) == 0x1ffffff &&
412 low_bits_mask(26) == 0x3ffffff &&
413 low_bits_mask(27) == 0x7ffffff &&
414 low_bits_mask(28) == 0xfffffff &&
415 low_bits_mask(29) == 0x1fffffff &&
416 low_bits_mask(30) == 0x3fffffff &&
417 low_bits_mask(31) == 0x7fffffff &&
418 low_bits_mask(32) == 0xffffffff &&
419 low_bits_mask(64) == 0xffffffffffffffff
420 ) by (compute_only);
421}
422
423} macro_rules! lemma_low_bits_mask_is_mod {
426 ($name:ident, $and_split_low_bit:ident, $no_overflow:ident, $uN:ty) => {
427 #[cfg(verus_keep_ghost)]
428 verus! {
429 #[doc = "Proof that for natural n and x of type "]
430 #[doc = stringify!($uN)]
431 #[doc = ", and with the low n-bit mask is equivalent to modulo 2^n."]
432 pub broadcast proof fn $name(x: $uN, n: nat)
433 requires
434 n < <$uN>::BITS,
435 ensures
436 #[trigger] (x & (low_bits_mask(n) as $uN)) == x % (pow2(n) as $uN),
437 decreases n,
438 {
439 $no_overflow(n);
441 lemma_pow2_pos(n);
442
443 if n == 0 {
445 assert(low_bits_mask(0) == 0) by (compute_only);
446 assert(x & 0 == 0) by (bit_vector);
447 assert(pow2(0) == 1) by (compute_only);
448 assert(x % 1 == 0);
449 } else {
450 lemma_pow2_unfold(n);
451 assert((x % 2) == ((x % 2) & 1)) by (bit_vector);
452 calc!{ (==)
453 x % (pow2(n) as $uN);
454 {}
455 x % ((2 * pow2((n-1) as nat)) as $uN);
456 {
457 lemma_pow2_pos((n-1) as nat);
458 lemma_mod_breakdown(x as int, 2, pow2((n-1) as nat) as int);
459 }
460 add(mul(2, (x / 2) % (pow2((n-1) as nat) as $uN)), x % 2);
461 {
462 $name(x/2, (n-1) as nat);
463 }
464 add(mul(2, (x / 2) & (low_bits_mask((n-1) as nat) as $uN)), x % 2);
465 {
466 lemma_low_bits_mask_div2(n);
467 }
468 add(mul(2, (x / 2) & (low_bits_mask(n) as $uN / 2)), x % 2);
469 {
470 lemma_low_bits_mask_is_odd(n);
471 }
472 add(mul(2, (x / 2) & (low_bits_mask(n) as $uN / 2)), (x % 2) & ((low_bits_mask(n) as $uN) % 2));
473 {
474 $and_split_low_bit(x as $uN, low_bits_mask(n) as $uN);
475 }
476 x & (low_bits_mask(n) as $uN);
477 }
478 }
479 }
480
481 proof fn $and_split_low_bit(x: $uN, m: $uN)
483 by (bit_vector)
484 ensures
485 x & m == add(mul(((x / 2) & (m / 2)), 2), (x % 2) & (m % 2)),
486 {
487 }
488 }
489 };
490}
491
492lemma_low_bits_mask_is_mod!(
493 lemma_u128_low_bits_mask_is_mod,
494 lemma_u128_and_split_low_bit,
495 lemma_u128_pow2_no_overflow,
496 u128
497);
498lemma_low_bits_mask_is_mod!(
499 lemma_u64_low_bits_mask_is_mod,
500 lemma_u64_and_split_low_bit,
501 lemma_u64_pow2_no_overflow,
502 u64
503);
504lemma_low_bits_mask_is_mod!(
505 lemma_u32_low_bits_mask_is_mod,
506 lemma_u32_and_split_low_bit,
507 lemma_u32_pow2_no_overflow,
508 u32
509);
510lemma_low_bits_mask_is_mod!(
511 lemma_u16_low_bits_mask_is_mod,
512 lemma_u16_and_split_low_bit,
513 lemma_u16_pow2_no_overflow,
514 u16
515);
516lemma_low_bits_mask_is_mod!(
517 lemma_u8_low_bits_mask_is_mod,
518 lemma_u8_and_split_low_bit,
519 lemma_u8_pow2_no_overflow,
520 u8
521);
522lemma_low_bits_mask_is_mod!(
523 lemma_usize_low_bits_mask_is_mod,
524 lemma_usize_and_split_low_bit,
525 lemma_usize_pow2_no_overflow,
526 usize
527);