diff --git a/Cargo.toml b/Cargo.toml index 5b233bd5..241657f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ serde-codec = ["serde", "serde-big-array"] blake2b = ["blake2b_simd"] blake2s = ["blake2s_simd"] +# identity feature is depricated identity = [] sha1 = ["digest", "sha-1"] sha2 = ["digest", "sha-2"] diff --git a/examples/identity_hasher.rs b/examples/identity_hasher.rs new file mode 100644 index 00000000..7b572615 --- /dev/null +++ b/examples/identity_hasher.rs @@ -0,0 +1,83 @@ +use multihash::derive::Multihash; +use multihash::{Error, Hasher, MultihashDigest, MultihashGeneric, Sha2_256}; + +/// update appends to end of buffer but truncates/ignores bytes after len > S +#[derive(Debug)] +pub struct IdentityTrunk { + cursor: usize, + arr: [u8; S], +} + +impl Default for IdentityTrunk { + fn default() -> Self { + Self { + cursor: 0, + arr: [0u8; S], + } + } +} +impl Hasher for IdentityTrunk { + fn update(&mut self, input: &[u8]) { + let src_end = (self.cursor + input.len()).min(self.arr.len()); + let input_end = input.len().min(self.arr.len() - self.cursor); + + self.arr[self.cursor..src_end].copy_from_slice(&input[..input_end]); + self.cursor = src_end; + } + fn finalize(&mut self) -> &[u8] { + &self.arr[..self.cursor] + } + fn reset(&mut self) { + *self = Self { + cursor: 0, + arr: [0u8; S], + }; + } +} + +#[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)] +#[mh(alloc_size = 64)] +pub enum Code { + #[mh(code = 0x00, hasher = IdentityTrunk::<64>)] + IdentityTrunk, + #[mh(code = 0x12, hasher = Sha2_256)] + Sha2_256, +} + +fn main() { + // overwrite and trunk with code + + let src = b"hello world!"; + let ident_trunk = Code::IdentityTrunk.digest(src); + + assert_eq!(ident_trunk.digest(), src); + + // input bigger than default table, but still const sized + let big_src = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vehicula tempor magna quis egestas. Etiam quis rhoncus neque."; + + let truncated = Code::IdentityTrunk.digest(big_src); + assert_eq!(truncated.digest(), &big_src[..64]); + // + // Helper functions cannot be used with normal table if S != alloc_size, fancier const trait bounds in the future may allow for interop where S <= alloc_size + // + + pub const IDENTITY_CODE: u64 = 0x0; + // blind copy of the input array + pub fn identity_hash_arr(input: &[u8; S]) -> MultihashGeneric { + MultihashGeneric::wrap(IDENTITY_CODE, input).unwrap() + } + + // input is truncated to S size + pub fn identity_hash(input: &[u8]) -> MultihashGeneric { + let mut hasher = IdentityTrunk::::default(); + hasher.update(input); + MultihashGeneric::wrap(IDENTITY_CODE, hasher.finalize()).unwrap() + } + + // makes use of the const sized input to infer the output size + let big_arr_mh = identity_hash_arr(big_src); + assert_eq!(big_arr_mh.digest(), big_src); + // size must be specified + let big_mh = identity_hash::<128>(big_src); + assert_eq!(big_mh.digest(), big_src); +} diff --git a/src/lib.rs b/src/lib.rs index d561c27b..6114495c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,12 +11,11 @@ //! //! - `blake2b`: (default) Enable Blake2b hashers //! - `blake2s`: (default) Enable Blake2s hashers -//! - `identity`: Enable the Identity hashers (using it is discouraged as it's not a hash function -//! in the sense that it produces a fixed sized output independent of the input size) //! - `sha1`: Enable SHA-1 hasher //! - `sha2`: (default) Enable SHA-2 hashers //! - `sha3`: (default) Enable SHA-3 hashers //! - `strobe`: Enable Strobe hashers +//! - `identity`: A depricated feature for identity hashes. //! //! In order to enable all cryptographically secure hashers, you can set the `secure-hashes` //! feature flag (enabled by default). @@ -92,3 +91,13 @@ pub use crate::hasher_impl::sha3::{Keccak224, Keccak256, Keccak384, Keccak512}; pub use crate::hasher_impl::sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; #[cfg(feature = "strobe")] pub use crate::hasher_impl::strobe::{Strobe256, Strobe512, StrobeHasher}; + +/// Code reserved for Identity "hash" +pub const IDENTITY_CODE: u64 = 0x0; +/// Helper for generating Identity hashes (context https://github.com/multiformats/rust-multihash/pull/196). +/// Will error if `data.len() > S` +/// +/// See examples for a few other approaches if this doesn't fit your application +pub fn identity_hash(data: impl AsRef<[u8]>) -> Result> { + MultihashGeneric::wrap(IDENTITY_CODE, data.as_ref()) +} diff --git a/src/multihash_impl.rs b/src/multihash_impl.rs index 29face0b..17012257 100644 --- a/src/multihash_impl.rs +++ b/src/multihash_impl.rs @@ -83,12 +83,6 @@ pub enum Code { #[cfg(feature = "ripemd")] #[mh(code = 0x1055, hasher = crate::Ripemd320)] Ripemd320, - - // The following hashes are not cryptographically secure hashes and are not enabled by default - /// Identity hash (max. 64 bytes) - #[cfg(feature = "identity")] - #[mh(code = 0x00, hasher = crate::IdentityHasher::<64>)] - Identity, } #[cfg(test)]