Merge rust-bitcoin/rust-bitcoin#612: Fix `Uint256::increment` panics

5d71a9dd89 Correct input length check for uin128 fuzzer (Matt Corallo)
9c256cc88e Add a fuzz check for `Uint128::increment` (Matt Corallo)
a15f263c4e Move the `increment` fn into the uint macro to add it to Uint128 (Matt Corallo)
d52b88b525 Fix increment of Uint256 with carry (carolcapps)

Pull request description:

  This is #578 with review feedback addressed.

ACKs for top commit:
  apoelstra:
    ACK 5d71a9dd89
  sanket1729:
    ACK 5d71a9d

Tree-SHA512: 32e5ea6387943ecad8f190a0de336a545fda72b6ff7388d3479037a5f880434276a7d0607f5cf61710d45e984c01954f4e3199a60c542be48b397717afb3d406
This commit is contained in:
Andrew Poelstra 2021-09-27 17:45:48 +00:00
commit 454379cdfa
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 62 additions and 17 deletions

View File

@ -27,7 +27,7 @@ fn do_test(data: &[u8]) {
} } } }
} }
if data.len() != 16*2 + 1 { return; } if data.len() != 16*2 { return; }
let (a_native, a) = read_ints!(0); let (a_native, a) = read_ints!(0);
// Checks using only a: // Checks using only a:
@ -40,6 +40,10 @@ fn do_test(data: &[u8]) {
assert_eq!(128 - a_native.leading_zeros() as usize, a.bits()); assert_eq!(128 - a_native.leading_zeros() as usize, a.bits());
assert_eq!(a_native as u64, bitcoin::util::uint::Uint128::from_u64(a_native as u64).unwrap().low_u64()); assert_eq!(a_native as u64, bitcoin::util::uint::Uint128::from_u64(a_native as u64).unwrap().low_u64());
let mut a_inc = a.clone();
a_inc.increment();
check_eq!(a_native.wrapping_add(1), a_inc);
// Checks with two numbers: // Checks with two numbers:
let (b_native, b) = read_ints!(16); let (b_native, b) = read_ints!(16);

View File

@ -162,6 +162,16 @@ macro_rules! construct_uint {
($name(ret), sub_copy) ($name(ret), sub_copy)
} }
/// Increment by 1
#[inline]
pub fn increment(&mut self) {
let &mut $name(ref mut arr) = self;
for i in 0..$n_words {
arr[i] = arr[i].wrapping_add(1);
if arr[i] != 0 { break; }
}
}
} }
impl PartialOrd for $name { impl PartialOrd for $name {
@ -516,22 +526,6 @@ impl ::core::fmt::Display for ParseLengthError {
impl ::std::error::Error for ParseLengthError {} impl ::std::error::Error for ParseLengthError {}
impl Uint256 { impl Uint256 {
/// Increment by 1
#[inline]
pub fn increment(&mut self) {
let &mut Uint256(ref mut arr) = self;
arr[0] += 1;
if arr[0] == 0 {
arr[1] += 1;
if arr[1] == 0 {
arr[2] += 1;
if arr[2] == 0 {
arr[3] += 1;
}
}
}
}
/// Decay to a uint128 /// Decay to a uint128
#[inline] #[inline]
pub fn low_128(&self) -> Uint128 { pub fn low_128(&self) -> Uint128 {
@ -693,6 +687,53 @@ mod tests {
0x4AFCFF6F0375C608u64, 0x928D92B4D7F5DF33u64])); 0x4AFCFF6F0375C608u64, 0x928D92B4D7F5DF33u64]));
} }
#[test]
pub fn increment_test() {
let mut val = Uint256([
0xFFFFFFFFFFFFFFFEu64,
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
0xEFFFFFFFFFFFFFFFu64,
]);
val.increment();
assert_eq!(
val,
Uint256([
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
0xEFFFFFFFFFFFFFFFu64,
])
);
val.increment();
assert_eq!(
val,
Uint256([
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
0xF000000000000000u64,
])
);
let mut val = Uint256([
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
0xFFFFFFFFFFFFFFFFu64,
]);
val.increment();
assert_eq!(
val,
Uint256([
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
0x0000000000000000u64,
])
);
}
#[test] #[test]
pub fn uint256_bitslice_test() { pub fn uint256_bitslice_test() {
let init = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap(); let init = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap();