diff --git a/README.md b/README.md index c658273..edd8a4a 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,6 @@ For JSONRPC interaction with Bitcoin Core, it is recommended to use [rust-jsonrp which uses the underlying [strason library](https://github.com/apoelstra/strason) which parses decimal numbers as strings, preventing precision errors. -# Usage - -To use rust-bitcoin, just add the following to your Cargo.toml. - -```toml -[dependencies] -bitcoin = "0.12" -``` # Known limitations diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 351693c..82905b1 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -77,6 +77,10 @@ macro_rules! impl_array_newtype { #[inline] /// Returns whether the object, as an array, is empty. Always false. pub fn is_empty(&self) -> bool { false } + + #[inline] + /// Returns the underlying data. + pub fn data(&self) -> [$ty; $len] { self.0.clone() } } impl<'a> From<&'a [$ty]> for $thing { diff --git a/src/macros.rs b/src/macros.rs index 24eedb5..ea6b09a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -105,6 +105,20 @@ macro_rules! user_enum { } } + impl ::std::str::FromStr for $name { + type Err = ::std::io::Error; + #[inline] + fn from_str(s: &str) -> Result { + match s { + $($txt => Ok($name::$elem)),*, + _ => Err(::std::io::Error::new( + ::std::io::ErrorKind::InvalidInput, + format!("Unknown network (type {})", s), + )), + } + } + } + impl ::serde::Deserialize for $name { #[inline] fn deserialize(d: &mut D) -> Result<$name, D::Error> diff --git a/src/network/constants.rs b/src/network/constants.rs index 4c97cb0..bdd6fac 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -90,5 +90,15 @@ mod tests { let bad: Result = deserialize("fakenet".as_bytes()); assert!(bad.is_err()); } + + #[test] + fn string_test() { + assert_eq!(Network::Bitcoin.to_string(), "bitcoin"); + assert_eq!(Network::Testnet.to_string(), "testnet"); + + assert_eq!("bitcoin".parse::().unwrap(), Network::Bitcoin); + assert_eq!("testnet".parse::().unwrap(), Network::Testnet); + assert!("fakenet".parse::().is_err()); + } } diff --git a/src/util/hash.rs b/src/util/hash.rs index 9f1d674..03b5bb8 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -481,6 +481,18 @@ mod tests { "56944C5D3F98413EF45CF54545538103CC9F298E0575820AD3591376E2E0F65D"); } + #[test] + fn test_sha256d_data() { + assert_eq!( + Sha256dHash::from_data(&[]).data(), + [ + 0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xd3, 0x0a, 0x82, 0x75, 0x05, 0x8e, 0x29, + 0x9f, 0xcc, 0x03, 0x81, 0x53, 0x45, 0x45, 0xf5, 0x5c, 0xf4, 0x3e, 0x41, 0x98, 0x3f, + 0x5d, 0x4c, 0x94, 0x56, + ] + ); + } + #[test] fn sha256d_encoder() { let test = vec![true, false, true, true, false]; diff --git a/src/util/uint.rs b/src/util/uint.rs index 5b7c0a4..c6b5650 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -61,12 +61,17 @@ macro_rules! construct_uint { let mut carry = [0u64; $n_words]; let mut ret = [0u64; $n_words]; for i in 0..$n_words { + let not_last_word = i < $n_words - 1; let upper = other as u64 * (arr[i] >> 32); let lower = other as u64 * (arr[i] & 0xFFFFFFFF); - if i < 3 { + if not_last_word { carry[i + 1] += upper >> 32; } - ret[i] = lower + (upper << 32); + let (sum, overflow) = lower.overflowing_add(upper << 32); + ret[i] = sum; + if overflow && not_last_word { + carry[i + 1] += 1; + } } $name(ret) + $name(carry) } @@ -118,10 +123,11 @@ macro_rules! construct_uint { type Output = $name; fn mul(self, other: $name) -> $name { - let mut me = self; + let mut me = $name::zero(); // TODO: be more efficient about this for i in 0..(2 * $n_words) { - me = (me + me.mul_u32((other >> (32 * i)).low_u32())) << (32 * i); + let to_mul = (other >> (32 * i)).low_u32(); + me = me + (self.mul_u32(to_mul) << (32 * i)); } me } @@ -323,6 +329,12 @@ macro_rules! construct_uint { } } + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } + } + impl ::network::encodable::ConsensusEncodable for $name { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { @@ -401,6 +413,19 @@ mod tests { assert!(!Uint256::from_u64(10).unwrap().bit(4)); } + #[test] + pub fn uint256_display_test() { + assert_eq!(format!("{}", Uint256::from_u64(0xDEADBEEF).unwrap()), + "0x00000000000000000000000000000000000000000000000000000000deadbeef"); + assert_eq!(format!("{}", Uint256::from_u64(u64::max_value()).unwrap()), + "0x000000000000000000000000000000000000000000000000ffffffffffffffff"); + + let max_val = Uint256([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF]); + assert_eq!(format!("{}", max_val), + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + } + #[test] pub fn uint256_comp_test() { let small = Uint256([10u64, 0, 0, 0]); @@ -449,6 +474,39 @@ mod tests { // TODO: bit inversion } + #[test] + pub fn mul_u32_test() { + let u64_val = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap(); + + let u96_res = u64_val.mul_u32(0xFFFFFFFF); + let u128_res = u96_res.mul_u32(0xFFFFFFFF); + let u160_res = u128_res.mul_u32(0xFFFFFFFF); + let u192_res = u160_res.mul_u32(0xFFFFFFFF); + let u224_res = u192_res.mul_u32(0xFFFFFFFF); + let u256_res = u224_res.mul_u32(0xFFFFFFFF); + + assert_eq!(u96_res, Uint256([0xffffffff21524111u64, 0xDEADBEEE, 0, 0])); + assert_eq!(u128_res, Uint256([0x21524111DEADBEEFu64, 0xDEADBEEE21524110, 0, 0])); + assert_eq!(u160_res, Uint256([0xBD5B7DDD21524111u64, 0x42A4822200000001, 0xDEADBEED, 0])); + assert_eq!(u192_res, Uint256([0x63F6C333DEADBEEFu64, 0xBD5B7DDFBD5B7DDB, 0xDEADBEEC63F6C334, 0])); + assert_eq!(u224_res, Uint256([0x7AB6FBBB21524111u64, 0xFFFFFFFBA69B4558, 0x854904485964BAAA, 0xDEADBEEB])); + assert_eq!(u256_res, Uint256([0xA69B4555DEADBEEFu64, 0xA69B455CD41BB662, 0xD41BB662A69B4550, 0xDEADBEEAA69B455C])); + } + + #[test] + pub fn multiplication_test() { + let u64_val = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap(); + + let u128_res = u64_val * u64_val; + + assert_eq!(u128_res, Uint256([0x048D1354216DA321u64, 0xC1B1CD13A4D13D46, 0, 0])); + + let u256_res = u128_res * u128_res; + + assert_eq!(u256_res, Uint256([0xF4E166AAD40D0A41u64, 0xF5CF7F3618C2C886u64, + 0x4AFCFF6F0375C608u64, 0x928D92B4D7F5DF33u64])); + } + #[test] pub fn uint256_bitslice_test() { let init = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap();