From 635bf284b4e63552fdc6037b15cdff74fa81fbd5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 12 Jan 2016 23:44:30 +0100 Subject: [PATCH 01/10] Fix RLP on consensus. Add JSON helpers. --- src/crypto.rs | 13 ++++++++ src/json_aid.rs | 65 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ src/rlp/rlperrors.rs | 3 ++ src/rlp/untrusted_rlp.rs | 10 ++++++- 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/json_aid.rs diff --git a/src/crypto.rs b/src/crypto.rs index 9a27c68ae..35bb3b7eb 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -120,6 +120,8 @@ impl KeyPair { pub mod ec { use hash::*; + use uint::*; + use standard::*; use crypto::*; use crypto::{self}; @@ -136,6 +138,7 @@ pub mod ec { } /// Returns siganture of message hash. pub fn sign(secret: &Secret, message: &H256) -> Result { + // TODO: allow creation of only low-s signatures. use secp256k1::*; let context = Secp256k1::new(); let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; @@ -165,6 +168,16 @@ pub mod ec { } } + /// Check if this is a "low" signature. + pub fn is_low(sig: &Signature) -> bool { + H256::from_slice(&sig[32..64]) <= h256_from_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0") + } + + /// Check if this is a "low" signature. + pub fn is_low_s(s: &U256) -> bool { + s <= &U256::from_str("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0").unwrap() + } + /// Check if each component of the signature is in range. pub fn is_valid(sig: &Signature) -> bool { sig[64] <= 1 && diff --git a/src/json_aid.rs b/src/json_aid.rs new file mode 100644 index 000000000..ccfdee490 --- /dev/null +++ b/src/json_aid.rs @@ -0,0 +1,65 @@ +use common::*; + +pub fn clean(s: &str) -> &str { + if s.len() >= 2 && &s[0..2] == "0x" { + &s[2..] + } else { + s + } +} + +pub fn bytes_from_json(json: &Json) -> Bytes { + let s = json.as_string().unwrap_or(""); + if s.len() % 2 == 1 { + FromHex::from_hex(&("0".to_string() + &(clean(s).to_string()))[..]).unwrap_or(vec![]) + } else { + FromHex::from_hex(clean(s)).unwrap_or(vec![]) + } +} + +pub fn address_from_json(json: &Json) -> Address { + let s = json.as_string().unwrap_or("0000000000000000000000000000000000000000"); + if s.len() % 2 == 1 { + address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..]) + } else { + address_from_hex(clean(s)) + } +} + +pub fn h256_from_json(json: &Json) -> H256 { + let s = json.as_string().unwrap_or("0000000000000000000000000000000000000000000000000000000000000000"); + if s.len() % 2 == 1 { + h256_from_hex(&("0".to_string() + &(clean(s).to_string()))[..]) + } else { + h256_from_hex(clean(s)) + } +} + +pub fn u256_from_json(json: &Json) -> U256 { + let s = json.as_string().unwrap_or(""); + if s.len() >= 2 && &s[0..2] == "0x" { + U256::from_str(&s[2..]).unwrap_or(U256::from(0)) + } else { + U256::from_dec_str(s).unwrap_or(U256::from(0)) + } +} + +pub fn usize_from_json(json: &Json) -> usize { + u256_from_json(json).low_u64() as usize +} + +pub fn u64_from_json(json: &Json) -> u64 { + u256_from_json(json).low_u64() +} + +pub fn u32_from_json(json: &Json) -> u32 { + u256_from_json(json).low_u32() +} + +pub fn u16_from_json(json: &Json) -> u16 { + u256_from_json(json).low_u32() as u16 +} + +pub fn u8_from_json(json: &Json) -> u8 { + u256_from_json(json).low_u32() as u8 +} diff --git a/src/lib.rs b/src/lib.rs index b856431cd..7bfe147f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ pub mod hash; pub mod uint; pub mod bytes; pub mod rlp; +pub mod json_aid; pub mod vector; pub mod sha3; pub mod hashdb; @@ -74,6 +75,7 @@ pub mod semantic_version; pub mod network; pub use common::*; +pub use json_aid::*; pub use rlp::*; pub use hashdb::*; pub use memorydb::*; diff --git a/src/rlp/rlperrors.rs b/src/rlp/rlperrors.rs index 27b3082b5..9ea470abf 100644 --- a/src/rlp/rlperrors.rs +++ b/src/rlp/rlperrors.rs @@ -9,6 +9,9 @@ pub enum DecoderError { RlpExpectedToBeList, RlpExpectedToBeData, RlpIncorrectListLen, + RlpDataLenWithZeroPrefix, + RlpListLenWithZeroPrefix, + RlpInvalidIndirection, } impl StdError for DecoderError { diff --git a/src/rlp/untrusted_rlp.rs b/src/rlp/untrusted_rlp.rs index 452a198bb..c0e7c4cf7 100644 --- a/src/rlp/untrusted_rlp.rs +++ b/src/rlp/untrusted_rlp.rs @@ -269,6 +269,7 @@ impl<'a> BasicDecoder<'a> { Some(l @ 0xb8...0xbf) => { let len_of_len = l as usize - 0xb7; let header_len = 1 + len_of_len; + if bytes[1] == 0 { return Err(DecoderError::RlpDataLenWithZeroPrefix); } let value_len = try!(usize::from_bytes(&bytes[1..header_len])); PayloadInfo::new(header_len, value_len) } @@ -277,6 +278,7 @@ impl<'a> BasicDecoder<'a> { let len_of_len = l as usize - 0xf7; let header_len = 1 + len_of_len; let value_len = try!(usize::from_bytes(&bytes[1..header_len])); + if bytes[1] == 0 { return Err(DecoderError::RlpListLenWithZeroPrefix); } PayloadInfo::new(header_len, value_len) }, // we cant reach this place, but rust requires _ to be implemented @@ -302,7 +304,13 @@ impl<'a> Decoder for BasicDecoder<'a> { // single byt value Some(l @ 0...0x7f) => Ok(try!(f(&[l]))), // 0-55 bytes - Some(l @ 0x80...0xb7) => Ok(try!(f(&bytes[1..(1 + l as usize - 0x80)]))), + Some(l @ 0x80...0xb7) => { + let d = &bytes[1..(1 + l as usize - 0x80)]; + if l == 0x81 && d[0] < 0x80 { + return Err(DecoderError::RlpInvalidIndirection); + } + Ok(try!(f(d))) + }, // longer than 55 bytes Some(l @ 0xb8...0xbf) => { let len_of_len = l as usize - 0xb7; From 6447f9b90bde28a9851605730899e661ace850ad Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 01:18:33 +0100 Subject: [PATCH 02/10] Additional helper function. --- src/json_aid.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/json_aid.rs b/src/json_aid.rs index ccfdee490..a382c61ec 100644 --- a/src/json_aid.rs +++ b/src/json_aid.rs @@ -35,8 +35,7 @@ pub fn h256_from_json(json: &Json) -> H256 { } } -pub fn u256_from_json(json: &Json) -> U256 { - let s = json.as_string().unwrap_or(""); +pub fn u256_from_hex(s: &str) -> U256 { if s.len() >= 2 && &s[0..2] == "0x" { U256::from_str(&s[2..]).unwrap_or(U256::from(0)) } else { @@ -44,6 +43,10 @@ pub fn u256_from_json(json: &Json) -> U256 { } } +pub fn u256_from_json(json: &Json) -> U256 { + u256_from_hex(json.as_string().unwrap_or("")) +} + pub fn usize_from_json(json: &Json) -> usize { u256_from_json(json).low_u64() as usize } From 4be539a9656c35ad6d928333eab3c8dd62522454 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 12:16:10 +0100 Subject: [PATCH 03/10] Stirct ordering for hashes. --- src/hash.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hash.rs b/src/hash.rs index 087454ceb..5eb76a05e 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -224,16 +224,22 @@ macro_rules! impl_hash { } } - impl PartialOrd for $from { - fn partial_cmp(&self, other: &Self) -> Option { + impl Ord for $from { + fn cmp(&self, other: &Self) -> Ordering { for i in 0..$size { if self.0[i] > other.0[i] { - return Some(Ordering::Greater); + return Ordering::Greater; } else if self.0[i] < other.0[i] { - return Some(Ordering::Less); + return Ordering::Less; } } - Some(Ordering::Equal) + Ordering::Equal + } + } + + impl PartialOrd for $from { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } From df3e3edc8a40b959aa21dd1544cdfbae8a6d61f0 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 13 Jan 2016 15:14:24 +0100 Subject: [PATCH 04/10] bytes_ref --- src/bytes.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/bytes.rs b/src/bytes.rs index 8c56d6bf3..e925d4509 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -39,6 +39,7 @@ use std::fmt; use std::slice; use std::cmp::Ordering; use std::error::Error as StdError; +use std::ops::{Deref, DerefMut}; use uint::{U128, U256}; use hash::FixedHash; @@ -89,6 +90,31 @@ impl ToPretty for Bytes { } } +pub enum BytesRef<'a> { + Flexible(&'a mut Bytes), + Fixed(&'a mut [u8]) +} + +impl<'a> Deref for BytesRef<'a> { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + match self { + &BytesRef::Flexible(ref bytes) => bytes, + &BytesRef::Fixed(ref bytes) => bytes + } + } +} + +impl <'a> DerefMut for BytesRef<'a> { + fn deref_mut(&mut self) -> &mut [u8] { + match self { + &mut BytesRef::Flexible(ref mut bytes) => bytes, + &mut BytesRef::Fixed(ref mut bytes) => bytes + } + } +} + /// Vector of bytes pub type Bytes = Vec; @@ -436,4 +462,4 @@ fn populate_big_types() { let mut h = h256_from_u64(0x69); h.copy_raw_from(&a); assert_eq!(h, h256_from_hex("ffffffffffffffffffffffffffffffffffffffff000000000000000000000069")); -} \ No newline at end of file +} From 6c44f29b061d478b5f15d97e36bb128576c3fde0 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 13 Jan 2016 17:42:57 +0100 Subject: [PATCH 05/10] json aid changes --- src/json_aid.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/json_aid.rs b/src/json_aid.rs index a382c61ec..c0b5a5180 100644 --- a/src/json_aid.rs +++ b/src/json_aid.rs @@ -18,8 +18,13 @@ pub fn bytes_from_json(json: &Json) -> Bytes { } pub fn address_from_json(json: &Json) -> Address { - let s = json.as_string().unwrap_or("0000000000000000000000000000000000000000"); - if s.len() % 2 == 1 { + address_from_str(json.as_string().unwrap_or("0000000000000000000000000000000000000000")) +} + +pub fn address_from_str<'a>(s: &'a str) -> Address { + if s.len() == 0 { + Address::new() + } else if s.len() % 2 == 1 { address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..]) } else { address_from_hex(clean(s)) @@ -35,7 +40,7 @@ pub fn h256_from_json(json: &Json) -> H256 { } } -pub fn u256_from_hex(s: &str) -> U256 { +pub fn u256_from_str(s: &str) -> U256 { if s.len() >= 2 && &s[0..2] == "0x" { U256::from_str(&s[2..]).unwrap_or(U256::from(0)) } else { @@ -44,7 +49,7 @@ pub fn u256_from_hex(s: &str) -> U256 { } pub fn u256_from_json(json: &Json) -> U256 { - u256_from_hex(json.as_string().unwrap_or("")) + u256_from_str(json.as_string().unwrap_or("")) } pub fn usize_from_json(json: &Json) -> usize { From dd99ebd85914f61ad16b8504ad854ec96cbe516b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 18:41:33 +0100 Subject: [PATCH 06/10] From::from(u64) for hashes. --- src/hash.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hash.rs b/src/hash.rs index 5eb76a05e..67d502633 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -377,6 +377,19 @@ macro_rules! impl_hash { pub fn from_bloomed(b: &T) -> Self where T: FixedHash { b.bloom_part($size) } } + + impl From for $from { + fn from(mut value: u64) -> $from { + let mut ret = $from::new(); + for i in 0..8 { + if i < $size { + ret.0[$size - i - 1] = (value & 0xff) as u8; + value >>= 8; + } + } + ret + } + } } } @@ -387,7 +400,7 @@ impl<'a> From<&'a U256> for H256 { value.to_bytes(&mut ret); ret } - } + } } impl From for Address { From 5cc5e7780ce15be0ca315a1f5f1ca1274668e9c2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 18:58:57 +0100 Subject: [PATCH 07/10] Tests and an additional From::from for hex string -> hash that defaults to 0s for bad strings. --- src/hash.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/hash.rs b/src/hash.rs index 67d502633..544e82fd2 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -35,6 +35,14 @@ pub trait FixedHash: Sized + BytesConvertable + Populatable { fn is_zero(&self) -> bool; } +fn clean_0x(s: &str) -> &str { + if s.len() >= 2 && &s[0..2] == "0x" { + &s[2..] + } else { + s + } +} + macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] @@ -390,6 +398,17 @@ macro_rules! impl_hash { ret } } + + impl<'_> From<&'_ str> for $from { + fn from(s: &'_ str) -> $from { + use std::str::FromStr; + if s.len() % 2 == 1 { + $from::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap_or($from::new()) + } else { + $from::from_str(clean_0x(s)).unwrap_or($from::new()) + } + } + } } } @@ -518,5 +537,19 @@ mod tests { let a = Address::from(h); assert_eq!(address, a); } + + #[test] + fn from_u64() { + assert_eq!(H128::from(0x1234567890abcdef), H128::from_str("00000000000000001234567890abcdef").unwrap()); + assert_eq!(H64::from(0x1234567890abcdef), H64::from_str("1234567890abcdef").unwrap()); + assert_eq!(H32::from(0x1234567890abcdef), H32::from_str("90abcdef").unwrap()); + } + + #[test] + fn from_str() { + assert_eq!(H64::from(0x1234567890abcdef), H64::from("0x1234567890abcdef")); + assert_eq!(H64::from(0x1234567890abcdef), H64::from("1234567890abcdef")); + assert_eq!(H64::from(0x234567890abcdef), H64::from("0x234567890abcdef")); + } } From 3a1d829b1dbff866ba460c1d4e1e740d368f26c1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 19:00:19 +0100 Subject: [PATCH 08/10] Additional test. --- src/hash.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hash.rs b/src/hash.rs index 544e82fd2..73ffdd538 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -550,6 +550,8 @@ mod tests { assert_eq!(H64::from(0x1234567890abcdef), H64::from("0x1234567890abcdef")); assert_eq!(H64::from(0x1234567890abcdef), H64::from("1234567890abcdef")); assert_eq!(H64::from(0x234567890abcdef), H64::from("0x234567890abcdef")); + // too short. + assert_eq!(H64::from(0), H64::from("0x34567890abcdef")); } } From 90645e30a6db01f2938744f8e8e535c489e5e799 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 13 Jan 2016 22:05:10 +0100 Subject: [PATCH 09/10] update pr to use From::from --- src/json_aid.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/json_aid.rs b/src/json_aid.rs index c0b5a5180..d015bb13c 100644 --- a/src/json_aid.rs +++ b/src/json_aid.rs @@ -18,17 +18,7 @@ pub fn bytes_from_json(json: &Json) -> Bytes { } pub fn address_from_json(json: &Json) -> Address { - address_from_str(json.as_string().unwrap_or("0000000000000000000000000000000000000000")) -} - -pub fn address_from_str<'a>(s: &'a str) -> Address { - if s.len() == 0 { - Address::new() - } else if s.len() % 2 == 1 { - address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..]) - } else { - address_from_hex(clean(s)) - } + From::from(json.as_string().unwrap_or("0000000000000000000000000000000000000000")) } pub fn h256_from_json(json: &Json) -> H256 { From b23ec6ee69bd8da6fbca82ff7104e68263a24e32 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Jan 2016 23:06:44 +0100 Subject: [PATCH 10/10] Nice macros. --- src/common.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/common.rs b/src/common.rs index 39294155c..c57357af8 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,3 +5,31 @@ pub use uint::*; pub use bytes::*; pub use vector::*; pub use sha3::*; + +#[macro_export] +macro_rules! map { + ( $( $x:expr => $y:expr ),* ) => { + vec![ $( ($x, $y) ),* ].into_iter().collect::>() + } +} + +#[macro_export] +macro_rules! mapx { + ( $( $x:expr => $y:expr ),* ) => { + vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::>() + } +} + +#[macro_export] +macro_rules! x { + ( $x:expr ) => { + From::from($x) + } +} + +#[macro_export] +macro_rules! xx { + ( $x:expr ) => { + From::from(From::from($x)) + } +}