BLAKE3 Documentation

The official Rust and C implementations of the BLAKE3 cryptographic hash function

6,208 stars Assembly 1 file ยท ~6,580 tokens
RAW Doc

File: README.md

BLAKE3

BLAKE3 is a cryptographic hash function that is:

  • Much faster than MD5, SHA-1, SHA-2, SHA-3, and BLAKE2.
  • Secure, unlike MD5 and SHA-1. And secure against length extension,
    unlike SHA-2.
  • Highly parallelizable across any number of threads and SIMD lanes,
    because it's a Merkle tree on the inside.
  • Capable of verified streaming and incremental updates, again
    because it's a Merkle tree.
  • A PRF, MAC, KDF, and XOF, as well as a regular hash.
  • One algorithm with no variants, which is fast on x86-64 and also
    on smaller architectures.

The chart below
is an example benchmark of 16 KiB inputs on a Cascade Lake-SP 8275CL server CPU
from 2019. For more detailed benchmarks, see the
BLAKE3 paper.

BLAKE3 is based on an optimized instance of the established hash
function BLAKE2 and on the original Bao tree
mode
.
The specifications and design rationale are available in the BLAKE3
paper
.
The default output size is 256 bits. The current version of
Bao implements verified streaming
with BLAKE3.

This repository is the official implementation of BLAKE3. It includes:

  • The blake3 Rust crate, which
    includes optimized implementations for SSE2, SSE4.1, AVX2, AVX-512,
    NEON, and WASM, with automatic runtime CPU feature detection on x86.
    The rayon feature provides multithreading.

  • The b3sum Rust crate, which
    provides a command line interface. It uses multithreading by default,
    making it an order of magnitude faster than e.g. sha256sum on
    typical desktop hardware.

  • The C implementation, which like the Rust implementation includes SIMD
    optimizations (all except WASM), CPU feature detection on x86, and optional
    multithreading. See c/README.md.

  • The Rust reference implementation,
    which is discussed in Section 5.1 of the BLAKE3
    paper
    .
    This implementation is much smaller and simpler than the optimized
    ones above. If you want to see how BLAKE3 works, or you're writing a
    port that doesn't need multithreading or SIMD optimizations, start
    here. Ports of the reference implementation to other languages are
    hosted in separate repositories
    (C,
    Python).

  • A set of test
    vectors

    that covers extended outputs, all three modes, and a variety of input
    lengths.

BLAKE3 was designed by:

The development of BLAKE3 was sponsored by Electric Coin Company.

BLAKE3 is also specified in the Community
Cryptography Specification Project (C2SP)
.

NOTE: BLAKE3 is not a password hashing algorithm, because it's
designed to be fast, whereas password hashing should not be fast. If you
hash passwords to store the hashes or if you derive keys from passwords,
we recommend Argon2.

Usage

The `b3sum` utility

The b3sum command line utility prints the BLAKE3 hashes of files or of
standard input. Prebuilt binaries are available for Linux, Windows, and
macOS (requiring the unidentified developer
workaround
)
on the releases page.
If you've installed Rust and
Cargo
,
you can also build b3sum yourself with:

bash
cargo install b3sum

If rustup didn't configure your PATH for you, you might need to go
looking for the installed binary in e.g. ~/.cargo/bin. You can test
out how fast BLAKE3 is on your machine by creating a big file and
hashing it, for example:

bash
# Create a 1 GB file.
head -c 1000000000 /dev/zero > /tmp/bigfile
# Hash it with SHA-256.
time openssl sha256 /tmp/bigfile
# Hash it with BLAKE3.
time b3sum /tmp/bigfile

