Skip to content

Commit 6ad032d

Browse files
committed
[Support] Introduce the BLAKE3 hashing function implementation
BLAKE3 is a cryptographic hash function that is secure and very performant. The C implementation originates from https://github.com/BLAKE3-team/BLAKE3/tree/1.3.1/c License is at https://github.com/BLAKE3-team/BLAKE3/blob/1.3.1/LICENSE This patch adds: * `llvm/include/llvm-c/blake3.h`: The BLAKE3 C API * `llvm/include/llvm/Support/BLAKE3.h`: C++ wrapper of the C API * `llvm/lib/Support/BLAKE3`: Directory containing the BLAKE3 C implementation files, including the `LICENSE` file * `llvm/unittests/Support/BLAKE3Test.cpp`: unit tests for the BLAKE3 C++ wrapper This initial patch contains the pristine BLAKE3 sources, a follow-up patch will introduce LLVM-specific prefixes to avoid conflicts if a client also links with its own BLAKE3 version. And here's some timings comparing BLAKE3 with LLVM's SHA1/SHA256/MD5. Timings include `AVX512`, `AVX2`, `neon`, and the generic/portable implementations. The table shows the speed-up multiplier of BLAKE3 for hashing 100 MBs: | Processor | SHA1 | SHA256 | MD5 | |-------------------------|-------|--------|------| | Intel Xeon W (AVX512) | 10.4x | 27x | 9.4x | | Intel Xeon W (AVX2) | 6.5x | 17x | 5.9x | | Intel Xeon W (portable) | 1.3x | 3.3x | 1.1x | | M1Pro (neon) | 2.1x | 4.7x | 2.8x | | M1Pro (portable) | 1.1x | 2.4x | 1.5x | Differential Revision: https://reviews.llvm.org/D121510
1 parent 58b73ef commit 6ad032d

31 files changed

+31785
-0
lines changed

llvm/include/llvm-c/blake3.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#ifndef BLAKE3_H
2+
#define BLAKE3_H
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
#define BLAKE3_VERSION_STRING "1.3.1"
12+
#define BLAKE3_KEY_LEN 32
13+
#define BLAKE3_OUT_LEN 32
14+
#define BLAKE3_BLOCK_LEN 64
15+
#define BLAKE3_CHUNK_LEN 1024
16+
#define BLAKE3_MAX_DEPTH 54
17+
18+
// This struct is a private implementation detail. It has to be here because
19+
// it's part of blake3_hasher below.
20+
typedef struct {
21+
uint32_t cv[8];
22+
uint64_t chunk_counter;
23+
uint8_t buf[BLAKE3_BLOCK_LEN];
24+
uint8_t buf_len;
25+
uint8_t blocks_compressed;
26+
uint8_t flags;
27+
} blake3_chunk_state;
28+
29+
typedef struct {
30+
uint32_t key[8];
31+
blake3_chunk_state chunk;
32+
uint8_t cv_stack_len;
33+
// The stack size is MAX_DEPTH + 1 because we do lazy merging. For example,
34+
// with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk
35+
// requires a 4th entry, rather than merging everything down to 1, because we
36+
// don't know whether more input is coming. This is different from how the
37+
// reference implementation does things.
38+
uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN];
39+
} blake3_hasher;
40+
41+
const char *blake3_version(void);
42+
void blake3_hasher_init(blake3_hasher *self);
43+
void blake3_hasher_init_keyed(blake3_hasher *self,
44+
const uint8_t key[BLAKE3_KEY_LEN]);
45+
void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context);
46+
void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context,
47+
size_t context_len);
48+
void blake3_hasher_update(blake3_hasher *self, const void *input,
49+
size_t input_len);
50+
void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out,
51+
size_t out_len);
52+
void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek,
53+
uint8_t *out, size_t out_len);
54+
void blake3_hasher_reset(blake3_hasher *self);
55+
56+
#ifdef __cplusplus
57+
}
58+
#endif
59+
60+
#endif /* BLAKE3_H */

