diff --git a/src/hasher_impl.rs b/src/hasher_impl.rs index 925e47c6..24a04aa2 100644 --- a/src/hasher_impl.rs +++ b/src/hasher_impl.rs @@ -102,6 +102,14 @@ pub mod blake3 { digest: [u8; S], } + impl Blake3Hasher { + /// using blake3's XOF function, fills the given slice with hash output + pub fn finalize_xof_fill(&mut self, digest_out: &mut [u8]) { + let mut digest = self.hasher.finalize_xof(); + digest.fill(digest_out) + } + } + impl Default for Blake3Hasher { fn default() -> Self { let hasher = ::blake3::Hasher::new(); @@ -119,11 +127,9 @@ pub mod blake3 { } fn finalize(&mut self) -> &[u8] { - let digest = self.hasher.finalize(); //default is 32 bytes anyway - 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 + let mut output = self.hasher.finalize_xof(); + output.fill(&mut self.digest); + &self.digest } fn reset(&mut self) { diff --git a/tests/lib.rs b/tests/lib.rs index 3fdcba3b..cd475d16 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -335,3 +335,43 @@ fn multihash_errors() { "Should error on wrong hash length" ); } + +#[test] +fn blak3_non_default_digest() { + use multihash::Blake3Hasher; + const DIGEST_SIZE: usize = 16; + pub struct ContentHasher(Blake3Hasher); + + pub struct ContentHash([u8; DIGEST_SIZE]); + + impl ContentHasher { + fn new() -> ContentHasher { + ContentHasher(Blake3Hasher::default()) + } + + fn write(&mut self, input: &[u8]) { + self.0.update(input); + } + + fn finish(&mut self) -> ContentHash { + let hash = multihash::Code::Blake3_256.wrap(self.0.finalize()).unwrap(); + let resized_hash = hash.resize::().unwrap(); + + let mut content = ContentHash([0u8; DIGEST_SIZE]); + content.0.copy_from_slice(resized_hash.digest()); + content + } + + fn reset(&mut self) { + self.0.reset(); + } + } + + let mut hasher = ContentHasher::new(); + hasher.write("foobar".as_bytes()); + let content_hash = hasher.finish(); + hasher.reset(); + + let expected = hex::decode("aa51dcd43d5c6c5203ee16906fd6b35d").unwrap(); + assert_eq!(&content_hash.0, expected.as_slice()) +}