Skip to content

Commit 9cb302e

Browse files
committed
Merge rust-bitcoin#3782: A couple of kani fixes
f4617e7 kani: Verify no out of bounds for ArrayVec (Tobin C. Harding) e378cdd kani: Don't bother checking signed to unsigned conversion (Tobin C. Harding) 50224ee kani: Don't overflow the tests (Tobin C. Harding) Pull request description: PR does two things because a recent upgrade of `kani` broke our setup. I'm not sure why it just showed up. We fix the verification for `amount` types which recently broke because of `MAX_MONEY` changes and then we add a verification function to `internals` because build fails and one fix is to just add something. - Patch 1: units: Assumes correct values - Patch 2: units: Removes a stale check now that MAX_MONEY is being used for MAX - Patch 3: Add verification to `internals::ArrayVec`. ACKs for top commit: apoelstra: ACK f4617e7; successfully ran local tests Tree-SHA512: dfef05a7bbb5372415efa8acab7f79801aa7326ac298c007b173786f00bcccd0b1b81d327113723c359fb2797895414a586cc3fb86e495476a03fcac02a96899
2 parents ebe43b6 + f4617e7 commit 9cb302e

File tree

3 files changed

+57
-57
lines changed

3 files changed

+57
-57
lines changed

internals/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ all-features = true
3535
rustdoc-args = ["--cfg", "docsrs"]
3636

3737
[lints.rust]
38-
unexpected_cfgs = { level = "deny" }
38+
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(kani)'] }

internals/src/array_vec.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,45 @@ mod tests {
188188
av.extend_from_slice(b"abc");
189189
}
190190
}
191+
192+
#[cfg(kani)]
193+
mod verification {
194+
use super::*;
195+
196+
#[kani::unwind(16)] // One greater than 15 (max number of elements).
197+
#[kani::proof]
198+
fn no_out_of_bounds_less_than_cap() {
199+
const CAP: usize = 32;
200+
let n = kani::any::<u32>();
201+
let elements = (n & 0x0F) as usize; // Just use 4 bits.
202+
203+
let val = kani::any::<u32>();
204+
205+
let mut v = ArrayVec::<u32, CAP>::new();
206+
for _ in 0..elements {
207+
v.push(val);
208+
}
209+
210+
for i in 0..elements {
211+
assert_eq!(v[i], val);
212+
}
213+
}
214+
215+
#[kani::unwind(16)] // One grater than 15.
216+
#[kani::proof]
217+
fn no_out_of_bounds_upto_cap() {
218+
const CAP: usize = 15;
219+
let elements = CAP;
220+
221+
let val = kani::any::<u32>();
222+
223+
let mut v = ArrayVec::<u32, CAP>::new();
224+
for _ in 0..elements {
225+
v.push(val);
226+
}
227+
228+
for i in 0..elements {
229+
assert_eq!(v[i], val);
230+
}
231+
}
232+
}

units/src/amount/verification.rs