llvm/include/llvm/Support/BLAKE3.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//==- BLAKE3.h - BLAKE3 C++ wrapper for LLVM ---------------------*- C++ -*-==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This is a C++ wrapper of the BLAKE3 C interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_SUPPORT_BLAKE3_H
14+
#define LLVM_SUPPORT_BLAKE3_H
15+
16+
#include "llvm-c/blake3.h"
17+
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/StringRef.h"
19+
20+
namespace llvm {
21+
22+
/// The constant \p BLAKE3_OUT_LEN provides the default output length,
23+
/// 32 bytes, which is recommended for most callers.
24+
///
25+
/// Outputs shorter than the default length of 32 bytes (256 bits) provide
26+
/// less security. An N-bit BLAKE3 output is intended to provide N bits of
27+
/// first and second preimage resistance and N/2 bits of collision
28+
/// resistance, for any N up to 256. Longer outputs don't provide any
29+
/// additional security.
30+
///
31+
/// Shorter BLAKE3 outputs are prefixes of longer ones. Explicitly
32+
/// requesting a short output is equivalent to truncating the default-length
33+
/// output.
34+
template <size_t NumBytes = BLAKE3_OUT_LEN>
35+
using BLAKE3Result = std::array<uint8_t, NumBytes>;
36+
37+
/// A class that wrap the BLAKE3 algorithm.
38+
class BLAKE3 {
39+
public:
40+
BLAKE3() { init(); }
41+
42+
/// Reinitialize the internal state
43+
void init() { blake3_hasher_init(&Hasher); }
44+
45+
/// Digest more data.
46+
void update(ArrayRef<uint8_t> Data) {
47+
blake3_hasher_update(&Hasher, Data.data(), Data.size());
48+
}
49+
50+
/// Digest more data.
51+
void update(StringRef Str) {
52+
blake3_hasher_update(&Hasher, Str.data(), Str.size());
53+
}
54+
55+
/// Finalize the hasher and put the result in \p Result.
56+
/// This doesn't modify the hasher itself, and it's possible to finalize again
57+
/// after adding more input.
58+
template <size_t NumBytes = BLAKE3_OUT_LEN>
59+
void final(BLAKE3Result<NumBytes> &Result) {
60+
blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
61+
}
62+
63+
/// Finalize the hasher and return an output of any length, given in bytes.
64+
/// This doesn't modify the hasher itself, and it's possible to finalize again
65+
/// after adding more input.
66+
template <size_t NumBytes = BLAKE3_OUT_LEN> BLAKE3Result<NumBytes> final() {
67+
BLAKE3Result<NumBytes> Result;
68+
blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
69+
return Result;
70+
}
71+
72+
/// Returns a BLAKE3 hash for the given data.
73+
template <size_t NumBytes = BLAKE3_OUT_LEN>
74+
static BLAKE3Result<NumBytes> hash(ArrayRef<uint8_t> Data) {
75+
BLAKE3 Hasher;
76+
Hasher.update(Data);
77+
return Hasher.final<NumBytes>();
78+
}
79+
80+
private:
81+
blake3_hasher Hasher;
82+
};
83+
84+
} // namespace llvm
85+
86+
#endif

llvm/lib/Support/BLAKE3/.clang-format

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DisableFormat: true
2+
SortIncludes: Never
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
set(LLVM_BLAKE3_FILES
2+
BLAKE3/blake3.c
3+
BLAKE3/blake3_dispatch.c
4+
BLAKE3/blake3_portable.c
5+
)
6+
7+
# The BLAKE3 team recommends using the assembly versions, from the README:
8+
#
9+
# "For each of the x86 SIMD instruction sets, four versions are available:
10+
# three flavors of assembly (Unix, Windows MSVC, and Windows GNU) and one
11+
# version using C intrinsics. The assembly versions are generally
12+
# preferred. They perform better, they perform more consistently across
13+
# different compilers, and they build more quickly."
14+
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
15+
if (MSVC)
16+
list(APPEND LLVM_BLAKE3_FILES
17+
BLAKE3/blake3_sse2_x86-64_windows_msvc.asm
18+
BLAKE3/blake3_sse41_x86-64_windows_msvc.asm
19+
BLAKE3/blake3_avx2_x86-64_windows_msvc.asm
20+
BLAKE3/blake3_avx512_x86-64_windows_msvc.asm
21+
)
22+
elseif(WIN32)
23+
list(APPEND LLVM_BLAKE3_FILES
24+
BLAKE3/blake3_sse2_x86-64_windows_gnu.S
25+
BLAKE3/blake3_sse41_x86-64_windows_gnu.S
26+
BLAKE3/blake3_avx2_x86-64_windows_gnu.S
27+
BLAKE3/blake3_avx512_x86-64_windows_gnu.S
28+
)
29+
else()
30+
list(APPEND LLVM_BLAKE3_FILES
31+
BLAKE3/blake3_sse2_x86-64_unix.S
32+
BLAKE3/blake3_sse41_x86-64_unix.S
33+
BLAKE3/blake3_avx2_x86-64_unix.S
34+
BLAKE3/blake3_avx512_x86-64_unix.S
35+
)
36+
endif()
37+
endif()
38+
39+
if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
40+
list(APPEND LLVM_BLAKE3_FILES
41+
BLAKE3/blake3_neon.c
42+
)
43+
endif()
44+
45+
set(LLVM_BLAKE3_FILES
46+
${LLVM_BLAKE3_FILES}
47+
PARENT_SCOPE
48+
)

0 commit comments

Comments
 (0)