From 006fe20287978c07a5908fa0f182e9fa7a2f325d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 27 Nov 2015 17:54:33 +0100 Subject: [PATCH] Add SHA3 --- Cargo.toml | 2 +- src/bytes.rs | 229 +++++++++++++++++++++++++++------------------------ src/hash.rs | 11 +++ src/lib.rs | 1 + src/sha3.rs | 29 +++++++ 5 files changed, 165 insertions(+), 107 deletions(-) create mode 100644 src/sha3.rs diff --git a/Cargo.toml b/Cargo.toml index cc0953f8f..19c64113c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,5 +13,5 @@ rustc-serialize = "0.3" arrayvec = "0.3" mio = "0.*" rand = "0.*" -tiny-keccak = "0.2" +tiny-keccak = "0.3" rocksdb = "0.2.1" diff --git a/src/bytes.rs b/src/bytes.rs index 1b331cf15..73592643d 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -10,74 +10,91 @@ use std::fmt; use std::error::Error as StdError; use uint::{U128, U256}; +pub trait BytesConvertable { + fn bytes(&self) -> &[u8]; +} + +impl<'a> BytesConvertable for &'a [u8] { + fn bytes(&self) -> &[u8] { self } +} + +impl BytesConvertable for Vec { + fn bytes(&self) -> &[u8] { self } +} + +#[test] +fn bytes_convertable() { + assert_eq!(vec![0x12u8, 0x34].bytes(), &[0x12u8, 0x34]); +} + /// TODO: optimise some conversations pub trait ToBytes { - fn to_bytes(&self) -> Vec; - fn to_bytes_len(&self) -> usize { self.to_bytes().len() } - fn first_byte(&self) -> Option { self.to_bytes().first().map(|&x| { x })} + fn to_bytes(&self) -> Vec; + fn to_bytes_len(&self) -> usize { self.to_bytes().len() } + fn first_byte(&self) -> Option { self.to_bytes().first().map(|&x| { x })} } impl <'a> ToBytes for &'a str { - fn to_bytes(&self) -> Vec { - From::from(*self) - } - - fn to_bytes_len(&self) -> usize { self.len() } + fn to_bytes(&self) -> Vec { + From::from(*self) + } + + fn to_bytes_len(&self) -> usize { self.len() } } impl ToBytes for String { - fn to_bytes(&self) -> Vec { - let s: &str = self.as_ref(); - From::from(s) - } - - fn to_bytes_len(&self) -> usize { self.len() } + fn to_bytes(&self) -> Vec { + let s: &str = self.as_ref(); + From::from(s) + } + + fn to_bytes_len(&self) -> usize { self.len() } } impl ToBytes for u8 { - fn to_bytes(&self) -> Vec { - match *self { - 0 => vec![], - _ => vec![*self] - } - } + fn to_bytes(&self) -> Vec { + match *self { + 0 => vec![], + _ => vec![*self] + } + } - fn to_bytes_len(&self) -> usize { - match *self { - 0 => 0, - _ => 1 - } - } - fn first_byte(&self) -> Option { - match *self { - 0 => None, - _ => Some(*self) - } - } + fn to_bytes_len(&self) -> usize { + match *self { + 0 => 0, + _ => 1 + } + } + fn first_byte(&self) -> Option { + match *self { + 0 => None, + _ => Some(*self) + } + } } impl ToBytes for u64 { - fn to_bytes(&self) -> Vec { - let mut res= vec![]; - let count = self.to_bytes_len(); - res.reserve(count); - for i in 0..count { - let j = count - 1 - i; - res.push((*self >> (j * 8)) as u8); - } - res - } + fn to_bytes(&self) -> Vec { + let mut res= vec![]; + let count = self.to_bytes_len(); + res.reserve(count); + for i in 0..count { + let j = count - 1 - i; + res.push((*self >> (j * 8)) as u8); + } + res + } - fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } + fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } } macro_rules! impl_map_to_bytes { - ($from: ident, $to: ty) => { - impl ToBytes for $from { - fn to_bytes(&self) -> Vec { (*self as $to).to_bytes() } - fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } - } - } + ($from: ident, $to: ty) => { + impl ToBytes for $from { + fn to_bytes(&self) -> Vec { (*self as $to).to_bytes() } + fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } + } + } } impl_map_to_bytes!(usize, u64); @@ -85,21 +102,21 @@ impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); macro_rules! impl_uint_to_bytes { - ($name: ident) => { - impl ToBytes for $name { - fn to_bytes(&self) -> Vec { - let mut res= vec![]; - let count = self.to_bytes_len(); - res.reserve(count); - for i in 0..count { - let j = count - 1 - i; - res.push(self.byte(j)); - } - res - } - fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } - } - } + ($name: ident) => { + impl ToBytes for $name { + fn to_bytes(&self) -> Vec { + let mut res= vec![]; + let count = self.to_bytes_len(); + res.reserve(count); + for i in 0..count { + let j = count - 1 - i; + res.push(self.byte(j)); + } + res + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } } impl_uint_to_bytes!(U256); @@ -107,17 +124,17 @@ impl_uint_to_bytes!(U128); #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { - UnexpectedEnd + UnexpectedEnd } impl StdError for FromBytesError { - fn description(&self) -> &str { "from_bytes error" } + fn description(&self) -> &str { "from_bytes error" } } impl fmt::Display for FromBytesError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } } pub type FromBytesResult = Result; @@ -126,48 +143,48 @@ pub type FromBytesResult = Result; /// of the return type /// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { - fn from_bytes(bytes: &[u8]) -> FromBytesResult; + fn from_bytes(bytes: &[u8]) -> FromBytesResult; } impl FromBytes for String { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - Ok(::std::str::from_utf8(bytes).unwrap().to_string()) - } + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + Ok(::std::str::from_utf8(bytes).unwrap().to_string()) + } } impl FromBytes for u8 { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(0), - _ => Ok(bytes[0]) - } - } + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(0), + _ => Ok(bytes[0]) + } + } } impl FromBytes for u64 { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(0), - l => { - let mut res = 0u64; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as u64) << shift); - } - Ok(res) - } - } - } + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(0), + l => { + let mut res = 0u64; + for i in 0..l { + let shift = (l - 1 - i) * 8; + res = res + ((bytes[i] as u64) << shift); + } + Ok(res) + } + } + } } macro_rules! impl_map_from_bytes { - ($from: ident, $to: ident) => { - impl FromBytes for $from { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$from> { - $to::from_bytes(bytes).map(| x | { x as $from }) - } - } - } + ($from: ident, $to: ident) => { + impl FromBytes for $from { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$from> { + $to::from_bytes(bytes).map(| x | { x as $from }) + } + } + } } impl_map_from_bytes!(usize, u64); @@ -175,13 +192,13 @@ impl_map_from_bytes!(u16, u64); impl_map_from_bytes!(u32, u64); macro_rules! impl_uint_from_bytes { - ($name: ident) => { - impl FromBytes for $name { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { - Ok($name::from(bytes)) - } - } - } + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + Ok($name::from(bytes)) + } + } + } } impl_uint_from_bytes!(U256); diff --git a/src/hash.rs b/src/hash.rs index 17f1c6c71..044153e0c 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -6,6 +6,7 @@ use rustc_serialize::hex::*; use error::EthcoreError; use rand::Rng; use rand::os::OsRng; +use bytes::BytesConvertable; macro_rules! impl_hash { ($from: ident, $size: expr) => { @@ -25,6 +26,16 @@ macro_rules! impl_hash { let mut rng = OsRng::new().unwrap(); rng.fill_bytes(&mut self.0); } + + pub fn mut_bytes(&mut self) -> &mut [u8; $size] { + &mut self.0 + } + } + + impl BytesConvertable for $from { + fn bytes(&self) -> &[u8] { + &self.0 + } } impl FromStr for $from { diff --git a/src/lib.rs b/src/lib.rs index 5b6676169..7c480c02b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ pub mod bytes; pub mod rlp; pub mod vector; pub mod db; +pub mod sha3; //pub mod network; diff --git a/src/sha3.rs b/src/sha3.rs new file mode 100644 index 000000000..61c5c26f8 --- /dev/null +++ b/src/sha3.rs @@ -0,0 +1,29 @@ +use std::mem::uninitialized; +use tiny_keccak::keccak_256; +use bytes::BytesConvertable; +use hash::H256; + +trait Hashable { + fn sha3(&self) -> H256; +} + +impl Hashable for T where T: BytesConvertable { + fn sha3(&self) -> H256 { + unsafe { + let mut ret: H256 = uninitialized(); + keccak_256(self.bytes(), ret.mut_bytes()); + ret + } + } +} + +#[test] +fn sha3_empty() { + use std::str::FromStr; + assert_eq!((&[0u8; 0][..]).sha3(), H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap()); +} +#[test] +fn sha3_as() { + use std::str::FromStr; + assert_eq!((&[0x41u8; 32][..]).sha3(), H256::from_str("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8").unwrap()); +}