Lines changed: 14 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ use super::*;
2323
fn u_amount_homomorphic() {
2424
let n1 = kani::any::<u64>();
2525
let n2 = kani::any::<u64>();
26-
kani::assume(n1.checked_add(n2).is_some()); // assume we don't overflow in the actual test
26+
// Assume we don't overflow in the actual tests.
27+
kani::assume(n1.checked_add(n2).is_some()); // Adding u64s doesn't overflow.
28+
let a1 = Amount::from_sat(n1); // TODO: If from_sat enforces invariant assume this `is_ok()`.
29+
let a2 = Amount::from_sat(n2);
30+
kani::assume(a1.checked_add(a2).is_some()); // Adding amounts doesn't overflow.
31+
2732
assert_eq!(Amount::from_sat(n1) + Amount::from_sat(n2), Amount::from_sat(n1 + n2));
2833

2934
let mut amt = Amount::from_sat(n1);
@@ -37,39 +42,21 @@ fn u_amount_homomorphic() {
3742
let mut amt = Amount::from_sat(max);
3843
amt -= Amount::from_sat(min);
3944
assert_eq!(amt, Amount::from_sat(max - min));
40-
41-
assert_eq!(
42-
Amount::from_sat(n1).to_signed(),
43-
if n1 <= i64::MAX as u64 {
44-
Ok(SignedAmount::from_sat(n1.try_into().unwrap()))
45-
} else {
46-
Err(OutOfRangeError::too_big(true))
47-
},
48-
);
49-
}
50-
51-
#[kani::unwind(4)]
52-
#[kani::proof]
53-
fn u_amount_homomorphic_checked() {
54-
let n1 = kani::any::<u64>();
55-
let n2 = kani::any::<u64>();
56-
assert_eq!(
57-
Amount::from_sat(n1).checked_add(Amount::from_sat(n2)),
58-
n1.checked_add(n2).map(Amount::from_sat),
59-
);
60-
assert_eq!(
61-
Amount::from_sat(n1).checked_sub(Amount::from_sat(n2)),
62-
n1.checked_sub(n2).map(Amount::from_sat),
63-
);
6445
}
6546

6647
#[kani::unwind(4)]
6748
#[kani::proof]
6849
fn s_amount_homomorphic() {
6950
let n1 = kani::any::<i64>();
7051
let n2 = kani::any::<i64>();
71-
kani::assume(n1.checked_add(n2).is_some()); // assume we don't overflow in the actual test
72-
kani::assume(n1.checked_sub(n2).is_some()); // assume we don't overflow in the actual test
52+
// Assume we don't overflow in the actual tests.
53+
kani::assume(n1.checked_add(n2).is_some()); // Adding i64s doesn't overflow.
54+
kani::assume(n1.checked_sub(n2).is_some()); // Subbing i64s doesn't overflow.
55+
let a1 = SignedAmount::from_sat(n1); // TODO: If from_sat enforces invariant assume this `is_ok()`.
56+
let a2 = SignedAmount::from_sat(n2);
57+
kani::assume(a1.checked_add(a2).is_some()); // Adding amounts doesn't overflow.
58+
kani::assume(a1.checked_sub(a2).is_some()); // Subbing amounts doesn't overflow.
59+
7360
assert_eq!(
7461
SignedAmount::from_sat(n1) + SignedAmount::from_sat(n2),
7562
SignedAmount::from_sat(n1 + n2)
@@ -85,33 +72,4 @@ fn s_amount_homomorphic() {
8572
let mut amt = SignedAmount::from_sat(n1);
8673
amt -= SignedAmount::from_sat(n2);
8774
assert_eq!(amt, SignedAmount::from_sat(n1 - n2));
88-
89-
assert_eq!(
90-
SignedAmount::from_sat(n1).to_unsigned(),
91-
if n1 >= 0 {
92-
Ok(Amount::from_sat(n1.try_into().unwrap()))
93-
} else {
94-
Err(OutOfRangeError { is_signed: false, is_greater_than_max: false })
95-
},
96-
);
97-
}
98-
99-
#[kani::unwind(4)]
100-
#[kani::proof]
101-
fn s_amount_homomorphic_checked() {
102-
let n1 = kani::any::<i64>();
103-
let n2 = kani::any::<i64>();
104-
assert_eq!(
105-
SignedAmount::from_sat(n1).checked_add(SignedAmount::from_sat(n2)),
106-
n1.checked_add(n2).map(SignedAmount::from_sat),
107-
);
108-
assert_eq!(
109-
SignedAmount::from_sat(n1).checked_sub(SignedAmount::from_sat(n2)),
110-
n1.checked_sub(n2).map(SignedAmount::from_sat),
111-
);
112-
113-
assert_eq!(
114-
SignedAmount::from_sat(n1).positive_sub(SignedAmount::from_sat(n2)),
115-
if n1 >= 0 && n2 >= 0 && n1 >= n2 { Some(SignedAmount::from_sat(n1 - n2)) } else { None },
116-
);
11775
}

0 commit comments

Comments
 (0)