Skip to content

Commit dc0e0f9

Browse files
authored
feat: add Blake3 support (#74)
Implements trivial support for blake3 using the default 32 byte digest.
1 parent e916ea0 commit dc0e0f9

File tree

5 files changed

+103
-21
lines changed

5 files changed

+103
-21
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ edition = "2018"
1313
[dependencies]
1414
blake2b_simd = { version = "0.5.9", default-features = false }
1515
blake2s_simd = { version = "0.5.9", default-features = false }
16+
blake3 = "0.3.5"
1617
digest = { version = "0.8", default-features = false }
1718
sha-1 = { version = "0.8", default-features = false }
1819
sha2 = { version = "0.8", default-features = false }
@@ -23,6 +24,7 @@ rand = { version = "0.7.3", optional = true }
2324

2425
[dev-dependencies]
2526
criterion = "0.3"
27+
hex = "0.4.2"
2628
quickcheck = "0.9.2"
2729
rand = "0.7.3"
2830

benches/multihash.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
22
use rand::Rng;
33

44
use multihash::{
5-
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Identity, Keccak224, Keccak256, Keccak384,
6-
Keccak512, MultihashDigest, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
5+
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3, Identity, Keccak224, Keccak256,
6+
Keccak384, Keccak512, MultihashDigest, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384,
7+
Sha3_512,
78
};
89

910
macro_rules! group_digest {
@@ -61,6 +62,7 @@ fn bench_digest(c: &mut Criterion) {
6162
"blake2b_512" => Blake2b512, &data
6263
"blake2s_128" => Blake2s128, &data
6364
"blake2s_256" => Blake2s256, &data
65+
"blake3" => Blake3, &data
6466
);
6567
}
6668

@@ -85,6 +87,7 @@ fn bench_stream(c: &mut Criterion) {
8587
"blake2b_512" => Blake2b512, &data
8688
"blake2s_128" => Blake2s128, &data
8789
"blake2s_256" => Blake2s256, &data
90+
"blake3" => Blake3, &data
8891
);
8992
}
9093

src/arb.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use rand::seq::SliceRandom;
33

44
use crate::{Code, Code::*, Multihash, MultihashDigest};
55

6-
const HASHES: [Code; 16] = [
6+
const HASHES: [Code; 17] = [
77
Identity, Sha1, Sha2_256, Sha2_512, Sha3_512, Sha3_384, Sha3_256, Sha3_224, Keccak224,
8-
Keccak256, Keccak384, Keccak512, Blake2b256, Blake2b512, Blake2s128, Blake2s256,
8+
Keccak256, Keccak384, Keccak512, Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3,
99
];
1010

1111
/// Generates a random hash algorithm.

src/hashes.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,80 @@ macro_rules! derive_digest {
205205
}
206206
)*
207207
};
208+
($(
209+
#[$doc:meta]
210+
@blake3 $type:ty as $name:ident;
211+
@code_doc $code_doc:literal,
212+
)*) => {
213+
$(
214+
#[$doc]
215+
#[derive(Clone, Debug)]
216+
pub struct $name($type);
217+
impl $name {
218+
#[doc = $code_doc]
219+
pub const CODE: Code = Code::$name;
220+
/// Hash some input and return the Multihash digest.
221+
pub fn digest(data: &[u8]) -> Multihash {
222+
let digest = blake3::hash(data);
223+
wrap(Self::CODE, digest.as_bytes())
224+
}
225+
}
226+
impl Multihasher<Code> for $name {
227+
const CODE: Code = Code::$name;
228+
#[inline]
229+
fn digest(data: &[u8]) -> Multihash {
230+
Self::digest(data)
231+
}
232+
}
233+
impl Default for $name {
234+
fn default() -> Self {
235+
$name(blake3::Hasher::new())
236+
}
237+
}
238+
impl MultihashDigest<Code> for $name {
239+
#[inline]
240+
fn code(&self) -> Code {
241+
Self::CODE
242+
}
243+
#[inline]
244+
fn digest(&self, data: &[u8]) -> Multihash {
245+
Self::digest(data)
246+
}
247+
#[inline]
248+
fn input(&mut self, data: &[u8]) {
249+
self.0.update(data);
250+
}
251+
#[inline]
252+
fn result(self) -> Multihash {
253+
let digest = self.0.finalize();
254+
wrap(Self::CODE, digest.as_bytes())
255+
}
256+
#[inline]
257+
fn result_reset(&mut self) -> Multihash {
258+
let digest = self.0.finalize();
259+
let hash = wrap(Self::CODE, digest.as_bytes());
260+
self.0.reset();
261+
hash
262+
}
263+
#[inline]
264+
fn reset(&mut self) {
265+
self.0.reset();
266+
}
267+
}
268+
impl ::std::io::Write for $name {
269+
#[inline]
270+
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
271+
<$name as MultihashDigest<Code>>::input(self, buf);
272+
Ok(buf.len())
273+
}
274+
#[inline]
275+
fn flush(&mut self) -> ::std::io::Result<()> {
276+
self.0.finalize();
277+
Ok(())
278+
}
279+
}
280+
)*
281+
}
208282
}
209283

