Skip to content

BLAKE3

Header: #include <cryptopp/blake3.h> | Namespace: CryptoPP Since: cryptopp-modern 2025.11.0 (runtime input validation: 2026.8.0) Thread Safety: Not thread-safe per instance; use separate instances per thread

Fast cryptographic hash function based on Bao and BLAKE2. BLAKE3 is designed for high performance and supports parallel hashing, tree hashing, keyed hashing (MAC), and key derivation. The cryptopp-modern implementation includes SIMD acceleration with automatic runtime CPU detection (AVX-512, AVX2, SSE4.1, or portable C++ fallback).

Quick Example

#include <cryptopp/blake3.h>
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <iostream>
#include <string>

int main() {
    using namespace CryptoPP;

    BLAKE3 hash;
    std::string message = "abc";
    std::string digest, hexOutput;

    hash.Update(reinterpret_cast<const byte*>(message.data()), message.size());
    digest.resize(hash.DigestSize());
    hash.Final(reinterpret_cast<byte*>(&digest[0]));

    StringSource(digest, true, new HexEncoder(new StringSink(hexOutput)));
    std::cout << "BLAKE3: " << hexOutput << std::endl;
    // Expected: 6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85

    return 0;
}

Overview

BLAKE3 is a cryptographic hash function designed for speed in software while maintaining a high security margin; on the recorded benchmarks below it substantially outperforms the compared SHA-2 and BLAKE2 builds. It can be used as a general-purpose hash function, a keyed hash (MAC), or a key derivation function (KDF).

Key features:

  • Fast in software - Designed for high throughput; see the recorded benchmarks below
  • SIMD accelerated - Runtime detection of AVX-512 (16-way parallel), AVX2 (8-way parallel), SSE4.1 (4-way parallel), or portable C++
  • Parallelisable - Merkle tree structure enables parallel chunk processing
  • Variable output - Output lengths from 1 to 1,024 bytes, configured at construction
  • Multiple modes - Standard hash, keyed hash (MAC), or KDF
  • No length extension - Secure against length extension attacks

Usage Guidelines

Do:

  • Use BLAKE3 for general-purpose hashing, file integrity, and content addressing
  • Use keyed mode (MAC) for message authentication with a secret key
  • Use KDF mode for deriving keys from high-entropy secrets or existing keys (for example, the output of Argon2)
  • Reuse the same instance for multiple messages; Final() and TruncatedFinal() restart it automatically
  • Check AlgorithmProvider() for the highest SIMD capability the build detected

Avoid:

  • Using BLAKE3 KDF as a replacement for Argon2 for password hashing (use Argon2 instead - it’s memory-hard)
  • Using keyed mode as a replacement for digital signatures (use Ed25519 instead)
  • Reusing the same key for multiple purposes (use different keys or context strings)
  • Using user-supplied strings directly as KDF context (use fixed, application-specific strings)

Constants

  • DIGESTSIZE = 32 - Default output size in bytes
  • BLOCKSIZE = 64 - Internal block size in bytes
  • CHUNKSIZE = 1024 - Chunk size for tree hashing
  • DEFAULT_KEYLENGTH = 32 - Recommended key length for keyed hashing
  • MIN_KEYLENGTH = 32 - Keyed mode requires exactly 32 bytes of key material
  • MAX_KEYLENGTH = 32 - Maximum supported key length in bytes

Constructors

Default Constructor

BLAKE3(unsigned int digestSize = DIGESTSIZE)

Constructs a BLAKE3 hash object with the specified output size. The implementation supports output lengths from 1 to 1,024 bytes.

Parameters:

  • digestSize - Desired hash output size in bytes (default: 32)

Exceptions:

  • Throws InvalidArgument if digestSize is 0 or larger than 1,024

Example:

BLAKE3 hash;           // 32-byte output
BLAKE3 hash256(32);    // Explicit 32-byte output
BLAKE3 hashXOF(128);   // 128-byte extended output

Keyed Constructor (MAC Mode)

BLAKE3(const byte* key, size_t keyLength, unsigned int digestSize = DIGESTSIZE)

Constructs a BLAKE3 object for keyed hashing (MAC mode). Use this for message authentication with a secret key.

