Skip to content
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
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,12 @@ add_subdirectory(src)
# utils, programs, examples and tests
#

# mtmd needs this even when common is not built
add_subdirectory(vendor/hash)

if (LLAMA_BUILD_COMMON)
add_subdirectory(common)
add_subdirectory(vendor/cpp-httplib)
add_subdirectory(vendor/hash)
endif()

if (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
Expand Down
5 changes: 4 additions & 1 deletion examples/gguf-hash/gguf-hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ extern "C" {
#endif

#include "xxhash/xxhash.h"
#include "sha1/sha1.h"
#include "sha256/sha256.h"

#ifdef __cplusplus
}
#endif

// sha1 is compiled as C++ and lives in a namespace, see scripts/sync_vendor.py
#include "sha1/sha1.h"
using namespace vendor_hash;


// uuid.uuid5(uuid.NAMESPACE_URL, 'en.wikipedia.org/wiki/Llama.cpp')
#define UUID_NAMESPACE_LLAMA_CPP "ef001206-dadc-5f6d-a15f-3359e577d4e5"
Expand Down
38 changes: 38 additions & 0 deletions scripts/sync_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,44 @@
' && (defined(_MSC_VER) && (_MSC_VER >= 1000) || !defined(_MSC_VER)) /* >= C11 */\n'
)],

# sha1 exports a bare "SHA1" symbol, which clashes with the boringssl one at link time.
# we compile it as C++ (see vendor/hash/CMakeLists.txt) and put it in a namespace.
"vendor/hash/sha1/sha1.h": [
(
'#if defined(__cplusplus)\n'
'extern "C" {\n'
'#endif\n',

'namespace vendor_hash {\n'
),
(
'#if defined(__cplusplus)\n'
'}\n'
'#endif\n',

'} // namespace vendor_hash\n'
),
],

"vendor/hash/sha1/sha1.c": [
(
'#include "sha1.h"\n',

'#include "sha1.h"\n'
'\n'
'namespace vendor_hash {\n'
),
(
' SHA1Final((unsigned char *)hash_out, &ctx);\n'
'}\n',

' SHA1Final((unsigned char *)hash_out, &ctx);\n'
'}\n'
'\n'
'} // namespace vendor_hash\n'
),
],

