1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
//! This file contains proofs related to powers of 2. These are part
//! of the math standard library.
//!
//! It's based on the following file from the Dafny math standard library:
//! `Source/DafnyStandardLibraries/src/Std/Arithmetic/Power2.dfy`.
//! That file has the following copyright notice:
//! /*******************************************************************************
//! * Original: Copyright (c) Microsoft Corporation
//! * SPDX-License-Identifier: MIT
//! *
//! * Modifications and Extensions: Copyright by the contributors to the Dafny Project
//! * SPDX-License-Identifier: MIT
//! *******************************************************************************/
#[allow(unused_imports)]
use super::super::prelude::*;
verus! {
#[cfg(verus_keep_ghost)]
use super::power::{pow, lemma_pow_positive, lemma_pow_adds, lemma_pow_strictly_increases};
/// This function computes 2 to the power of the given natural number
/// `e`. It's opaque so that the SMT solver doesn't waste time
/// repeatedly recursively unfolding it.
#[verifier::opaque]
pub open spec fn pow2(e: nat) -> nat
decreases
e // ensures pow2(e) > 0
// cannot have ensurs clause in spec functions
// a workaround is the lemma_pow2_pos below
,
{
// you cannot reveal in a spec function, which cause more reveals clauses
// for the proof
// reveal(pow);
pow(2, e) as nat
}
/// Proof that 2 to the power of any natural number (specifically,
/// `e`) is positive
pub broadcast proof fn lemma_pow2_pos(e: nat)
ensures
#[trigger] pow2(e) > 0,
{
reveal(pow2);
lemma_pow_positive(2, e);
}
/// Proof that `pow2(e)` is equivalent to `pow(2, e)`
pub broadcast proof fn lemma_pow2(e: nat)
ensures
#[trigger] pow2(e) == pow(2, e) as int,
decreases e,
{
reveal(pow);
reveal(pow2);
if e != 0 {
lemma_pow2((e - 1) as nat);
}
}
/// Proof relating 2^e to 2^(e-1).
pub broadcast proof fn lemma_pow2_unfold(e: nat)
requires
e > 0,
ensures
#[trigger] pow2(e) == 2 * pow2((e - 1) as nat),
{
lemma_pow2(e);
lemma_pow2((e - 1) as nat);
}
/// Proof that `2^(e1 + e2)` is equivalent to `2^e1 * 2^e2`.
pub broadcast proof fn lemma_pow2_adds(e1: nat, e2: nat)
ensures
#[trigger] pow2(e1 + e2) == pow2(e1) * pow2(e2),
{
lemma_pow2(e1);
lemma_pow2(e2);
lemma_pow2(e1 + e2);
lemma_pow_adds(2, e1, e2);
}
/// Proof that if `e1 < e2` then `2^e1 < 2^e2`.
pub broadcast proof fn lemma_pow2_strictly_increases(e1: nat, e2: nat)
requires
e1 < e2,
ensures
#[trigger] pow2(e1) < #[trigger] pow2(e2),
{
lemma_pow2(e1);
lemma_pow2(e2);
lemma_pow_strictly_increases(2, e1, e2);
}
/// Proof establishing the concrete values for all powers of 2 from 0 to 32 and also 2^64
pub proof fn lemma2_to64()
ensures
pow2(0) == 0x1,
pow2(1) == 0x2,
pow2(2) == 0x4,
pow2(3) == 0x8,
pow2(4) == 0x10,
pow2(5) == 0x20,
pow2(6) == 0x40,
pow2(7) == 0x80,
pow2(8) == 0x100,
pow2(9) == 0x200,
pow2(10) == 0x400,
pow2(11) == 0x800,
pow2(12) == 0x1000,
pow2(13) == 0x2000,
pow2(14) == 0x4000,
pow2(15) == 0x8000,
pow2(16) == 0x10000,
pow2(17) == 0x20000,
pow2(18) == 0x40000,
pow2(19) == 0x80000,
pow2(20) == 0x100000,
pow2(21) == 0x200000,
pow2(22) == 0x400000,
pow2(23) == 0x800000,
pow2(24) == 0x1000000,
pow2(25) == 0x2000000,
pow2(26) == 0x4000000,
pow2(27) == 0x8000000,
pow2(28) == 0x10000000,
pow2(29) == 0x20000000,
pow2(30) == 0x40000000,
pow2(31) == 0x80000000,
pow2(32) == 0x100000000,
pow2(64) == 0x10000000000000000,
{
reveal(pow2);
reveal(pow);
#[verusfmt::skip]
assert(
pow2(0) == 0x1 &&
pow2(1) == 0x2 &&
pow2(2) == 0x4 &&
pow2(3) == 0x8 &&
pow2(4) == 0x10 &&
pow2(5) == 0x20 &&
pow2(6) == 0x40 &&
pow2(7) == 0x80 &&
pow2(8) == 0x100 &&
pow2(9) == 0x200 &&
pow2(10) == 0x400 &&
pow2(11) == 0x800 &&
pow2(12) == 0x1000 &&
pow2(13) == 0x2000 &&
pow2(14) == 0x4000 &&
pow2(15) == 0x8000 &&
pow2(16) == 0x10000 &&
pow2(17) == 0x20000 &&
pow2(18) == 0x40000 &&
pow2(19) == 0x80000 &&
pow2(20) == 0x100000 &&
pow2(21) == 0x200000 &&
pow2(22) == 0x400000 &&
pow2(23) == 0x800000 &&
pow2(24) == 0x1000000 &&
pow2(25) == 0x2000000 &&
pow2(26) == 0x4000000 &&
pow2(27) == 0x8000000 &&
pow2(28) == 0x10000000 &&
pow2(29) == 0x20000000 &&
pow2(30) == 0x40000000 &&
pow2(31) == 0x80000000 &&
pow2(32) == 0x100000000 &&
pow2(64) == 0x10000000000000000
) by(compute_only);
}
} // verus!