Parameters:

  • key - Pointer to key bytes (must not be null)
  • keyLength - Length of key in bytes. Keyed BLAKE3 requires exactly 32 bytes of key material; use the default constructor for unkeyed hashing
  • digestSize - Desired hash output size in bytes (default: 32)

Exceptions:

  • Throws InvalidKeyLength if keyLength is not 32
  • Throws InvalidArgument if key is null, or if digestSize is 0 or larger than 1,024

When to use: Message authentication where both parties share a secret key (similar to HMAC).

Example:

SecByteBlock key(32);
AutoSeededRandomPool rng;
rng.GenerateBlock(key, key.size());

BLAKE3 mac(key, key.size());  // Create MAC with 32-byte key

KDF Constructor (Key Derivation Mode)

BLAKE3(const char* context, unsigned int digestSize = DIGESTSIZE)

Constructs a BLAKE3 object for key derivation (KDF mode) with a context string for domain separation.

Parameters:

  • context - Context string for domain separation; a fixed, globally unique application string
  • digestSize - Desired output size in bytes (default: 32)

Exceptions:

  • Throws InvalidArgument if context is null, or if digestSize is 0 or larger than 1,024

When to use: Deriving multiple keys from a single secret, or creating domain-separated hashes. The context should be a fixed, application-specific string, not user input. An empty context remains accepted for compatibility, but it provides no domain separation; use a fixed, globally unique application string.

Example:

BLAKE3 kdf("MyApp 2025-11-25 Encryption Key", 32);
BLAKE3 kdf2("MyApp 2025-11-25 MAC Key", 32);  // Different context = different output

Public Methods

StaticAlgorithmName()

static const char* StaticAlgorithmName()

Returns the algorithm name as a static string: "BLAKE3".

Thread Safety: Thread-safe (static method).


AlgorithmName()

std::string AlgorithmName() const

Returns the algorithm name with digest size, e.g. "BLAKE3-256" for 32-byte output.

Thread Safety: Thread-safe (const method, read-only).


AlgorithmProvider()

std::string AlgorithmProvider() const

Returns the highest SIMD capability the runtime detection found. This is not necessarily the path used for every input: the parallel implementations engage only once enough complete chunks are buffered, so small messages use SSE4.1 or portable C++ even when this returns "AVX2" or "AVX512". ARM builds use the portable path and report "C++".

Returns: One of "C++", "SSE4.1", "AVX2", or "AVX512".

Thread Safety: Thread-safe (const method).

Example:

BLAKE3 hash;
std::cout << "Using: " << hash.AlgorithmProvider() << std::endl;
// Might print "AVX2" on modern x86 CPUs

DigestSize()

unsigned int DigestSize() const

Returns the configured output size in bytes.

Thread Safety: Thread-safe (const method).


BlockSize()

unsigned int BlockSize() const

Returns the internal block size (64 bytes).

Thread Safety: Thread-safe (const method).


Update()

void Update(const byte* input, size_t length)

Updates the hash with additional input data. Can be called multiple times for incremental hashing.

Parameters:

  • input - Pointer to input data
  • length - Length of input data in bytes

Exceptions:

  • None (safe to call with length = 0)

Thread Safety: Not thread-safe. Do not call from multiple threads on the same instance.


TruncatedFinal()

void TruncatedFinal(byte* hash, size_t size)

Finalizes the hash and writes the output. After calling this, the object is reset and can be reused.

Parameters:

  • hash - Buffer to receive hash output (must be allocated by caller)
  • size - Number of bytes to write, up to the digest size configured at construction

Exceptions:

  • Throws InvalidArgument if size exceeds the configured digest size. Safe to call with size = 0

Thread Safety: Not thread-safe.

Note: Calling TruncatedFinal() automatically restarts the instance, so it can be immediately reused. This is not a seekable XOF reader like the official implementation’s OutputReader: producing a different output length requires hashing the input again.


Final()

void Final(byte* hash)

Finalises the hash and writes the configured digest size to the output buffer. Equivalent to TruncatedFinal(hash, DigestSize()).

Parameters:

  • hash - Buffer to receive hash output (must be at least DigestSize() bytes, which may be up to 1,024)