The `blake3` crate [](https://docs.rs/blake3)

To use BLAKE3 from Rust code, add a dependency on the blake3 crate to
your Cargo.toml. Here's an example of hashing some input bytes:

rust
// Hash an input all at once.
let hash1 = blake3::hash(b"foobarbaz");

// Hash an input incrementally.
let mut hasher = blake3::Hasher::new();
hasher.update(b"foo");
hasher.update(b"bar");
hasher.update(b"baz");
let hash2 = hasher.finalize();
assert_eq!(hash1, hash2);

// Extended output. OutputReader also implements Read and Seek.
let mut output = [0; 1000];
let mut output_reader = hasher.finalize_xof();
output_reader.fill(&mut output);
assert_eq!(hash1, output[..32]);

// Print a hash as hex.
println!("{}", hash1);

Besides hash, BLAKE3 provides two other modes, keyed_hash and
derive_key. The keyed_hash mode takes a 256-bit key:

rust
// MAC an input all at once.
let example_key = [42u8; 32];
let mac1 = blake3::keyed_hash(&example_key, b"example input");

// MAC incrementally.
let mut hasher = blake3::Hasher::new_keyed(&example_key);
hasher.update(b"example input");
let mac2 = hasher.finalize();
assert_eq!(mac1, mac2);

The derive_key mode takes a context string and some key material (not a
password). The context string should be hardcoded, globally unique, and
application-specific. A good default format for the context string is
"[application] [commit timestamp] [purpose]":

rust
// Derive a couple of subkeys for different purposes.
const EMAIL_CONTEXT: &str = "BLAKE3 example 2020-01-07 17:10:44 email key";
const API_CONTEXT: &str = "BLAKE3 example 2020-01-07 17:11:21 API key";
let input_key_material = b"usually at least 32 random bytes, not a password";
let email_key = blake3::derive_key(EMAIL_CONTEXT, input_key_material);
let api_key = blake3::derive_key(API_CONTEXT, input_key_material);
assert_ne!(email_key, api_key);

The C implementation

See c/README.md.

Other implementations

There are too many implementations out there for us to keep track of,
but some highlights include an optimized Go
implementation
, Wasm bindings for
Node.js and browsers
, binary
wheels for Python
, .NET
bindings
, and a pure Java
implementation
.

Contributing

Please see CONTRIBUTING.md.

Licenses

This work is released into the public domain with CC0 1.0.
Alternatively, it is licensed under any of the following:

Adoption & deployment

Miscellany


File: b3sum/README.md

b3sum

A command line utility for calculating
BLAKE3 hashes, similar to
Coreutils tools like b2sum or md5sum.

text
Usage: b3sum [OPTIONS] [FILE]...

Arguments:
  [FILE]...  Files to hash, or checkfiles to check

Options:
      --keyed                 Use the keyed mode, reading the 32-byte key from stdin
      --derive-key <CONTEXT>  Use the key derivation mode, with the given context string
  -l, --length <LEN>          The number of output bytes, before hex encoding [default: 32]
      --seek <SEEK>           The starting output byte offset, before hex encoding [default: 0]
      --num-threads <NUM>     The maximum number of threads to use
      --no-mmap               Disable memory mapping
      --no-names              Omit filenames in the output
      --raw                   Write raw output bytes to stdout, rather than hex
      --tag                   Output BSD-style checksums: BLAKE3 ([FILE]) = [HASH]
  -c, --check                 Read BLAKE3 sums from the [FILE]s and check them
      --quiet                 Skip printing OK for each checked file
  -h, --help                  Print help (see more with '--help')
  -V, --version               Print version

See also this document about how the --check flag
works
.

Example

Hash the file foo.txt:

bash
b3sum foo.txt

Time hashing a gigabyte of data, to see how fast it is:

bash
# Create a 1 GB file.
head -c 1000000000 /dev/zero > /tmp/bigfile
# Hash it with SHA-256.
time openssl sha256 /tmp/bigfile
# Hash it with BLAKE3.
time b3sum /tmp/bigfile

Installation

Prebuilt binaries are available for Linux, Windows, and macOS (requiring
the unidentified developer
workaround
)
on the releases page.
If you've installed Rust and
Cargo
,
you can also build b3sum yourself with:

text
cargo install b3sum

On Linux for example, Cargo will put the compiled binary in
~/.cargo/bin. You might want to add that directory to your $PATH, or
rustup might have done it for you when you installed Cargo.

If you want to install directly from this directory, you can run cargo install --path .. Or you can just build with cargo build --release,
which puts the binary at ./target/release/b3sum.


File: c/blake3_c_rust_bindings/README.md

These are Rust bindings for the C implementation of BLAKE3. As there is
a native Rust implementation of BLAKE3 provided in this same repo, these
bindings are not expected to be used in production. They're intended for
testing and benchmarking.


File: c/README.md

The official C implementation of BLAKE3.

Example

An example program that hashes bytes from standard input and prints the
result:

c
#include "blake3.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include 

int main(void) {
  // Initialize the hasher.
  blake3_hasher hasher;
  blake3_hasher_init(&hasher);

  // Read input bytes from stdin.
  unsigned char buf[65536];
  while (1) {
    ssize_t n = read(STDIN_FILENO, buf, sizeof(buf));
    if (n > 0) {
      blake3_hasher_update(&hasher, buf, n);
    } else if (n == 0) {
      break; // end of file
    } else {
      fprintf(stderr, "read failed: %s\n", strerror(errno));
      return 1;
    }
  }

  // Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes.
  uint8_t output[BLAKE3_OUT_LEN];
  blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN);

  // Print the hash as hexadecimal.
  for (size_t i = 0; i < BLAKE3_OUT_LEN; i++) {
    printf("%02x", output[i]);
  }
  printf("\n");
  return 0;
}

