diff --git a/README.md b/README.md index b0835557..d0167806 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,9 @@ use multihash::MultihashCode; #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)] #[mh(alloc_size = 64)] pub enum Code { - #[mh(code = 0x01, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] + #[mh(code = 0x01, hasher = multihash::Sha2_256)] Foo, - #[mh(code = 0x02, hasher = multihash::Sha2_512, digest = multihash::Sha2Digest<64>)] + #[mh(code = 0x02, hasher = multihash::Sha2_512)] Bar, } diff --git a/benches/multihash.rs b/benches/multihash.rs index aebad4ec..0b75ea15 100644 --- a/benches/multihash.rs +++ b/benches/multihash.rs @@ -4,7 +4,7 @@ use rand::Rng; use multihash::{ Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Hasher, Keccak224, Keccak256, Keccak384, Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, - StatefulHasher, Strobe256, Strobe512, + Strobe256, Strobe512, }; macro_rules! group_digest { @@ -13,7 +13,9 @@ macro_rules! group_digest { $( group.bench_function($id, |b| { b.iter(|| { - let _ = black_box($hash::digest($input)); + let mut hasher = $hash::default(); + hasher.update(black_box($input)); + let _ = black_box(hasher.finalize()); }) }); )* @@ -27,14 +29,13 @@ macro_rules! group_stream { $( group.bench_function($id, |b| { b.iter(|| { - let _ = black_box({ - let mut hasher = <$hash>::default(); - for i in 0..3 { - let start = i * 256; - hasher.update(&$input[start..(start + 256)]); - } - hasher.finalize() - }); + let input = black_box($input); + let mut hasher = <$hash>::default(); + for i in 0..3 { + let start = i * 256; + hasher.update(&input[start..(start + 256)]); + } + let _ = black_box(hasher.finalize()); }) }); )* diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 84189842..a9c633ec 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -24,9 +24,9 @@ //! #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)] //! #[mh(alloc_size = 64)] //! pub enum Code { -//! #[mh(code = 0x01, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] +//! #[mh(code = 0x01, hasher = multihash::Sha2_256)] //! Foo, -//! #[mh(code = 0x02, hasher = multihash::Sha2_512, digest = multihash::Sha2Digest<64>)] +//! #[mh(code = 0x02, hasher = multihash::Sha2_512)] //! Bar, //! } //! diff --git a/derive/src/multihash.rs b/derive/src/multihash.rs index afd47340..d03dcec2 100644 --- a/derive/src/multihash.rs +++ b/derive/src/multihash.rs @@ -6,6 +6,7 @@ use quote::quote; #[cfg(not(test))] use quote::ToTokens; use syn::parse::{Parse, ParseStream}; +#[cfg(not(test))] use syn::spanned::Spanned; use synstructure::{Structure, VariantInfo}; @@ -13,11 +14,9 @@ mod kw { use syn::custom_keyword; custom_keyword!(code); - custom_keyword!(digest); custom_keyword!(hasher); custom_keyword!(mh); custom_keyword!(alloc_size); - custom_keyword!(no_alloc_size_errors); } /// Attributes for the enum items. @@ -26,7 +25,6 @@ mod kw { enum MhAttr { Code(utils::Attr), Hasher(utils::Attr>), - Digest(utils::Attr), } impl Parse for MhAttr { @@ -36,7 +34,7 @@ impl Parse for MhAttr { } else if input.peek(kw::hasher) { Ok(MhAttr::Hasher(input.parse()?)) } else { - Ok(MhAttr::Digest(input.parse()?)) + Err(syn::Error::new(input.span(), "unknown attribute")) } } } @@ -45,15 +43,12 @@ impl Parse for MhAttr { #[derive(Debug)] enum DeriveAttr { AllocSize(utils::Attr), - NoAllocSizeErrors(kw::no_alloc_size_errors), } impl Parse for DeriveAttr { fn parse(input: ParseStream) -> syn::Result { if input.peek(kw::alloc_size) { Ok(Self::AllocSize(input.parse()?)) - } else if input.peek(kw::no_alloc_size_errors) { - Ok(Self::NoAllocSizeErrors(input.parse()?)) } else { Err(syn::Error::new(input.span(), "unknown attribute")) } @@ -69,7 +64,6 @@ struct Hash { ident: syn::Ident, code: syn::Expr, hasher: Box, - digest: syn::Path, } impl Hash { @@ -91,29 +85,16 @@ impl Hash { let hasher = &self.hasher; let code = &self.code; quote!(Self::#ident => { - let digest = #hasher::digest(input); - Multihash::wrap(#code, &digest.as_ref()).unwrap() + let mut hasher = #hasher::default(); + hasher.update(input); + Multihash::wrap(#code, hasher.finalize()).unwrap() }) } - - fn from_digest(&self, params: &Params) -> TokenStream { - let digest = &self.digest; - let code_enum = ¶ms.code_enum; - let ident = &self.ident; - quote! { - impl From<&#digest> for #code_enum { - fn from(digest: &#digest) -> Self { - Self::#ident - } - } - } - } } impl<'a> From<&'a VariantInfo<'a>> for Hash { fn from(bi: &'a VariantInfo<'a>) -> Self { let mut code = None; - let mut digest = None; let mut hasher = None; for attr in bi.ast().attrs { let attr: Result, _> = syn::parse2(attr.tokens.clone()); @@ -122,7 +103,6 @@ impl<'a> From<&'a VariantInfo<'a>> for Hash { match attr { MhAttr::Code(attr) => code = Some(attr.value), MhAttr::Hasher(attr) => hasher = Some(attr.value), - MhAttr::Digest(attr) => digest = Some(attr.value), } } } @@ -143,18 +123,10 @@ impl<'a> From<&'a VariantInfo<'a>> for Hash { #[cfg(not(test))] proc_macro_error::abort!(ident, msg); }); - let digest = digest.unwrap_or_else(|| { - let msg = "Missing digest atttibute: e.g. #[mh(digest = multihash::Sha2Digest<32>)]"; - #[cfg(test)] - panic!("{}", msg); - #[cfg(not(test))] - proc_macro_error::abort!(ident, msg); - }); Self { ident, code, hasher, - digest, } } } @@ -162,9 +134,8 @@ impl<'a> From<&'a VariantInfo<'a>> for Hash { /// Parse top-level enum [#mh()] attributes. /// /// Returns the `alloc_size` and whether errors regarding to `alloc_size` should be reported or not. -fn parse_code_enum_attrs(ast: &syn::DeriveInput) -> (syn::LitInt, bool) { +fn parse_code_enum_attrs(ast: &syn::DeriveInput) -> syn::LitInt { let mut alloc_size = None; - let mut no_alloc_size_errors = false; for attr in &ast.attrs { let derive_attrs: Result, _> = syn::parse2(attr.tokens.clone()); @@ -174,13 +145,12 @@ fn parse_code_enum_attrs(ast: &syn::DeriveInput) -> (syn::LitInt, bool) { DeriveAttr::AllocSize(alloc_size_attr) => { alloc_size = Some(alloc_size_attr.value) } - DeriveAttr::NoAllocSizeErrors(_) => no_alloc_size_errors = true, } } } } match alloc_size { - Some(alloc_size) => (alloc_size, no_alloc_size_errors), + Some(alloc_size) => alloc_size, None => { let msg = "enum is missing `alloc_size` attribute: e.g. #[mh(alloc_size = 64)]"; #[cfg(test)] @@ -227,73 +197,6 @@ fn error_code_duplicates(hashes: &[Hash]) { #[derive(Debug)] struct ParseError(Span); -/// Returns the max size as u64. -/// -/// Emits an error if the `#mh(alloc_size)` attribute doesn't contain a valid unsigned integer. -fn parse_alloc_size_attribute(alloc_size: &syn::LitInt) -> u64 { - alloc_size.base10_parse().unwrap_or_else(|_| { - let msg = "`alloc_size` attribute must be an integer, e.g. #[mh(alloc_size = 64)]"; - #[cfg(test)] - panic!("{}", msg); - #[cfg(not(test))] - proc_macro_error::abort!(&alloc_size, msg); - }) -} - -/// Return a warning/error if the specified alloc_size is smaller than the biggest digest -fn error_alloc_size(hashes: &[Hash], expected_alloc_size_type: &syn::LitInt) { - let expected_alloc_size = parse_alloc_size_attribute(expected_alloc_size_type); - - let maybe_error: Result<(), ParseError> = hashes - .iter() - .try_for_each(|hash| { - // The digest type must have an integer as size parameter, else we error. - match hash.digest.segments.last() { - Some(path_segment) => match &path_segment.arguments { - syn::PathArguments::AngleBracketed(arguments) => match arguments.args.last() { - Some(syn::GenericArgument::Const(syn::Expr::Lit(expr_lit))) => match &expr_lit.lit { - syn::Lit::Int(lit_int) => match lit_int.base10_parse::() { - Ok(max_digest_size) => { - if max_digest_size > expected_alloc_size { - let msg = format!("The `#mh(alloc_size) attribute must be bigger than the maximum defined digest size ({})", - max_digest_size); - #[cfg(test)] - panic!("{}", msg); - #[cfg(not(test))] - { - let digest = &hash.digest.to_token_stream().to_string().replace(" ", ""); - let line = &hash.digest.span().start().line; - proc_macro_error::emit_error!( - &expected_alloc_size_type, msg; - note = "the bigger digest is `{}` at line {}", digest, line; - ); - } - } - Ok(()) - }, - _ => Err(ParseError(lit_int.span())), - }, - _ => Err(ParseError(expr_lit.span())), - }, - _ => Err(ParseError(arguments.args.span())), - }, - _ => Err(ParseError(path_segment.span())), - }, - None => Err(ParseError(hash.digest.span())), - } - }); - - if let Err(_error) = maybe_error { - let msg = "Invalid byte size. It must be a unsigned integer, e.g. `32`"; - #[cfg(test)] - panic!("{}", msg); - #[cfg(not(test))] - { - proc_macro_error::emit_error!(&_error.0, msg); - } - } -} - pub fn multihash(s: Structure) -> TokenStream { let mh_crate = match utils::use_crate("multihash") { Ok(ident) => ident, @@ -303,15 +206,11 @@ pub fn multihash(s: Structure) -> TokenStream { } }; let code_enum = &s.ast().ident; - let (alloc_size, no_alloc_size_errors) = parse_code_enum_attrs(s.ast()); + let alloc_size = parse_code_enum_attrs(s.ast()); let hashes: Vec<_> = s.variants().iter().map(Hash::from).collect(); error_code_duplicates(&hashes); - if !no_alloc_size_errors { - error_alloc_size(&hashes, &alloc_size); - } - let params = Params { code_enum: code_enum.clone(), }; @@ -319,11 +218,10 @@ pub fn multihash(s: Structure) -> TokenStream { let code_into_u64 = hashes.iter().map(|h| h.code_into_u64(¶ms)); let code_from_u64 = hashes.iter().map(|h| h.code_from_u64()); let code_digest = hashes.iter().map(|h| h.code_digest()); - let from_digest = hashes.iter().map(|h| h.from_digest(¶ms)); quote! { /// A Multihash with the same allocated size as the Multihashes produces by this derive. - pub type Multihash = #mh_crate::MultihashGeneric::<#alloc_size>; + pub type Multihash = #mh_crate::MultihashGeneric<#alloc_size>; impl #mh_crate::MultihashDigest<#alloc_size> for #code_enum { fn digest(&self, input: &[u8]) -> Multihash { @@ -334,13 +232,8 @@ pub fn multihash(s: Structure) -> TokenStream { } } - fn multihash_from_digest<'a, D, const S: usize>(digest: &'a D) -> Multihash - where - D: #mh_crate::Digest, - Self: From<&'a D>, - { - let code = Self::from(&digest); - Multihash::wrap(code.into(), &digest.as_ref()).unwrap() + fn wrap(&self, digest: &[u8]) -> Result { + Multihash::wrap((*self).into(), digest) } } @@ -363,8 +256,6 @@ pub fn multihash(s: Structure) -> TokenStream { } } } - - #(#from_digest)* } } @@ -378,45 +269,40 @@ mod tests { #[derive(Clone, Multihash)] #[mh(alloc_size = 32)] pub enum Code { - #[mh(code = multihash::IDENTITY, hasher = multihash::Identity256, digest = multihash::IdentityDigest<32>)] + #[mh(code = multihash::IDENTITY, hasher = multihash::Identity256)] Identity256, /// Multihash array for hash function. - #[mh(code = 0x38b64f, hasher = multihash::Strobe256, digest = multihash::StrobeDigest<32>)] + #[mh(code = 0x38b64f, hasher = multihash::Strobe256)] Strobe256, } }; let expected = quote! { /// A Multihash with the same allocated size as the Multihashes produces by this derive. - pub type Multihash = multihash::MultihashGeneric::<32>; + pub type Multihash = multihash::MultihashGeneric<32>; impl multihash::MultihashDigest<32> for Code { - fn digest(&self, input: &[u8]) -> Multihash { use multihash::Hasher; match self { Self::Identity256 => { - let digest = multihash::Identity256::digest(input); - Multihash::wrap(multihash::IDENTITY, &digest.as_ref()).unwrap() + let mut hasher = multihash::Identity256::default(); + hasher.update(input); + Multihash::wrap(multihash::IDENTITY, hasher.finalize()).unwrap() }, Self::Strobe256 => { - let digest = multihash::Strobe256::digest(input); - Multihash::wrap(0x38b64f, &digest.as_ref()).unwrap() + let mut hasher = multihash::Strobe256::default(); + hasher.update(input); + Multihash::wrap(0x38b64f, hasher.finalize()).unwrap() }, _ => unreachable!(), } } - fn multihash_from_digest<'a, D, const S: usize>(digest: &'a D) -> Multihash - where - D: multihash::Digest, - Self: From<&'a D>, - { - let code = Self::from(&digest); - Multihash::wrap(code.into(), &digest.as_ref()).unwrap() + fn wrap(&self, digest: &[u8]) -> Result { + Multihash::wrap((*self).into(), digest) } } - impl From for u64 { fn from(code: Code) -> Self { match code { @@ -438,17 +324,6 @@ mod tests { } } } - - impl From<&multihash::IdentityDigest<32> > for Code { - fn from(digest: &multihash::IdentityDigest<32>) -> Self { - Self::Identity256 - } - } - impl From<&multihash::StrobeDigest<32> > for Code { - fn from(digest: &multihash::StrobeDigest<32>) -> Self { - Self::Strobe256 - } - } }; let derive_input = syn::parse2(input).unwrap(); let s = Structure::new(&derive_input); @@ -465,9 +340,9 @@ mod tests { #[derive(Clone, Multihash)] #[mh(alloc_size = 64)] pub enum Multihash { - #[mh(code = multihash::SHA2_256, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] + #[mh(code = multihash::SHA2_256, hasher = multihash::Sha2_256)] Identity256, - #[mh(code = multihash::SHA2_256, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] + #[mh(code = multihash::SHA2_256, hasher = multihash::Sha2_256)] Identity256, } }; @@ -483,9 +358,9 @@ mod tests { #[derive(Clone, Multihash)] #[mh(alloc_size = 32)] pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] + #[mh(code = 0x14, hasher = multihash::Sha2_256)] Identity256, - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] + #[mh(code = 0x14, hasher = multihash::Sha2_256)] Identity256, } }; @@ -493,103 +368,4 @@ mod tests { let s = Structure::new(&derive_input); multihash(s); } - - #[test] - #[should_panic( - expected = "enum is missing `alloc_size` attribute: e.g. #[mh(alloc_size = 64)]" - )] - fn test_multihash_error_no_alloc_size() { - let input = quote! { - #[derive(Clone, Multihash)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } - - #[test] - #[should_panic( - expected = "The `#mh(alloc_size) attribute must be bigger than the maximum defined digest size (32)" - )] - fn test_multihash_error_too_small_alloc_size() { - let input = quote! { - #[derive(Clone, Multihash)] - #[mh(alloc_size = 16)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<32>)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } - - #[test] - #[should_panic(expected = "Invalid byte size. It must be a unsigned integer, e.g. `32`")] - fn test_multihash_error_digest_invalid_size_type() { - let input = quote! { - #[derive(Clone, Multihash)] - #[mh(alloc_size = 32)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } - - #[test] - #[should_panic(expected = "Invalid byte size. It must be a unsigned integer, e.g. `32`")] - fn test_multihash_error_digest_invalid_size_type2() { - let input = quote! { - #[derive(Clone, Multihash)] - #[mh(alloc_size = 32)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = multihash::Sha2Digest<_>)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } - - #[test] - #[should_panic(expected = "Invalid byte size. It must be a unsigned integer, e.g. `32`")] - fn test_multihash_error_digest_without_size() { - let input = quote! { - #[derive(Clone, Multihash)] - #[mh(alloc_size = 32)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = Sha2_256Digest)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } - - // This one does not panic, die to `no_alloc_size_errors` - #[test] - fn test_multihash_error_digest_without_size_no_alloc_size_errors() { - let input = quote! { - #[derive(Clone, Multihash)] - #[mh(alloc_size = 32, no_alloc_size_errors)] - pub enum Code { - #[mh(code = 0x14, hasher = multihash::Sha2_256, digest = Sha2_256Digest)] - Sha2_256, - } - }; - let derive_input = syn::parse2(input).unwrap(); - let s = Structure::new(&derive_input); - multihash(s); - } } diff --git a/examples/custom_table.rs b/examples/custom_table.rs index 183f3977..f96c22f5 100644 --- a/examples/custom_table.rs +++ b/examples/custom_table.rs @@ -1,23 +1,18 @@ use std::convert::TryFrom; use multihash::derive::Multihash; -use multihash::{ - Digest, Error, Hasher, MultihashDigest, MultihashGeneric, Sha2Digest, Sha2_256, StatefulHasher, -}; +use multihash::{Error, Hasher, MultihashDigest, MultihashGeneric, Sha2_256}; // You can implement a custom hasher. This is a SHA2 256-bit hasher that returns a hash that is // truncated to 160 bits. #[derive(Default, Debug)] pub struct Sha2_256Truncated20(Sha2_256); -impl StatefulHasher<20> for Sha2_256Truncated20 { - type Digest = Sha2Digest<{ Self::SIZE }>; +impl Hasher for Sha2_256Truncated20 { fn update(&mut self, input: &[u8]) { self.0.update(input) } - fn finalize(&self) -> Self::Digest { - let digest = self.0.finalize(); - let truncated = &digest.as_ref()[..20]; - Self::Digest::try_from(truncated).expect("digest sizes always match") + fn finalize(&mut self) -> &[u8] { + &self.0.finalize()[..20] } fn reset(&mut self) { self.0.reset(); @@ -28,10 +23,10 @@ impl StatefulHasher<20> for Sha2_256Truncated20 { #[mh(alloc_size = 64)] pub enum Code { /// Example for using a custom hasher which returns truncated hashes - #[mh(code = 0x12, hasher = Sha2_256Truncated20, digest = multihash::Sha2Digest<20>)] + #[mh(code = 0x12, hasher = Sha2_256Truncated20)] Sha2_256Truncated20, /// Example for using a hasher with a bit size that is not exported by default - #[mh(code = 0xb219, hasher = multihash::Blake2bHasher::<25>, digest = multihash::Blake2bDigest<25>)] + #[mh(code = 0xb219, hasher = multihash::Blake2bHasher::<25>)] Blake2b200, } diff --git a/src/hasher.rs b/src/hasher.rs index 94989bd6..894cab30 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -1,117 +1,11 @@ -use crate::error::Error; -use core::fmt::Debug; - -#[cfg(feature = "std")] -use std::io; - -#[cfg(not(feature = "std"))] -use core2::io; - -/// Stack allocated digest trait. -pub trait Digest: - AsRef<[u8]> - + AsMut<[u8]> - + From<[u8; S]> - + Into<[u8; S]> - + Clone - + core::hash::Hash - + Debug - + Default - + Eq - + Send - + Sync - + 'static -{ - /// Size of the digest. Maximum for Some of the Blake family is 2^64-1 bytes - const SIZE: usize = S; - - /// Wraps the digest bytes. - fn wrap(digest: &[u8]) -> Result { - if digest.len() != S { - return Err(Error::InvalidSize(digest.len() as _)); - } - let mut array = [0; S]; - let len = digest.len().min(array.len()); - array[..len].copy_from_slice(&digest[..len]); - Ok(array.into()) - } - - /// Reads a multihash digest from a byte stream that contains the digest prefixed with the size. - /// - /// The byte stream must not contain the code as prefix. - fn from_reader(mut r: R) -> Result - where - R: io::Read, - { - use crate::multihash::read_u64; - - let size = read_u64(&mut r)?; - if size > S as u64 || size > u8::MAX as u64 { - return Err(Error::InvalidSize(size)); - } - let mut digest = [0; S]; - r.read_exact(&mut digest[..size as usize])?; - Ok(Self::from(digest)) - } -} - /// Trait implemented by a hash function implementation. -pub trait StatefulHasher: Default + Send + Sync { - /// The Digest type to distinguish the output of different `Hasher` implementations. - type Digest: Digest; - +pub trait Hasher { /// Consume input and update internal state. fn update(&mut self, input: &[u8]); /// Returns the final digest. - fn finalize(&self) -> Self::Digest; + fn finalize(&mut self) -> &[u8]; /// Reset the internal hasher state. fn reset(&mut self); } - -/// Trait implemented by a hash function implementation. -/// -/// It specifies its own Digest type, so that the output of the hash function can later be -/// distinguished. This way you can create a [`MultihashDigest`] from a `Digest`. -/// -/// Every hashing algorithm that is used with Multihash needs to implement those. This trait is -/// very similar to the external [`digest::Digest` trait]. There is a small significant -/// difference, which needed the introduction of this `Hasher` trait instead of re-using the -/// widely used `digest::Digest` trait. -/// -/// The external `digest::Digest` trait has a single return type called [`Output`], which is used -/// for all hashers that implement it. It's basically a wrapper around the hashed result bytes. -/// For Multihashes we need to distinguish those bytes, as we care about which hash function they -/// were created with (which is the whole point of [Multihashes]). Therefore the [`Hasher`] trait -/// defines an [associated type] [`Hasher::Digest`] for the output of the hasher. This way the -/// implementers can specify their own, hasher specific type (which implements [`Digest`]) for -/// their output. -/// -/// [`digest::Digest` trait]: https://docs.rs/digest/0.9.0/digest/trait.Digest.html -/// [`Output`]: https://docs.rs/digest/0.9.0/digest/type.Output.html -/// [Multihashes]: https://github.com/multiformats/multihash -/// [associated type]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types -/// [`MultihashDigest`]: crate::MultihashDigest -pub trait Hasher: Default + Send + Sync { - /// The Digest type to distinguish the output of different `Hasher` implementations. - type Digest: Digest; - - ///the allocated size of the digest. - const SIZE: usize = S; - - /// Hashes the given `input` data and returns its hash digest. - fn digest(input: &[u8]) -> Self::Digest - where - Self: Sized; -} - -impl, const S: usize> Hasher for T { - type Digest = T::Digest; - - fn digest(input: &[u8]) -> Self::Digest { - let mut hasher = Self::default(); - hasher.update(input); - hasher.finalize() - } -} diff --git a/src/hasher_impl.rs b/src/hasher_impl.rs index c55483eb..925e47c6 100644 --- a/src/hasher_impl.rs +++ b/src/hasher_impl.rs @@ -1,6 +1,4 @@ -use crate::error::Error; -use crate::hasher::{Digest, StatefulHasher}; -use core::convert::TryFrom; +use crate::hasher::Hasher; #[cfg(feature = "std")] use std::io; @@ -8,57 +6,6 @@ use std::io; #[cfg(not(feature = "std"))] use core2::io; -macro_rules! derive_digest { - ($name:ident) => { - /// Multihash digest. - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct $name([u8; S]); - - impl Default for $name { - fn default() -> Self { - [0u8; S].into() - } - } - - impl AsRef<[u8]> for $name { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for $name { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - - impl From<[u8; S]> for $name { - fn from(array: [u8; S]) -> Self { - Self(array) - } - } - - impl From<$name> for [u8; S] { - fn from(digest: $name) -> Self { - digest.0 - } - } - - /// Convert slice to `Digest`. - /// - /// It errors when the length of the slice does not match the size of the `Digest`. - impl TryFrom<&[u8]> for $name { - type Error = Error; - - fn try_from(slice: &[u8]) -> Result { - Self::wrap(slice) - } - } - - impl Digest for $name {} - }; -} - macro_rules! derive_write { ($name:ident) => { impl io::Write for $name { @@ -76,13 +23,12 @@ macro_rules! derive_write { #[cfg(any(feature = "blake2b", feature = "blake2s"))] macro_rules! derive_hasher_blake { - ($module:ident, $name:ident, $digest:ident) => { - derive_digest!($digest); - + ($module:ident, $name:ident) => { /// Multihash hasher. #[derive(Debug)] pub struct $name { state: $module::State, + digest: [u8; S], } impl Default for $name { @@ -91,22 +37,22 @@ macro_rules! derive_hasher_blake { params.hash_length(S); Self { state: params.to_state(), + digest: [0; S], } } } - impl StatefulHasher for $name { - type Digest = $digest; - + impl Hasher for $name { fn update(&mut self, input: &[u8]) { self.state.update(input); } - fn finalize(&self) -> Self::Digest { + fn finalize(&mut self) -> &[u8] { let digest = self.state.finalize(); - let mut array = [0; S]; - array.clone_from_slice(digest.as_bytes()); - array.into() + let digest_bytes = digest.as_bytes(); + let digest_out = &mut self.digest[..digest_bytes.len().max(S)]; + digest_out.copy_from_slice(digest_bytes); + digest_out } fn reset(&mut self) { @@ -123,7 +69,7 @@ macro_rules! derive_hasher_blake { pub mod blake2b { use super::*; - derive_hasher_blake!(blake2b_simd, Blake2bHasher, Blake2bDigest); + derive_hasher_blake!(blake2b_simd, Blake2bHasher); /// 256 bit blake2b hasher. pub type Blake2b256 = Blake2bHasher<32>; @@ -136,7 +82,7 @@ pub mod blake2b { pub mod blake2s { use super::*; - derive_hasher_blake!(blake2s_simd, Blake2sHasher, Blake2sDigest); + derive_hasher_blake!(blake2s_simd, Blake2sHasher); /// 256 bit blake2b hasher. pub type Blake2s128 = Blake2sHasher<16>; @@ -149,35 +95,35 @@ pub mod blake2s { pub mod blake3 { use super::*; - // derive_hasher_blake!(blake3, Blake3Hasher, Blake3Digest); - derive_digest!(Blake3Digest); - /// Multihash hasher. #[derive(Debug)] pub struct Blake3Hasher { hasher: ::blake3::Hasher, + digest: [u8; S], } impl Default for Blake3Hasher { fn default() -> Self { let hasher = ::blake3::Hasher::new(); - Self { hasher } + Self { + hasher, + digest: [0; S], + } } } - impl StatefulHasher for Blake3Hasher { - type Digest = Blake3Digest; - + impl Hasher for Blake3Hasher { fn update(&mut self, input: &[u8]) { self.hasher.update(input); } - fn finalize(&self) -> Self::Digest { + fn finalize(&mut self) -> &[u8] { let digest = self.hasher.finalize(); //default is 32 bytes anyway - let mut array = [0; S]; - array.clone_from_slice(digest.as_bytes()); - array.into() + let digest_bytes = digest.as_bytes(); + let digest_out = &mut self.digest[..digest_bytes.len().max(S)]; + digest_out.copy_from_slice(digest_bytes); + digest_out } fn reset(&mut self) { @@ -193,27 +139,36 @@ pub mod blake3 { #[cfg(feature = "digest")] macro_rules! derive_hasher_sha { - ($module:ty, $name:ident, $size:expr, $digest:ident) => { + ($module:ty, $name:ident, $size:expr) => { /// Multihash hasher. - #[derive(Debug, Default)] + #[derive(Debug)] pub struct $name { state: $module, + digest: [u8; $size], } - impl $crate::hasher::StatefulHasher<$size> for $name { - type Digest = $digest<$size>; + impl Default for $name { + fn default() -> Self { + $name { + state: Default::default(), + digest: [0; $size], + } + } + } + impl $crate::hasher::Hasher for $name { fn update(&mut self, input: &[u8]) { use digest::Digest; self.state.update(input) } - fn finalize(&self) -> Self::Digest { + fn finalize(&mut self) -> &[u8] { use digest::Digest; let digest = self.state.clone().finalize(); - let mut array = [0; $size]; - array.copy_from_slice(digest.as_slice()); - array.into() + let digest_bytes = digest.as_slice(); + let digest_out = &mut self.digest[..digest_bytes.len().max($size)]; + digest_out.copy_from_slice(digest_bytes); + digest_out } fn reset(&mut self) { @@ -239,106 +194,34 @@ macro_rules! derive_hasher_sha { pub mod sha1 { use super::*; - derive_digest!(Sha1Digest); - derive_hasher_sha!(::sha1::Sha1, Sha1, 20, Sha1Digest); + derive_hasher_sha!(::sha1::Sha1, Sha1, 20); } #[cfg(feature = "sha2")] pub mod sha2 { use super::*; - derive_digest!(Sha2Digest); - derive_hasher_sha!(sha_2::Sha256, Sha2_256, 32, Sha2Digest); - derive_hasher_sha!(sha_2::Sha512, Sha2_512, 64, Sha2Digest); + derive_hasher_sha!(sha_2::Sha256, Sha2_256, 32); + derive_hasher_sha!(sha_2::Sha512, Sha2_512, 64); } #[cfg(feature = "sha3")] pub mod sha3 { use super::*; - derive_digest!(Sha3Digest); - derive_hasher_sha!(sha_3::Sha3_224, Sha3_224, 28, Sha3Digest); - derive_hasher_sha!(sha_3::Sha3_256, Sha3_256, 32, Sha3Digest); - derive_hasher_sha!(sha_3::Sha3_384, Sha3_384, 48, Sha3Digest); - derive_hasher_sha!(sha_3::Sha3_512, Sha3_512, 64, Sha3Digest); - - derive_digest!(KeccakDigest); - derive_hasher_sha!(sha_3::Keccak224, Keccak224, 28, KeccakDigest); - derive_hasher_sha!(sha_3::Keccak256, Keccak256, 32, KeccakDigest); - derive_hasher_sha!(sha_3::Keccak384, Keccak384, 48, KeccakDigest); - derive_hasher_sha!(sha_3::Keccak512, Keccak512, 64, KeccakDigest); + derive_hasher_sha!(sha_3::Sha3_224, Sha3_224, 28); + derive_hasher_sha!(sha_3::Sha3_256, Sha3_256, 32); + derive_hasher_sha!(sha_3::Sha3_384, Sha3_384, 48); + derive_hasher_sha!(sha_3::Sha3_512, Sha3_512, 64); + + derive_hasher_sha!(sha_3::Keccak224, Keccak224, 28); + derive_hasher_sha!(sha_3::Keccak256, Keccak256, 32); + derive_hasher_sha!(sha_3::Keccak384, Keccak384, 48); + derive_hasher_sha!(sha_3::Keccak512, Keccak512, 64); } pub mod identity { use super::*; - use crate::error::Error; - - /// Multihash digest. - #[derive(Clone, Debug, Eq, Hash, PartialEq)] - pub struct IdentityDigest(usize, [u8; S]); - - impl Default for IdentityDigest { - fn default() -> Self { - Self { 0: 0, 1: [0u8; S] } - } - } - - impl AsRef<[u8]> for IdentityDigest { - fn as_ref(&self) -> &[u8] { - &self.1[..self.0 as usize] - } - } - - impl AsMut<[u8]> for IdentityDigest { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.1[..self.0 as usize] - } - } - - impl From<[u8; S]> for IdentityDigest { - fn from(array: [u8; S]) -> Self { - Self(array.len(), array) - } - } - - impl From> for [u8; S] { - fn from(digest: IdentityDigest) -> Self { - digest.1 - } - } - - impl Digest for IdentityDigest { - const SIZE: usize = S; - - // A custom implementation is needed as an identity hash value might be shorter than the - // allocated Digest. - fn wrap(digest: &[u8]) -> Result { - if digest.len() > S { - return Err(Error::InvalidSize(digest.len() as _)); - } - let mut array = [0; S]; - let len = digest.len().min(array.len()); - array[..len].copy_from_slice(&digest[..len]); - Ok(Self(len, array)) - } - - // A custom implementation is needed as an identity hash also stores the actual size of - // the given digest. - fn from_reader(mut r: R) -> Result - where - R: io::Read, - { - use crate::multihash::read_u64; - - let size = read_u64(&mut r)?; - if size > S as u64 || size > u8::MAX as u64 { - return Err(Error::InvalidSize(size)); - } - let mut digest = [0; S]; - r.read_exact(&mut digest[..size as usize])?; - Ok(Self(size as usize, digest)) - } - } /// Identity hasher with a maximum size. /// @@ -347,8 +230,8 @@ pub mod identity { /// Panics if the input is bigger than the maximum size. #[derive(Debug)] pub struct IdentityHasher { - bytes: [u8; S], i: usize, + bytes: [u8; S], } impl Default for IdentityHasher { @@ -360,9 +243,7 @@ pub mod identity { } } - impl StatefulHasher for IdentityHasher { - type Digest = IdentityDigest; - + impl Hasher for IdentityHasher { fn update(&mut self, input: &[u8]) { let start = self.i.min(self.bytes.len()); let end = (self.i + input.len()).min(self.bytes.len()); @@ -370,13 +251,12 @@ pub mod identity { self.i = end; } - fn finalize(&self) -> Self::Digest { - IdentityDigest(self.i, self.bytes) + fn finalize(&mut self) -> &[u8] { + &self.bytes[..self.i] } fn reset(&mut self) { - self.bytes = [0; S]; - self.i = 0; + self.i = 0 } } @@ -390,22 +270,16 @@ pub mod identity { pub type Identity256 = IdentityHasher<32>; } -pub mod unknown { - use super::*; - derive_digest!(UnknownDigest); -} - #[cfg(feature = "strobe")] pub mod strobe { use super::*; use strobe_rs::{SecParam, Strobe}; - derive_digest!(StrobeDigest); - /// Strobe hasher. pub struct StrobeHasher { strobe: Strobe, initialized: bool, + digest: [u8; S], } impl Default for StrobeHasher { @@ -413,22 +287,20 @@ pub mod strobe { Self { strobe: Strobe::new(b"StrobeHash", SecParam::B128), initialized: false, + digest: [0; S], } } } - impl StatefulHasher for StrobeHasher { - type Digest = StrobeDigest; - + impl Hasher for StrobeHasher { fn update(&mut self, input: &[u8]) { self.strobe.ad(input, self.initialized); self.initialized = true; } - fn finalize(&self) -> Self::Digest { - let mut hash = [0; S]; - self.strobe.clone().prf(&mut hash, false); - Self::Digest::from(hash) + fn finalize(&mut self) -> &[u8] { + self.strobe.clone().prf(&mut self.digest, false); + &self.digest } fn reset(&mut self) { diff --git a/src/lib.rs b/src/lib.rs index dede97c6..e1b36366 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ mod multihash; mod multihash_impl; pub use crate::error::{Error, Result}; -pub use crate::hasher::{Digest, Hasher, StatefulHasher}; +pub use crate::hasher::Hasher; pub use crate::multihash::{Multihash as MultihashGeneric, MultihashDigest}; #[cfg(feature = "derive")] pub use multihash_derive as derive; @@ -74,20 +74,19 @@ pub use multihash_derive as derive; pub use crate::multihash_impl::{Code, Multihash}; #[cfg(feature = "blake2b")] -pub use crate::hasher_impl::blake2b::{Blake2b256, Blake2b512, Blake2bDigest, Blake2bHasher}; +pub use crate::hasher_impl::blake2b::{Blake2b256, Blake2b512, Blake2bHasher}; #[cfg(feature = "blake2s")] -pub use crate::hasher_impl::blake2s::{Blake2s128, Blake2s256, Blake2sDigest, Blake2sHasher}; +pub use crate::hasher_impl::blake2s::{Blake2s128, Blake2s256, Blake2sHasher}; #[cfg(feature = "blake3")] -pub use crate::hasher_impl::blake3::{Blake3Digest, Blake3Hasher, Blake3_256}; -pub use crate::hasher_impl::identity::{Identity256, IdentityDigest, IdentityHasher}; +pub use crate::hasher_impl::blake3::{Blake3Hasher, Blake3_256}; +pub use crate::hasher_impl::identity::{Identity256, IdentityHasher}; #[cfg(feature = "sha1")] -pub use crate::hasher_impl::sha1::{Sha1, Sha1Digest}; +pub use crate::hasher_impl::sha1::Sha1; #[cfg(feature = "sha2")] -pub use crate::hasher_impl::sha2::{Sha2Digest, Sha2_256, Sha2_512}; +pub use crate::hasher_impl::sha2::{Sha2_256, Sha2_512}; #[cfg(feature = "sha3")] -pub use crate::hasher_impl::sha3::{Keccak224, Keccak256, Keccak384, Keccak512, KeccakDigest}; +pub use crate::hasher_impl::sha3::{Keccak224, Keccak256, Keccak384, Keccak512}; #[cfg(feature = "sha3")] -pub use crate::hasher_impl::sha3::{Sha3Digest, Sha3_224, Sha3_256, Sha3_384, Sha3_512}; +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, StrobeDigest, StrobeHasher}; -pub use crate::hasher_impl::unknown::UnknownDigest; +pub use crate::hasher_impl::strobe::{Strobe256, Strobe512, StrobeHasher}; diff --git a/src/multihash.rs b/src/multihash.rs index 9432d778..19af27ad 100644 --- a/src/multihash.rs +++ b/src/multihash.rs @@ -1,4 +1,3 @@ -use crate::hasher::Digest; use crate::Error; #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -38,23 +37,19 @@ pub trait MultihashDigest: /// ``` fn digest(&self, input: &[u8]) -> Multihash; - /// Create a multihash from an existing [`Digest`]. + /// Create a multihash from an existing multihash digest. /// /// # Example /// /// ``` - /// use multihash::{Code, MultihashDigest, Sha3_256, StatefulHasher}; + /// use multihash::{Code, Hasher, MultihashDigest, Sha3_256}; /// /// let mut hasher = Sha3_256::default(); /// hasher.update(b"Hello world!"); - /// let hash = Code::multihash_from_digest(&hasher.finalize()); + /// let hash = Code::Sha3_256.wrap(&hasher.finalize()).unwrap(); /// println!("{:02x?}", hash); /// ``` - #[allow(clippy::needless_lifetimes)] - fn multihash_from_digest<'a, D, const DIGEST_SIZE: usize>(digest: &'a D) -> Multihash - where - D: Digest, - Self: From<&'a D>; + fn wrap(&self, digest: &[u8]) -> Result, Error>; } /// A Multihash instance that only supports the basic functionality and no hashing. @@ -386,14 +381,9 @@ mod tests { #[test] #[cfg(feature = "scale-codec")] fn test_scale() { - use crate::{Hasher, Sha2_256}; use parity_scale_codec::{Decode, Encode}; - let mh1 = Multihash::<32>::wrap( - Code::Sha2_256.into(), - Sha2_256::digest(b"hello world").as_ref(), - ) - .unwrap(); + let mh1 = Code::Sha2_256.digest(b"hello world"); // println!("mh1: code = {}, size = {}, digest = {:?}", mh1.code(), mh1.size(), mh1.digest()); let mh1_bytes = mh1.encode(); // println!("Multihash<32>: {}", hex::encode(&mh1_bytes)); diff --git a/src/multihash_impl.rs b/src/multihash_impl.rs index f52e0e03..7350c4f0 100644 --- a/src/multihash_impl.rs +++ b/src/multihash_impl.rs @@ -1,4 +1,4 @@ -use multihash_derive::Multihash; +pub use multihash_derive::Multihash; /// Default (cryptographically secure) Multihash implementation. /// @@ -11,69 +11,69 @@ use multihash_derive::Multihash; pub enum Code { /// SHA-256 (32-byte hash size) #[cfg(feature = "sha2")] - #[mh(code = 0x12, hasher = crate::Sha2_256, digest = crate::Sha2Digest<32>)] + #[mh(code = 0x12, hasher = crate::Sha2_256)] Sha2_256, /// SHA-512 (64-byte hash size) #[cfg(feature = "sha2")] - #[mh(code = 0x13, hasher = crate::Sha2_512, digest = crate::Sha2Digest<64>)] + #[mh(code = 0x13, hasher = crate::Sha2_512)] Sha2_512, /// SHA3-224 (28-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x17, hasher = crate::Sha3_224, digest = crate::Sha3Digest<28>)] + #[mh(code = 0x17, hasher = crate::Sha3_224)] Sha3_224, /// SHA3-256 (32-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x16, hasher = crate::Sha3_256, digest = crate::Sha3Digest<32>)] + #[mh(code = 0x16, hasher = crate::Sha3_256)] Sha3_256, /// SHA3-384 (48-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x15, hasher = crate::Sha3_384, digest = crate::Sha3Digest<48>)] + #[mh(code = 0x15, hasher = crate::Sha3_384)] Sha3_384, /// SHA3-512 (64-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x14, hasher = crate::Sha3_512, digest = crate::Sha3Digest<64>)] + #[mh(code = 0x14, hasher = crate::Sha3_512)] Sha3_512, /// Keccak-224 (28-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x1a, hasher = crate::Keccak224, digest = crate::KeccakDigest<28>)] + #[mh(code = 0x1a, hasher = crate::Keccak224)] Keccak224, /// Keccak-256 (32-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x1b, hasher = crate::Keccak256, digest = crate::KeccakDigest<32>)] + #[mh(code = 0x1b, hasher = crate::Keccak256)] Keccak256, /// Keccak-384 (48-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x1c, hasher = crate::Keccak384, digest = crate::KeccakDigest<48>)] + #[mh(code = 0x1c, hasher = crate::Keccak384)] Keccak384, /// Keccak-512 (64-byte hash size) #[cfg(feature = "sha3")] - #[mh(code = 0x1d, hasher = crate::Keccak512, digest = crate::KeccakDigest<64>)] + #[mh(code = 0x1d, hasher = crate::Keccak512)] Keccak512, /// BLAKE2b-256 (32-byte hash size) #[cfg(feature = "blake2b")] - #[mh(code = 0xb220, hasher = crate::Blake2b256, digest = crate::Blake2bDigest<32>)] + #[mh(code = 0xb220, hasher = crate::Blake2b256)] Blake2b256, /// BLAKE2b-512 (64-byte hash size) #[cfg(feature = "blake2b")] - #[mh(code = 0xb240, hasher = crate::Blake2b512, digest = crate::Blake2bDigest<64>)] + #[mh(code = 0xb240, hasher = crate::Blake2b512)] Blake2b512, /// BLAKE2s-128 (16-byte hash size) #[cfg(feature = "blake2s")] - #[mh(code = 0xb250, hasher = crate::Blake2s128, digest = crate::Blake2sDigest<16>)] + #[mh(code = 0xb250, hasher = crate::Blake2s128)] Blake2s128, /// BLAKE2s-256 (32-byte hash size) #[cfg(feature = "blake2s")] - #[mh(code = 0xb260, hasher = crate::Blake2s256, digest = crate::Blake2sDigest<32>)] + #[mh(code = 0xb260, hasher = crate::Blake2s256)] Blake2s256, /// BLAKE3-256 (32-byte hash size) #[cfg(feature = "blake3")] - #[mh(code = 0x1e, hasher = crate::Blake3_256, digest = crate::Blake3Digest<32>)] + #[mh(code = 0x1e, hasher = crate::Blake3_256)] Blake3_256, // 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>, digest = crate::IdentityDigest<64>)] + #[mh(code = 0x00, hasher = crate::IdentityHasher::<64>)] Identity, } @@ -86,23 +86,27 @@ mod tests { #[test] fn test_hasher_256() { - let digest = Sha3_256::digest(b"hello world"); - let hash = Code::multihash_from_digest(&digest); + let mut hasher = Sha3_256::default(); + hasher.update(b"hello world"); + let digest = hasher.finalize(); + let hash = Code::Sha3_256.wrap(digest).unwrap(); let hash2 = Code::Sha3_256.digest(b"hello world"); assert_eq!(hash.code(), u64::from(Code::Sha3_256)); assert_eq!(hash.size(), 32); - assert_eq!(hash.digest(), digest.as_ref()); + assert_eq!(hash.digest(), digest); assert_eq!(hash, hash2); } #[test] fn test_hasher_512() { - let digest = Sha3_512::digest(b"hello world"); - let hash = Code::multihash_from_digest(&digest); + let mut hasher = Sha3_512::default(); + hasher.update(b"hello world"); + let digest = hasher.finalize(); + let hash = Code::Sha3_512.wrap(digest).unwrap(); let hash2 = Code::Sha3_512.digest(b"hello world"); assert_eq!(hash.code(), u64::from(Code::Sha3_512)); assert_eq!(hash.size(), 64); - assert_eq!(hash.digest(), digest.as_ref()); + assert_eq!(hash.digest(), digest); assert_eq!(hash, hash2); } } diff --git a/tests/lib.rs b/tests/lib.rs index 21ce9c37..3fdcba3b 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,53 +1,51 @@ use std::io::{Cursor, Write}; use multihash::{ - derive::Multihash, Blake2b256, Blake2b512, Blake2bDigest, Blake2s128, Blake2s256, - Blake2sDigest, Blake3Digest, Blake3_256, Hasher, Identity256, IdentityDigest, Keccak224, - Keccak256, Keccak384, Keccak512, KeccakDigest, MultihashDigest, Sha1, Sha1Digest, Sha2Digest, - Sha2_256, Sha2_512, Sha3Digest, Sha3_224, Sha3_256, Sha3_384, Sha3_512, StatefulHasher, - Strobe256, Strobe512, StrobeDigest, + derive::Multihash, Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Hasher, + Identity256, Keccak224, Keccak256, Keccak384, Keccak512, MultihashDigest, Sha1, Sha2_256, + Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Strobe256, Strobe512, }; #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)] #[mh(alloc_size = 64)] pub enum Code { - #[mh(code = 0x00, hasher = Identity256, digest = IdentityDigest<32>)] + #[mh(code = 0x00, hasher = Identity256)] Identity, - #[mh(code = 0x11, hasher = Sha1, digest = Sha1Digest<20>)] + #[mh(code = 0x11, hasher = Sha1)] Sha1, - #[mh(code = 0x12, hasher = Sha2_256, digest = Sha2Digest<32>)] + #[mh(code = 0x12, hasher = Sha2_256)] Sha2_256, - #[mh(code = 0x13, hasher = Sha2_512, digest = Sha2Digest<64>)] + #[mh(code = 0x13, hasher = Sha2_512)] Sha2_512, - #[mh(code = 0x17, hasher = Sha3_224, digest = Sha3Digest<28>)] + #[mh(code = 0x17, hasher = Sha3_224)] Sha3_224, - #[mh(code = 0x16, hasher = Sha3_256, digest = Sha3Digest<32>)] + #[mh(code = 0x16, hasher = Sha3_256)] Sha3_256, - #[mh(code = 0x15, hasher = Sha3_384, digest = Sha3Digest<48>)] + #[mh(code = 0x15, hasher = Sha3_384)] Sha3_384, - #[mh(code = 0x14, hasher = Sha3_512, digest = Sha3Digest<64>)] + #[mh(code = 0x14, hasher = Sha3_512)] Sha3_512, - #[mh(code = 0x1a, hasher = Keccak224, digest = KeccakDigest<28>)] + #[mh(code = 0x1a, hasher = Keccak224)] Keccak224, - #[mh(code = 0x1b, hasher = Keccak256, digest = KeccakDigest<32>)] + #[mh(code = 0x1b, hasher = Keccak256)] Keccak256, - #[mh(code = 0x1c, hasher = Keccak384, digest = KeccakDigest<48>)] + #[mh(code = 0x1c, hasher = Keccak384)] Keccak384, - #[mh(code = 0x1d, hasher = Keccak512, digest = KeccakDigest<64>)] + #[mh(code = 0x1d, hasher = Keccak512)] Keccak512, - #[mh(code = 0xb220, hasher = Blake2b256, digest = Blake2bDigest<32>)] + #[mh(code = 0xb220, hasher = Blake2b256)] Blake2b256, - #[mh(code = 0xb240, hasher = Blake2b512, digest = Blake2bDigest<64>)] + #[mh(code = 0xb240, hasher = Blake2b512)] Blake2b512, - #[mh(code = 0xb250, hasher = Blake2s128, digest = Blake2sDigest<16>)] + #[mh(code = 0xb250, hasher = Blake2s128)] Blake2s128, - #[mh(code = 0xb260, hasher = Blake2s256, digest = Blake2sDigest<32>)] + #[mh(code = 0xb260, hasher = Blake2s256)] Blake2s256, - #[mh(code = 0x1e, hasher = Blake3_256, digest = Blake3Digest<32>)] + #[mh(code = 0x1e, hasher = Blake3_256)] Blake3_256, - #[mh(code = 0x3312e7, hasher = Strobe256, digest = StrobeDigest<16>)] + #[mh(code = 0x3312e7, hasher = Strobe256)] Strobe256, - #[mh(code = 0x3312e8, hasher = Strobe512, digest = StrobeDigest<32>)] + #[mh(code = 0x3312e8, hasher = Strobe512)] Strobe512, } @@ -64,18 +62,11 @@ macro_rules! assert_encode { "{:?} encodes correctly (from code)", stringify!($alg) ); - // From digest - assert_eq!( - Code::multihash_from_digest(&<$alg>::digest($data)).to_bytes(), - expected, - "{:?} encodes correctly (from digest)", stringify!($alg) - ); - // From incremental hashing let mut hasher = <$alg>::default(); hasher.update($data); assert_eq!( - Code::multihash_from_digest(&hasher.finalize()).to_bytes(), + $code.wrap(hasher.finalize()).unwrap().to_bytes(), expected, "{:?} encodes correctly (from hasher)", stringify!($alg) ); @@ -160,7 +151,7 @@ macro_rules! assert_roundtrip { { let mut hasher = <$alg>::default(); hasher.update(b"helloworld"); - let hash = Code::multihash_from_digest(&hasher.finalize()); + let hash = $code.wrap(hasher.finalize()).unwrap(); assert_eq!( Multihash::from_bytes(&hash.to_bytes()).unwrap().code(), hash.code() @@ -170,7 +161,7 @@ macro_rules! assert_roundtrip { { let mut hasher = <$alg>::default(); hasher.write_all(b"helloworld").unwrap(); - let hash = Code::multihash_from_digest(&hasher.finalize()); + let hash = $code.wrap(hasher.finalize()).unwrap(); assert_eq!( Multihash::from_bytes(&hash.to_bytes()).unwrap().code(), hash.code() @@ -203,10 +194,9 @@ fn assert_roundtrip() { } /// Testing the public interface of `Multihash` and coversions to it -fn multihash_methods(code: Code, prefix: &str, digest_str: &str) +fn multihash_methods(code: Code, prefix: &str, digest_str: &str) where - H: StatefulHasher, - Code: for<'a> From<&'a H::Digest>, + H: Hasher + Default, { let digest = hex::decode(digest_str).unwrap(); let expected_bytes = hex::decode(&format!("{}{}", prefix, digest_str)).unwrap(); @@ -227,7 +217,7 @@ where // Test from hasher digest conversion let mut hasher = H::default(); hasher.update(b"hello world"); - let multihash_from_digest = Code::multihash_from_digest(&hasher.finalize()); + let multihash_from_digest = code.wrap(hasher.finalize()).unwrap(); assert_eq!(multihash_from_digest.code(), u64::from(code)); assert_eq!(multihash_from_digest.size() as usize, digest.len()); assert_eq!(multihash_from_digest.digest(), digest); @@ -235,81 +225,77 @@ where #[test] fn test_multihash_methods() { - multihash_methods::( - Code::Identity, - "000b", - "68656c6c6f20776f726c64", - ); - multihash_methods::( + multihash_methods::(Code::Identity, "000b", "68656c6c6f20776f726c64"); + multihash_methods::( Code::Sha1, "1114", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", ); - multihash_methods::( + multihash_methods::( Code::Sha2_256, "1220", "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", ); - multihash_methods::( + multihash_methods::( Code::Sha2_512, "1340", "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"); - multihash_methods::( + multihash_methods::( Code::Sha3_224, "171C", "dfb7f18c77e928bb56faeb2da27291bd790bc1045cde45f3210bb6c5", ); - multihash_methods::( + multihash_methods::( Code::Sha3_256, "1620", "644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938", ); - multihash_methods::( + multihash_methods::( Code::Sha3_384, "1530", "83bff28dde1b1bf5810071c6643c08e5b05bdb836effd70b403ea8ea0a634dc4997eb1053aa3593f590f9c63630dd90b"); - multihash_methods::( + multihash_methods::( Code::Sha3_512, "1440", "840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a"); - multihash_methods::( + multihash_methods::( Code::Keccak224, "1A1C", "25f3ecfebabe99686282f57f5c9e1f18244cfee2813d33f955aae568", ); - multihash_methods::( + multihash_methods::( Code::Keccak256, "1B20", "47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad", ); - multihash_methods::( + multihash_methods::( Code::Keccak384, "1C30", "65fc99339a2a40e99d3c40d695b22f278853ca0f925cde4254bcae5e22ece47e6441f91b6568425adc9d95b0072eb49f"); - multihash_methods::( + multihash_methods::( Code::Keccak512, "1D40", "3ee2b40047b8060f68c67242175660f4174d0af5c01d47168ec20ed619b0b7c42181f40aa1046f39e2ef9efc6910782a998e0013d172458957957fac9405b67d"); - multihash_methods::( + multihash_methods::( Code::Blake2b512, "c0e40240", "021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0"); - multihash_methods::( + multihash_methods::( Code::Blake2s256, "e0e40220", "9aec6806794561107e594b1f6a8a6b0c92a0cba9acf5e5e93cca06f781813b0b", ); - multihash_methods::( + multihash_methods::( Code::Blake2b256, "a0e40220", "256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610", ); - multihash_methods::( + multihash_methods::( Code::Blake2s128, "d0e40210", "37deae0226c30da2ab424a7b8ee14e83", ); - multihash_methods::( + multihash_methods::( Code::Blake3_256, "1e20", "d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24", @@ -319,9 +305,9 @@ fn test_multihash_methods() { #[test] #[should_panic] fn test_long_identity_hash() { - // The identity hash panics if the input size is bigger than the maximum size - let input = b"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz"; - Identity256::digest(input); + // The identity hash allocates if the input size is bigger than the maximum size + let input = b"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz"; + Code::Identity.digest(input); } #[test]