Exceptions: None

Thread Safety: Not thread-safe.

Note: For the default 32-byte output, Final() is simpler than TruncatedFinal(). Use TruncatedFinal() when you need a different output size (XOF mode).


Restart()

void Restart()

Resets the hash to its initial state, allowing reuse of the object. Preserves the mode (standard, keyed, or KDF) and configuration.

Exceptions: None

Thread Safety: Not thread-safe.

Reserve explicit Restart() for abandoning a partially hashed message; Final() and TruncatedFinal() already restart the object.

Example:

BLAKE3 hash;
hash.Update(...);
hash.Final(...);  // The object restarts automatically

// Can immediately reuse:
hash.Update(...);
hash.Final(...);

Usage Modes

Basic Hash Mode

When to use: General-purpose hashing, file integrity verification, content addressing.

#include <cryptopp/blake3.h>
#include <cryptopp/hex.h>
#include <cryptopp/files.h>
#include <iostream>

int main() {
    CryptoPP::BLAKE3 hash;
    std::string message = "The quick brown fox jumps over the lazy dog";
    std::string digest;

    hash.Update(reinterpret_cast<const CryptoPP::byte*>(message.data()), message.size());
    digest.resize(hash.DigestSize());
    hash.Final(reinterpret_cast<CryptoPP::byte*>(&digest[0]));

    std::string hexOutput;
    CryptoPP::StringSource(digest, true,
        new CryptoPP::HexEncoder(new CryptoPP::StringSink(hexOutput))
    );

    std::cout << "BLAKE3: " << hexOutput << std::endl;
    return 0;
}

File hashing example:

BLAKE3 hash;
std::string digest;
FileSource("document.pdf", true,
    new HashFilter(hash,
        new StringSink(digest)
    )
);
// digest now contains the BLAKE3 hash of the file

Keyed Hash Mode (MAC)

When to use: Message authentication when both parties share a secret key.

#include <cryptopp/blake3.h>
#include <cryptopp/osrng.h>
#include <cryptopp/hex.h>
#include <iostream>

int main() {
    using namespace CryptoPP;

    // Generate a random 32-byte key (do this once, store securely)
    AutoSeededRandomPool rng;
    SecByteBlock key(32);
    rng.GenerateBlock(key, key.size());

    // Create keyed BLAKE3 (MAC)
    BLAKE3 mac(key, key.size());
    std::string message = "Authenticate this message";
    std::string tag;

    mac.Update(reinterpret_cast<const byte*>(message.data()), message.size());
    tag.resize(mac.DigestSize());
    mac.Final(reinterpret_cast<byte*>(&tag[0]));

    // Send message + tag to recipient
    // Recipient verifies by recomputing MAC with same key

    std::string hexTag;
    StringSource(tag, true, new HexEncoder(new StringSink(hexTag)));
    std::cout << "MAC: " << hexTag << std::endl;

    return 0;
}

Verification example:

// Receiver side:
BLAKE3 verifyMac(key, key.size());
verifyMac.Update(reinterpret_cast<const byte*>(receivedMessage.data()), receivedMessage.size());
std::string computedTag(32, '\0');
verifyMac.Final(reinterpret_cast<byte*>(&computedTag[0]));

// Check the length first (tag length is not secret), then compare in
// constant time. Comparing a fixed 32 bytes against a shorter received
// tag would read out of bounds.
const size_t tagSize = computedTag.size();
if (receivedTag.size() == tagSize &&
    VerifyBufsEqual(
        reinterpret_cast<const byte*>(computedTag.data()),
        reinterpret_cast<const byte*>(receivedTag.data()),
        tagSize))
{
    std::cout << "Message is authentic!" << std::endl;
} else {
    std::cout << "WARNING: Message has been tampered with!" << std::endl;
}

Key Derivation Mode (KDF)

When to use: Deriving multiple keys from a single secret, creating domain-separated keys.

#include <cryptopp/blake3.h>
#include <cryptopp/osrng.h>
#include <cryptopp/secblock.h>
#include <iostream>
#include <string>

