From 3224cf2b18399847ed8b6ac22ce2aee5ecd870f8 Mon Sep 17 00:00:00 2001 From: Aleksei Sidorov Date: Wed, 16 May 2018 12:22:07 +0300 Subject: [PATCH 1/7] Implement `FromStr` for Network constant --- src/macros.rs | 11 +++++++++++ src/network/constants.rs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index 24eedb5..f937b5e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -105,6 +105,17 @@ macro_rules! user_enum { } } + impl ::std::str::FromStr for $name { + type Err = ::serde::de::value::Error; + #[inline] + fn from_str(s: &str) -> Result { + match s { + $($txt => Ok($name::$elem)),*, + _ => Err(::serde::de::Error::syntax(stringify!(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 5cff16e..228f78c 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -84,5 +84,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(), Ok(Network::Bitcoin)); + assert_eq!("testnet".parse(), Ok(Network::Testnet)); + assert!("fakenet".parse::().is_err()); + } } From 5df8893ea120349b8e58d9c9640fed0dfcd513e4 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Wed, 16 May 2018 12:31:59 +0300 Subject: [PATCH 2/7] Macro impl_array_newtype now generates method for representing data as array --- src/internal_macros.rs | 4 ++++ 1 file changed, 4 insertions(+) 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 { From 539a74de12ad4f9c94332f006698d0aa1c9d094d Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Wed, 16 May 2018 12:44:30 +0300 Subject: [PATCH 3/7] Added test for Sha256dHash::data() --- src/util/hash.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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]; From 582afb161192546d5cf227058b0f36c26d48bee6 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Wed, 16 May 2018 13:13:48 +0300 Subject: [PATCH 4/7] Added impl display for uint --- src/util/uint.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/util/uint.rs b/src/util/uint.rs index 5b7c0a4..6b7bbd8 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -323,6 +323,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 +407,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]); From 5771841144c637a3489d1229c3c0bfd81411e771 Mon Sep 17 00:00:00 2001 From: Aleksey Sidorov Date: Fri, 18 May 2018 12:08:11 +0300 Subject: [PATCH 5/7] Replace serde error with the io error. --- src/macros.rs | 7 +++++-- src/network/constants.rs | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index f937b5e..ea6b09a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -106,12 +106,15 @@ macro_rules! user_enum { } impl ::std::str::FromStr for $name { - type Err = ::serde::de::value::Error; + type Err = ::std::io::Error; #[inline] fn from_str(s: &str) -> Result { match s { $($txt => Ok($name::$elem)),*, - _ => Err(::serde::de::Error::syntax(stringify!(s))) + _ => Err(::std::io::Error::new( + ::std::io::ErrorKind::InvalidInput, + format!("Unknown network (type {})", s), + )), } } } diff --git a/src/network/constants.rs b/src/network/constants.rs index 228f78c..6c10515 100644 --- a/src/network/constants.rs +++ b/src/network/constants.rs @@ -90,8 +90,8 @@ mod tests { assert_eq!(Network::Bitcoin.to_string(), "bitcoin"); assert_eq!(Network::Testnet.to_string(), "testnet"); - assert_eq!("bitcoin".parse(), Ok(Network::Bitcoin)); - assert_eq!("testnet".parse(), Ok(Network::Testnet)); + assert_eq!("bitcoin".parse::().unwrap(), Network::Bitcoin); + assert_eq!("testnet".parse::().unwrap(), Network::Testnet); assert!("fakenet".parse::().is_err()); } } From 131ac3b1ac1a56e2c6ef0e99dbf3ae6eb5a35324 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Sat, 26 May 2018 03:04:06 -0400 Subject: [PATCH 6/7] Remove cargo usage from README Everyone using rust can be expected to know how to do this, and besides, the version was wrong. :) --- README.md | 8 -------- 1 file changed, 8 deletions(-) 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 From 881972b2a5cecdf68f9a766632999dddfb4df5a0 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov <12111581+popzxc@users.noreply.github.com> Date: Mon, 28 May 2018 21:41:07 +0300 Subject: [PATCH 7/7] Fix multiplication for uint256 (#88) --- src/util/uint.rs | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/util/uint.rs b/src/util/uint.rs index 6b7bbd8..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 } @@ -468,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();