Skip to main content

vstd_extra/
bits.rs

1//! Bit-arithmetic predicates and lemmas for unsigned words.
2use vstd::prelude::*;
3
4/// Defines a bit-test predicate for an unsigned word type.
5macro_rules! define_bit_is_set {
6    ($name:ident, $uN:ty, $one:expr) => {
7        verus! {
8            /// Whether bit `b` of `w` is set.
9            pub open spec fn $name(w: $uN, b: int) -> bool {
10                (w & ($one << (b as usize))) != 0
11            }
12        }
13    };
14}
15
16define_bit_is_set!(u8_bit_is_set, u8, 1u8);
17define_bit_is_set!(u16_bit_is_set, u16, 1u16);
18define_bit_is_set!(u32_bit_is_set, u32, 1u32);
19define_bit_is_set!(u64_bit_is_set, u64, 1u64);
20define_bit_is_set!(u128_bit_is_set, u128, 1u128);
21define_bit_is_set!(usize_bit_is_set, usize, 1usize);
22
23/// Defines the common bit-algebra lemmas for an unsigned word type.
24macro_rules! define_unsigned_bit_lemmas {
25    (
26        $uN:ty, $zero:expr, $one:expr, $width:expr, $width_u32:expr,
27        $bit_is_set:ident,
28        $allones_bit_it_set:ident,
29        $unit_le_shl:ident,
30        $masked_bit_clear:ident,
31        $masked_bit_keep:ident,
32        $setbit_bit_is_set:ident,
33        $setbit_bit_unchanged:ident,
34        $clearbit_not_bit_is_set:ident,
35        $clearbit_bit_unchanged:ident,
36        $and_zero:ident,
37        $group:ident
38    ) => {
39        verus! {
40
41        /// Every bit of the all-ones word is set.
42        pub broadcast proof fn $allones_bit_it_set(k: int)
43            requires
44                0 <= k < $width,
45            ensures
46                #![trigger $bit_is_set(!$zero, k)]
47                $bit_is_set(!$zero, k),
48        {
49            let ku: u32 = k as u32;
50            assert((!$zero & ($one << ku)) == ($one << ku)) by (bit_vector);
51            assert((ku < $width_u32) ==> (($one << ku) != $zero)) by (bit_vector);
52        }
53
54        /// An in-range unit shift is at least `1`, so `(1 << k) - 1` cannot underflow.
55        pub broadcast proof fn $unit_le_shl(k: int)
56            requires
57                0 <= k < $width,
58            ensures
59                #![trigger ($one << (k as usize))]
60                $one <= ($one << (k as usize)),
61        {
62            let ku: u32 = k as u32;
63            assert((ku < $width_u32) ==> ($one <= ($one << ku))) by (bit_vector);
64        }
65
66        /// Masking with the low-`k`-bits mask clears every bit at or above `k`.
67        pub broadcast proof fn $masked_bit_clear(word: $uN, mask: $uN, k: int, b: int)
68            requires
69                0 <= k <= $width,
70                k <= b < $width,
71                mask == ($one << (k as usize)) - $one,
72            ensures
73                #![trigger $bit_is_set(word & mask, b), ($one << (k as usize))]
74                !$bit_is_set(word & mask, b),
75        {
76            let ku: u32 = k as u32;
77            let bu: u32 = b as u32;
78            assert(((word & mask) & ($one << bu)) == $zero) by (bit_vector)
79                requires
80                    ku <= bu,
81                    bu < $width_u32,
82                    mask == ($one << ku) - $one,
83            ;
84        }
85
86        /// Masking with the low-`k`-bits mask keeps every bit below `k` unchanged.
87        pub broadcast proof fn $masked_bit_keep(word: $uN, mask: $uN, k: int, b: int)
88            requires
89                0 < k <= $width,
90                0 <= b < k,
91                mask == ($one << (k as usize)) - $one,
92            ensures
93                #![trigger $bit_is_set(word & mask, b), ($one << (k as usize))]
94                $bit_is_set(word & mask, b) == $bit_is_set(word, b),
95        {
96            let ku: u32 = k as u32;
97            let bu: u32 = b as u32;
98            assert(((word & mask) & ($one << bu)) == (word & ($one << bu))) by (bit_vector)
99                requires
100                    bu < ku,
101                    ku <= $width_u32,
102                    mask == ($one << ku) - $one,
103            ;
104        }
105
106        /// Setting bit `b` makes that bit set.
107        pub broadcast proof fn $setbit_bit_is_set(word: $uN, b: int)
108            requires
109                0 <= b < $width,
110            ensures
111                #![trigger $bit_is_set(word | ($one << (b as usize)), b)]
112                $bit_is_set(word | ($one << (b as usize)), b),
113        {
114            let bu: u32 = b as u32;
115            assert(((word | ($one << bu)) & ($one << bu)) == ($one << bu)) by (bit_vector);
116            assert((bu < $width_u32) ==> (($one << bu) != $zero)) by (bit_vector);
117        }
118
119        /// Setting bit `b` leaves a different in-range bit `b2` unchanged.
120        pub broadcast proof fn $setbit_bit_unchanged(word: $uN, b: int, b2: int)
121            requires
122                0 <= b < $width,
123                0 <= b2 < $width,
124                b != b2,
125            ensures
126                #![trigger $bit_is_set(word | ($one << (b as usize)), b2), ($one << (b as usize))]
127                $bit_is_set(word | ($one << (b as usize)), b2) == $bit_is_set(word, b2),
128        {
129            let bu: u32 = b as u32;
130            let b2u: u32 = b2 as u32;
131            assert((bu != b2u) ==> (((word | ($one << bu)) & ($one << b2u))
132                == (word & ($one << b2u)))) by (bit_vector);
133        }
134
135        /// Clearing bit `b` makes that bit clear.
136        pub broadcast proof fn $clearbit_not_bit_is_set(word: $uN, b: int)
137            requires
138                0 <= b < $width,
139            ensures
140                #![trigger $bit_is_set(word & (!($one << (b as usize))), b)]
141                !$bit_is_set(word & (!($one << (b as usize))), b),
142        {
143            let bu: u32 = b as u32;
144            assert((word & (!($one << bu))) & ($one << bu) == $zero) by (bit_vector);
145        }
146
147        /// Clearing bit `b` leaves a different in-range bit `b2` unchanged.
148        pub broadcast proof fn $clearbit_bit_unchanged(word: $uN, b: int, b2: int)
149            requires
150                0 <= b < $width,
151                0 <= b2 < $width,
152                b != b2,
153            ensures
154                #![trigger $bit_is_set(word & (!($one << (b as usize))), b2), ($one << (b as usize))]
155                $bit_is_set(word & (!($one << (b as usize))), b2) == $bit_is_set(word, b2),
156        {
157            let bu: u32 = b as u32;
158            let b2u: u32 = b2 as u32;
159            assert((bu != b2u) ==> (((word & (!($one << bu))) & ($one << b2u))
160                == (word & ($one << b2u)))) by (bit_vector);
161        }
162
163        /// AND-ing the zero word with any word is zero.
164        pub proof fn $and_zero(x: $uN)
165            ensures
166                $zero & x == $zero,
167        {
168            assert($zero & x == $zero) by (bit_vector);
169        }
170
171        pub broadcast group $group {
172            $allones_bit_it_set,
173            $unit_le_shl,
174            $masked_bit_clear,
175            $masked_bit_keep,
176            $setbit_bit_is_set,
177            $setbit_bit_unchanged,
178            $clearbit_not_bit_is_set,
179            $clearbit_bit_unchanged,
180        }
181
182        } // verus!
183    };
184}
185
186define_unsigned_bit_lemmas!(
187    u8,
188    0u8,
189    1u8,
190    8,
191    8u32,
192    u8_bit_is_set,
193    lemma_u8_allones_bit_it_set,
194    lemma_u8_unit_le_shl,
195    lemma_u8_masked_bit_clear,
196    lemma_u8_masked_bit_keep,
197    lemma_u8_setbit_bit_is_set,
198    lemma_u8_setbit_bit_unchanged,
199    lemma_u8_clearbit_not_bit_is_set,
200    lemma_u8_clearbit_bit_unchanged,
201    lemma_u8_and_zero,
202    group_u8_bit_algebra
203);
204define_unsigned_bit_lemmas!(
205    u16,
206    0u16,
207    1u16,
208    16,
209    16u32,
210    u16_bit_is_set,
211    lemma_u16_allones_bit_it_set,
212    lemma_u16_unit_le_shl,
213    lemma_u16_masked_bit_clear,
214    lemma_u16_masked_bit_keep,
215    lemma_u16_setbit_bit_is_set,
216    lemma_u16_setbit_bit_unchanged,
217    lemma_u16_clearbit_not_bit_is_set,
218    lemma_u16_clearbit_bit_unchanged,
219    lemma_u16_and_zero,
220    group_u16_bit_algebra
221);
222define_unsigned_bit_lemmas!(
223    u32,
224    0u32,
225    1u32,
226    32,
227    32u32,
228    u32_bit_is_set,
229    lemma_u32_allones_bit_it_set,
230    lemma_u32_unit_le_shl,
231    lemma_u32_masked_bit_clear,
232    lemma_u32_masked_bit_keep,
233    lemma_u32_setbit_bit_is_set,
234    lemma_u32_setbit_bit_unchanged,
235    lemma_u32_clearbit_not_bit_is_set,
236    lemma_u32_clearbit_bit_unchanged,
237    lemma_u32_and_zero,
238    group_u32_bit_algebra
239);
240define_unsigned_bit_lemmas!(
241    u64,
242    0u64,
243    1u64,
244    64,
245    64u32,
246    u64_bit_is_set,
247    lemma_u64_allones_bit_it_set,
248    lemma_u64_unit_le_shl,
249    lemma_u64_masked_bit_clear,
250    lemma_u64_masked_bit_keep,
251    lemma_u64_setbit_bit_is_set,
252    lemma_u64_setbit_bit_unchanged,
253    lemma_u64_clearbit_not_bit_is_set,
254    lemma_u64_clearbit_bit_unchanged,
255    lemma_u64_and_zero,
256    group_u64_bit_algebra
257);
258define_unsigned_bit_lemmas!(
259    u128,
260    0u128,
261    1u128,
262    128,
263    128u32,
264    u128_bit_is_set,
265    lemma_u128_allones_bit_it_set,
266    lemma_u128_unit_le_shl,
267    lemma_u128_masked_bit_clear,
268    lemma_u128_masked_bit_keep,
269    lemma_u128_setbit_bit_is_set,
270    lemma_u128_setbit_bit_unchanged,
271    lemma_u128_clearbit_not_bit_is_set,
272    lemma_u128_clearbit_bit_unchanged,
273    lemma_u128_and_zero,
274    group_u128_bit_algebra
275);
276define_unsigned_bit_lemmas!(
277    usize,
278    0usize,
279    1usize,
280    usize::BITS as int,
281    usize::BITS,
282    usize_bit_is_set,
283    lemma_usize_allones_bit_it_set,
284    lemma_usize_unit_le_shl,
285    lemma_usize_masked_bit_clear,
286    lemma_usize_masked_bit_keep,
287    lemma_usize_setbit_bit_is_set,
288    lemma_usize_setbit_bit_unchanged,
289    lemma_usize_clearbit_not_bit_is_set,
290    lemma_usize_clearbit_bit_unchanged,
291    lemma_usize_and_zero,
292    group_usize_bit_algebra
293);