210284
impl_code! {
@@ -240,6 +314,8 @@ impl_code! {
240314
Blake2s128 => 0xb250,
241315
/// BLAKE2s-256 (32-byte hash size)
242316
Blake2s256 => 0xb260,
317+
/// BLAKE3 (32-byte hash size)
318+
Blake3 => 0x1e,
243319
}
244320

245321
/// The Identity hasher.
@@ -344,3 +420,8 @@ derive_digest! {
344420
@blake Blake2s | Blake2sParams as Blake2s256 32;
345421
@code_doc "The code of the Blake2-256 hasher, 0xb260.",
346422
}
423+
derive_digest! {
424+
/// The Blake3 hasher.
425+
@blake3 blake3::Hasher as Blake3;
426+
@code_doc "The code of the Blake3 hasher, 0x1e.",
427+
}

tests/lib.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,20 @@
11
use multihash::*;
22

3-
/// Helper function to convert a hex-encoded byte array back into a bytearray
4-
fn hex_to_bytes(s: &str) -> Vec<u8> {
5-
let mut c = 0;
6-
let mut v = Vec::new();
7-
while c < s.len() {
8-
v.push(u8::from_str_radix(&s[c..c + 2], 16).unwrap());
9-
c += 2;
10-
}
11-
v
12-
}
13-
143
macro_rules! assert_encode {
154
{$( $alg:ty, $data:expr, $expect:expr; )*} => {
165
$(
17-
let hex = hex_to_bytes($expect);
6+
let bytes = hex::decode($expect).unwrap();
187
assert_eq!(
198
<$alg>::digest($data).into_bytes(),
20-
hex,
9+
bytes,
2110
"{:?} encodes correctly", stringify!($alg)
2211
);
2312

2413
let mut hasher = <$alg>::default();
2514
&mut hasher.input($data);
2615
assert_eq!(
2716
hasher.result().into_bytes(),
28-
hex,
17+
bytes,
2918
"{:?} encodes correctly", stringify!($alg)
3019
);
3120
)*
@@ -55,13 +44,14 @@ fn multihash_encode() {
5544
Blake2s256, b"hello world", "e0e402209aec6806794561107e594b1f6a8a6b0c92a0cba9acf5e5e93cca06f781813b0b";
5645
Blake2b256, b"hello world", "a0e40220256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610";
5746
Blake2s128, b"hello world", "d0e4021037deae0226c30da2ab424a7b8ee14e83";
47+
Blake3, b"hello world", "1e20d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24";
5848
}
5949
}
6050

6151
macro_rules! assert_decode {
6252
{$( $alg:ty, $hash:expr; )*} => {
6353
$(
64-
let hash = hex_to_bytes($hash);
54+
let hash = hex::decode($hash).unwrap();
6555
assert_eq!(
6656
MultihashRef::from_slice(&hash).unwrap().algorithm(),
6757
<$alg>::CODE,
@@ -91,6 +81,7 @@ fn assert_decode() {
9181
Blake2s256, "e0e402209aec6806794561107e594b1f6a8a6b0c92a0cba9acf5e5e93cca06f781813b0b";
9282
Blake2b256, "a0e40220256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610";
9383
Blake2s128, "d0e4021037deae0226c30da2ab424a7b8ee14e83";
84+
Blake3, "1e20d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24";
9485
}
9586
}
9687

@@ -128,15 +119,15 @@ fn assert_roundtrip() {
128119

129120
/// Testing the public interface of `Multihash` and `MultihashRef`
130121
fn test_methods(hash: impl MultihashDigest<Code>, prefix: &str, digest: &str) {
131-
let expected_bytes = hex_to_bytes(&format!("{}{}", prefix, digest));
122+
let expected_bytes = hex::decode(&format!("{}{}", prefix, digest)).unwrap();
132123
let multihash = hash.digest(b"hello world");
133124
assert_eq!(
134125
Multihash::from_bytes(expected_bytes.clone()).unwrap(),
135126
multihash
136127
);
137128
assert_eq!(multihash.as_bytes(), &expected_bytes[..]);
138129
assert_eq!(multihash.algorithm(), hash.code());
139-
assert_eq!(multihash.digest(), &hex_to_bytes(digest)[..]);
130+
assert_eq!(multihash.digest(), hex::decode(digest).unwrap().as_slice());
140131

141132
let multihash_ref = multihash.as_ref();
142133
assert_eq!(multihash, multihash_ref);
@@ -226,6 +217,11 @@ fn multihash_methods() {
226217
"d0e40210",
227218
"37deae0226c30da2ab424a7b8ee14e83",
228219
);
220+
test_methods(
221+
Blake3::default(),
222+
"1e20",
223+
"d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24",
224+
);
229225
}
230226

231227
#[test]

0 commit comments

Comments
 (0)