From f0e0699c384b1d175063a04cf5afae397d8e9edf Mon Sep 17 00:00:00 2001 From: achamayou Date: Tue, 14 Jul 2026 13:33:17 +0000 Subject: [PATCH 1/3] Remove EverCrypt support Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CMakeLists.txt | 22 +-- test/CMakeLists.txt | 8 +- test/compare_evercrypt.cpp | 156 -------------------- test/compare_hash_functions.cpp | 246 -------------------------------- test/demo_tree.cpp | 4 - test/serialise_to_file.cpp | 4 - test/time_large_trees.cpp | 45 +----- 7 files changed, 3 insertions(+), 482 deletions(-) delete mode 100644 test/compare_evercrypt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e35781..8acf629 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -project(merklecpp LANGUAGES CXX C ASM) +project(merklecpp LANGUAGES CXX) cmake_minimum_required(VERSION 3.11) set(CMAKE_CXX_STANDARD 17) @@ -10,7 +10,6 @@ set(MERKLECPP_DIR ${CMAKE_CURRENT_SOURCE_DIR}) option(PROFILE "enable profiling" OFF) option(TESTS "enable testing" OFF) -option(EVERCRYPT "enable comparison with EverCrypt Merkle trees" OFF) option(OPENSSL "enable OpenSSL" OFF) option(TRACE "enable debug traces" OFF) option(CLANG_TIDY "enable clang-tidy checks during build" OFF) @@ -33,25 +32,6 @@ install(TARGETS merklecpp) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so") -if(EVERCRYPT) - if(NOT EVERCRYPT_DIR) - message(FATAL_ERROR "EverCrypt not found, add -DEVERCRYPT_DIR=...") - endif() - - file(GLOB EVERCRYPT_SRC "${EVERCRYPT_DIR}/*.c" - "${EVERCRYPT_DIR}/*-x86_64-linux.S" - ) - add_library(evercrypt STATIC ${EVERCRYPT_SRC}) - target_include_directories( - evercrypt PUBLIC ${EVERCRYPT_DIR} ${EVERCRYPT_DIR}/kremlin - ${EVERCRYPT_DIR}/kremlin/kremlib - ) - set_target_properties(evercrypt PROPERTIES LINKER_LANGUAGE C) - - target_compile_definitions(merklecpp INTERFACE HAVE_EVERCRYPT) - target_link_libraries(merklecpp INTERFACE evercrypt) -endif() - if(OPENSSL) find_package(OpenSSL) target_compile_definitions(merklecpp INTERFACE HAVE_OPENSSL) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e90a87c..6dee12c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,13 +30,7 @@ add_merklecpp_test(partial_serialisation partial_serialisation.cpp) add_merklecpp_test(serialise_to_file serialise_to_file.cpp) add_merklecpp_test(coverage coverage.cpp) -if(TARGET evercrypt.host) - add_merklecpp_test(compare_evercrypt compare_evercrypt.cpp) -endif() - -if(OPENSSL - OR EVERCRYPT -) +if(OPENSSL) add_merklecpp_test(compare_hash_functions compare_hash_functions.cpp) endif() diff --git a/test/compare_evercrypt.cpp b/test/compare_evercrypt.cpp deleted file mode 100644 index b637e76..0000000 --- a/test/compare_evercrypt.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "util.h" - -#include -#include -#include -#include - -#define HSZ 32 -#define PRNTSZ 3 - -void dump_ec_tree(merkle_tree* mt) -{ - std::cout << "hs=" << std::endl; - for (size_t i = 0; i < mt->hs.sz; i++) - { - MerkleTree_Low_Datastructures_hash_vec hv = mt->hs.vs[i]; - if (hv.sz > 0) - { - std::cout << i << ":"; - for (size_t j = 0; j < hv.sz; j++) - { - std::cout << " " << merkle::Hash(hv.vs[j]).to_string(PRNTSZ); - } - std::cout << std::endl; - } - } - std::cout << "root=" << merkle::Hash(mt->mroot).to_string(PRNTSZ) - << std::endl; - std::cout << "rhs="; - for (size_t i = 0; i < mt->rhs.sz; i++) - std::cout << " " << merkle::Hash(mt->rhs.vs[i]).to_string(PRNTSZ); - std::cout << std::endl; - std::cout << "rhs_ok=" << mt->rhs_ok << std::endl; - std::cout << "i=" << mt->i << ", j=" << mt->j << std::endl; -} - -void compare_roots(merkle::Tree& mt, merkle_tree* ec_mt) -{ - auto root = mt.root(); - - uint8_t* ec_root_bytes = mt_init_hash(HSZ); - mt_get_root(ec_mt, ec_root_bytes); - auto ec_root = merkle::Hash(ec_root_bytes); - mt_free_hash(ec_root_bytes); - - if (root != ec_root) - { - std::cout << mt.num_leaves() << ": " << root.to_string() - << " != " << ec_root.to_string() << std::endl; - std::cout << mt.to_string(PRNTSZ) << std::endl; - std::cout << "EverCrypt tree: " << std::endl; - dump_ec_tree(ec_mt); - throw std::runtime_error("root hash mismatch"); - } -} - -int main() -{ - merkle_tree* ec_mt = NULL; - uint8_t* ec_hash = mt_init_hash(HSZ); - - try - { -#ifndef NDEBUG - const size_t num_trees = 1024; - const size_t root_interval = 31; -#else - const size_t num_trees = 4096; - const size_t root_interval = 128; -#endif - - // std::srand(0); - std::srand(std::time(0)); - - size_t total_inserts = 0, total_flushes = 0, total_retractions = 0; - - for (size_t k = 0; k < num_trees; k++) - { - merkle::Tree mt; - - // Build trees with k+1 leaves - int j = 0; - std::vector hashes = make_hashes(k + 1); - for (const auto h : hashes) - { - mt.insert(h); - total_inserts++; - - memcpy(ec_hash, h.bytes, HSZ); - if (!ec_mt) - ec_mt = mt_create(ec_hash); - else - mt_insert(ec_mt, ec_hash); - - if ((j++ % root_interval) == 0) - { - size_t index = - mt.min_index() + ((mt.max_index() - mt.min_index()) / 3); - mt.flush_to(index); - if (!mt_flush_to_pre(ec_mt, index)) - throw std::runtime_error("EverCrypt flush precondition violation"); - mt_flush_to(ec_mt, index); - total_flushes++; - compare_roots(mt, ec_mt); - } - - if ((std::rand() / (double)RAND_MAX) > 0.9) - { - size_t index = random_index(mt); - mt.retract_to(index); - if (!mt_retract_to_pre(ec_mt, index)) - throw std::runtime_error( - "EverCrypt retract precondition violation"); - mt_retract_to(ec_mt, index); - total_retractions++; - compare_roots(mt, ec_mt); - } - - if ( - (total_inserts % 1000000 == 0) || - (k == num_trees - 1 && h == hashes.back())) - { - std::cout << k << " trees, " << total_inserts << " inserts, " - << total_flushes << " flushes, " << total_retractions - << " retractions: OK" << std::endl; - } - } - - compare_roots(mt, ec_mt); - - mt_free(ec_mt); - ec_mt = NULL; - } - } - catch (std::exception& ex) - { - std::cout << "Error: " << ex.what() << std::endl; - mt_free_hash(ec_hash); - mt_free(ec_mt); - return 1; - } - catch (...) - { - std::cout << "Error" << std::endl; - mt_free_hash(ec_hash); - mt_free(ec_mt); - return 1; - } - - mt_free_hash(ec_hash); - - return 0; -} \ No newline at end of file diff --git a/test/compare_hash_functions.cpp b/test/compare_hash_functions.cpp index 55b9245..1056a99 100644 --- a/test/compare_hash_functions.cpp +++ b/test/compare_hash_functions.cpp @@ -8,188 +8,10 @@ #include #include -constexpr size_t HSZ = 32; -constexpr size_t PRNTSZ = 3; - -#ifdef HAVE_EVERCRYPT -# include -# include - -void sha256_compress_evercrypt( - const merkle::HashT<32>& l, - const merkle::HashT<32>& r, - merkle::HashT<32>& out) -{ - mt_sha256_compress((uint8_t*)l.bytes, (uint8_t*)r.bytes, (uint8_t*)out.bytes); -} - -void sha256_evercrypt( - const merkle::HashT<32>& l, - const merkle::HashT<32>& r, - merkle::HashT<32>& out) -{ - uint8_t block[32 * 2]; - memcpy(&block[0], l.bytes, 32); - memcpy(&block[32], r.bytes, 32); - Hacl_Hash_SHA2_hash_256(block, sizeof(block), (uint8_t*)out.bytes); -} - -void mt_sha256_evercrypt(uint8_t* src1, uint8_t* src2, uint8_t* dst) -{ - uint8_t block[32 * 2]; - memcpy(&block[0], src1, 32); - memcpy(&block[32], src2, 32); - Hacl_Hash_SHA2_hash_256(block, sizeof(block), dst); -} - -typedef merkle::TreeT<32, sha256_compress_evercrypt> EverCryptTree; -typedef merkle::TreeT<32, sha256_evercrypt> EverCryptFullTree; -#endif - #ifdef HAVE_OPENSSL using OpenSSLFullTree = merkle::TreeT<32, merkle::sha256_openssl>; #endif -template < - void (*HF1)( - const merkle::HashT<32>& l, - const merkle::HashT<32>& r, - merkle::HashT<32>& out), - void (*HF2)( - const merkle::HashT<32>& l, - const merkle::HashT<32>& r, - merkle::HashT<32>& out)> -void compare_roots( - merkle::TreeT<32, HF1>& mt1, merkle::TreeT<32, HF2>& mt2, const char* name) -{ - auto mt1_root = mt1.root(); - auto mt2_root = mt2.root(); - - if (mt1_root != mt2_root) - { - std::cout << mt1.num_leaves() << ": " << mt1_root.to_string() - << " != " << mt2_root.to_string() << '\n'; - std::cout << "mt1: " << '\n'; - std::cout << mt1.to_string(PRNTSZ) << '\n'; - std::cout << name << ": " << '\n'; - std::cout << mt2.to_string(PRNTSZ) << '\n'; - throw std::runtime_error("root hash mismatch"); - } -} - -void compare_compression_hashes() -{ -#ifndef NDEBUG - const size_t num_trees = 1024; - const size_t root_interval = 31; -#else - const size_t num_trees = 4096; - const size_t root_interval = 128; -#endif - - size_t total_inserts = 0; - size_t total_roots = 0; - - for (size_t k = 0; k < num_trees; k++) - { - merkle::Tree mt; - -#ifdef HAVE_EVERCRYPT - EverCryptTree mte; -#endif - - // Build trees with k+1 leaves - int j = 0; - auto hashes = make_hashes(k + 1); - - for (const auto h : hashes) - { - mt.insert(h); - -#ifdef HAVE_EVERCRYPT - mte.insert(h); -#endif - - total_inserts++; - - if ((j++ % root_interval) == 0) - { -#ifdef HAVE_EVERCRYPT - compare_roots(mt, mte, "EverCrypt"); -#endif - - total_roots++; - } - } - -#ifdef HAVE_EVERCRYPT - compare_roots(mt, mte, "EverCrypt"); -#endif - - } - - std::cout << num_trees << " trees, " << total_inserts << " inserts, " - << total_roots << " roots with SHA256 compression function: OK" - << '\n'; -} - -#if defined(HAVE_OPENSSL) && defined(HAVE_EVERCRYPT) -void compare_full_hashes() -{ -# ifndef NDEBUG - const size_t num_trees = 1024; - const size_t root_interval = 31; -# else - const size_t num_trees = 4096; - const size_t root_interval = 128; -# endif - - size_t total_inserts = 0; - size_t total_roots = 0; - - for (size_t k = 0; k < num_trees; k++) - { - OpenSSLFullTree mto; - -# ifdef HAVE_EVERCRYPT - merkle::TreeT<32, sha256_evercrypt> mte; -# endif - - // Build trees with k+1 leaves - int j = 0; - auto hashes = make_hashes(k + 1); - - for (const auto h : hashes) - { - mto.insert(h); - -# ifdef HAVE_EVERCRYPT - mte.insert(h); -# endif - - total_inserts++; - - if ((j++ % root_interval) == 0) - { -# ifdef HAVE_EVERCRYPT - compare_roots(mto, mte, "EverCrypt"); -# endif - - total_roots++; - } - } - -# ifdef HAVE_EVERCRYPT - compare_roots(mto, mte, "OpenSSL"); -# endif - - } - - std::cout << num_trees << " trees, " << total_inserts << " inserts, " - << total_roots << " roots with full SHA256: OK" << '\n'; -} -#endif - template void bench( const std::vector& hashes, @@ -246,41 +68,6 @@ void benchT( << '\n'; } -#ifdef HAVE_EVERCRYPT -template -void bench_evercrypt( - const std::vector& hashes, - const std::string& name, - size_t root_interval) -{ - size_t j = 0, num_inserts = 0, num_roots = 0; - uint8_t* ec_root = mt_init_hash(32); - auto start = std::chrono::high_resolution_clock::now(); - merkle_tree* ec_mt = mt_create_custom(32, hashes[0], HASH_FUNCTION); - for (size_t i = 1; i < hashes.size(); i++) - { - mt_insert(ec_mt, hashes[i]); - num_inserts++; - if ((j++ % root_interval) == 0) - { - mt_get_root(ec_mt, ec_root); - num_roots++; - } - } - mt_get_root(ec_mt, ec_root); - num_roots++; - auto stop = std::chrono::high_resolution_clock::now(); - auto seconds = - std::chrono::duration_cast(stop - start).count() / - 1e9; - std::cout << std::left << std::setw(10) << name << ": " << num_inserts - << " insertions, " << num_roots << " roots in " << seconds << " sec" - << '\n'; - mt_free_hash(ec_root); - mt_free(ec_mt); -} -#endif - int main() { try @@ -288,12 +75,6 @@ int main() // std::srand(0); std::srand(std::time(nullptr)); - compare_compression_hashes(); - -#if defined(HAVE_EVERCRYPT) && defined(HAVE_OPENSSL) - compare_full_hashes(); -#endif - #ifndef NDEBUG const size_t num_leaves = static_cast(128) * 1024; const size_t root_interval = 128; @@ -309,10 +90,6 @@ int main() bench(hashes, "merklecpp", root_interval); -#ifdef HAVE_EVERCRYPT - bench(hashes, "EverCrypt", root_interval); -#endif - std::cout << "--- merklecpp trees with full SHA256: " << '\n'; #ifdef HAVE_OPENSSL @@ -332,29 +109,6 @@ int main() benchT(hashes512, "OpenSSL", root_interval); } #endif - -#ifdef HAVE_EVERCRYPT - bench(hashes, "EverCrypt", root_interval); -#endif - -#ifdef HAVE_EVERCRYPT - std::vector ec_hashes; - for (auto& h : hashes) - { - ec_hashes.push_back(mt_init_hash(32)); - memcpy(ec_hashes.back(), h.bytes, 32); - } - - std::cout << "--- EverCrypt trees with SHA256 compression function: " - << '\n'; - bench_evercrypt(ec_hashes, "EverCrypt", root_interval); - - std::cout << "--- EverCrypt trees with full SHA256: " << '\n'; - bench_evercrypt(ec_hashes, "EverCrypt", root_interval); - - for (auto h : ec_hashes) - mt_free_hash(h); -#endif } catch (std::exception& ex) { diff --git a/test/demo_tree.cpp b/test/demo_tree.cpp index 05d6f87..f997f5a 100644 --- a/test/demo_tree.cpp +++ b/test/demo_tree.cpp @@ -5,10 +5,6 @@ #include #include -#ifdef HAVE_EVERCRYPT -# include -#endif - #include "util.h" #include diff --git a/test/serialise_to_file.cpp b/test/serialise_to_file.cpp index 3f2dde4..8a79344 100644 --- a/test/serialise_to_file.cpp +++ b/test/serialise_to_file.cpp @@ -6,10 +6,6 @@ #include #include -#ifdef HAVE_EVERCRYPT -# include -#endif - #include "util.h" #include diff --git a/test/time_large_trees.cpp b/test/time_large_trees.cpp index f5ebfa1..a86113c 100644 --- a/test/time_large_trees.cpp +++ b/test/time_large_trees.cpp @@ -4,16 +4,10 @@ #include #include -#ifdef HAVE_EVERCRYPT -# include -#endif - #include "util.h" #include -constexpr size_t HSZ = 32; - int main() { try @@ -45,7 +39,7 @@ int main() static_cast(std::chrono::duration_cast(stop - start) .count()) / 1e9; - std::cout << "NEW: " << mt.statistics.to_string() << " in " << seconds + std::cout << "SHA256: " << mt.statistics.to_string() << " in " << seconds << " sec" << '\n'; #ifdef HAVE_OPENSSL @@ -97,43 +91,6 @@ int main() << seconds512 << " sec" << '\n'; } #endif - -#ifdef HAVE_EVERCRYPT - std::vector ec_hashes; - for (auto& h : hashes) - { - ec_hashes.push_back(mt_init_hash(HSZ)); - memcpy(ec_hashes.back(), h.bytes, HSZ); - } - - uint8_t* ec_root = mt_init_hash(HSZ); - size_t num_ec_roots = 1; - start = std::chrono::high_resolution_clock::now(); - merkle_tree* ec_mt = mt_create(ec_hashes[0]); - for (size_t i = 1; i < ec_hashes.size(); i++) - { - mt_insert(ec_mt, ec_hashes[i]); - if (i % root_interval == 0) - { - mt_get_root(ec_mt, ec_root); - num_ec_roots++; - } - } - mt_get_root(ec_mt, ec_root); - stop = std::chrono::high_resolution_clock::now(); - const double ec_seconds = std::chrono::duration_cast(stop - start) - .count() / - 1e9; - std::cout << "EC :" - << " num_insert=" << ec_hashes.size() - << " num_root=" << num_ec_roots << " in " << ec_seconds << " sec" - << '\n'; - - for (auto h : ec_hashes) - mt_free_hash(h); - mt_free_hash(ec_root); - mt_free(ec_mt); -#endif } catch (std::exception& ex) { From dcd0d4e3b04852ad7f9a1ca67ef9cbd8626ec7c3 Mon Sep 17 00:00:00 2001 From: achamayou Date: Tue, 14 Jul 2026 13:47:52 +0000 Subject: [PATCH 2/3] Include standard headers in hash benchmark Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/compare_hash_functions.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/compare_hash_functions.cpp b/test/compare_hash_functions.cpp index 1056a99..2bb7def 100644 --- a/test/compare_hash_functions.cpp +++ b/test/compare_hash_functions.cpp @@ -4,6 +4,8 @@ #include "util.h" #include +#include +#include #include #include #include From f1b7876622c2a5633c3242eb91e04cba79a86964 Mon Sep 17 00:00:00 2001 From: achamayou Date: Tue, 14 Jul 2026 15:42:58 +0000 Subject: [PATCH 3/3] Set a timeout for CI tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b12b1bf..8638695 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,6 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build/${{ matrix.build_type }} shell: bash - run: ctest -VV -C ${{ matrix.build_type }} + run: ctest -VV -C ${{ matrix.build_type }} --timeout 300 env: ASAN_OPTIONS: use_sigaltstack=false # To avoid SetAlternateSignalStack with clang-11