The code above is included in this directory as example.c. If you're
on x86_64 with a Unix-like OS, you can compile a working binary like
this:

bash
gcc -O3 -o example example.c blake3.c blake3_dispatch.c blake3_portable.c \
    blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S blake3_avx2_x86-64_unix.S \
    blake3_avx512_x86-64_unix.S

API

The Struct

c
typedef struct {
  // private fields
} blake3_hasher;

An incremental BLAKE3 hashing state, which can accept any number of
updates. This implementation doesn't allocate any heap memory, but
sizeof(blake3_hasher) itself is relatively large, currently 1912 bytes
on x86-64. This size can be reduced by restricting the maximum input
length, as described in Section 5.4 of the BLAKE3
spec
,
but this implementation doesn't currently support that strategy.

Common API Functions

c
void blake3_hasher_init(
  blake3_hasher *self);

Initialize a blake3_hasher in the default hashing mode.


c
void blake3_hasher_update(
  blake3_hasher *self,
  const void *input,
  size_t input_len);

Add input to the hasher. This can be called any number of times. This function
is always single-threaded; for multithreading see blake3_hasher_update_tbb
below.


c
void blake3_hasher_finalize(
  const blake3_hasher *self,
  uint8_t *out,
  size_t out_len);

Finalize the hasher and return an output of any length, given in bytes.
This doesn't modify the hasher itself, and it's possible to finalize
again after adding more input. The constant BLAKE3_OUT_LEN provides
the default output length, 32 bytes, which is recommended for most
callers. See the Security Notes below.

Less Common API Functions

c
void blake3_hasher_init_keyed(
  blake3_hasher *self,
  const uint8_t key[BLAKE3_KEY_LEN]);

Initialize a blake3_hasher in the keyed hashing mode. The key must be
exactly 32 bytes.


c
void blake3_hasher_init_derive_key(
  blake3_hasher *self,
  const char *context);

Initialize a blake3_hasher in the key derivation mode. The context
string is given as an initialization parameter, and afterwards input key
material should be given with blake3_hasher_update. The context string
is a null-terminated C string which should be hardcoded, globally
unique, and application-specific
. The context string should not
include any dynamic input like salts, nonces, or identifiers read from a
database at runtime. A good default format for the context string is
"[application] [commit timestamp] [purpose]", e.g., "example.com 2019-12-25 16:18:03 session tokens v1".

This function is intended for application code written in C. For
language bindings, see blake3_hasher_init_derive_key_raw below.


c
void blake3_hasher_init_derive_key_raw(
  blake3_hasher *self,
  const void *context,
  size_t context_len);

As blake3_hasher_init_derive_key above, except that the context string
is given as a pointer to an array of arbitrary bytes with a provided
length. This is intended for writing language bindings, where C string
conversion would add unnecessary overhead and new error cases. Unicode
strings should be encoded as UTF-8.

Application code in C should prefer blake3_hasher_init_derive_key,
which takes the context as a C string. If you need to use arbitrary
bytes as a context string in application code, consider whether you're
violating the requirement that context strings should be hardcoded.


c
void blake3_hasher_update_tbb(
  blake3_hasher *self,
  const void *input,
  size_t input_len);

Add input to the hasher, using oneTBB to process large inputs using multiple
threads. This can be called any number of times. This gives the same result as
blake3_hasher_update above.

NOTE: This function is only enabled when the library is compiled with CMake option BLAKE3_USE_TBB
and when the oneTBB library is detected on the host system. See the building instructions for
further details.

