зеркало из https://github.com/microsoft/CCF.git
Merkle trees: add OpenSSL and mbedTLS hash functions and switch History to full SHA256 (#2031)
Co-authored-by: Amaury Chamayou <amchamay@microsoft.com>
This commit is contained in:
Родитель
c27ecbcb34
Коммит
7d11a18993
|
@ -425,8 +425,9 @@ if(BUILD_TESTS)
|
|||
# Merkle Tree memory test
|
||||
add_executable(merkle_mem src/node/test/merkle_mem.cpp)
|
||||
target_link_libraries(
|
||||
merkle_mem PRIVATE ccfcrypto.host secp256k1.host
|
||||
${CMAKE_THREAD_LIBS_INIT} $<BUILD_INTERFACE:merklecpp>
|
||||
merkle_mem
|
||||
PRIVATE ccfcrypto.host secp256k1.host ${CMAKE_THREAD_LIBS_INIT}
|
||||
$<BUILD_INTERFACE:merklecpp> crypto
|
||||
)
|
||||
use_client_mbedtls(merkle_mem)
|
||||
|
||||
|
@ -474,12 +475,12 @@ if(BUILD_TESTS)
|
|||
add_picobench(
|
||||
merkle_bench
|
||||
SRCS src/node/test/merkle_bench.cpp
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host crypto
|
||||
)
|
||||
add_picobench(
|
||||
history_bench
|
||||
SRCS src/node/test/history_bench.cpp
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host crypto
|
||||
)
|
||||
add_picobench(
|
||||
kv_bench
|
||||
|
|
|
@ -46,6 +46,7 @@ if(LVI_MITIGATIONS)
|
|||
set(OE_TARGET_ENCLAVE_AND_STD
|
||||
openenclave::oeenclave-lvi-cfg openenclave::oecryptombedtls-lvi-cfg
|
||||
openenclave::oelibcxx-lvi-cfg openenclave::oelibc-lvi-cfg
|
||||
openenclave::oecryptoopenssl-lvi-cfg
|
||||
)
|
||||
set(OE_TARGET_ENCLAVE_CORE_LIBS
|
||||
openenclave::oeenclave-lvi-cfg openenclave::oecryptombedtls-lvi-cfg
|
||||
|
|
|
@ -7,15 +7,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# merklecpp traces are disabled by default to avoid unnecessary clutter.
|
||||
set(TRACE
|
||||
OFF
|
||||
CACHE BOOL "Enable merklecpp traces"
|
||||
)
|
||||
set(USE_CCF_LOG
|
||||
ON
|
||||
CACHE BOOL "Use the CCF logging infrastructure for traces"
|
||||
)
|
||||
add_subdirectory(${CCF_DIR}/src/libmerklecpp)
|
||||
|
||||
set(PYTHON unbuffer python3)
|
||||
|
@ -205,7 +196,7 @@ function(add_unit_test name)
|
|||
enable_coverage(${name})
|
||||
target_link_libraries(
|
||||
${name} PRIVATE ${LINK_LIBCXX} ccfcrypto.host openenclave::oehostverify
|
||||
$<BUILD_INTERFACE:merklecpp>
|
||||
$<BUILD_INTERFACE:merklecpp> crypto
|
||||
)
|
||||
use_client_mbedtls(${name})
|
||||
add_san(${name})
|
||||
|
|
|
@ -7,7 +7,7 @@ add_picobench(
|
|||
SRCS ${CMAKE_CURRENT_LIST_DIR}/tests/small_bank_serdes_bench.cpp
|
||||
src/crypto/symmetric_key.cpp src/enclave/thread_local.cpp
|
||||
INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host
|
||||
LINK_LIBS ccfcrypto.host secp256k1.host crypto
|
||||
)
|
||||
|
||||
add_client_exe(
|
||||
|
|
|
@ -6,55 +6,61 @@ set(CMAKE_CXX_STANDARD 17)
|
|||
set(MERKLECPP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
option(PROFILE "enable profiling" OFF)
|
||||
option(EVERCRYPT "enable comparison with EverCrypt Merkle trees" OFF)
|
||||
option(TESTS "enable testing" OFF)
|
||||
|
||||
option(EVERCRYPT "enable comparison with EverCrypt Merkle trees" OFF)
|
||||
option(OPENSSL "enable OpenSSL" OFF)
|
||||
option(MBEDTLS "enable mbedTLS" OFF)
|
||||
option(TRACE "enable debug traces" OFF)
|
||||
option(USE_CCF_LOG "Use the CCF logging infrastructure for traces" OFF)
|
||||
|
||||
add_library(merklecpp INTERFACE)
|
||||
target_include_directories(merklecpp INTERFACE .)
|
||||
|
||||
if(TRACE)
|
||||
target_compile_definitions(merklecpp INTERFACE WITH_TRACE)
|
||||
endif()
|
||||
|
||||
if(USE_CCF_LOG)
|
||||
target_compile_definitions(merklecpp INTERFACE USE_CCF_LOG)
|
||||
target_compile_definitions(merklecpp INTERFACE MERKLECPP_TRACE_ENABLED)
|
||||
endif()
|
||||
|
||||
install(TARGETS merklecpp)
|
||||
|
||||
if(TESTS)
|
||||
if(EVERCRYPT)
|
||||
if(NOT (DEFINED $ENV{EVERCRYPT_DIR}))
|
||||
set(EVERCRYPT_DIR ../../3rdparty/hacl-star/evercrypt)
|
||||
endif()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
|
||||
|
||||
file(GLOB EVERCRYPT_SRC "${EVERCRYPT_DIR}/*.c"
|
||||
"${EVERCRYPT_DIR}/*-x86_64-linux.S"
|
||||
)
|
||||
add_library(evercrypt.host STATIC ${EVERCRYPT_SRC})
|
||||
target_include_directories(
|
||||
evercrypt.host PUBLIC ${EVERCRYPT_DIR} ${EVERCRYPT_DIR}/kremlin
|
||||
${EVERCRYPT_DIR}/kremlin/kremlib
|
||||
)
|
||||
set_target_properties(evercrypt.host PROPERTIES LINKER_LANGUAGE C)
|
||||
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)
|
||||
target_link_libraries(merklecpp INTERFACE crypto)
|
||||
endif()
|
||||
|
||||
if(MBEDTLS)
|
||||
find_library(MBEDCRYPTO_LIBRARY NMAMES libmbedcrypto.a)
|
||||
target_compile_definitions(merklecpp INTERFACE HAVE_MBEDTLS)
|
||||
target_link_libraries(merklecpp INTERFACE mbedcrypto)
|
||||
endif()
|
||||
|
||||
if(TESTS)
|
||||
enable_testing()
|
||||
|
||||
function(add_unit_test NAME SRC)
|
||||
add_executable(${NAME} ${SRC})
|
||||
target_link_libraries(${NAME} PRIVATE $<BUILD_INTERFACE:merklecpp>)
|
||||
|
||||
if(TRACE)
|
||||
target_compile_definitions(${NAME} PRIVATE WITH_TRACE)
|
||||
if(USE_CCF_LOG)
|
||||
target_compile_definitions(${NAME} PRIVATE USE_CCF_LOG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PROFILE)
|
||||
target_compile_options(${NAME} PRIVATE -g -pg)
|
||||
target_link_options(${NAME} PRIVATE -g -pg)
|
||||
|
@ -67,11 +73,6 @@ if(TESTS)
|
|||
target_link_options(${NAME} PRIVATE -fsanitize=address)
|
||||
endif()
|
||||
|
||||
if(EVERCRYPT)
|
||||
target_link_libraries(${NAME} PRIVATE evercrypt.host)
|
||||
target_compile_definitions(${NAME} PRIVATE HAVE_EVERCRYPT)
|
||||
endif()
|
||||
|
||||
add_test(${NAME} ${NAME})
|
||||
endfunction()
|
||||
|
||||
|
|
|
@ -32,30 +32,29 @@
|
|||
# undef max
|
||||
#endif
|
||||
|
||||
// Hashes in the trace output are truncated to TRACE_HASH_SIZE bytes.
|
||||
#define TRACE_HASH_SIZE 3
|
||||
#ifdef HAVE_OPENSSL
|
||||
# include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_TRACE
|
||||
# ifdef USE_CCF_LOG
|
||||
// Use the CCF logging infrastructure to enable tracing in enclaves.
|
||||
# include "ds/logger.h"
|
||||
# define TRACE(X) \
|
||||
{ \
|
||||
X; \
|
||||
};
|
||||
# define TOUT LOG_TRACE
|
||||
# else
|
||||
// Send trace output to std::cout.
|
||||
#ifdef HAVE_MBEDTLS
|
||||
# include <mbedtls/sha256.h>
|
||||
#endif
|
||||
|
||||
#ifdef MERKLECPP_TRACE_ENABLED
|
||||
// Hashes in the trace output are truncated to TRACE_HASH_SIZE bytes.
|
||||
# define TRACE_HASH_SIZE 3
|
||||
|
||||
# ifndef MERKLECPP_TRACE
|
||||
# include <iostream>
|
||||
# define TOUT std::cout
|
||||
# define TRACE(X) \
|
||||
# define MERKLECPP_TOUT std::cout
|
||||
# define MERKLECPP_TRACE(X) \
|
||||
{ \
|
||||
X; \
|
||||
TOUT.flush(); \
|
||||
MERKLECPP_TOUT.flush(); \
|
||||
};
|
||||
# endif
|
||||
#else
|
||||
# define TRACE(X)
|
||||
# define MERKLECPP_TRACE(X)
|
||||
#endif
|
||||
|
||||
namespace merkle
|
||||
|
@ -160,14 +159,14 @@ namespace merkle
|
|||
|
||||
void serialise(std::vector<uint8_t>& buffer) const
|
||||
{
|
||||
TRACE(TOUT << "> HashT::serialise " << std::endl);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> HashT::serialise " << std::endl);
|
||||
for (auto& b : bytes)
|
||||
buffer.push_back(b);
|
||||
}
|
||||
|
||||
void deserialise(const std::vector<uint8_t>& buffer, size_t& position)
|
||||
{
|
||||
TRACE(TOUT << "> HashT::deserialise " << std::endl);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> HashT::deserialise " << std::endl);
|
||||
if (buffer.size() - position < SIZE)
|
||||
throw std::runtime_error("not enough bytes");
|
||||
for (size_t i = 0; i < sizeof(bytes); i++)
|
||||
|
@ -241,34 +240,38 @@ namespace merkle
|
|||
bool verify(const HashT<HASH_SIZE>& root) const
|
||||
{
|
||||
HashT<HASH_SIZE> result = _leaf, tmp;
|
||||
TRACE(
|
||||
TOUT << "> PathT::verify " << _leaf.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << "> PathT::verify " << _leaf.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl);
|
||||
for (const Element& e : elements)
|
||||
{
|
||||
if (e.direction == PATH_LEFT)
|
||||
{
|
||||
TRACE(
|
||||
TOUT << " - " << e.hash.to_string(TRACE_HASH_SIZE) << " x "
|
||||
<< result.to_string(TRACE_HASH_SIZE) << std::endl);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << " - " << e.hash.to_string(TRACE_HASH_SIZE)
|
||||
<< " x " << result.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl);
|
||||
HASH_FUNCTION(e.hash, result, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE(
|
||||
TOUT << " - " << result.to_string(TRACE_HASH_SIZE) << " x "
|
||||
<< e.hash.to_string(TRACE_HASH_SIZE) << std::endl);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << " - " << result.to_string(TRACE_HASH_SIZE)
|
||||
<< " x " << e.hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl);
|
||||
HASH_FUNCTION(result, e.hash, tmp);
|
||||
}
|
||||
std::swap(result, tmp);
|
||||
}
|
||||
TRACE(TOUT << " = " << result.to_string(TRACE_HASH_SIZE) << std::endl);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << " = " << result.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl);
|
||||
return result == root;
|
||||
}
|
||||
|
||||
void serialise(std::vector<uint8_t>& bytes) const
|
||||
{
|
||||
TRACE(TOUT << "> PathT::serialise " << std::endl);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> PathT::serialise " << std::endl);
|
||||
_leaf.serialise(bytes);
|
||||
serialise_size_t(_leaf_index, bytes);
|
||||
serialise_size_t(_max_index, bytes);
|
||||
|
@ -282,7 +285,7 @@ namespace merkle
|
|||
|
||||
void deserialise(const std::vector<uint8_t>& bytes, size_t& position)
|
||||
{
|
||||
TRACE(TOUT << "> PathT::deserialise " << std::endl);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> PathT::deserialise " << std::endl);
|
||||
elements.clear();
|
||||
_leaf.deserialise(bytes, position);
|
||||
_leaf_index = deserialise_size_t(bytes, position);
|
||||
|
@ -540,8 +543,9 @@ namespace merkle
|
|||
|
||||
void insert(const Hash& hash)
|
||||
{
|
||||
TRACE(TOUT << "> insert " << hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> insert "
|
||||
<< hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
uninserted_leaf_nodes.push_back(Node::make(hash));
|
||||
statistics.num_insert++;
|
||||
}
|
||||
|
@ -560,14 +564,16 @@ namespace merkle
|
|||
|
||||
void flush_to(size_t index)
|
||||
{
|
||||
TRACE(TOUT << "> flush_to " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> flush_to " << index << std::endl;);
|
||||
statistics.num_flush++;
|
||||
|
||||
walk_to(index, false, [this](Node*& n, bool go_right) {
|
||||
if (go_right && n->left)
|
||||
{
|
||||
TRACE(TOUT << " - conflate "
|
||||
<< n->left->hash.to_string(TRACE_HASH_SIZE) << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " - conflate "
|
||||
<< n->left->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
if (n->left && n->left->dirty)
|
||||
hash(n->left);
|
||||
delete (n->left->left);
|
||||
|
@ -586,7 +592,7 @@ namespace merkle
|
|||
|
||||
void retract_to(size_t index)
|
||||
{
|
||||
TRACE(TOUT << "> retract_to " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> retract_to " << index << std::endl;);
|
||||
statistics.num_retract++;
|
||||
|
||||
if (max_index() < index)
|
||||
|
@ -611,9 +617,10 @@ namespace merkle
|
|||
n->dirty = true;
|
||||
if (go_left && n->right)
|
||||
{
|
||||
TRACE(TOUT << " - eliminate "
|
||||
<< n->right->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " - eliminate "
|
||||
<< n->right->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
bool is_root = n == _root;
|
||||
|
||||
Node* old_parent = n->parent;
|
||||
|
@ -638,16 +645,18 @@ namespace merkle
|
|||
|
||||
if (is_root)
|
||||
{
|
||||
TRACE(TOUT << " - new root: " << n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << " - new root: "
|
||||
<< n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
assert(n->parent == nullptr);
|
||||
assert(_root == n);
|
||||
}
|
||||
|
||||
assert(n->invariant());
|
||||
|
||||
TRACE(TOUT << " - after elimination: " << std::endl
|
||||
<< to_string(TRACE_HASH_SIZE) << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " - after elimination: " << std::endl
|
||||
<< to_string(TRACE_HASH_SIZE) << std::endl;);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -683,7 +692,8 @@ namespace merkle
|
|||
|
||||
const Tree split(size_t index)
|
||||
{
|
||||
TRACE(TOUT << "> split (slow) at " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> split (slow) at " << index
|
||||
<< std::endl;);
|
||||
Tree other = *this;
|
||||
if (index > num_flushed)
|
||||
other.retract_to(index - 1);
|
||||
|
@ -693,24 +703,27 @@ namespace merkle
|
|||
|
||||
const Hash& root()
|
||||
{
|
||||
TRACE(TOUT << "> root" << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> root" << std::endl;);
|
||||
statistics.num_root++;
|
||||
compute_root();
|
||||
assert(_root && !_root->dirty);
|
||||
TRACE(TOUT << " - root: " << _root->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " - root: " << _root->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
return _root->hash;
|
||||
}
|
||||
|
||||
std::shared_ptr<Hash> past_root(size_t index)
|
||||
{
|
||||
TRACE(TOUT << "> past_root " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> past_root " << index << std::endl;);
|
||||
statistics.num_past_root++;
|
||||
|
||||
auto p = path(index);
|
||||
auto result = std::make_shared<Hash>(p->leaf());
|
||||
TRACE(TOUT << " - " << p->to_string(TRACE_HASH_SIZE) << std::endl;
|
||||
TOUT << " - " << result->to_string(TRACE_HASH_SIZE) << std::endl;);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << " - " << p->to_string(TRACE_HASH_SIZE) << std::endl;
|
||||
MERKLECPP_TOUT << " - " << result->to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
for (auto e : *p)
|
||||
{
|
||||
if (e.direction == Path::Direction::PATH_LEFT)
|
||||
|
@ -746,9 +759,12 @@ namespace merkle
|
|||
bool go_right = (it >> (8 * sizeof(it) - 1)) & 0x01;
|
||||
if (update)
|
||||
walk_stack.push_back(cur);
|
||||
TRACE(TOUT << " - at " << cur->hash.to_string(TRACE_HASH_SIZE) << " ("
|
||||
<< cur->size << "/" << (unsigned)cur->height << ")"
|
||||
<< " (" << (go_right ? "R" : "L") << ")" << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " - at " << cur->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< " (" << cur->size << "/" << (unsigned)cur->height
|
||||
<< ")"
|
||||
<< " (" << (go_right ? "R" : "L") << ")"
|
||||
<< std::endl;);
|
||||
if (cur->height == height)
|
||||
{
|
||||
if (!f(cur, go_right))
|
||||
|
@ -770,7 +786,7 @@ namespace merkle
|
|||
|
||||
std::unique_ptr<Path> path(size_t index)
|
||||
{
|
||||
TRACE(TOUT << "> path from " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> path from " << index << std::endl;);
|
||||
std::list<typename Path::Element> elements;
|
||||
|
||||
walk_to(index, false, [&elements](Node* n, bool go_right) {
|
||||
|
@ -787,11 +803,12 @@ namespace merkle
|
|||
|
||||
void serialise(std::vector<uint8_t>& bytes)
|
||||
{
|
||||
TRACE(TOUT << "> serialise " << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> serialise " << std::endl;);
|
||||
|
||||
compute_root();
|
||||
|
||||
TRACE(TOUT << to_string(TRACE_HASH_SIZE) << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
|
||||
serialise_size_t(leaf_nodes.size() + uninserted_leaf_nodes.size(), bytes);
|
||||
serialise_size_t(num_flushed, bytes);
|
||||
|
@ -819,7 +836,7 @@ namespace merkle
|
|||
|
||||
void deserialise(const std::vector<uint8_t>& bytes, size_t& position)
|
||||
{
|
||||
TRACE(TOUT << "> deserialise " << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> deserialise " << std::endl;);
|
||||
|
||||
delete (_root);
|
||||
leaf_nodes.clear();
|
||||
|
@ -844,8 +861,8 @@ namespace merkle
|
|||
|
||||
std::vector<Node*> level = leaf_nodes, next_level;
|
||||
size_t it = num_flushed;
|
||||
TRACE(TOUT << "num_flushed=" << num_flushed << " it=" << it
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "num_flushed=" << num_flushed
|
||||
<< " it=" << it << std::endl;);
|
||||
uint8_t level_no = 0;
|
||||
while (it != 0 || level.size() > 1)
|
||||
{
|
||||
|
@ -853,7 +870,7 @@ namespace merkle
|
|||
if (it & 0x01)
|
||||
{
|
||||
Hash h(bytes, position);
|
||||
TRACE(TOUT << "+";);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "+";);
|
||||
auto n = Node::make(h);
|
||||
n->height = level_no + 1;
|
||||
n->size = (1 << n->height) - 1;
|
||||
|
@ -861,10 +878,10 @@ namespace merkle
|
|||
level.insert(level.begin(), n);
|
||||
}
|
||||
|
||||
TRACE(for (auto& n
|
||||
: level) TOUT
|
||||
<< " " << n->hash.to_string(TRACE_HASH_SIZE);
|
||||
TOUT << std::endl;);
|
||||
MERKLECPP_TRACE(for (auto& n
|
||||
: level) MERKLECPP_TOUT
|
||||
<< " " << n->hash.to_string(TRACE_HASH_SIZE);
|
||||
MERKLECPP_TOUT << std::endl;);
|
||||
|
||||
// Rebuild the level
|
||||
for (size_t i = 0; i < level.size(); i += 2)
|
||||
|
@ -905,7 +922,7 @@ namespace merkle
|
|||
|
||||
const Hash& leaf(size_t index) const
|
||||
{
|
||||
TRACE(TOUT << "> leaf " << index << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << "> leaf " << index << std::endl;);
|
||||
if (index >= num_leaves())
|
||||
throw std::runtime_error("leaf index out of bounds");
|
||||
if (index - num_flushed >= leaf_nodes.size())
|
||||
|
@ -1043,7 +1060,7 @@ namespace merkle
|
|||
|
||||
void hash(Node* n, size_t indent = 2) const
|
||||
{
|
||||
#ifndef WITH_TRACE
|
||||
#ifndef MERKLECPP_WITH_TRACE
|
||||
(void)indent;
|
||||
#endif
|
||||
|
||||
|
@ -1065,12 +1082,13 @@ namespace merkle
|
|||
assert(n->left && n->right);
|
||||
HASH_FUNCTION(n->left->hash, n->right->hash, n->hash);
|
||||
statistics.num_hash++;
|
||||
TRACE(
|
||||
TOUT << std::string(indent, ' ') << "+ h("
|
||||
<< n->left->hash.to_string(TRACE_HASH_SIZE) << ", "
|
||||
<< n->right->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< ") == " << n->hash.to_string(TRACE_HASH_SIZE) << " ("
|
||||
<< n->size << "/" << (unsigned)n->height << ")" << std::endl);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << std::string(indent, ' ') << "+ h("
|
||||
<< n->left->hash.to_string(TRACE_HASH_SIZE) << ", "
|
||||
<< n->right->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< ") == " << n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< " (" << n->size << "/" << (unsigned)n->height
|
||||
<< ")" << std::endl);
|
||||
n->dirty = false;
|
||||
hashing_stack.pop_back();
|
||||
}
|
||||
|
@ -1106,8 +1124,9 @@ namespace merkle
|
|||
}
|
||||
else
|
||||
{
|
||||
TRACE(TOUT << " @ " << n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << " @ "
|
||||
<< n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
assert(n->left && n->right);
|
||||
if (!n->left->is_full())
|
||||
insert_leaf_recursive(n->left, new_leaf);
|
||||
|
@ -1123,8 +1142,9 @@ namespace merkle
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
TRACE(TOUT << " @ " << n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << " @ "
|
||||
<< n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
assert(n->invariant());
|
||||
|
||||
if (n->is_full())
|
||||
|
@ -1160,10 +1180,11 @@ namespace merkle
|
|||
|
||||
Node* process_insertion_stack(bool complete = true)
|
||||
{
|
||||
TRACE(TOUT << " X " << (complete ? "complete" : "continue") << ":";
|
||||
for (size_t i = 0; i < insertion_stack.size(); i++) TOUT
|
||||
<< " " << insertion_stack[i].n->hash.to_string(TRACE_HASH_SIZE);
|
||||
TOUT << std::endl;);
|
||||
MERKLECPP_TRACE(
|
||||
MERKLECPP_TOUT << " X " << (complete ? "complete" : "continue") << ":";
|
||||
for (size_t i = 0; i < insertion_stack.size(); i++) MERKLECPP_TOUT
|
||||
<< " " << insertion_stack[i].n->hash.to_string(TRACE_HASH_SIZE);
|
||||
MERKLECPP_TOUT << std::endl;);
|
||||
|
||||
Node* result = insertion_stack.back().n;
|
||||
insertion_stack.pop_back();
|
||||
|
@ -1189,8 +1210,10 @@ namespace merkle
|
|||
|
||||
if (!complete && !result->is_full())
|
||||
{
|
||||
TRACE(TOUT << " X save " << result->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< " X save "
|
||||
<< result->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1202,8 +1225,9 @@ namespace merkle
|
|||
|
||||
void insert_leaf(Node*& root, Node* n)
|
||||
{
|
||||
TRACE(TOUT << " - insert_leaf " << n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT << " - insert_leaf "
|
||||
<< n->hash.to_string(TRACE_HASH_SIZE)
|
||||
<< std::endl;);
|
||||
leaf_nodes.push_back(n);
|
||||
if (insertion_stack.empty() && !root)
|
||||
root = n;
|
||||
|
@ -1218,8 +1242,9 @@ namespace merkle
|
|||
{
|
||||
if (!uninserted_leaf_nodes.empty())
|
||||
{
|
||||
TRACE(TOUT << "* insert_leaves " << leaf_nodes.size() << " +"
|
||||
<< uninserted_leaf_nodes.size() << std::endl;);
|
||||
MERKLECPP_TRACE(MERKLECPP_TOUT
|
||||
<< "* insert_leaves " << leaf_nodes.size() << " +"
|
||||
<< uninserted_leaf_nodes.size() << std::endl;);
|
||||
// Potential future improvement: make this go fast when there are many
|
||||
// leaves to insert.
|
||||
for (auto& n : uninserted_leaf_nodes)
|
||||
|
@ -1232,7 +1257,7 @@ namespace merkle
|
|||
};
|
||||
|
||||
// clang-format off
|
||||
static void sha256_compress(const HashT<32> &l, const HashT<32> &r, HashT<32> &out) {
|
||||
void sha256_compress(const HashT<32> &l, const HashT<32> &r, HashT<32> &out) {
|
||||
static const uint32_t constants[] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
|
@ -1291,14 +1316,13 @@ namespace merkle
|
|||
// clang-format on
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
# include <openssl/sha.h>
|
||||
// Note: Some versions of OpenSSL don't provide SHA256_Transform.
|
||||
void sha256_compress_openssl(
|
||||
const uint8_t* h1, const uint8_t* h2, uint8_t* out)
|
||||
inline void sha256_compress_openssl(
|
||||
const HashT<32>& l, const HashT<32>& r, HashT<32>& out)
|
||||
{
|
||||
unsigned char block[HASH_SIZE * 2];
|
||||
memcpy(&block[0], h1, HASH_SIZE);
|
||||
memcpy(&block[HASH_SIZE], h2, HASH_SIZE);
|
||||
unsigned char block[32 * 2];
|
||||
memcpy(&block[0], l.bytes, 32);
|
||||
memcpy(&block[32], r.bytes, 32);
|
||||
|
||||
SHA256_CTX ctx;
|
||||
if (SHA256_Init(&ctx) != 1)
|
||||
|
@ -1306,7 +1330,49 @@ namespace merkle
|
|||
SHA256_Transform(&ctx, &block[0]);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
((uint32_t*)out)[i] = htobe32(((uint32_t*)ctx.h)[i]);
|
||||
((uint32_t*)out.bytes)[i] = htobe32(((uint32_t*)ctx.h)[i]);
|
||||
}
|
||||
|
||||
inline void sha256_openssl(
|
||||
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);
|
||||
SHA256(block, sizeof(block), out.bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
// Note: Technically, mbedtls_internal_sha256_process is for internal use
|
||||
// only.
|
||||
inline void sha256_compress_mbedtls(
|
||||
const HashT<32>& l, const HashT<32>& r, HashT<32>& out)
|
||||
{
|
||||
unsigned char block[32 * 2];
|
||||
memcpy(&block[0], l.bytes, 32);
|
||||
memcpy(&block[32], r.bytes, 32);
|
||||
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, false);
|
||||
mbedtls_internal_sha256_process(&ctx, &block[0]);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
((uint32_t*)out.bytes)[i] = htobe32(ctx.state[i]);
|
||||
}
|
||||
|
||||
inline void sha256_mbedtls(
|
||||
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);
|
||||
mbedtls_sha256_ret(block, sizeof(block), out.bytes, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -11,3 +11,12 @@ add_unit_test(${MERKLECPP_TEST_PREFIX}serialisation serialisation.cpp)
|
|||
if(TARGET evercrypt.host)
|
||||
add_unit_test(${MERKLECPP_TEST_PREFIX}compare_evercrypt compare_evercrypt.cpp)
|
||||
endif()
|
||||
|
||||
if(OPENSSL
|
||||
OR MBEDTLS
|
||||
OR EVERCRYPT
|
||||
)
|
||||
add_unit_test(
|
||||
${MERKLECPP_TEST_PREFIX}compare_hash_functions compare_hash_functions.cpp
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <merklecpp.h>
|
||||
|
||||
#define HSZ 32
|
||||
#define PRNTSZ 3
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
# include <Hacl_Hash.h>
|
||||
# include <MerkleTree.h>
|
||||
|
||||
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
|
||||
typedef merkle::TreeT<32, merkle::sha256_compress_openssl> OpenSSLTree;
|
||||
typedef merkle::TreeT<32, merkle::sha256_openssl> OpenSSLFullTree;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
typedef merkle::TreeT<32, merkle::sha256_compress_mbedtls> MbedTLSTree;
|
||||
typedef merkle::TreeT<32, merkle::sha256_mbedtls> MbedTLSFullTree;
|
||||
#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() << std::endl;
|
||||
std::cout << "mt1: " << std::endl;
|
||||
std::cout << mt1.to_string(PRNTSZ) << std::endl;
|
||||
std::cout << name << ": " << std::endl;
|
||||
std::cout << mt2.to_string(PRNTSZ) << std::endl;
|
||||
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, total_roots = 0;
|
||||
|
||||
for (size_t k = 0; k < num_trees; k++)
|
||||
{
|
||||
merkle::Tree mt;
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
EverCryptTree mte;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
OpenSSLTree mto;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
MbedTLSTree mtm;
|
||||
#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
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
mto.insert(h);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
mtm.insert(h);
|
||||
#endif
|
||||
|
||||
total_inserts++;
|
||||
|
||||
if ((j++ % root_interval) == 0)
|
||||
{
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
compare_roots(mt, mte, "EverCrypt");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
compare_roots(mt, mto, "OpenSSL");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
compare_roots(mt, mtm, "mbedTLS");
|
||||
#endif
|
||||
|
||||
total_roots++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
compare_roots(mt, mte, "EverCrypt");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
compare_roots(mt, mto, "OpenSSL");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
compare_roots(mt, mtm, "mbedTLS");
|
||||
#endif
|
||||
}
|
||||
|
||||
static char time_str[256] = "";
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::strftime(time_str, sizeof(time_str), "%R", std::localtime(&t));
|
||||
std::cout << time_str << ": " << num_trees << " trees, " << total_inserts
|
||||
<< " inserts, " << total_roots
|
||||
<< " roots with SHA256 compression function: OK" << std::endl;
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL) && (defined(HAVE_EVERCRYPT) || defined(HAVE_MBEDTLS))
|
||||
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, total_roots = 0;
|
||||
|
||||
for (size_t k = 0; k < num_trees; k++)
|
||||
{
|
||||
OpenSSLFullTree mto;
|
||||
|
||||
# ifdef HAVE_EVERCRYPT
|
||||
merkle::TreeT<32, sha256_evercrypt> mte;
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_MBEDTLS
|
||||
MbedTLSFullTree mtm;
|
||||
# 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
|
||||
|
||||
# ifdef HAVE_MBEDTLS
|
||||
mtm.insert(h);
|
||||
# endif
|
||||
|
||||
total_inserts++;
|
||||
|
||||
if ((j++ % root_interval) == 0)
|
||||
{
|
||||
# ifdef HAVE_EVERCRYPT
|
||||
compare_roots(mto, mte, "EverCrypt");
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_MBEDTLS
|
||||
compare_roots(mto, mtm, "mbedTLS");
|
||||
# endif
|
||||
|
||||
total_roots++;
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef HAVE_EVERCRYPT
|
||||
compare_roots(mto, mte, "OpenSSL");
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_MBEDTLS
|
||||
compare_roots(mto, mtm, "mbedTLS");
|
||||
# endif
|
||||
}
|
||||
|
||||
static char time_str[256] = "";
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::strftime(time_str, sizeof(time_str), "%R", std::localtime(&t));
|
||||
std::cout << time_str << ": " << num_trees << " trees, " << total_inserts
|
||||
<< " inserts, " << total_roots << " roots with full SHA256: OK"
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
void bench(
|
||||
const std::vector<merkle::Hash>& hashes,
|
||||
const std::string& name,
|
||||
size_t root_interval)
|
||||
{
|
||||
size_t j = 0;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
T mt;
|
||||
for (auto& h : hashes)
|
||||
{
|
||||
mt.insert(h);
|
||||
if ((j++ % root_interval) == 0)
|
||||
mt.root();
|
||||
}
|
||||
mt.root();
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
double seconds =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start).count() /
|
||||
1e9;
|
||||
std::cout << std::left << std::setw(10) << name << ": "
|
||||
<< mt.statistics.num_insert << " insertions, "
|
||||
<< mt.statistics.num_root << " roots in " << seconds << " sec"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
template <void (*HASH_FUNCTION)(uint8_t* l, uint8_t* r, uint8_t* out)>
|
||||
void bench_evercrypt(
|
||||
const std::vector<uint8_t*>& 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<std::chrono::nanoseconds>(stop - start).count() /
|
||||
1e9;
|
||||
std::cout << std::left << std::setw(10) << name << ": " << num_inserts
|
||||
<< " insertions, " << num_roots << " roots in " << seconds << " sec"
|
||||
<< std::endl;
|
||||
mt_free_hash(ec_root);
|
||||
mt_free(ec_mt);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
// std::srand(0);
|
||||
std::srand(std::time(0));
|
||||
|
||||
compare_compression_hashes();
|
||||
|
||||
#if defined(HAVE_EVERCRYPT) && (defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS))
|
||||
compare_full_hashes();
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
const size_t num_leaves = 128 * 1024;
|
||||
const size_t root_interval = 128;
|
||||
#else
|
||||
const size_t num_leaves = 16 * 1024 * 1024;
|
||||
const size_t root_interval = 1024;
|
||||
#endif
|
||||
|
||||
auto hashes = make_hashes(num_leaves);
|
||||
|
||||
std::cout << "--- merklecpp trees with SHA256 compression function: "
|
||||
<< std::endl;
|
||||
|
||||
bench<merkle::Tree>(hashes, "merklecpp", root_interval);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
bench<OpenSSLTree>(hashes, "OpenSSL", root_interval);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
bench<MbedTLSTree>(hashes, "mbedTLS", root_interval);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
bench<EverCryptTree>(hashes, "EverCrypt", root_interval);
|
||||
#endif
|
||||
|
||||
std::cout << "--- merklecpp trees with full SHA256: " << std::endl;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
bench<OpenSSLFullTree>(hashes, "OpenSSL", root_interval);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
bench<MbedTLSFullTree>(hashes, "mbedTLS", root_interval);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
bench<EverCryptFullTree>(hashes, "EverCrypt", root_interval);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
std::vector<uint8_t*> 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: "
|
||||
<< std::endl;
|
||||
bench_evercrypt<mt_sha256_compress>(ec_hashes, "EverCrypt", root_interval);
|
||||
|
||||
std::cout << "--- EverCrypt trees with full SHA256: " << std::endl;
|
||||
bench_evercrypt<mt_sha256_evercrypt>(ec_hashes, "EverCrypt", root_interval);
|
||||
|
||||
for (auto h : ec_hashes)
|
||||
mt_free_hash(h);
|
||||
#endif
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "Error: " << ex.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Error" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
project(evercrypt LANGUAGES C ASM)
|
||||
|
||||
option(PROFILE "enable profiling" OFF)
|
||||
option(EVERCRYPT "enable comparison with EverCrypt Merkle trees" OFF)
|
||||
|
||||
if(EVERCRYPT)
|
||||
if(NOT (DEFINED $ENV{EVERCRYPT_DIR}))
|
||||
set(EVERCRYPT_DIR ../../../../3rdparty/hacl-star/evercrypt)
|
||||
endif()
|
||||
|
||||
set(EVERCRYPT_INC ${EVERCRYPT_DIR} ${EVERCRYPT_DIR}/kremlin
|
||||
${EVERCRYPT_DIR}/kremlin/kremlib
|
||||
)
|
||||
|
||||
file(GLOB EVEREST_SRC "${EVERCRYPT_DIR}/*.c"
|
||||
"${EVERCRYPT_DIR}/*-x86_64-linux.S"
|
||||
)
|
||||
|
||||
add_library(evercrypt STATIC ${EVEREST_SRC})
|
||||
target_include_directories(evercrypt PRIVATE ${EVERCRYPT_INC})
|
||||
|
||||
if(PROFILE)
|
||||
target_compile_options(evercrypt PRIVATE -g -pg)
|
||||
target_link_options(evercrypt PRIVATE -g -pg)
|
||||
endif()
|
||||
endif()
|
|
@ -31,13 +31,13 @@ int main()
|
|||
merkle::Tree mt;
|
||||
size_t j = 0;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
for (auto h : hashes)
|
||||
for (auto& h : hashes)
|
||||
{
|
||||
mt.insert(h);
|
||||
if ((j++ % root_interval) == 0)
|
||||
mt.root();
|
||||
}
|
||||
// auto root = mt.root();
|
||||
auto root = mt.root();
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
double seconds =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start)
|
||||
|
@ -48,7 +48,7 @@ int main()
|
|||
|
||||
#ifdef HAVE_EVERCRYPT
|
||||
std::vector<uint8_t*> ec_hashes;
|
||||
for (auto h : hashes)
|
||||
for (auto& h : hashes)
|
||||
{
|
||||
ec_hashes.push_back(mt_init_hash(HSZ));
|
||||
memcpy(ec_hashes.back(), h.bytes, HSZ);
|
||||
|
@ -58,7 +58,6 @@ int main()
|
|||
size_t num_ec_roots = 1;
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
merkle_tree* ec_mt = mt_create(ec_hashes[0]);
|
||||
mt_get_root(ec_mt, ec_root);
|
||||
for (size_t i = 1; i < ec_hashes.size(); i++)
|
||||
{
|
||||
mt_insert(ec_mt, ec_hashes[i]);
|
||||
|
@ -68,6 +67,7 @@ int main()
|
|||
num_ec_roots++;
|
||||
}
|
||||
}
|
||||
mt_get_root(ec_mt, ec_root);
|
||||
stop = std::chrono::high_resolution_clock::now();
|
||||
seconds = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start)
|
||||
.count() /
|
||||
|
|
|
@ -16,9 +16,14 @@
|
|||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <merklecpp.h>
|
||||
#include <string.h>
|
||||
|
||||
#define HAVE_OPENSSL
|
||||
#define HAVE_MBEDTLS
|
||||
// merklecpp traces are off by default, even when CCF tracing is enabled
|
||||
// #include "merklecpp_trace.h"
|
||||
#include <merklecpp.h>
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <>
|
||||
|
@ -198,11 +203,13 @@ namespace ccf
|
|||
}
|
||||
};
|
||||
|
||||
typedef merkle::TreeT<32, merkle::sha256_openssl> HistoryTree;
|
||||
|
||||
class Receipt
|
||||
{
|
||||
private:
|
||||
merkle::Hash root;
|
||||
std::shared_ptr<merkle::Path> path = nullptr;
|
||||
HistoryTree::Hash root;
|
||||
std::shared_ptr<HistoryTree::Path> path = nullptr;
|
||||
|
||||
public:
|
||||
Receipt() {}
|
||||
|
@ -211,10 +218,10 @@ namespace ccf
|
|||
{
|
||||
size_t position = 0;
|
||||
root.deserialise(v, position);
|
||||
path = std::make_shared<merkle::Path>(v, position);
|
||||
path = std::make_shared<HistoryTree::Path>(v, position);
|
||||
}
|
||||
|
||||
Receipt(merkle::Tree* tree, uint64_t index)
|
||||
Receipt(HistoryTree* tree, uint64_t index)
|
||||
{
|
||||
root = tree->root();
|
||||
path = tree->path(index);
|
||||
|
@ -222,7 +229,7 @@ namespace ccf
|
|||
|
||||
Receipt(const Receipt&) = delete;
|
||||
|
||||
bool verify(merkle::Tree* tree) const
|
||||
bool verify(HistoryTree* tree) const
|
||||
{
|
||||
return tree->max_index() == path->max_index() && tree->root() == root &&
|
||||
path->verify(root);
|
||||
|
@ -239,19 +246,19 @@ namespace ccf
|
|||
|
||||
class MerkleTreeHistory
|
||||
{
|
||||
merkle::Tree* tree;
|
||||
HistoryTree* tree;
|
||||
|
||||
public:
|
||||
MerkleTreeHistory(MerkleTreeHistory const&) = delete;
|
||||
|
||||
MerkleTreeHistory(const std::vector<uint8_t>& serialised)
|
||||
{
|
||||
tree = new merkle::Tree(serialised);
|
||||
tree = new HistoryTree(serialised);
|
||||
}
|
||||
|
||||
MerkleTreeHistory(crypto::Sha256Hash first_hash = {})
|
||||
{
|
||||
tree = new merkle::Tree(merkle::Hash(first_hash.h));
|
||||
tree = new HistoryTree(merkle::Hash(first_hash.h));
|
||||
}
|
||||
|
||||
~MerkleTreeHistory()
|
||||
|
@ -263,7 +270,7 @@ namespace ccf
|
|||
void deserialise(const std::vector<uint8_t>& serialised)
|
||||
{
|
||||
delete (tree);
|
||||
tree = new merkle::Tree(serialised);
|
||||
tree = new HistoryTree(serialised);
|
||||
}
|
||||
|
||||
void append(crypto::Sha256Hash& hash)
|
||||
|
@ -283,7 +290,7 @@ namespace ccf
|
|||
{
|
||||
delete (tree);
|
||||
crypto::Sha256Hash root(rhs.get_root());
|
||||
tree = new merkle::Tree(merkle::Hash(root.h));
|
||||
tree = new HistoryTree(merkle::Hash(root.h));
|
||||
}
|
||||
|
||||
void flush(uint64_t index)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ds/logger.h"
|
||||
|
||||
// Use the CCF logging infrastructure for merklecpp traces.
|
||||
#define MERKLECPP_TRACE_ENABLED
|
||||
#define MERKLECPP_TRACE(X) \
|
||||
{ \
|
||||
X; \
|
||||
};
|
||||
#define MERKLECPP_TOUT LOG_TRACE
|
Загрузка…
Ссылка в новой задаче