diff --git a/Cargo.lock b/Cargo.lock index 3e4998a44..d9142b1b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -548,7 +548,7 @@ dependencies = [ "bigint 4.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.1.0", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2201,9 +2201,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "plain_hasher" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crunchy 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3394,7 +3393,6 @@ dependencies = [ "checksum phf_generator 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "db005608fd99800c8c74106a7c894cf582055b689aa14a79462cefdcb7dc1cc3" "checksum phf_shared 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fee4d039930e4f45123c9b15976cf93a499847b6483dc09c42ea0ec4940f2aa6" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83ae80873992f511142c07d0ec6c44de5636628fdb7e204abd655932ea79d995" "checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0" "checksum pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2412f3332a07c7a2a50168988dcc184f32180a9758ad470390e5f55e089f6b6e" "checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4" diff --git a/util/bigint/Cargo.toml b/util/bigint/Cargo.toml index 1d0d4c63a..fcca56078 100644 --- a/util/bigint/Cargo.toml +++ b/util/bigint/Cargo.toml @@ -13,7 +13,7 @@ rustc-hex = "1.0" rand = "0.3.12" libc = "0.2" heapsize = { version = "0.4", optional = true } -plain_hasher = "0.1" +plain_hasher = { path = "../plain_hasher" } [features] x64asm_arithmetic=[] diff --git a/util/plain_hasher/Cargo.toml b/util/plain_hasher/Cargo.toml new file mode 100644 index 000000000..0ed45ba36 --- /dev/null +++ b/util/plain_hasher/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "plain_hasher" +description = "Hasher for 32-bit keys." +version = "0.1.0" +authors = ["Parity Technologies "] +license = "MIT" +keywords = ["hash", "hasher"] +categories = ["no-std"] +homepage = "https://github.com/paritytech/plain_hasher" + +[dependencies] +crunchy = "0.1.6" diff --git a/util/plain_hasher/benches/bench.rs b/util/plain_hasher/benches/bench.rs new file mode 100644 index 000000000..e7e8570ab --- /dev/null +++ b/util/plain_hasher/benches/bench.rs @@ -0,0 +1,33 @@ +#![feature(test)] + +extern crate test; +extern crate plain_hasher; + +use std::hash::Hasher; +use std::collections::hash_map::DefaultHasher; +use test::{Bencher, black_box}; +use plain_hasher::PlainHasher; + +#[bench] +fn write_plain_hasher(b: &mut Bencher) { + b.iter(|| { + let n: u8 = black_box(100); + (0..n).fold(PlainHasher::default(), |mut old, new| { + let bb = black_box([new; 32]); + old.write(&bb as &[u8]); + old + }); + }); +} + +#[bench] +fn write_default_hasher(b: &mut Bencher) { + b.iter(|| { + let n: u8 = black_box(100); + (0..n).fold(DefaultHasher::default(), |mut old, new| { + let bb = black_box([new; 32]); + old.write(&bb as &[u8]); + old + }); + }); +} diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs new file mode 100644 index 000000000..b16596363 --- /dev/null +++ b/util/plain_hasher/src/lib.rs @@ -0,0 +1,55 @@ +#![no_std] +#[macro_use] +extern crate crunchy; + +use core::{hash, mem}; + +/// Hasher that just takes 8 bytes of the provided value. +/// May only be used for keys which are 32 bytes. +#[derive(Default)] +pub struct PlainHasher { + prefix: u64, +} + +impl hash::Hasher for PlainHasher { + #[inline] + fn finish(&self) -> u64 { + self.prefix + } + + #[inline] + #[allow(unused_assignments)] + fn write(&mut self, bytes: &[u8]) { + debug_assert!(bytes.len() == 32); + + unsafe { + let mut bytes_ptr = bytes.as_ptr(); + let prefix_u8: &mut [u8; 8] = mem::transmute(&mut self.prefix); + let mut prefix_ptr = prefix_u8.as_mut_ptr(); + + unroll! { + for _i in 0..8 { + *prefix_ptr ^= (*bytes_ptr ^ *bytes_ptr.offset(8)) ^ (*bytes_ptr.offset(16) ^ *bytes_ptr.offset(24)); + + bytes_ptr = bytes_ptr.offset(1); + prefix_ptr = prefix_ptr.offset(1); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use core::hash::Hasher; + use super::PlainHasher; + + #[test] + fn it_works() { + let mut bytes = [32u8; 32]; + bytes[0] = 15; + let mut hasher = PlainHasher::default(); + hasher.write(&bytes); + assert_eq!(hasher.prefix, 47); + } +}