To get any performance benefit from multithreading, the input buffer needs to
be large. As a rule of thumb on x86_64, blake3_hasher_update_tbb is slower
than blake3_hasher_update for inputs under 128 KiB. That threshold varies
quite a lot across different processors, and it's important to benchmark your
specific use case.

Hashing large files with this function usually requires
memory-mapping, since
reading a file into memory in a single-threaded loop takes longer than hashing
the resulting buffer. Note that hashing a memory-mapped file with this function
produces a "random" pattern of disk reads, which can be slow on spinning disks.
Again it's important to benchmark your specific use case.

This implementation doesn't require configuration of thread resources and will
use as many cores as possible by default. More fine-grained control of
resources is possible using the oneTBB API.


c
void blake3_hasher_finalize_seek(
  const blake3_hasher *self,
  uint64_t seek,
  uint8_t *out,
  size_t out_len);

The same as blake3_hasher_finalize, but with an additional seek
parameter for the starting byte position in the output stream. To
efficiently stream a large output without allocating memory, call this
function in a loop, incrementing seek by the output length each time.


c
void blake3_hasher_reset(
  blake3_hasher *self);

Reset the hasher to its initial state, prior to any calls to
blake3_hasher_update. Currently this is no different from calling
blake3_hasher_init or similar again.

Security Notes

Outputs shorter than the default length of 32 bytes (256 bits) provide less security. An N-bit
BLAKE3 output is intended to provide N bits of first and second preimage resistance and N/2
bits of collision resistance, for any N up to 256. Longer outputs don't provide any additional
security.

Avoid relying on the secrecy of the output offset, that is, the seek argument of
blake3_hasher_finalize_seek. Block-Cipher-Based Tree Hashing by Aldo
Gunsing
shows that an attacker who knows both the message
and the key (if any) can easily determine the offset of an extended output. For comparison,
AES-CTR has a similar property: if you know the key, you can decrypt a block from an unknown
position in the output stream to recover its block index. Callers with strong secret keys
aren't affected in practice, but secret offsets are a design
smell
in any case.

Building

The easiest and most complete method of compiling this library is with CMake.
This is the method described in the next section. Toward the end of the
building section there are more in depth notes about compiling manually and
things that are useful to understand if you need to integrate this library with
another build system.

CMake

The minimum version of CMake is 3.9. The following invocations will compile and
install libblake3. With recent CMake:

bash
cmake -S c -B c/build "-DCMAKE_INSTALL_PREFIX=/usr/local"
cmake --build c/build --target install

With an older CMake:

bash
cd c
mkdir build
cd build
cmake .. "-DCMAKE_INSTALL_PREFIX=/usr/local"
cmake --build . --target install

The following options are available when compiling with CMake:

  • BLAKE3_USE_TBB: Enable oneTBB parallelism (Requires a C++20 capable compiler)
  • BLAKE3_FETCH_TBB: Allow fetching oneTBB from GitHub (only if not found on system)
  • BLAKE3_EXAMPLES: Compile and install example programs

Options can be enabled like this:

bash
cmake -S c -B c/build "-DCMAKE_INSTALL_PREFIX=/usr/local" -DBLAKE3_USE_TBB=1 -DBLAKE3_FETCH_TBB=1

Building manually

We try to keep the build simple enough that you can compile this library "by
hand", and it's expected that many callers will integrate it with their
pre-existing build systems. See the gcc one-liner in the "Example" section
above.

x86

Dynamic dispatch is enabled by default on x86. The implementation will
query the CPU at runtime to detect SIMD support, and it will use the
widest instruction set available. By default, blake3_dispatch.c
expects to be linked with code for five different instruction sets:
portable C, SSE2, SSE4.1, AVX2, and AVX-512.

For each of the x86 SIMD instruction sets, four versions are available:
three flavors of assembly (Unix, Windows MSVC, and Windows GNU) and one
version using C intrinsics. The assembly versions are generally
preferred. They perform better, they perform more consistently across
different compilers, and they build more quickly. On the other hand, the
assembly versions are x86_64-only, and you need to select the right
flavor for your target platform.

Here's an example of building a shared library on x86_64 Linux using
the assembly implementations:

bash
gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c \
    blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S blake3_avx2_x86-64_unix.S \
    blake3_avx512_x86-64_unix.S

