vstd/arithmetic/
power2.rs

1//! This file contains proofs related to powers of 2. These are part
2//! of the math standard library.
3//!
4//! It's based on the following file from the Dafny math standard library:
5//! `Source/DafnyStandardLibraries/src/Std/Arithmetic/Power2.dfy`.
6//! That file has the following copyright notice:
7//! /*******************************************************************************
8//! *  Original: Copyright (c) Microsoft Corporation
9//! *  SPDX-License-Identifier: MIT
10//! *
11//! *  Modifications and Extensions: Copyright by the contributors to the Dafny Project
12//! *  SPDX-License-Identifier: MIT
13//! *******************************************************************************/
14#[allow(unused_imports)]
15use super::super::prelude::*;
16
17verus! {
18
19#[cfg(verus_keep_ghost)]
20use super::power::{
21    pow,
22    lemma_pow_positive,
23    lemma_pow_adds,
24    lemma_pow_strictly_increases,
25    lemma_pow_subtracts,
26};
27
28/// This function computes 2 to the power of the given natural number
29/// `e`. It's opaque so that the SMT solver doesn't waste time
30/// repeatedly recursively unfolding it.
31#[verifier::opaque]
32pub open spec fn pow2(e: nat) -> nat
33    decreases
34            e  // ensures pow2(e) > 0
35            // cannot have ensurs clause in spec functions
36            // a workaround is the lemma_pow2_pos below
37            ,
38{
39    // you cannot reveal in a spec function, which cause more reveals clauses
40    // for the proof
41    // reveal(pow);
42    pow(2, e) as nat
43}
44
45/// Proof that 2 to the power of any natural number (specifically,
46/// `e`) is positive.
47pub broadcast proof fn lemma_pow2_pos(e: nat)
48    ensures
49        #[trigger] pow2(e) > 0,
50{
51    reveal(pow2);
52    lemma_pow_positive(2, e);
53}
54
55/// Proof that `pow2(e)` is equivalent to `pow(2, e)`.
56pub broadcast proof fn lemma_pow2(e: nat)
57    ensures
58        #[trigger] pow2(e) == pow(2, e) as int,
59    decreases e,
60{
61    reveal(pow);
62    reveal(pow2);
63    if e != 0 {
64        lemma_pow2((e - 1) as nat);
65    }
66}
67
68/// Proof relating 2^e to 2^(e-1).
69pub broadcast proof fn lemma_pow2_unfold(e: nat)
70    requires
71        e > 0,
72    ensures
73        #[trigger] pow2(e) == 2 * pow2((e - 1) as nat),
74{
75    reveal(pow);
76    lemma_pow2(e);
77    lemma_pow2((e - 1) as nat);
78}
79
80/// Proof that `2^(e1 + e2)` is equivalent to `2^e1 * 2^e2`.
81pub broadcast proof fn lemma_pow2_adds(e1: nat, e2: nat)
82    ensures
83        #[trigger] pow2(e1 + e2) == pow2(e1) * pow2(e2),
84{
85    lemma_pow2(e1);
86    lemma_pow2(e2);
87    lemma_pow2(e1 + e2);
88    lemma_pow_adds(2, e1, e2);
89}
90
91/// Proof that, as long as `e1 <= e2`, `2^(e2 - e1)` is equivalent to `2^e2 / 2^e1`.
92pub broadcast proof fn lemma_pow2_subtracts(e1: nat, e2: nat)
93    requires
94        e1 <= e2,
95    ensures
96        #[trigger] pow2((e2 - e1) as nat) == pow2(e2) / pow2(e1) > 0,
97{
98    lemma_pow2(e1);
99    lemma_pow2(e2);
100    lemma_pow2((e2 - e1) as nat);
101    lemma_pow_subtracts(2, e1, e2);
102}
103
104/// Proof that if `e1 < e2` then `2^e1 < 2^e2`.
105pub broadcast proof fn lemma_pow2_strictly_increases(e1: nat, e2: nat)
106    requires
107        e1 < e2,
108    ensures
109        #[trigger] pow2(e1) < #[trigger] pow2(e2),
110{
111    lemma_pow2(e1);
112    lemma_pow2(e2);
113    lemma_pow_strictly_increases(2, e1, e2);
114}
115
116/// Proof establishing the concrete values for all powers of 2 from 0 to 32 and also 2^64.
117pub proof fn lemma2_to64()
118    ensures
119        pow2(0) == 0x1,
120        pow2(1) == 0x2,
121        pow2(2) == 0x4,
122        pow2(3) == 0x8,
123        pow2(4) == 0x10,
124        pow2(5) == 0x20,
125        pow2(6) == 0x40,
126        pow2(7) == 0x80,
127        pow2(8) == 0x100,
128        pow2(9) == 0x200,
129        pow2(10) == 0x400,
130        pow2(11) == 0x800,
131        pow2(12) == 0x1000,
132        pow2(13) == 0x2000,
133        pow2(14) == 0x4000,
134        pow2(15) == 0x8000,
135        pow2(16) == 0x10000,
136        pow2(17) == 0x20000,
137        pow2(18) == 0x40000,
138        pow2(19) == 0x80000,
139        pow2(20) == 0x100000,
140        pow2(21) == 0x200000,
141        pow2(22) == 0x400000,
142        pow2(23) == 0x800000,
143        pow2(24) == 0x1000000,
144        pow2(25) == 0x2000000,
145        pow2(26) == 0x4000000,
146        pow2(27) == 0x8000000,
147        pow2(28) == 0x10000000,
148        pow2(29) == 0x20000000,
149        pow2(30) == 0x40000000,
150        pow2(31) == 0x80000000,
151        pow2(32) == 0x100000000,
152        pow2(64) == 0x10000000000000000,
153{
154    reveal(pow2);
155    reveal(pow);
156    #[verusfmt::skip]
157    assert(
158        pow2(0) == 0x1 &&
159        pow2(1) == 0x2 &&
160        pow2(2) == 0x4 &&
161        pow2(3) == 0x8 &&
162        pow2(4) == 0x10 &&
163        pow2(5) == 0x20 &&
164        pow2(6) == 0x40 &&
165        pow2(7) == 0x80 &&
166        pow2(8) == 0x100 &&
167        pow2(9) == 0x200 &&
168        pow2(10) == 0x400 &&
169        pow2(11) == 0x800 &&
170        pow2(12) == 0x1000 &&
171        pow2(13) == 0x2000 &&
172        pow2(14) == 0x4000 &&
173        pow2(15) == 0x8000 &&
174        pow2(16) == 0x10000 &&
175        pow2(17) == 0x20000 &&
176        pow2(18) == 0x40000 &&
177        pow2(19) == 0x80000 &&
178        pow2(20) == 0x100000 &&
179        pow2(21) == 0x200000 &&
180        pow2(22) == 0x400000 &&
181        pow2(23) == 0x800000 &&
182        pow2(24) == 0x1000000 &&
183        pow2(25) == 0x2000000 &&
184        pow2(26) == 0x4000000 &&
185        pow2(27) == 0x8000000 &&
186        pow2(28) == 0x10000000 &&
187        pow2(29) == 0x20000000 &&
188        pow2(30) == 0x40000000 &&
189        pow2(31) == 0x80000000 &&
190        pow2(32) == 0x100000000 &&
191        pow2(64) == 0x10000000000000000
192    ) by(compute_only);
193}
194
195/// Proof establishing the concrete values for all powers of 2 from 33 to 64.
196/// This lemma is separated from `lemma2_to64()` to avoid a stack overflow issue
197/// while executing ./tools/docs.sh.
198pub proof fn lemma2_to64_rest()
199    ensures
200        pow2(33) == 0x200000000,
201        pow2(34) == 0x400000000,
202        pow2(35) == 0x800000000,
203        pow2(36) == 0x1000000000,
204        pow2(37) == 0x2000000000,
205        pow2(38) == 0x4000000000,
206        pow2(39) == 0x8000000000,
207        pow2(40) == 0x10000000000,
208        pow2(41) == 0x20000000000,
209        pow2(42) == 0x40000000000,
210        pow2(43) == 0x80000000000,
211        pow2(44) == 0x100000000000,
212        pow2(45) == 0x200000000000,
213        pow2(46) == 0x400000000000,
214        pow2(47) == 0x800000000000,
215        pow2(48) == 0x1000000000000,
216        pow2(49) == 0x2000000000000,
217        pow2(50) == 0x4000000000000,
218        pow2(51) == 0x8000000000000,
219        pow2(52) == 0x10000000000000,
220        pow2(53) == 0x20000000000000,
221        pow2(54) == 0x40000000000000,
222        pow2(55) == 0x80000000000000,
223        pow2(56) == 0x100000000000000,
224        pow2(57) == 0x200000000000000,
225        pow2(58) == 0x400000000000000,
226        pow2(59) == 0x800000000000000,
227        pow2(60) == 0x1000000000000000,
228        pow2(61) == 0x2000000000000000,
229        pow2(62) == 0x4000000000000000,
230        pow2(63) == 0x8000000000000000,
231        pow2(64) == 0x10000000000000000,
232{
233    reveal(pow2);
234    reveal(pow);
235    #[verusfmt::skip]
236    assert(
237        pow2(33) == 0x200000000 &&
238        pow2(34) == 0x400000000 &&
239        pow2(35) == 0x800000000 &&
240        pow2(36) == 0x1000000000 &&
241        pow2(37) == 0x2000000000 &&
242        pow2(38) == 0x4000000000 &&
243        pow2(39) == 0x8000000000 &&
244        pow2(40) == 0x10000000000 &&
245        pow2(41) == 0x20000000000 &&
246        pow2(42) == 0x40000000000 &&
247        pow2(43) == 0x80000000000 &&
248        pow2(44) == 0x100000000000 &&
249        pow2(45) == 0x200000000000 &&
250        pow2(46) == 0x400000000000 &&
251        pow2(47) == 0x800000000000 &&
252        pow2(48) == 0x1000000000000 &&
253        pow2(49) == 0x2000000000000 &&
254        pow2(50) == 0x4000000000000 &&
255        pow2(51) == 0x8000000000000 &&
256        pow2(52) == 0x10000000000000 &&
257        pow2(53) == 0x20000000000000 &&
258        pow2(54) == 0x40000000000000 &&
259        pow2(55) == 0x80000000000000 &&
260        pow2(56) == 0x100000000000000 &&
261        pow2(57) == 0x200000000000000 &&
262        pow2(58) == 0x400000000000000 &&
263        pow2(59) == 0x800000000000000 &&
264        pow2(60) == 0x1000000000000000 &&
265        pow2(61) == 0x2000000000000000 &&
266        pow2(62) == 0x4000000000000000 &&
267        pow2(63) == 0x8000000000000000 &&
268        pow2(64) == 0x10000000000000000
269    ) by(compute_only);
270}
271
272} // verus!