Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,5 @@ MigrationBackup/
doc/html
doc/xml
build/*
_codeql_build_dir/
_codeql_detected_source_root
62 changes: 62 additions & 0 deletions merklecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,68 @@ namespace merkle
throw std::runtime_error("EVP_Digest failed: " + std::to_string(rc));
}
}

/// @brief OpenSSL SHA384
/// @param l Left node hash
/// @param r Right node hash
/// @param out Output node hash
static inline void sha384_openssl(
const merkle::HashT<48>& l,
const merkle::HashT<48>& r,
merkle::HashT<48>& out)
{
uint8_t block[48 * 2];
memcpy(&block[0], l.bytes, 48);
memcpy(&block[48], r.bytes, 48);

const EVP_MD* md = EVP_sha384();
int rc =
EVP_Digest(&block[0], sizeof(block), out.bytes, nullptr, md, nullptr);
if (rc != 1)
{
throw std::runtime_error("EVP_Digest failed: " + std::to_string(rc));
}
}

/// @brief OpenSSL SHA512
/// @param l Left node hash
/// @param r Right node hash
/// @param out Output node hash
static inline void sha512_openssl(
const merkle::HashT<64>& l,
const merkle::HashT<64>& r,
merkle::HashT<64>& out)
{
uint8_t block[64 * 2];
memcpy(&block[0], l.bytes, 64);
memcpy(&block[64], r.bytes, 64);

const EVP_MD* md = EVP_sha512();
int rc =
EVP_Digest(&block[0], sizeof(block), out.bytes, nullptr, md, nullptr);
if (rc != 1)
{
throw std::runtime_error("EVP_Digest failed: " + std::to_string(rc));
}
}

/// @brief Type of hashes in the SHA384 tree type
typedef HashT<48> Hash384;

/// @brief Type of paths in the SHA384 tree type
typedef PathT<48, sha384_openssl> Path384;

/// @brief SHA384 tree with OpenSSL hash function
typedef TreeT<48, sha384_openssl> Tree384;

/// @brief Type of hashes in the SHA512 tree type
typedef HashT<64> Hash512;

/// @brief Type of paths in the SHA512 tree type
typedef PathT<64, sha512_openssl> Path512;

/// @brief SHA512 tree with OpenSSL hash function
typedef TreeT<64, sha512_openssl> Tree512;
#endif

/// @brief Type of hashes in the default tree type
Expand Down
40 changes: 40 additions & 0 deletions test/compare_hash_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,32 @@ void bench(
<< std::endl;
}

template <typename T, size_t HASH_SIZE>
void benchT(
const std::vector<merkle::HashT<HASH_SIZE>>& 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(
Expand Down Expand Up @@ -287,6 +313,20 @@ int main()
bench<OpenSSLFullTree>(hashes, "OpenSSL", root_interval);
#endif

#ifdef HAVE_OPENSSL
{
std::cout << "--- merklecpp trees with full SHA384: " << std::endl;
auto hashes384 = make_hashesT<48>(num_leaves);
benchT<merkle::Tree384, 48>(hashes384, "OpenSSL", root_interval);
}

{
std::cout << "--- merklecpp trees with full SHA512: " << std::endl;
auto hashes512 = make_hashesT<64>(num_leaves);
benchT<merkle::Tree512, 64>(hashes512, "OpenSSL", root_interval);
}
#endif

#ifdef HAVE_EVERCRYPT
bench<EverCryptFullTree>(hashes, "EverCrypt", root_interval);
#endif
Expand Down
46 changes: 46 additions & 0 deletions test/time_large_trees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,52 @@ int main()
std::cout << "NEW: " << mt.statistics.to_string() << " in " << seconds
<< " sec" << std::endl;

#ifdef HAVE_OPENSSL
{
auto hashes384 = make_hashesT<48>(num_leaves);

merkle::Tree384 mt384;
size_t j384 = 0;
auto start384 = std::chrono::high_resolution_clock::now();
for (auto& h : hashes384)
{
mt384.insert(h);
if ((j384++ % root_interval) == 0)
mt384.root();
}
mt384.root();
auto stop384 = std::chrono::high_resolution_clock::now();
double seconds384 =
std::chrono::duration_cast<std::chrono::nanoseconds>(stop384 - start384)
.count() /
1e9;
std::cout << "SHA384: " << mt384.statistics.to_string() << " in "
<< seconds384 << " sec" << std::endl;
}

{
auto hashes512 = make_hashesT<64>(num_leaves);

merkle::Tree512 mt512;
size_t j512 = 0;
auto start512 = std::chrono::high_resolution_clock::now();
for (auto& h : hashes512)
{
mt512.insert(h);
if ((j512++ % root_interval) == 0)
mt512.root();
}
mt512.root();
auto stop512 = std::chrono::high_resolution_clock::now();
double seconds512 =
std::chrono::duration_cast<std::chrono::nanoseconds>(stop512 - start512)
.count() /
1e9;
std::cout << "SHA512: " << mt512.statistics.to_string() << " in "
<< seconds512 << " sec" << std::endl;
}
#endif

#ifdef HAVE_EVERCRYPT
std::vector<uint8_t*> ec_hashes;
for (auto& h : hashes)
Expand Down
Loading
Loading