int main() {
    using namespace CryptoPP;

    // Input key material must be high-entropy: a randomly generated key,
    // Argon2 output, or a secret loaded from protected key storage.
    SecByteBlock inputKeyMaterial(32);
    AutoSeededRandomPool rng;
    rng.GenerateBlock(inputKeyMaterial, inputKeyMaterial.size());

    // Derive encryption key
    BLAKE3 kdfEncrypt("MyApplication 2025-11-25 Encryption Key", 32);
    kdfEncrypt.Update(inputKeyMaterial.data(), inputKeyMaterial.size());
    std::string encryptionKey(32, '\0');
    kdfEncrypt.Final(reinterpret_cast<byte*>(&encryptionKey[0]));

    // Derive MAC key (different context = different output)
    BLAKE3 kdfMac("MyApplication 2025-11-25 MAC Key", 32);
    kdfMac.Update(inputKeyMaterial.data(), inputKeyMaterial.size());
    std::string macKey(32, '\0');
    kdfMac.Final(reinterpret_cast<byte*>(&macKey[0]));

    // encryptionKey and macKey are now independent, derived keys
    std::cout << "Derived two independent keys from one secret" << std::endl;

    return 0;
}

For password hashing, use Argon2 instead!

BLAKE3 KDF is fast, which is good for key derivation but bad for password hashing. Argon2 is deliberately memory-hard and slow, making it resistant to brute-force attacks.


Extendable Output (XOF)

When to use: Protocols that need output longer than 32 bytes.

The implementation supports variable output lengths from 1 to 1,024 bytes. Configure the maximum output size in the constructor; TruncatedFinal() may emit up to that configured size. This is not a seekable XOF reader like the official implementation’s OutputReader: finalisation restarts the object, so producing another length means hashing the input again.

#include <cryptopp/blake3.h>
#include <iostream>
#include <string>

int main() {
    using namespace CryptoPP;

    BLAKE3 hash(128);  // configure the maximum output size up front
    std::string message = "Generate extended output";

    hash.Update(
        reinterpret_cast<const byte*>(message.data()),
        message.size());

    std::string output(128, '\0');
    hash.TruncatedFinal(
        reinterpret_cast<byte*>(&output[0]),
        output.size());

    std::cout << "Generated " << output.size() << "-byte hash output" << std::endl;

    // A different length requires hashing the input again:
    BLAKE3 short16(16);
    short16.Update(
        reinterpret_cast<const byte*>(message.data()),
        message.size());
    std::string small(16, '\0');
    short16.TruncatedFinal(reinterpret_cast<byte*>(&small[0]), small.size());

    return 0;
}

Performance

The figures below are one recorded build on one machine, not a general claim; throughput varies with architecture, SIMD availability and message size.

SIMD Acceleration

cryptopp-modern’s BLAKE3 implementation includes optimised SIMD code paths with automatic runtime CPU detection:

SIMD LevelParallel ChunksMinimum BufferApprox. Speed
AVX-51216 at a time16KB~4500 MiB/s
AVX28 at a time8KB~2600 MiB/s
SSE4.14 at a time4KB~1800 MiB/s
C++1 at a timeAny~800 MiB/s

Benchmarks on Intel Core Ultra 7 155H, Windows 11, MinGW-w64 GCC

Comparison with Other Hash Functions

AlgorithmProviderSpeed (MiB/s)vs BLAKE2b
BLAKE3AVX-512~45005.5x faster
BLAKE3AVX225993.15x faster
BLAKE3SSE4.1~18002.2x faster
BLAKE3C++~800Similar
BLAKE2bSSE4.1822baseline

Performance Tips

  • Use large buffers: For maximum throughput with large data, use 16KB+ buffers to enable full AVX-512 parallel processing (or 8KB+ for AVX2)
  • Check your provider: Use AlgorithmProvider() to inspect the highest detected SIMD capability
  • Small data is fine: BLAKE3 adapts automatically - small inputs work correctly, just without SIMD parallelism
#include <fstream>
#include <stdexcept>
#include <vector>

// Large buffers enable the parallel SIMD paths
BLAKE3 hash;
const size_t BUFFER_SIZE = 65536;  // 64 KiB
std::vector<byte> buffer(BUFFER_SIZE);

