Skip to content

[stable/20211026] Cherry-pick the BLAKE3 hashing function implementation #4133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions llvm/include/llvm-c/blake3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*===-- llvm-c/blake3.h - BLAKE3 C Interface ----------------------*- C -*-===*\
|* *|
|* Released into the public domain with CC0 1.0 *|
|* See 'llvm/lib/Support/BLAKE3/LICENSE' for info. *|
|* SPDX-License-Identifier: CC0-1.0 *|
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* This header declares the C interface to LLVM's BLAKE3 implementation. *|
|* Original BLAKE3 C API: https://github.com/BLAKE3-team/BLAKE3/tree/1.3.1/c *|
|* *|
|* Symbols are prefixed with 'llvm' to avoid a potential conflict with *|
|* another BLAKE3 version within the same program. *|
|* *|
\*===----------------------------------------------------------------------===*/

#ifndef LLVM_C_BLAKE3_H
#define LLVM_C_BLAKE3_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define LLVM_BLAKE3_VERSION_STRING "1.3.1"
#define LLVM_BLAKE3_KEY_LEN 32
#define LLVM_BLAKE3_OUT_LEN 32
#define LLVM_BLAKE3_BLOCK_LEN 64
#define LLVM_BLAKE3_CHUNK_LEN 1024
#define LLVM_BLAKE3_MAX_DEPTH 54

// This struct is a private implementation detail. It has to be here because
// it's part of llvm_blake3_hasher below.
typedef struct {
uint32_t cv[8];
uint64_t chunk_counter;
uint8_t buf[LLVM_BLAKE3_BLOCK_LEN];
uint8_t buf_len;
uint8_t blocks_compressed;
uint8_t flags;
} llvm_blake3_chunk_state;

typedef struct {
uint32_t key[8];
llvm_blake3_chunk_state chunk;
uint8_t cv_stack_len;
// The stack size is MAX_DEPTH + 1 because we do lazy merging. For example,
// with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk
// requires a 4th entry, rather than merging everything down to 1, because we
// don't know whether more input is coming. This is different from how the
// reference implementation does things.
uint8_t cv_stack[(LLVM_BLAKE3_MAX_DEPTH + 1) * LLVM_BLAKE3_OUT_LEN];
} llvm_blake3_hasher;

const char *llvm_blake3_version(void);
void llvm_blake3_hasher_init(llvm_blake3_hasher *self);
void llvm_blake3_hasher_init_keyed(llvm_blake3_hasher *self,
const uint8_t key[LLVM_BLAKE3_KEY_LEN]);
void llvm_blake3_hasher_init_derive_key(llvm_blake3_hasher *self,
const char *context);
void llvm_blake3_hasher_init_derive_key_raw(llvm_blake3_hasher *self,
const void *context,
size_t context_len);
void llvm_blake3_hasher_update(llvm_blake3_hasher *self, const void *input,
size_t input_len);
void llvm_blake3_hasher_finalize(const llvm_blake3_hasher *self, uint8_t *out,
size_t out_len);
void llvm_blake3_hasher_finalize_seek(const llvm_blake3_hasher *self,
uint64_t seek, uint8_t *out,
size_t out_len);
void llvm_blake3_hasher_reset(llvm_blake3_hasher *self);

#ifdef __cplusplus
}
#endif

#endif /* LLVM_C_BLAKE3_H */
87 changes: 87 additions & 0 deletions llvm/include/llvm/Support/BLAKE3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//==- BLAKE3.h - BLAKE3 C++ wrapper for LLVM ---------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is a C++ wrapper of the BLAKE3 C interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_BLAKE3_H
#define LLVM_SUPPORT_BLAKE3_H

#include "llvm-c/blake3.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"

namespace llvm {

/// The constant \p LLVM_BLAKE3_OUT_LEN provides the default output length,
/// 32 bytes, which is recommended for most callers.
///
/// 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.
///
/// Shorter BLAKE3 outputs are prefixes of longer ones. Explicitly
/// requesting a short output is equivalent to truncating the default-length
/// output.
template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
using BLAKE3Result = std::array<uint8_t, NumBytes>;

/// A class that wrap the BLAKE3 algorithm.
class BLAKE3 {
public:
BLAKE3() { init(); }

/// Reinitialize the internal state
void init() { llvm_blake3_hasher_init(&Hasher); }

/// Digest more data.
void update(ArrayRef<uint8_t> Data) {
llvm_blake3_hasher_update(&Hasher, Data.data(), Data.size());
}

/// Digest more data.
void update(StringRef Str) {
llvm_blake3_hasher_update(&Hasher, Str.data(), Str.size());
}

/// Finalize the hasher and put the result in \p Result.
/// This doesn't modify the hasher itself, and it's possible to finalize again
/// after adding more input.
template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
void final(BLAKE3Result<NumBytes> &Result) {
llvm_blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
}

/// 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.
template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
BLAKE3Result<NumBytes> final() {
BLAKE3Result<NumBytes> Result;
llvm_blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
return Result;
}

/// Returns a BLAKE3 hash for the given data.
template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
static BLAKE3Result<NumBytes> hash(ArrayRef<uint8_t> Data) {
BLAKE3 Hasher;
Hasher.update(Data);
return Hasher.final<NumBytes>();
}

private:
llvm_blake3_hasher Hasher;
};

} // namespace llvm

#endif
2 changes: 2 additions & 0 deletions llvm/lib/Support/BLAKE3/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DisableFormat: true
SortIncludes: Never
56 changes: 56 additions & 0 deletions llvm/lib/Support/BLAKE3/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
set(LLVM_BLAKE3_FILES
blake3.c
blake3_dispatch.c
blake3_portable.c
)

# The BLAKE3 team recommends using the assembly versions, from the README:
#
# "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."

if (MSVC)
check_symbol_exists(_M_X64 "" IS_X64)
check_symbol_exists(_M_ARM64 "" IS_ARM64)
else()
check_symbol_exists(__x86_64__ "" IS_X64)
check_symbol_exists(__aarch64__ "" IS_ARM64)
endif()

if (IS_X64)
if (MSVC)
enable_language(ASM_MASM)
list(APPEND LLVM_BLAKE3_FILES
blake3_sse2_x86-64_windows_msvc.asm
blake3_sse41_x86-64_windows_msvc.asm
blake3_avx2_x86-64_windows_msvc.asm
blake3_avx512_x86-64_windows_msvc.asm
)
elseif(WIN32)
list(APPEND LLVM_BLAKE3_FILES
blake3_sse2_x86-64_windows_gnu.S
blake3_sse41_x86-64_windows_gnu.S
blake3_avx2_x86-64_windows_gnu.S
blake3_avx512_x86-64_windows_gnu.S
)
else()
list(APPEND LLVM_BLAKE3_FILES
blake3_sse2_x86-64_unix.S
blake3_sse41_x86-64_unix.S
blake3_avx2_x86-64_unix.S
blake3_avx512_x86-64_unix.S
)
endif()
endif()

if (IS_ARM64)
list(APPEND LLVM_BLAKE3_FILES
blake3_neon.c
)
endif()

add_library(LLVMSupportBlake3 OBJECT EXCLUDE_FROM_ALL ${LLVM_BLAKE3_FILES})
llvm_update_compile_flags(LLVMSupportBlake3)
Loading