From 5520497e8156d86e21f435f0e976d5fd023cc153 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 21:25:55 +0100 Subject: [PATCH 1/4] Fixed Uint output. --- src/rlp/rlpin.rs | 9 +++++++++ src/uint.rs | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/rlp/rlpin.rs b/src/rlp/rlpin.rs index 2179643d1..821511405 100644 --- a/src/rlp/rlpin.rs +++ b/src/rlp/rlpin.rs @@ -133,3 +133,12 @@ impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { result } } + +#[test] +fn break_it() { + use common::*; + let h: Bytes = FromHex::from_hex("f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap(); + let r: Rlp = Rlp::new(&h); + let u: U256 = r.val_at(1); + assert_eq!(format!("{}", u), "0x10efbef67941f79b2"); +} diff --git a/src/uint.rs b/src/uint.rs index 038c85458..2a18a2fb0 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -597,8 +597,15 @@ macro_rules! construct_uint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let &$name(ref data) = self; try!(write!(f, "0x")); + let mut latch = false; for ch in data.iter().rev() { - try!(write!(f, "{:02x}", ch)); + for x in 0..16 { + let ch = ch & (15u64 << ((15 - x) * 4) as u64) >> ((15 - x) * 4) as u64; + if !latch { latch = ch != 0 } + if latch { + try!(write!(f, "{:01x}", ch)); + } + } } Ok(()) } @@ -608,8 +615,15 @@ macro_rules! construct_uint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let &$name(ref data) = self; try!(write!(f, "0x")); + let mut latch = false; for ch in data.iter().rev() { - try!(write!(f, "{:02x}", ch)); + for x in 0..16 { + let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); + if !latch { latch = nibble != 0 } + if latch { + try!(write!(f, "{:x}", nibble)); + } + } } Ok(()) } From a79644d982cf5ee1b7a6b0f7c5ea7ef5c4c1a987 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 16 Jan 2016 14:29:36 +0100 Subject: [PATCH 2/4] Fast SHA3. --- Cargo.toml | 4 + benches/trie.rs | 4 +- build.rs | 10 +++ src/network/host.rs | 10 +-- src/network/service.rs | 1 + src/sha3.rs | 19 +++-- src/tinykeccak.c | 178 +++++++++++++++++++++++++++++++++++++++++ src/uint.rs | 6 +- 8 files changed, 214 insertions(+), 18 deletions(-) create mode 100644 build.rs create mode 100644 src/tinykeccak.c diff --git a/Cargo.toml b/Cargo.toml index 4ed14551f..6b60fddf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,10 @@ license = "GPL-3.0" name = "ethcore-util" version = "0.1.0" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +gcc = "0.3" [dependencies] log = "0.3" diff --git a/benches/trie.rs b/benches/trie.rs index 8f1a2a42d..5f02b15cf 100644 --- a/benches/trie.rs +++ b/benches/trie.rs @@ -188,10 +188,10 @@ fn triehash_insertions_six_low(b: &mut Bencher) { } #[bench] -fn sha3x1000(b: &mut Bencher) { +fn sha3x10000(b: &mut Bencher) { b.iter(||{ let mut seed = H256::new(); - for _ in 0..1000 { + for _ in 0..10000 { seed = seed.sha3() } }) diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..706da0907 --- /dev/null +++ b/build.rs @@ -0,0 +1,10 @@ + // build.rs + +// Bring in a dependency on an externally maintained `gcc` package which manages +// invoking the C compiler. +extern crate gcc; + +fn main() { + gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]); +} + diff --git a/src/network/host.rs b/src/network/host.rs index 8b1038c8a..4d8f0d056 100644 --- a/src/network/host.rs +++ b/src/network/host.rs @@ -561,13 +561,13 @@ impl IoHandler> for Host where Messa let port = self.info.config.listen_address.port(); self.info.listen_port = port; - //self.add_node("enode://c022e7a27affdd1632f2e67dffeb87f02bf506344bb142e08d12b28e7e5c6e5dbb8183a46a77bff3631b51c12e8cf15199f797feafdc8834aaf078ad1a2bcfa0@127.0.0.1:30303"); + self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303"); // GO bootnodes - self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE - self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR - self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG +// self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE +// self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR +// self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG // ETH/DEV cpp-ethereum (poc-9.ethdev.com) - self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"); +// self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"); } fn stream_hup<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage>, stream: StreamToken) { diff --git a/src/network/service.rs b/src/network/service.rs index 48cc11152..4c333b8af 100644 --- a/src/network/service.rs +++ b/src/network/service.rs @@ -17,6 +17,7 @@ impl NetworkService where Message: Send + 'static { let mut io_service = try!(IoService::>::start()); let host = Box::new(Host::new()); let host_info = host.info.client_version.clone(); + info!("NetworkService::start(): id={:?}", host.info.id()); try!(io_service.register_handler(host)); Ok(NetworkService { io_service: io_service, diff --git a/src/sha3.rs b/src/sha3.rs index c23dfc7a9..ed3fe65a3 100644 --- a/src/sha3.rs +++ b/src/sha3.rs @@ -1,12 +1,15 @@ //! Wrapper around tiny-keccak crate. use std::mem::uninitialized; -use tiny_keccak::Keccak; -use bytes::{BytesConvertable,Populatable}; +use bytes::BytesConvertable; use hash::{H256, FixedHash}; pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] ); +extern { + fn sha3_256(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32; +} + /// Types implementing this trait are sha3able. /// /// ``` @@ -29,17 +32,17 @@ pub trait Hashable { impl Hashable for T where T: BytesConvertable { fn sha3(&self) -> H256 { unsafe { - let mut keccak = Keccak::new_keccak256(); - keccak.update(self.bytes()); + let input: &[u8] = self.bytes(); let mut ret: H256 = uninitialized(); - keccak.finalize(ret.as_slice_mut()); + sha3_256(ret.as_mut_ptr(), ret.len(), input.as_ptr(), input.len()); ret } } fn sha3_into(&self, dest: &mut [u8]) { - let mut keccak = Keccak::new_keccak256(); - keccak.update(self.bytes()); - keccak.finalize(dest); + unsafe { + let input: &[u8] = self.bytes(); + sha3_256(dest.as_mut_ptr(), dest.len(), input.as_ptr(), input.len()); + } } } diff --git a/src/tinykeccak.c b/src/tinykeccak.c new file mode 100644 index 000000000..ddc3f5be2 --- /dev/null +++ b/src/tinykeccak.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include + +/** libkeccak-tiny + * + * A single-file implementation of SHA-3 and SHAKE. + * + * Implementor: David Leon Gil + * License: CC0, attribution kindly requested. Blame taken too, + * but not liability. + */ + +#define decshake(bits) \ + int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); + +decshake(128) +decshake(256) +decsha3(224) +decsha3(256) +decsha3(384) +decsha3(512) + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +/*** Helper macros to define SHA3 and SHAKE instances. ***/ +#define defshake(bits) \ + int shake##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ + } +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHAKE VOFs ***/ +defshake(128) +defshake(256) + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(224) +defsha3(256) +defsha3(384) +defsha3(512) + + + diff --git a/src/uint.rs b/src/uint.rs index 2a18a2fb0..58c25243d 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -600,10 +600,10 @@ macro_rules! construct_uint { let mut latch = false; for ch in data.iter().rev() { for x in 0..16 { - let ch = ch & (15u64 << ((15 - x) * 4) as u64) >> ((15 - x) * 4) as u64; - if !latch { latch = ch != 0 } + let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); + if !latch { latch = nibble != 0 } if latch { - try!(write!(f, "{:01x}", ch)); + try!(write!(f, "{:x}", nibble)); } } } From 8e9ea7969aeca5b113f46749a80286a7fd98baa5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 16 Jan 2016 15:29:36 +0100 Subject: [PATCH 3/4] Cleanup and docs. --- src/sha3.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sha3.rs b/src/sha3.rs index ed3fe65a3..c251edcfb 100644 --- a/src/sha3.rs +++ b/src/sha3.rs @@ -1,7 +1,7 @@ //! Wrapper around tiny-keccak crate. use std::mem::uninitialized; -use bytes::BytesConvertable; +use bytes::{BytesConvertable, Populatable}; use hash::{H256, FixedHash}; pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] ); @@ -23,7 +23,10 @@ extern { /// } /// ``` pub trait Hashable { + /// Calculate SHA3 of this object. fn sha3(&self) -> H256; + + /// Calculate SHA3 of this object and place result into dest. fn sha3_into(&self, dest: &mut [u8]) { self.sha3().copy_to(dest); } @@ -32,9 +35,8 @@ pub trait Hashable { impl Hashable for T where T: BytesConvertable { fn sha3(&self) -> H256 { unsafe { - let input: &[u8] = self.bytes(); let mut ret: H256 = uninitialized(); - sha3_256(ret.as_mut_ptr(), ret.len(), input.as_ptr(), input.len()); + self.sha3_into(ret.as_slice_mut()); ret } } From 60678a21a658d699c4663733d80a155ec95e2b9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 16 Jan 2016 15:45:45 +0100 Subject: [PATCH 4/4] Put boot nodes back. --- src/network/host.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/host.rs b/src/network/host.rs index 8bafaefd0..32ac713ef 100644 --- a/src/network/host.rs +++ b/src/network/host.rs @@ -561,13 +561,13 @@ impl IoHandler> for Host where Messa let port = self.info.config.listen_address.port(); self.info.listen_port = port; - self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303"); +// self.add_node("enode://a9a921de2ff09a9a4d38b623c67b2d6b477a8e654ae95d874750cbbcb31b33296496a7b4421934e2629269e180823e52c15c2b19fc59592ec51ffe4f2de76ed7@127.0.0.1:30303"); // GO bootnodes -// self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE -// self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR -// self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG + self.add_node("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"); // IE + self.add_node("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"); // BR + self.add_node("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"); // SG // ETH/DEV cpp-ethereum (poc-9.ethdev.com) -// self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"); + self.add_node("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"); } fn stream_hup<'s>(&'s mut self, io: &mut IoContext<'s, NetworkIoMessage>, stream: StreamToken) {