# silence a maybe-uninitialized warning
"vendor/hash/sha256/sha256.c": [(
" uint32_t W[16];\n",
Expand Down
2 changes: 1 addition & 1 deletion tools/mtmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ set_target_properties(mtmd PROPERTIES
)

target_link_libraries (mtmd PUBLIC ggml llama)
target_link_libraries (mtmd PRIVATE Threads::Threads)
target_link_libraries (mtmd PRIVATE Threads::Threads vendor-hash)
target_include_directories(mtmd PUBLIC .)
target_include_directories(mtmd PRIVATE ../..)
target_include_directories(mtmd PRIVATE ../../vendor)
Expand Down
17 changes: 4 additions & 13 deletions tools/mtmd/mtmd-helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "mtmd-helper-common.h"
#include "llama.h"

#include "hash.h"

#include <algorithm>
#include <cinttypes>
#include <vector>
Expand Down Expand Up @@ -356,25 +358,14 @@ static bool decode_audio_from_buf(const unsigned char * buf_in, size_t len, int

} // namespace audio_helpers

// Computes FNV-1a hash of the data
static std::string fnv_hash(const uint8_t * data, size_t len) {
const uint64_t fnv_prime = 0x100000001b3ULL;
uint64_t hash = 0xcbf29ce484222325ULL;

for (size_t i = 0; i < len; ++i) {
hash ^= data[i];
hash *= fnv_prime;
}
return std::to_string(hash);
}

mtmd_helper_bitmap_wrapper mtmd_helper_bitmap_init_from_buf(mtmd_context * ctx, const unsigned char * buf, size_t len, bool placeholder) {
// calculate the hash if needed
std::string id;
mtmd_bitmap * result = nullptr;

if (!placeholder) {
id = fnv_hash(buf, len);
// use sha256 to prevent cache poisoning
id = hash_sha256_hex(buf, len);
}

if (audio_helpers::is_audio_file((const char *)buf, len)) {
Expand Down
2 changes: 1 addition & 1 deletion tools/mtmd/mtmd-helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ MTMD_API struct mtmd_helper_bitmap_wrapper mtmd_helper_bitmap_init_from_file(mtm
// note:
// - for now, video input is only supported via C++ helper functions
// - audio files will be auto-detected based on magic bytes
// - output bitmap will have FNV hash as the ID
// - output bitmap will have SHA-256 hash (hex string) as the ID
// returns nullptr on failure
// this function is thread-safe
MTMD_API struct mtmd_helper_bitmap_wrapper mtmd_helper_bitmap_init_from_buf(mtmd_context * ctx, const unsigned char * buf, size_t len, bool placeholder);
Expand Down
2 changes: 2 additions & 0 deletions tools/ui/embed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ int main(int argc, char ** argv) {
}
cpp += fmt("static const unsigned char asset_%d_data[] = {", i);
append_bytes_hex(cpp, bytes);

// note: this is a simple hash for cache busting, not a cryptographic hash; fnv is enough here
const auto hash = fnv_hash(bytes.data(), bytes.size());

cpp += fmt("};\nstatic const std::size_t asset_%d_size = %zu;\n",
Expand Down
20 changes: 16 additions & 4 deletions vendor/hash/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,30 @@ llama_add_compile_flags()

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

add_library(${TARGET} STATIC
set(VENDOR_SRCS
xxhash/xxhash.c
sha1/sha1.c
sha256/sha256.c
)

# disable warnings in 3rd party code
add_library(${TARGET} STATIC
hash.cpp
hash.h
${VENDOR_SRCS}
)

target_compile_features(${TARGET} PRIVATE cxx_std_17)

# disable warnings in 3rd party code, but keep them for hash.cpp
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${TARGET} PRIVATE /w)
set(NO_WARN_FLAG /w)
else()
target_compile_options(${TARGET} PRIVATE -w)
set(NO_WARN_FLAG -w)
endif()
set_source_files_properties(${VENDOR_SRCS} PROPERTIES COMPILE_OPTIONS ${NO_WARN_FLAG})

# sha1 lives in a namespace to avoid a clash with boringssl, see scripts/sync_vendor.py
set_source_files_properties(sha1/sha1.c PROPERTIES LANGUAGE CXX)

# sha256.c includes "rotate-bits/rotate-bits.h", so consumers get this dir too
target_include_directories(${TARGET} PUBLIC .)
23 changes: 23 additions & 0 deletions vendor/hash/hash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "hash.h"

extern "C" {
#include "sha256/sha256.h"
}

static std::string to_hex(const unsigned char * digest, size_t len) {
static const char hex[] = "0123456789abcdef";

std::string out;
out.reserve(2*len);
for (size_t i = 0; i < len; ++i) {
out += hex[digest[i] >> 4];
out += hex[digest[i] & 0xf];
}
return out;
}

std::string hash_sha256_hex(const void * data, size_t len) {
unsigned char digest[SHA256_DIGEST_SIZE];
sha256_hash(digest, (const unsigned char *) data, len);
return to_hex(digest, SHA256_DIGEST_SIZE);
}
9 changes: 9 additions & 0 deletions vendor/hash/hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

// C++ wrapper for the vendored hash functions

#include <cstddef>
#include <string>

// returns the SHA-256 digest as a lowercase hex string
std::string hash_sha256_hex(const void * data, size_t len);
4 changes: 4 additions & 0 deletions vendor/hash/sha1/sha1.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ A million repetitions of "a"

#include "sha1.h"

namespace vendor_hash {


#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

Expand Down Expand Up @@ -293,3 +295,5 @@ void SHA1(
SHA1Final((unsigned char *)hash_out, &ctx);
}

} // namespace vendor_hash

8 changes: 2 additions & 6 deletions vendor/hash/sha1/sha1.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

#include "stdint.h"

#if defined(__cplusplus)
extern "C" {
#endif
namespace vendor_hash {

typedef struct
{
Expand Down Expand Up @@ -45,8 +43,6 @@ void SHA1(
const char *str,
uint32_t len);

#if defined(__cplusplus)
}
#endif
} // namespace vendor_hash

#endif /* SHA1_H */
Loading