diff --git a/fuzz/fuzz_targets/uint128_fuzz.rs b/fuzz/fuzz_targets/uint128_fuzz.rs index 11b2b620..1c72b927 100644 --- a/fuzz/fuzz_targets/uint128_fuzz.rs +++ b/fuzz/fuzz_targets/uint128_fuzz.rs @@ -1,5 +1,6 @@ extern crate bitcoin; use std::str::FromStr; +use std::convert::Into; fn do_test(data: &[u8]) { macro_rules! read_ints { @@ -11,6 +12,12 @@ fn do_test(data: &[u8]) { } // Note BE: let uint128 = bitcoin::util::uint::Uint128::from(&[native as u64, (native >> 8*8) as u64][..]); + + // Checking two conversion methods against each other + let mut slice = [0u8; 16]; + slice.copy_from_slice(&data[$start..$start + 16]); + assert_eq!(uint128, bitcoin::util::uint::Uint128::from_be_bytes(slice)); + (native, uint128) } } } diff --git a/src/util/endian.rs b/src/util/endian.rs index 8c10b57a..37b59a19 100644 --- a/src/util/endian.rs +++ b/src/util/endian.rs @@ -52,6 +52,7 @@ macro_rules! define_le_to_array { } define_slice_to_be!(slice_to_u32_be, u32); +define_slice_to_be!(slice_to_u64_be, u64); define_be_to_array!(u32_to_array_be, u32, 4); define_slice_to_le!(slice_to_u16_le, u16); define_slice_to_le!(slice_to_u32_le, u32); @@ -105,6 +106,7 @@ mod tests { #[test] fn endianness_test() { assert_eq!(slice_to_u32_be(&[0xde, 0xad, 0xbe, 0xef]), 0xdeadbeef); + assert_eq!(slice_to_u64_be(&[0xde, 0xad, 0xbe, 0xef, 0x1b, 0xad, 0xca, 0xfe]), 0xdeadbeef1badcafe); assert_eq!(u32_to_array_be(0xdeadbeef), [0xde, 0xad, 0xbe, 0xef]); assert_eq!(slice_to_u16_le(&[0xad, 0xde]), 0xdead); diff --git a/src/util/uint.rs b/src/util/uint.rs index 29f7d1c4..b721263a 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -73,6 +73,7 @@ macro_rules! construct_uint { } /// Create an object from a given unsigned 64-bit integer + #[inline] pub fn from_u64(init: u64) -> Option<$name> { let mut ret = [0; $n_words]; ret[0] = init; @@ -80,11 +81,24 @@ macro_rules! construct_uint { } /// Create an object from a given signed 64-bit integer + #[inline] pub fn from_i64(init: i64) -> Option<$name> { assert!(init >= 0); $name::from_u64(init as u64) } + /// Creates big integer value from a byte slice array using + /// big-endian encoding + pub fn from_be_bytes(bytes: [u8; $n_words * 8]) -> $name { + use super::endian::slice_to_u64_be; + let mut slice = [0u64; $n_words]; + slice.iter_mut() + .rev() + .zip(bytes.chunks(8)) + .for_each(|(word, bytes)| *word = slice_to_u64_be(bytes)); + $name(slice) + } + // divmod like operation, returns (quotient, remainder) #[inline] fn div_rem(self, other: Self) -> (Self, Self) { @@ -409,7 +423,7 @@ impl Uint256 { #[cfg(test)] mod tests { use consensus::{deserialize, serialize}; - use util::uint::Uint256; + use util::uint::{Uint256, Uint128}; use util::BitArray; #[test] @@ -467,6 +481,16 @@ mod tests { assert!(small <= small); } + #[test] + pub fn uint_from_be_bytes() { + assert_eq!(Uint128::from_be_bytes([0x1b, 0xad, 0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xaf, 0xba, 0xbe, 0x2b, 0xed, 0xfe, 0xed]), + Uint128([0xdeafbabe2bedfeed, 0x1badcafedeadbeef])); + + assert_eq!(Uint256::from_be_bytes([0x1b, 0xad, 0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xaf, 0xba, 0xbe, 0x2b, 0xed, 0xfe, 0xed, + 0xba, 0xad, 0xf0, 0x0d, 0xde, 0xfa, 0xce, 0xda, 0x11, 0xfe, 0xd2, 0xba, 0xd1, 0xc0, 0xff, 0xe0]), + Uint256([0x11fed2bad1c0ffe0, 0xbaadf00ddefaceda, 0xdeafbabe2bedfeed, 0x1badcafedeadbeef])); + } + #[test] pub fn uint256_arithmetic_test() { let init = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap();