The BLAKE3 cryptographic hash function
github.com
github.com
The first change is reducing the number of rounds from 10 to 7. Think of it like making a smoothie - you add bits of fruit to the drink (the input data), then pulse the blades to blend it up (making the output hash). This change basically runs the blades for 7 seconds instead of 10 seconds each time they add fruit. They cite evidence that the extra 3 seconds aren't doing much - once the fruit's fully liquid, extra blending doesn't help - but I worry that this reduces the security margin. Maybe those extra 3 rounds aren't useful against current attacks, but they may be useful against unknown future attacks.
The other change they make is to break the input into 1KiB chunks, then hash each chunk independently. Finally, they combine the individual chunk hashes into a single big hash using a binary tree. The benefit is that if you have 4KiB of data, you can use 4-way SIMD instructions to process all four chunks simultaneously. The more data you have, the more parallelism you can unlock, unlike traditional hash functions that process everything sequentially. On the flip side, modern SIMD instructions can handle 2 x 32-bit instructions just as fast as 1 x 64-bit instructions, so building the algorithm out of 32-bit arithmetic doesn't cost anything, but gives a big boost to low-end 32-bit CPU's that struggle with 64-bit arithmetic. The tree structure is a big win overall.
With hashes of hashes, the prefixes have to be the same length, and possibly very short.
This was covered in more detail in previous "Too Much Crypto" paper [1], which argued that many standards have excessively high round counts. Note that Aumasson is author of both Blake3 and Too Much Crypto
> Our goal is to propose numbers of rounds for which we have strong confidence that the algorithm will never be wounded
They take algorithms, past 10 years of public crypto research and shave off rounds, until it just about starts falling apart. AFAIU having security-reducing attacks is the target.
I prefer to have ample confidence in my crypto algorithms. Would not recommend BLAKE3 (without those extra rounds).
time openssl sha256 /tmp/bigfile
real 0m28.160s
user 0m27.750s
sys 0m0.272s
time shasum -a 256 /tmp/bigfile real 0m6.146s
user 0m5.407s
sys 0m0.560s
time b2sum /tmp/bigfile real 0m1.732s
user 0m1.450s
sys 0m0.244s
time b3sum /tmp/bigfile real 0m0.212s
user 0m0.996s
sys 0m0.379s
TIL OpenSSL sha256 invocation is really slow compared to the shasum program. Also BLAKE3 is really fast.Edit: bigfile is 1GB of /dev/random
sha256sum uses 128KiB blocks when reading, which may be more optimized than the openssl program.
sha256sum supports using openssl libs as they are generally faster. This is enabled on Red Hat flavored distros and arch, but not debian flavored as yet
The upcoming release of sha256sum (8.32) will auto enable use of openssl for >= v 3, as openssl's licence has changed to apache in that version
b3sum ./1GB 0m0.124s
md5sum ./1GB 0m1.620s
sha512sum ./1GB 0m2.988s
sha256sum ./1GB 0m4.738s
I was even more impressed when I timed dd: $ time dd if=./1GB of=/dev/null bs=65536
16384+0 records in
16384+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.10451 s, 10.3 GB/s
real 0m0.107sI remember watching Bao, a general purpose cryptographic tree hash, and perhaps the fastest hash function in the world: https://www.youtube.com/watch?v=Dya9c2DXMqQ a while ago.
Nice job!
The README lists 4 designers, including yourself. However the Bao project doesn't list anybody, so presumably you are the only designer. What exactly were the contributions of the other 3 people to warrant being listed?
At what point did the Bao project become "BLAKE3" and why?
https://github.com/BLAKE3-team/BLAKE3/blob/master/reference_...
https://github.com/BLAKE2/BLAKE2/blob/master/ref/blake2b-ref...
Which, yeah, that alone will get you a significant improvement over Blake2B. But definitely doesn't account for the huge improvement they're showing. Most of that is the ability to take advantage of AVX512 parallelism, I think. The difference will be more incremental on AVX2-only amd64 or other platforms, I think.
[1]: Well, TMC recommended 8 rounds for Blake2B and 7 for Blake2S.
Not surprising considering that one of they is the author of Too Much Crypto
b3sum -l 256 big-2.6Gfile
real 0m0.384s
user 0m2.302s
sys 0m0.175s
b2sum -l 256 big-2.6Gfile rear 0m3.616s
user 0m3.360s
sys 0m0.256s
(Intel® Core™ i7-8550U CPU @ 1.80GHz × 8 )EDIT: ah, the catch. blake3 targets 128 bit security. It competes with SipHash for speed and security
EDIT2 scratch the previous edit.
No no, BLAKE3 is a general-purpose cryptographic hash just like BLAKE2, SHA-2, and SHA-3. The confusion here is that a hash function's security level is half of its output size, because of the birthday problem. BLAKE3, like BLAKE2s and SHA-256, has a 256-bit output and a 128-bit security level. (BLAKE3 also supports extendable output, but that doesn't affect the security level.)
> holy moly it really is fast
Thank you :)
A hash can have different security levels against different attacks. BLAKE3 appears to have 128 bits of security against all attacks.
SHA3-256 was originally designed to have 128 bits of collision security and 256 bits of preimage security. NIST then made a change to it giving it 128 bits of security against all attacks. A lot of people got mad. Then NIST caved and changed it back to 128 bits of collision security and 256 bits of preimage security.
It looks like BLAKE3 agrees with how NIST wanted SHA3 to be. I wonder if people will be mad at BLAKE3.
https://en.wikipedia.org/wiki/SHA-3#Capacity_change_controve...
For a more fair performance comparison against SHA3, you should compare against SHAKE128(256). That is, the version with 128 bits of security all around and a 256 bit output (how NIST wanted it). Although maybe it's pointless, because according to Wikipedia SHAKE128(256) is only 8% faster than SHA3-256 for large inputs.
I don't know if you need twice as many bits of preimage resistance, but I'd feel a lot more comfortable with an extra 32.
Would a 128 bit difficulty preimage attack against SHAKE128(256) be as simple as trying every single input? Trying every single input would be a 256 bit difficulty attack I would assume. To get it to a 128 bit attack I would think the attack would need something more advanced.
You do need a more complex calculation to try to mount a preimage attack. But from what I can figure out it still tends to use big blocks of standalone arithmetic, something that's still very easy to accelerate with limited I/O.
This is mainly due to SHA3's humongous 1600-bit state, which is not very friendly to embedded systems. In sponge constructions with smaller states, or generally primitives with smaller states, the difference is much larger.
Also in general I would say that small message performance is usually more important than large message performance, since large messages with desktop/laptop CPUs are so incredibly fast anyway with most hash functions that the bottleneck goes somewhere else. (Storage, network, etc.)
That's not accurate. The best pseudo-preimage attack on BLAKE2s has complexity 2^{253.8} against 6.75 rounds (section 3.2 of https://eprint.iacr.org/2019/1492.pdf ). The best full-preimage attack on BLAKE2s is against 2.75 rounds. BLAKE3's round function is identical to BLAKE2s (although used in a different mode). Currently there isn't any known classical preimage attack on BLAKE3 better than these ones against reduced BLAKE2s. This should be interpreted with caution since the design has only just been published.
[Disclosure of interest: I know Zooko and work for Electric Coin Company. This is only based on a cursory review of the paper, though; I had not seen it prior to publication.]
-- Daira Hopwood
Skimming and interpreting the Too Much Crypto paper[1], the security target is strictly less than 128-bit security. If it maintained 128-bit security, it would be considered too many rounds.
Not really. 128 bits for collision (using a 256 bit hash) is not the same as 128 bits for key recovery or preimage. It is much, much stronger.
Preimage and key recovery attacks have a linear drop off: halving the number of tries halves your chances of success. Collisions have a quadratic drop off: halving your number of tries divides your chances of success by four.
Moreover, it is easier to find one key if you have many keys to try (finding 1 key among N is N times easier than finding any specific key). No such considerations for collisions: finding any collision is just as hard as finding one collision among many.
512-bit hashes were never needed for their security levels. Though in some circumstances (deriving multiple keys, EdDSA), bigger digests come in handy.
On the other hand if someone says "I want < 99% chance of an attack" then 128 bits of preimage resistance will be more secure. But people probably don't have this goal, so 128 bits of collision resistance is better overall.
But another aspect is once you start finding collisions, you're likely to find more faster (whereas with preimages they keep coming linearly). This would actually be a worse point for collision resistance.
> (finding 1 key among N is N times easier than finding any specific key)
Yes, but only up to a point. You have to compare the cost of computing a hash vs comparing the hash. If the time to hash is 10000x the time to compare, then no matter how large N is, you'll never get faster than a 10000x speedup. This is essentially Amdahl's law. But this speedup is still quite significant.
In my extremely limited testing (on AVX2, but not AVX512 hardware), (buffered) reduced (four) round Chacha is only about 1.5-2x slower than fast non-cryptographic PRNGs like JSF, SFC, Lehmer, or pcg64_fast (all with Clang -O2 -flto, the fast PRNGs are header-only implementations and only chacha is two files).
This thing still uses 7 rounds, but that is easy to tune down. Very neat.
Blake3 wouldn't compete with Chacha20, it would compete with Chacha8.
I'm working on exporting the rust version to C, so all can be compared properly.
https://github.com/ndsol/git-mine/blob/master/sha1.cl
We are considering doing a Blake3 implementation, but haven't committed to do it yet.
http://rurban.github.io/smhasher/doc/table.html
It's of course much faster as most of the other crypto hashes, but not faster than the hardware variants of SHA1-NI and SHA256-NI. About 4x faster than blake2.
Faster than SipHash, not faster than SipHash13.
The tests fail on MomentChi2 dramatically, which describe how good the user-provided random seed is mixed in. I tried by mixing a seed for IV[0], as with all other hardened crypto hashes, and for all 8 IV's, which didn't help. So I'm not convinced that a seeded IV is properly mixed in. Which is outside the usage pattern of a crypto or digest hash (b3sum), but inside a normal usage.
Rust staticlib is still in work, which would parallize the hashing in chunks for big keys. For small keys it should be even a bit slower. b3sum is so much faster, because it uses many more tricks, such as mmap.
The numbers look astonishing.
Clearly the benefits of AVX512 really exaggerate the comparison on hardware that supports it, and the benefit over Blake2S is pretty muted on hardware without vector intrinsics (low end 32-bit ARM). But I'm interested in the middle — e.g., Zen1/2 AMD, Broadwell and earlier Intel x86-64.
Thanks!
This made me curious. Is it because at this stage it is a proposal that has not yet been verified/analysed or are there actual reasons that you know of that make this not "general purpose strong"?
I do believe that it meets the requirements for being a MAC function, and I'm completely certain that it is a great non-cryptographic hash function.
time ~/.cargo/bin/b3sum ubuntu-19.10-beta-desktop-amd64.iso 0899b731b6b57d75a65273fe29d54802653b3bbe3bae6732140c487c4f0ece71 ubuntu-19.10-beta-desktop-amd64.iso
real 0m0,180s user 0m1,735s sys 0m0,092s
time meow_example ubuntu-19.10-beta-desktop-amd64.iso meow_example 0.5/calico - basic usage example of the Meow hash (C) Copyright 2018-2019 by Molly Rocket, Inc. (https://mollyrocket.com) See https://mollyrocket.com/meowhash for details.
Hash of "ubuntu-19.10-beta-desktop-amd64.iso":
E5CC524A-522BDE7E-ED34A277-5C7D73AF
real 0m0,766s
user 0m0,119s
sys 0m0,645s Benchmark #1: cat b1
Time (mean ± σ): 1.076 s ± 0.007 s [User: 5.3 ms, System: 1069.4 ms]
Range (min … max): 1.069 s … 1.093 s 10 runs
Benchmark #2: sha256sum b1
Time (mean ± σ): 6.583 s ± 0.064 s [User: 5.440 s, System: 1.137 s]
Range (min … max): 6.506 s … 6.695 s 10 runs
Benchmark #3: sha1sum b1
Time (mean ± σ): 6.322 s ± 0.086 s [User: 5.212 s, System: 1.103 s]
Range (min … max): 6.214 s … 6.484 s 10 runs
Benchmark #4: b2sum b1
Time (mean ± σ): 13.184 s ± 0.108 s [User: 12.090 s, System: 1.080 s]
Range (min … max): 13.087 s … 13.382 s 10 runs
Benchmark #5: b3sum b1
Time (mean ± σ): 577.0 ms ± 5.4 ms [User: 12.276 s, System: 0.669 s]
Range (min … max): 572.4 ms … 587.0 ms 10 runs
Benchmark #6: md5sum b1
Time (mean ± σ): 14.851 s ± 0.175 s [User: 13.717 s, System: 1.117 s]
Range (min … max): 14.495 s … 15.128 s 10 runs
Summary
'b3sum b1' ran
1.86 ± 0.02 times faster than 'cat b1'
10.96 ± 0.18 times faster than 'sha1sum b1'
11.41 ± 0.15 times faster than 'sha256sum b1'
22.85 ± 0.28 times faster than 'b2sum b1'
25.74 ± 0.39 times faster than 'md5sum b1'
gotdang that's some solid performance. (here running against 10GiB of random bytes; machine has the Sha ASM extensions, which is why sha256/sha1 perform so well)edit: actually not a straight algo comparison, as b3sum here is heavily benefiting from multi-threading; without that it looks more like this:
Benchmark #1: cat b1
Time (mean ± σ): 1.090 s ± 0.007 s [User: 2.9 ms, System: 1084.8 ms]
Range (min … max): 1.071 s … 1.096 s 10 runs
Benchmark #2: sha256sum b1
Time (mean ± σ): 6.480 s ± 0.097 s [User: 5.359 s, System: 1.115 s]
Range (min … max): 6.346 s … 6.587 s 10 runs
Benchmark #3: sha1sum b1
Time (mean ± σ): 6.120 s ± 0.090 s [User: 5.027 s, System: 1.082 s]
Range (min … max): 5.979 s … 6.233 s 10 runs
Benchmark #4: b2sum b1
Time (mean ± σ): 12.866 s ± 0.208 s [User: 11.722 s, System: 1.133 s]
Range (min … max): 12.549 s … 13.124 s 10 runs
Benchmark #5: b3sum b1
Time (mean ± σ): 5.813 s ± 0.079 s [User: 4.606 s, System: 1.202 s]
Range (min … max): 5.699 s … 5.933 s 10 runs
Benchmark #6: md5sum b1
Time (mean ± σ): 14.355 s ± 0.184 s [User: 13.305 s, System: 1.039 s]
Range (min … max): 14.119 s … 14.605 s 10 runs
Summary
'cat b1' ran
5.33 ± 0.08 times faster than 'b3sum b1'
5.62 ± 0.09 times faster than 'sha1sum b1'
5.95 ± 0.10 times faster than 'sha256sum b1'
11.81 ± 0.21 times faster than 'b2sum b1'
13.17 ± 0.19 times faster than 'md5sum b1'
still beating the dedicated sha extensions, but not nearly as dramatically.I'm guessing not for password hashes simply because a fast hash is bad for passwords (makes brute forcing/rainbow tables easier).
So is this mostly just for file signing?
While programming, just try to think of a scenario where having a mapping between some kind of arbitrary data (and maybe a key) and a fixed-size, uniformly random-looking output could be useful. Opportunities to sprinkle some hashes on things come up quite often when you look for them.
My understanding is that plenty of stream ciphers are based on hashes. For example each block of the stream can be hash(key + nonce + block counter + constants) that you xor with your plaintext (or don't, if you just want a CSPRNG).
Is this frequently done in practice? The CSPRNG code for ChaCha20 I've looked at rotates the key itself using 32 out of every 768 bytes. In that case rolling the counter isn't a concern.
Now I wonder where this 768 bytes could possibly come from. It's only a multiple of 256, which can only take advantage of 128-bit vectors (4 blocks at a time). Ideally you want an 8 way parallelism (AVX2) or even 16 way parallelism (AVX-512). That is, either 512 byte blocks, or 1024 byte blocks.
I believe the 768 byte figure comes from DJB's blog on fast key erasure[1]. Why he picked 768, I do not know.
This is totally implementation defined, it's not required by the spec. As loeg says (below) I was looking at a reference implementation by djb. I did a quick skim of OpenBSD's arc4random (which also uses ChaCha20) and if I'm reading it correctly, it rekeys every 1024 bytes.
> Ideally you want an 8 way parallelism (AVX2) or even 16 way parallelism (AVX-512)
My guess is that 768 was thought to be a decent enough trade-off between maximum and average latency for calls to the CSPRNG. I wouldn't be surprised to see that most implementations that are optimized for specific CPU architectures use different values.
As far as I can tell, BLAKE2 has effectively all the properties BLAKE3 has (arbitrary output length, keyed hash mode), so the upgrade for communications boils down to negotiating/determining which of the two hash functions to use over the wire (with all the downsides that come with agility of cryptographic primitives); for stored hashes, they have to be recomputed and replaced (or you could store a flag is BLAKE2/is BLAKE3 and update them as you touch hashes, kind of similar to how password hashes are swapped at login time).
Note that BLAKE3 existing doesn't break BLAKE2. It's perfectly fine to just keep trucking BLAKE2, it's just that BLAKE3 has better performance characteristics that make it very attractive.
Though for Wireguard, you'd compete with Blake2b as well, which has the advantage of using 64-bit words. And if you want a fair comparison, you should reduce the rounds of Blake2b down to 8 (instead of 12), as recommended in Aumasson's "Too Much Crypto".
On a 64-bit machine, such a reduced Blake2b would be much faster than Blake3 on inputs greater than 128 bytes and smaller than 4Kib.
The concern about 64-bit machines and using 64-bit word sizes vs 32-bit word sizes really only matters if your 64-bit machine doesn't have SIMD vector extensions. (All amd64 hardware, for example, has at least SSE2.) And as they point out, being 32-bit native really helps on low-end 32-bit machines without SIMD intrinsics.
(Re: the hypothetical, if wireguard were to do a protocol revision and replace Blake2B with this, it would make sense to also replace Chacha20 with Chacha8 or 12 at the same time. I doubt the WG authors will do any such thing any time soon.)
My understanding is that for password hashing you want two things - cryptographic security (can't go from hash -> password by attacking the algorithm ) - and you want it to be "as slow as is usable" to counter brute force attacks? Also per-password salts like bcrypt uses counters rainbow attacks don't hurt.
What else do you need to do to keep it secure ?
The first two references you cite are attacks against a password hash. Blake3 is not a password hash, it is a general-purpose hash.
The third reference is not an attack on the hash function timing, it is an attack against hash table timing, which is not at all the same thing. From the abstract:
"Our attack does not rely on any weakness of a particular hash function and can work against any hash."
Once again: Blake3 is a general-purpose hash, not a password hash. General-purpose hashes cannot be constant-time because they must operate on inputs of arbitrary length.
And each round of Blake3 is constant-time, irrespective of input. We're talking about rounds (or, alternatively, constant-time for equivalent length input).
It's a little unclear whether rurban was saying that they must have this property, or merely that they do have it. But that is neither here nor there because...
> each round of Blake3 is constant-time
That is not the same thing as the entire algorithm being constant-time.
This whole thread has turned into a horrible mess.
Yes, all else being equal, constant time/power is nice to have. But the only circumstance under which it is necessary is if you are processing secret data in a situation where an adversary can potentially observe side channels. But this is true for any algorithm, not just hashes. Furthermore, most common application of hashing a secret is password hashing, and there is is much more important that the hash be expensive than that it be constant time and power.
But Blake3 is not a password hash. It can be used as a component of a password hash, and there its constant-round time becomes a useful property. But to emphasize this in the context in which rurban's comment appears is at best badly misleading.
> Capable of verified streaming and incremental updates, again because it's a Merkle tree.
I don't really understand what this means (verified streaming + incremental updates), could someone clarify? Merkle Trees are simple (https://en.wikipedia.org/wiki/Merkle_tree for people who don't know)
Basically to verify a video file using serial hash functions you need to download the entire video file before you can perform the hashing. In BLAKE3 you can verify each chunk of the video as it is being streamed because the hash internally is just a Merkle Tree.