BLAKE3
Header: #include <cryptopp/blake3.h> | Namespace: CryptoPP
Since: cryptopp-modern 2025.11.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 (AVX2, SSE4.1, NEON, or C++ fallback).
Quick Example
#include <cryptopp/blake3.h>
#include <cryptopp/hex.h>
#include <iostream>
int main() {
using namespace CryptoPP;
BLAKE3 hash;
std::string message = "abc";
std::string digest, hexOutput;
hash.Update((const byte*)message.data(), message.size());
digest.resize(hash.DigestSize());
hash.Final((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 that is significantly faster than MD5, SHA-1, SHA-2, SHA-3, and BLAKE2, while maintaining a high security margin. It can be used as a general-purpose hash function, a keyed hash (MAC), or a key derivation function (KDF).
Key features:
- Extremely fast - Outperforms all standard hash functions
- SIMD accelerated - Runtime detection of AVX2 (8-way parallel), SSE4.1 (4-way parallel), NEON (ARM), or C++ fallback
- Parallelisable - Merkle tree structure enables parallel chunk processing
- Extendable output - Can generate hashes of any length
- 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)
- Use the same instance for multiple messages (call
Restart()between them) - Use hardware-accelerated builds (
AlgorithmProvider()shows what’s active)
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 bytesBLOCKSIZE = 64- Internal block size in bytesCHUNKSIZE = 1024- Chunk size for tree hashingDEFAULT_KEYLENGTH = 32- Recommended key length for keyed hashingMIN_KEYLENGTH = 0- Minimum key length in bytes (0 = unkeyed hashing; keyed mode is defined for 32-byte keys)MAX_KEYLENGTH = 32- Maximum supported key length in bytes
Constructors
Default Constructor
BLAKE3(unsigned int digestSize = DIGESTSIZE)Constructs a BLAKE3 hash object with specified output size. The digestSize can be any value (BLAKE3 supports extendable output).
Parameters:
digestSize- Desired hash output size in bytes (default: 32)
Exceptions:
- None
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 byteskeyLength- Length of key in bytes (up to 32; BLAKE3 is defined for 32-byte keys, so 32 is recommended for new designs)digestSize- Desired hash output size in bytes (default: 32)
Exceptions:
- Throws
InvalidKeyLengthifkeyLength > MAX_KEYLENGTH
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 (null-terminated)digestSize- Desired output size in bytes (default: 32)
Exceptions:
- Throws
InvalidArgumentifcontextis nullptr or empty
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.
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() constReturns the algorithm name as a std::string: "BLAKE3".
Thread Safety: Thread-safe (const method, read-only).
AlgorithmProvider()
std::string AlgorithmProvider() constReturns the implementation provider, indicating if hardware acceleration is used.
Returns: One of "C++", "SSE4.1", "AVX2", or "NEON" (on ARM platforms).
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() constReturns the configured output size in bytes.
Thread Safety: Thread-safe (const method).
BlockSize()
unsigned int BlockSize() constReturns 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 datalength- 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 (can be any size due to extendable output)
Exceptions:
- None (safe to call with
size = 0, produces empty output)
Thread Safety: Not thread-safe.
Note: Calling TruncatedFinal() automatically calls Restart(), so the instance can be immediately reused.
Final()
void Final(byte* hash)Finalizes the hash and writes the default digest size (32 bytes) to the output buffer. Equivalent to TruncatedFinal(hash, DigestSize()).
Parameters:
hash- Buffer to receive hash output (must be at leastDigestSize()bytes)
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.
Example:
BLAKE3 hash;
hash.Update(...);
hash.Final(...); // Implicitly calls Restart()
// 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((const CryptoPP::byte*)message.data(), message.size());
digest.resize(hash.DigestSize());
hash.Final((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((const byte*)message.data(), message.size());
tag.resize(mac.DigestSize());
mac.Final((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((const byte*)receivedMessage.data(), receivedMessage.size());
std::string computedTag(32, '\0');
verifyMac.Final((byte*)&computedTag[0]);
// Use constant-time comparison for MACs
if (VerifyBufsEqual(
reinterpret_cast<const byte*>(computedTag.data()),
reinterpret_cast<const byte*>(receivedTag.data()),
32))
{
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/hex.h>
#include <iostream>
int main() {
using namespace CryptoPP;
// Derive different keys from the same input material
std::string inputKeyMaterial = "high_entropy_key_material"; // e.g. a random 32-byte key or Argon2 output
// Derive encryption key
BLAKE3 kdfEncrypt("MyApplication 2025-11-25 Encryption Key", 32);
kdfEncrypt.Update((const byte*)inputKeyMaterial.data(), inputKeyMaterial.size());
std::string encryptionKey(32, '\0');
kdfEncrypt.Final((byte*)&encryptionKey[0]);
// Derive MAC key (different context = different output)
BLAKE3 kdfMac("MyApplication 2025-11-25 MAC Key", 32);
kdfMac.Update((const byte*)inputKeyMaterial.data(), inputKeyMaterial.size());
std::string macKey(32, '\0');
kdfMac.Final((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: Need arbitrary-length output for specific protocols or applications.
#include <cryptopp/blake3.h>
#include <cryptopp/hex.h>
#include <iostream>
int main() {
using namespace CryptoPP;
BLAKE3 hash;
std::string message = "Generate arbitrary length output";
std::string output;
hash.Update((const byte*)message.data(), message.size());
// Generate 128 bytes of output (or any size you need)
output.resize(128);
hash.TruncatedFinal((byte*)&output[0], output.size());
std::cout << "Generated " << output.size() << "-byte hash output" << std::endl;
// Can also generate different lengths from the same hash state:
hash.Restart();
hash.Update((const byte*)message.data(), message.size());
std::string short16(16, '\0');
hash.TruncatedFinal((byte*)&short16[0], 16);
return 0;
}Performance
BLAKE3 is one of the fastest cryptographic hash functions available, with SIMD-accelerated implementations that provide significant speedups.
SIMD Acceleration
cryptopp-modern’s BLAKE3 implementation includes optimised SIMD code paths with automatic runtime CPU detection:
| SIMD Level | Parallel Chunks | Minimum Buffer | Approx. Speed |
|---|---|---|---|
| AVX2 | 8 at a time | 8KB | ~2600 MiB/s |
| SSE4.1 | 4 at a time | 4KB | ~1800 MiB/s |
| C++ | 1 at a time | Any | ~800 MiB/s |
Benchmarks on Intel Core Ultra 7 155H, Windows 11, MinGW-w64 GCC
Comparison with Other Hash Functions
| Algorithm | Provider | Speed (MiB/s) | vs BLAKE2b |
|---|---|---|---|
| BLAKE3 | AVX2 | 2599 | 3.15x faster |
| BLAKE3 | SSE4.1 | ~1800 | 2.2x faster |
| BLAKE3 | C++ | ~800 | Similar |
| BLAKE2b | SSE4.1 | 822 | baseline |
Performance Tips
- Use large buffers: For maximum throughput with large data, use 8KB+ buffers to enable full AVX2 parallel processing
- Check your provider: Use
AlgorithmProvider()to verify which SIMD implementation is active - Small data is fine: BLAKE3 adapts automatically - small inputs work correctly, just without SIMD parallelism
// Optimal: Large buffer enables AVX2 parallel processing
BLAKE3 hash;
const size_t BUFFER_SIZE = 65536; // 64KB
std::vector<byte> buffer(BUFFER_SIZE);
std::ifstream file("largefile.bin", std::ios::binary);
while (file.read(reinterpret_cast<char*>(buffer.data()), BUFFER_SIZE)) {
hash.Update(buffer.data(), file.gcount()); // ~2600 MiB/s with AVX2
}Additional Performance Characteristics
- Constant-time - No data-dependent branches (resistant to timing attacks)
- 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
- Classical security (≥ 32-byte output): BLAKE3 targets ~128-bit security for all standard hash goals (preimage, second-preimage, collision), as per the BLAKE3 specification.
- Output length: The default 32-byte (256-bit) output is recommended for general use. Longer outputs are deterministic extensions of the same root value and do not increase the underlying security level beyond ~128 bits.
- 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, and can act as a drop-in replacement for many HMAC-SHA-256 uses.
- 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 function is designed without secret-dependent branches or table lookups, and the cryptopp-modern implementation aims to be constant-time for secret inputs (subject to usual platform and compiler caveats).
Security notes
- Use at least 32 bytes of output for cryptographic purposes. Shorter digests (e.g. 16 bytes) are fine for non-critical identifiers but reduce the security margin.
- BLAKE3’s classical security level is ~128 bits. Under generic quantum attacks (e.g. Grover’s algorithm), effective preimage security is roughly ~64 bits, so treat it like any other 128-bit symmetric primitive in post-quantum planning.
- 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
BLAKE3instance from multiple threads simultaneously. - Multi-instance: Thread-safe. You can safely use different
BLAKE3instances 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(...);
hash.Restart();
}
}Use Cases
- File integrity - Checksums and file verification (faster than SHA-256)
- Digital signatures - Hash messages before signing with Ed25519
- 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 hashing for identifiers/keys (basic mode; still cryptographic-strength)
Test Vectors
Use these to verify your BLAKE3 implementation:
| Mode | Input | Key/Context | Output (first 32 bytes, hex) |
|---|---|---|---|
| Basic | "" (empty) | - | af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262 |
| Basic | "abc" | - | 6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85 |
| Keyed | "message" | 32-byte zero key | 03bf25008eb0c585f9ad2d89621b7e3d1f5b5b40e46fca0e4920f3d02e00ef97 |
| KDF | "input" | Context: "test" | ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad618a1ea7a851e9d21 |
Note: These are BLAKE3 reference vectors. Your output should match exactly if your build is correct.
See Also
- BLAKE3 Guide - Detailed guide with more examples
- Hash Functions Guide - Overview of all hash functions
- Algorithm Reference - Complete algorithm catalog
- Argon2 - Use this for password hashing, not BLAKE3
- HMAC - Alternative MAC construction
- BLAKE3 Specification - Official specification