std::ifstream file("largefile.bin", std::ios::binary);
if (!file)
    throw std::runtime_error("Could not open largefile.bin");

while (file) {
    file.read(
        reinterpret_cast<char*>(buffer.data()),
        static_cast<std::streamsize>(buffer.size()));

    const std::streamsize count = file.gcount();
    if (count > 0)
        hash.Update(buffer.data(), static_cast<size_t>(count));
}

if (!file.eof())
    throw std::runtime_error("Error reading largefile.bin");

A while (file.read(...)) loop silently drops the final partial block: the last short read sets the stream failure state before its bytes are hashed.

Additional Performance Characteristics

  • Side-channel shape - Compression uses fixed operations without secret-indexed lookup tables; no platform-wide constant-time guarantee is made
  • Memory alignment - Buffers aligned to 32 bytes (AVX2) or 16 bytes (SSE4.1) may provide marginal improvements, though unaligned access is fully supported

Security

Security properties

  • Security strength: BLAKE3 targets roughly 128-bit security for preimage, second-preimage and collision attacks.
  • Output length: The default 32-byte output is recommended for general use. Longer outputs do not increase BLAKE3’s claimed security level.
  • Length-extension resistance: Tree-based construction; not vulnerable to classic SHA-2 style length-extension attacks.
  • Keyed mode (MAC / PRF): With a 32-byte secret key, BLAKE3 behaves as a secure PRF/MAC with ~128-bit security. It is suitable as a MAC/PRF in new designs that explicitly specify BLAKE3 keyed mode; it is not a drop-in replacement for HMAC at the API, protocol or interoperability level.
  • KDF mode: With a fixed, application-specific context string and high-entropy key material, BLAKE3 provides a secure KDF for deriving multiple, domain-separated keys.
  • Side-channel behaviour: The compression paths use fixed operations without secret-indexed lookup tables. No independent constant-time guarantee is made for every platform and compiler.

Security notes

  • Use at least 32 bytes of output for cryptographic purposes. A 16-byte output provides at most about 64-bit collision resistance; use it only where that bound is acceptable.
  • For a generic quantum search, a 128-bit preimage bound is reduced to roughly 64 bits.
  • Do not use BLAKE3 directly for password hashing or deriving keys from low-entropy passwords. Use Argon2 for password hashing, and treat BLAKE3 KDF as a fast, follow-on KDF once you already have high-entropy key material.
  • In keyed mode, treat BLAKE3 as a MAC/PRF, not as a digital signature. Use Ed25519/RSA/etc. where you need non-repudiation.
  • When deriving multiple keys from the same input (e.g. encryption key + MAC key), always use distinct, fixed context strings to enforce domain separation between outputs.

Thread Safety

  • Per-instance: Not thread-safe. Do not use the same BLAKE3 instance from multiple threads simultaneously.
  • Multi-instance: Thread-safe. You can safely use different BLAKE3 instances in different threads.
  • Static methods: Thread-safe (StaticAlgorithmName()).

Example (safe):

// Each thread has its own instance
void workerThread(const std::vector<std::string>& messages) {
    BLAKE3 hash;  // Thread-local instance
    for (const auto& msg : messages) {
        hash.Update(...);
        hash.TruncatedFinal(...);  // restarts the object for the next message
    }
}

Use Cases

  • File integrity - Checksums and file verification (often faster than SHA-256, depending on platform and input size)
  • Signature prehashing - Only in protocols that explicitly specify BLAKE3 as their prehash; Ed25519 and the other signature schemes hash internally
  • Content addressing - IPFS and similar systems
  • Deduplication - Fast hash for identifying duplicate data
  • Message authentication - Use keyed mode for MAC
  • Key derivation - Derive multiple keys from one secret (use KDF mode)
  • Hash tables - Fast keyed hashing for identifiers and keys

Test Vectors

Use these to verify your BLAKE3 implementation:

ModeInputOutput (hex)
Basic"" (empty)af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262
Basic"abc"6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85

The official BLAKE3 project publishes the authoritative vector set covering the basic, keyed and derive-key modes with extended output; the library’s own known-answer tests run against TestVectors/blake3.txt.

See Also