When building the intrinsics-based implementations, you need to build
each implementation separately, with the corresponding instruction set
explicitly enabled in the compiler. Here's the same shared library using
the intrinsics-based implementations:

bash
gcc -c -fPIC -O3 -msse2 blake3_sse2.c -o blake3_sse2.o
gcc -c -fPIC -O3 -msse4.1 blake3_sse41.c -o blake3_sse41.o
gcc -c -fPIC -O3 -mavx2 blake3_avx2.c -o blake3_avx2.o
gcc -c -fPIC -O3 -mavx512f -mavx512vl blake3_avx512.c -o blake3_avx512.o
gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c \
    blake3_avx2.o blake3_avx512.o blake3_sse41.o blake3_sse2.o

Note above that building blake3_avx512.c requires both -mavx512f and
-mavx512vl under GCC and Clang. Under MSVC, the single /arch:AVX512
flag is sufficient. The MSVC equivalent of -mavx2 is /arch:AVX2.
MSVC enables SSE2 and SSE4.1 by default, and it doesn't have a
corresponding flag.

If you want to omit SIMD code entirely, you need to explicitly disable
each instruction set. Here's an example of building a shared library on
x86 with only portable code:

bash
gcc -shared -O3 -o libblake3.so -DBLAKE3_NO_SSE2 -DBLAKE3_NO_SSE41 -DBLAKE3_NO_AVX2 \
    -DBLAKE3_NO_AVX512 blake3.c blake3_dispatch.c blake3_portable.c

ARM NEON

The NEON implementation is enabled by default on AArch64, but not on
other ARM targets, since not all of them support it. To enable it, set
BLAKE3_USE_NEON=1. Here's an example of building a shared library on
ARM Linux with NEON support:

bash
gcc -shared -O3 -o libblake3.so -DBLAKE3_USE_NEON=1 blake3.c blake3_dispatch.c \
    blake3_portable.c blake3_neon.c

To explicitiy disable using NEON instructions on AArch64, set
BLAKE3_USE_NEON=0.

bash
gcc -shared -O3 -o libblake3.so -DBLAKE3_USE_NEON=0 blake3.c blake3_dispatch.c \
    blake3_portable.c

Note that on some targets (ARMv7 in particular), extra flags may be
required to activate NEON support in the compiler. If you see an error
like...

text
/usr/lib/gcc/armv7l-unknown-linux-gnueabihf/9.2.0/include/arm_neon.h:635:1: error: inlining failed
in call to always_inline โ€˜vaddq_u32โ€™: target specific option mismatch

...then you may need to add something like -mfpu=neon-vfpv4 -mfloat-abi=hard.

Other Platforms

The portable implementation should work on most other architectures. For
example:

bash
gcc -shared -O3 -o libblake3.so blake3.c blake3_dispatch.c blake3_portable.c

Multithreading

Multithreading is available using oneTBB, by compiling the optional C++
support file blake3_tbb.cpp. For an example of using
mmap (non-Windows) and blake3_hasher_update_tbb to get large-file
performance on par with b3sum, see
example_tbb.c. You can build it like this:

bash
g++ -c -O3 -fno-exceptions -fno-rtti -DBLAKE3_USE_TBB -o blake3_tbb.o blake3_tbb.cpp
gcc -O3 -o example_tbb -lstdc++ -ltbb -DBLAKE3_USE_TBB blake3_tbb.o example_tbb.c blake3.c \
    blake3_dispatch.c blake3_portable.c blake3_sse2_x86-64_unix.S blake3_sse41_x86-64_unix.S \
    blake3_avx2_x86-64_unix.S blake3_avx512_x86-64_unix.S

NOTE: -fno-exceptions or equivalent is required to compile blake3_tbb.cpp,
and public API methods with external C linkage are marked noexcept. Compiling
that file with exceptions enabled will fail. Compiling with RTTI disabled isn't
required but is recommended for code size.


File: reference_impl/README.md

This is the reference implementation of BLAKE3. It is used for testing and
as a readable example of the algorithms involved. Section 5.1 of the BLAKE3
spec

discusses this implementation. You can render docs for this implementation
by running cargo doc --open in this directory.

This implementation is a single file
(reference_impl.rs) with no dependencies. It is
not optimized for performance.

There are ports of this reference implementation to other languages: