diff --git a/Cargo.lock b/Cargo.lock index d0752af..221c74f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,76 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "rustc-stable-hash" version = "0.1.0" +dependencies = [ + "blake2", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml index 976ab8c..6bf864d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,9 @@ readme = "README.md" repository = "https://github.com/rust-lang/rustc-stable-hash" edition = "2021" +[dependencies] +blake2 = { version = "0.10.0", default-features = false, optional = true } + [features] +default = ["blake2"] nightly = [] # for feature(hasher_prefixfree_extras) diff --git a/src/blake2.rs b/src/blake2.rs new file mode 100644 index 0000000..ff8a29f --- /dev/null +++ b/src/blake2.rs @@ -0,0 +1,55 @@ +//! This is the adapted version of the Blake 2 hashing algos. + +use blake2::Digest; +use std::hash::Hasher; + +use crate::ExtendedHasher; + +#[cfg(test)] +mod tests; + +/// Hash type for the [`Blake2sHasher256`] providing 256-bits hashses. +pub struct Blake2s256Hash(pub [u8; 32]); + +/// Blake2s 256-bits Hasher +#[derive(Debug, Clone, Default)] +pub struct Blake2sHasher256 { + state: blake2::Blake2s256, +} + +impl ExtendedHasher for Blake2sHasher256 { + type Hash = Blake2s256Hash; + + #[inline] + fn finish(self) -> Self::Hash { + let mut hash = self.state.finalize(); + Blake2s256Hash(*hash.as_mut()) + } +} + +impl Hasher for Blake2sHasher256 { + #[inline] + fn write(&mut self, bytes: &[u8]) { + self.state.update(bytes); + } + + // TODO: Improve this function hashing-combine with a better thing + #[inline] + fn finish(&self) -> u64 { + let mut hash = self.state.clone().finalize(); + + let [a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7, c0, c1, c2, c3, c4, c5, c6, c7, d0, d1, d2, d3, d4, d5, d6, d7] = + *hash.as_mut(); + + let p0 = u64::from_ne_bytes([a0, a1, a2, a3, a4, a5, a6, a7]); + let p1 = u64::from_ne_bytes([b0, b1, b2, b3, b4, b5, b6, b7]); + let p2 = u64::from_ne_bytes([c0, c1, c2, c3, c4, c5, c6, c7]); + let p3 = u64::from_ne_bytes([d0, d1, d2, d3, d4, d5, d6, d7]); + + p0.wrapping_mul(3) + .wrapping_add(p1) + .wrapping_add(p2) + .wrapping_mul(p3) + .to_le() + } +} diff --git a/src/blake2/tests.rs b/src/blake2/tests.rs new file mode 100644 index 0000000..40a1e25 --- /dev/null +++ b/src/blake2/tests.rs @@ -0,0 +1,9 @@ +use super::*; + +#[test] +fn simple_blake2s() { + let mut hasher = Blake2sHasher256::default(); + hasher.write_u16(0xFF); + hasher.write_u32(0xFF); + let _h = hasher.finish(); +} diff --git a/src/lib.rs b/src/lib.rs index e68d2d1..a2b7ba9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ #![deny(unsafe_op_in_unsafe_fn)] #![deny(unreachable_pub)] +#[cfg(feature = "blake2")] +mod blake2; mod int_overflow; mod sip128; mod stable_hasher; @@ -14,19 +16,27 @@ pub mod hashers { #[doc(inline)] pub use super::sip128::{SipHasher128, SipHasher128Hash}; + #[cfg(feature = "blake2")] + #[doc(inline)] + pub use super::blake2::{Blake2s256Hash, Blake2sHasher256}; + /// Stable 128-bits Sip Hasher /// /// [`StableHasher`] version of [`SipHasher128`]. /// /// [`StableHasher`]: super::StableHasher pub type StableSipHasher128 = super::StableHasher; + + /// Stable 256-bits Blake2s Hasher + #[cfg(feature = "blake2")] + pub type StableBlake2sHasher256 = super::StableHasher; } #[doc(inline)] pub use stable_hasher::StableHasher; #[doc(inline)] -pub use stable_hasher::FromStableHash; +pub use stable_hasher::{FromStableHash, IntoStableHash}; #[doc(inline)] pub use stable_hasher::ExtendedHasher; diff --git a/src/stable_hasher.rs b/src/stable_hasher.rs index 62e092c..b751add 100644 --- a/src/stable_hasher.rs +++ b/src/stable_hasher.rs @@ -74,9 +74,7 @@ pub trait ExtendedHasher: Hasher { /// use std::hash::Hasher; /// /// struct Hash128([u64; 2]); -/// impl FromStableHash for Hash128 { -/// type Hash = SipHasher128Hash; -/// +/// impl FromStableHash for Hash128 { /// fn from(SipHasher128Hash(hash): SipHasher128Hash) -> Hash128 { /// Hash128(hash) /// } @@ -101,9 +99,7 @@ pub struct StableHasher { /// /// struct Hash128(u128); /// -/// impl FromStableHash for Hash128 { -/// type Hash = [u64; 2]; -/// +/// impl FromStableHash<[u64; 2]> for Hash128 { /// fn from(hash: [u64; 2]) -> Hash128 { /// let upper: u128 = hash[0] as u128; /// let lower: u128 = hash[1] as u128; @@ -112,12 +108,30 @@ pub struct StableHasher { /// } /// } /// ``` -pub trait FromStableHash: Sized { - type Hash; - +pub trait FromStableHash: Sized { /// Convert the finalized state of a [`StableHasher`] and construct /// an [`Self`] containing the processed hash. - fn from(hash: Self::Hash) -> Self; + fn from(hash: H) -> Self; +} + +/// Corrolary to [`FromStableHash`] +pub trait IntoStableHash: Sized { + fn into(self) -> T; +} + +impl IntoStableHash for T +where + U: FromStableHash, +{ + /// Calls `U::from(self)`. + /// + /// That is, this conversion is whatever the implementation of + /// [FromStableHash]<T> for U chooses to do. + #[inline] + #[track_caller] + fn into(self) -> U { + U::from(self) + } } impl StableHasher { @@ -163,8 +177,11 @@ impl StableHasher { /// To be used in-place of [`Hasher::finish`]. #[inline] #[must_use] - pub fn finish>(self) -> W { - W::from(self.state.finish()) + pub fn finish(self) -> W + where + H::Hash: IntoStableHash, + { + IntoStableHash::into(self.state.finish()) } } diff --git a/src/stable_hasher/tests.rs b/src/stable_hasher/tests.rs index 3eec9c9..fc11d9a 100644 --- a/src/stable_hasher/tests.rs +++ b/src/stable_hasher/tests.rs @@ -13,10 +13,8 @@ use crate::{SipHasher128Hash, StableSipHasher128}; #[derive(Debug, PartialEq)] struct TestHash([u64; 2]); -impl FromStableHash for TestHash { - type Hash = SipHasher128Hash; - - fn from(SipHasher128Hash(hash): Self::Hash) -> TestHash { +impl FromStableHash for TestHash { + fn from(SipHasher128Hash(hash): SipHasher128Hash) -> TestHash { TestHash(hash) } }