diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..be6c954 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,54 @@ +--- +Checks: > + -*, + bugprone-*, + -bugprone-easily-swappable-parameters, + -bugprone-unhandled-self-assignment, + cert-*, + -cert-err33-c, + -cert-err34-c, + -cert-msc30-c, + -cert-msc32-c, + -cert-msc50-cpp, + -cert-msc51-cpp, + -cert-oop54-cpp, + clang-analyzer-*, + concurrency-*, + -concurrency-mt-unsafe, + cppcoreguidelines-*, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-c-copy-assignment-signature, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-member-init, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-special-member-functions, + hicpp-*, + -hicpp-avoid-c-arrays, + -hicpp-explicit-conversions, + -hicpp-member-init, + -hicpp-no-array-decay, + -hicpp-signed-bitwise, + -hicpp-special-member-functions, + -hicpp-vararg, + misc-*, + -misc-confusable-identifiers, + -misc-include-cleaner, + -misc-non-private-member-variables-in-classes, + -misc-unconventional-assign-operator, + modernize-*, + -modernize-avoid-c-arrays, + -modernize-use-trailing-return-type, + performance-*, + portability-*, + readability-*, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-magic-numbers +WarningsAsErrors: '*' +FormatStyle: file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 910293b..a6a6eef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Install packages - run: sudo apt install doctest-dev clang + run: sudo apt install doctest-dev clang clang-tidy if: matrix.os == 'ubuntu-latest' - uses: actions/checkout@v4 @@ -47,7 +47,7 @@ jobs: working-directory: ${{github.workspace}}/build/${{ matrix.build_type }} run: | if [ "$RUNNER_OS" == "Linux" ]; then - cmake $GITHUB_WORKSPACE -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DTESTS=ON -DOPENSSL=ON + cmake $GITHUB_WORKSPACE -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DTESTS=ON -DOPENSSL=ON -DCLANG_TIDY=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON else cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DTESTS=ON fi @@ -57,6 +57,11 @@ jobs: shell: bash run: cmake --build . --config ${{ matrix.build_type }} + - name: Clang-Tidy Header + if: matrix.os == 'ubuntu-latest' + shell: bash + run: clang-tidy merklecpp.h -p build/${{ matrix.build_type }} --warnings-as-errors='*' + - name: Test working-directory: ${{github.workspace}}/build/${{ matrix.build_type }} shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index cd0e846..d9e232a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,17 @@ 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) + +if(CLANG_TIDY) + find_program(CLANG_TIDY_PROGRAM clang-tidy) + if(CLANG_TIDY_PROGRAM) + set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_PROGRAM}) + set(CMAKE_C_CLANG_TIDY ${CLANG_TIDY_PROGRAM}) + else() + message(FATAL_ERROR "clang-tidy not found") + endif() +endif() add_library(merklecpp INTERFACE) target_include_directories(merklecpp INTERFACE .) diff --git a/merklecpp.h b/merklecpp.h index 26ae030..965a384 100644 --- a/merklecpp.h +++ b/merklecpp.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #ifdef HAVE_OPENSSL @@ -38,9 +39,12 @@ # define MERKLECPP_TRACE(X) #endif -#define MERKLECPP_VERSION_MAJOR 1 -#define MERKLECPP_VERSION_MINOR 0 -#define MERKLECPP_VERSION_PATCH 0 +enum : std::uint8_t +{ + MERKLECPP_VERSION_MAJOR = 1, + MERKLECPP_VERSION_MINOR = 0, + MERKLECPP_VERSION_PATCH = 0 +}; namespace merkle { @@ -67,19 +71,23 @@ namespace merkle static inline void serialise_uint64_t(uint64_t n, std::vector& bytes) { - size_t sz = sizeof(uint64_t); + size_t const sz = sizeof(uint64_t); bytes.reserve(bytes.size() + sz); for (uint64_t i = 0; i < sz; i++) + { bytes.push_back((n >> (8 * (sz - i - 1))) & 0xFF); + } } static inline uint64_t deserialise_uint64_t( const std::vector& bytes, size_t& index) { uint64_t r = 0; - uint64_t sz = sizeof(uint64_t); + uint64_t const sz = sizeof(uint64_t); for (uint64_t i = 0; i < sz; i++) + { r |= static_cast(bytes.at(index++)) << (8 * (sz - i - 1)); + } return r; } @@ -109,10 +117,12 @@ namespace merkle HashT(const std::string& s) { if (s.length() != 2 * SIZE) + { throw std::runtime_error("invalid hash string"); + } for (size_t i = 0; i < SIZE; i++) { - int tmp; + int tmp = 0; sscanf(s.c_str() + 2 * i, "%02x", &tmp); bytes[i] = tmp; } @@ -123,7 +133,9 @@ namespace merkle HashT(const std::vector& bytes) { if (bytes.size() < SIZE) + { throw std::runtime_error("not enough bytes"); + } deserialise(bytes); } @@ -133,7 +145,9 @@ namespace merkle HashT(const std::vector& bytes, size_t& position) { if (bytes.size() - position < SIZE) + { throw std::runtime_error("not enough bytes"); + } deserialise(bytes, position); } @@ -145,7 +159,7 @@ namespace merkle } /// @brief The size of the hash (in number of bytes) - size_t size() const + [[nodiscard]] size_t size() const { return SIZE; } @@ -157,7 +171,7 @@ namespace merkle } /// @brief The size of the serialisation of the hash (in number of bytes) - size_t serialised_size() const + [[nodiscard]] size_t serialised_size() const { return SIZE; } @@ -165,16 +179,19 @@ namespace merkle /// @brief Convert a hash to a hex-encoded string /// @param num_bytes The maximum number of bytes to convert /// @param lower_case Enables lower-case hex characters - std::string to_string(size_t num_bytes = SIZE, bool lower_case = true) const + [[nodiscard]] std::string to_string( + size_t num_bytes = SIZE, bool lower_case = true) const { - size_t num_chars = 2 * num_bytes; + size_t const num_chars = 2 * num_bytes; std::string r(num_chars, '_'); for (size_t i = 0; i < num_bytes; i++) + { snprintf( const_cast(r.data() + 2 * i), num_chars + 1 - 2 * i, lower_case ? "%02x" : "%02X", bytes[i]); + } return r; } @@ -203,7 +220,9 @@ namespace merkle { MERKLECPP_TRACE(MERKLECPP_TOUT << "> HashT::serialise " << std::endl); for (auto& b : bytes) + { buffer.push_back(b); + } } /// @brief Deserialises a hash @@ -213,9 +232,13 @@ namespace merkle { 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++) + { bytes[i] = buffer[position++]; + } } /// @brief Deserialises a hash @@ -248,14 +271,10 @@ namespace merkle { public: /// @brief Path direction - typedef enum - { - PATH_LEFT, - PATH_RIGHT - } Direction; + using Direction = enum { PATH_LEFT, PATH_RIGHT }; /// @brief Path element - typedef struct + using Element = struct { /// @brief The hash of the path element HashT hash; @@ -264,7 +283,7 @@ namespace merkle /// @note If @p direction == PATH_LEFT, @p hash joins at the left, i.e. /// if t is the current hash, e.g. a leaf, then t' = Hash( @p hash, t ); Direction direction; - } Element; + }; /// @brief Path constructor /// @param leaf @@ -279,24 +298,19 @@ namespace merkle _leaf(leaf), _leaf_index(leaf_index), _max_index(max_index), - elements(elements) + elements(std::move(elements)) {} /// @brief Path copy constructor /// @param other Path to copy - PathT(const PathT& other) - { - _leaf = other._leaf; - elements = other.elements; - } + PathT(const PathT& other) : _leaf(other._leaf), elements(other.elements) {} /// @brief Path move constructor /// @param other Path to move - PathT(PathT&& other) - { - _leaf = std::move(other._leaf); - elements = std::move(other.elements); - } + PathT(PathT&& other) noexcept : + _leaf(std::move(other._leaf)), + elements(std::move(other.elements)) + {} /// @brief Deserialises a path /// @param bytes Vector to deserialise from @@ -382,7 +396,7 @@ namespace merkle _leaf.deserialise(bytes, position); _leaf_index = deserialise_uint64_t(bytes, position); _max_index = deserialise_uint64_t(bytes, position); - size_t num_elements = deserialise_uint64_t(bytes, position); + size_t const num_elements = deserialise_uint64_t(bytes, position); for (size_t i = 0; i < num_elements; i++) { HashT hash(bytes, position); @@ -412,13 +426,13 @@ namespace merkle } /// @brief The number of elements on the path - size_t size() const + [[nodiscard]] size_t size() const { return elements.size(); } /// @brief The size of the serialised path in number of bytes - size_t serialised_size() const + [[nodiscard]] size_t serialised_size() const { return sizeof(_leaf) + sizeof(uint64_t) + // leaf index @@ -431,13 +445,13 @@ namespace merkle } /// @brief Index of the leaf of the path - size_t leaf_index() const + [[nodiscard]] size_t leaf_index() const { return _leaf_index; } /// @brief Maximum index of the tree at the time the path was extracted - size_t max_index() const + [[nodiscard]] size_t max_index() const { return _max_index; } @@ -450,7 +464,7 @@ namespace merkle } /// @brief Iterator for path elements - typedef typename std::list::const_iterator const_iterator; + using const_iterator = typename std::list::const_iterator; /// @brief Start iterator for path elements const_iterator begin() const @@ -467,14 +481,16 @@ namespace merkle /// @brief Convert a path to a string /// @param num_bytes The maximum number of bytes to convert /// @param lower_case Enables lower-case hex characters - std::string to_string( + [[nodiscard]] std::string to_string( size_t num_bytes = HASH_SIZE, bool lower_case = true) const { std::stringstream stream; stream << _leaf.to_string(num_bytes); for (auto& e : elements) + { stream << " " << e.hash.to_string(num_bytes, lower_case) << (e.direction == PATH_LEFT ? "(L)" : "(R)"); + } return stream.str(); } @@ -488,13 +504,17 @@ namespace merkle bool operator==(const PathT& other) const { if (_leaf != other._leaf || elements.size() != other.elements.size()) + { return false; + } auto it = elements.begin(); auto other_it = other.elements.begin(); while (it != elements.end() && other_it != other.elements.end()) { if (it->hash != other_it->hash || it->direction != other_it->direction) + { return false; + } it++; other_it++; } @@ -580,7 +600,9 @@ namespace merkle size_t indent = 0) { if (from == nullptr) + { return nullptr; + } Node* r = make(from->hash); r->size = from->size; @@ -603,9 +625,13 @@ namespace merkle if (leaf_nodes && r->size == 1 && !r->left && !r->right) { if (*num_flushed == 0) + { leaf_nodes->push_back(r); + } else + { *num_flushed = *num_flushed - 1; + } } return r; } @@ -620,7 +646,7 @@ namespace merkle bool cl = !left || left->invariant(); bool cr = !right || right->invariant(); bool ch = height <= sizeof(size) * 8; - bool r = c1 && c2 && cl && cr && ch; + bool const r = c1 && c2 && cl && cr && ch; return r; } @@ -636,7 +662,7 @@ namespace merkle /// @brief Indicates whether a subtree is full /// @note A subtree is full if the number of nodes under a tree is /// 2**height-1. - bool is_full() const + [[nodiscard]] bool is_full() const { size_t max_size = (1 << height) - 1; assert(size <= max_size); @@ -652,7 +678,9 @@ namespace merkle height = std::max(left->height, right->height) + 1; } else + { size = height = 1; + } } /// @brief The Hash of the node @@ -678,16 +706,16 @@ namespace merkle public: /// @brief The type of hashes in the tree - typedef HashT Hash; + using Hash = HashT; /// @brief The type of paths in the tree - typedef PathT Path; + using Path = PathT; /// @brief The type of the tree - typedef TreeT Tree; + using Tree = TreeT; /// @brief Constructs an empty tree - TreeT() {} + TreeT() = default; /// @brief Copies a tree TreeT(const TreeT& other) @@ -697,7 +725,7 @@ namespace merkle /// @brief Moves a tree /// @param other Tree to move - TreeT(TreeT&& other) : + TreeT(TreeT&& other) noexcept : leaf_nodes(std::move(other.leaf_nodes)), uninserted_leaf_nodes(std::move(other.uninserted_leaf_nodes)), _root(std::move(other._root)), @@ -734,7 +762,9 @@ namespace merkle { delete (_root); for (auto n : uninserted_leaf_nodes) + { delete (n); + } } /// @brief Invariant of the tree @@ -766,7 +796,9 @@ namespace merkle void insert(const std::vector& hashes) { for (auto hash : hashes) + { insert(hash); + } } /// @brief Inserts multiple hashes into the tree @@ -774,7 +806,9 @@ namespace merkle void insert(const std::list& hashes) { for (auto hash : hashes) + { insert(hash); + } } /// @brief Flush the tree to some leaf @@ -787,7 +821,9 @@ namespace merkle statistics.num_flush++; if (index <= min_index()) + { return; + } walk_to(index, false, [this](Node*& n, bool go_right) { if (go_right && n->left) @@ -797,7 +833,9 @@ namespace merkle << n->left->hash.to_string(TRACE_HASH_SIZE) << std::endl;); if (n->left && n->left->dirty) + { hash(n->left); + } delete (n->left->left); n->left->left = nullptr; delete (n->left->right); @@ -822,10 +860,14 @@ namespace merkle statistics.num_retract++; if (max_index() < index) + { return; + } if (index < min_index()) + { throw std::runtime_error("leaf index out of bounds"); + } if (index >= num_flushed + leaf_nodes.size()) { @@ -861,7 +903,9 @@ namespace merkle old_left = nullptr; if (n->left && n->right) + { n->dirty = true; + } if (is_root) { @@ -879,8 +923,7 @@ namespace merkle << to_string(TRACE_HASH_SIZE) << std::endl;); return false; } - else - return true; + return true; }); // The leaf is now elsewhere, save the pointer. @@ -888,9 +931,13 @@ namespace merkle size_t num_retracted = num_leaves() - index - 1; if (num_retracted < leaf_nodes.size()) + { leaf_nodes.resize(leaf_nodes.size() - num_retracted); + } else + { leaf_nodes.clear(); + } assert(num_leaves() == index + 1); } @@ -902,7 +949,9 @@ namespace merkle { leaf_nodes.clear(); for (auto n : uninserted_leaf_nodes) + { delete (n); + } uninserted_leaf_nodes.clear(); insertion_stack.clear(); hashing_stack.clear(); @@ -916,7 +965,9 @@ namespace merkle other.min_index(), other.max_index()); for (auto n : other.uninserted_leaf_nodes) + { uninserted_leaf_nodes.push_back(Node::copy_node(n)); + } num_flushed = other.num_flushed; assert(min_index() == other.min_index()); assert(max_index() == other.max_index()); @@ -958,8 +1009,12 @@ namespace merkle << std::endl;); for (auto e : *p) + { if (e.direction == Path::Direction::PATH_LEFT) + { HASH_FUNCTION(e.hash, *result, *result); + } + } return result; } @@ -971,11 +1026,13 @@ namespace merkle /// @param f Function to call for each node on the path; the Boolean /// indicates whether the current step is a right or left turn. /// @return The final leaf node in the walk - inline Node* walk_to( + Node* walk_to( size_t index, bool update, const std::function&& f) { if (index < min_index() || max_index() < index) + { throw std::runtime_error("invalid leaf index"); + } compute_root(); @@ -984,15 +1041,19 @@ namespace merkle Node* cur = _root; size_t it = 0; if (_root->height > 1) + { it = index << (sizeof(index) * 8 - _root->height + 1); + } assert(walk_stack.empty()); for (uint8_t height = _root->height; height > 1;) { assert(cur->invariant()); - bool go_right = (it >> (8 * sizeof(it) - 1)) & 0x01; + bool go_right = ((it >> (8 * sizeof(it) - 1)) & 0x01) != 0U; if (update) + { walk_stack.push_back(cur); + } MERKLECPP_TRACE(MERKLECPP_TOUT << " - at " << cur->hash.to_string(TRACE_HASH_SIZE) << " (" << cur->size << "/" << (unsigned)cur->height @@ -1002,7 +1063,9 @@ namespace merkle if (cur->height == height) { if (!f(cur, go_right)) + { continue; + } cur = (go_right ? cur->right : cur->left); } it <<= 1; @@ -1010,11 +1073,13 @@ namespace merkle } if (update) + { while (!walk_stack.empty()) { walk_stack.back()->update_sizes(); walk_stack.pop_back(); } + } return cur; } @@ -1056,7 +1121,9 @@ namespace merkle if ( (index < min_index() || max_index() < index) || (as_of < min_index() || max_index() < as_of) || index > as_of) + { throw std::runtime_error("invalid leaf indices"); + } compute_root(); @@ -1066,12 +1133,15 @@ namespace merkle // the node at which they fork (recorded in `root_to_fork`), then // separately to `index` and `as_of`, recording their paths // in `fork_to_index` and `fork_to_as_of`. - std::list root_to_fork, fork_to_index, - fork_to_as_of; + std::list root_to_fork; + std::list fork_to_index; + std::list fork_to_as_of; Node* fork_node = nullptr; - Node *cur_i = _root, *cur_a = _root; - size_t it_i = 0, it_a = 0; + Node* cur_i = _root; + Node* cur_a = _root; + size_t it_i = 0; + size_t it_a = 0; if (_root->height > 1) { it_i = index << (sizeof(index) * 8 - _root->height + 1); @@ -1081,8 +1151,8 @@ namespace merkle for (uint8_t height = _root->height; height > 1;) { assert(cur_i->invariant() && cur_a->invariant()); - bool go_right_i = (it_i >> (8 * sizeof(it_i) - 1)) & 0x01; - bool go_right_a = (it_a >> (8 * sizeof(it_a) - 1)) & 0x01; + bool const go_right_i = ((it_i >> (8 * sizeof(it_i) - 1)) & 0x01) != 0U; + bool const go_right_a = ((it_a >> (8 * sizeof(it_a) - 1)) & 0x01) != 0U; MERKLECPP_TRACE(MERKLECPP_TOUT << " - at " << (unsigned)height << ": " @@ -1176,9 +1246,13 @@ namespace merkle // The hashes along the path from the fork to `index` remain unchanged. if (!fork_to_index.empty()) + { fork_to_index.pop_front(); + } for (auto it = fork_to_index.rbegin(); it != fork_to_index.rend(); it++) + { path.push_back(std::move(*it)); + } if (fork_node) { @@ -1187,9 +1261,13 @@ namespace merkle // `as_of`. Hash as_of_hash = cur_a->hash; if (!fork_to_as_of.empty()) + { fork_to_as_of.pop_front(); + } for (auto it = fork_to_as_of.rbegin(); it != fork_to_as_of.rend(); it++) + { HASH_FUNCTION(it->hash, as_of_hash, as_of_hash); + } MERKLECPP_TRACE({ MERKLECPP_TOUT << " - as_of hash: " @@ -1205,7 +1283,9 @@ namespace merkle // The hashes along the path from the fork (now with new fork hash) to the // (past) root remains unchanged. for (auto it = root_to_fork.rbegin(); it != root_to_fork.rend(); it++) + { path.push_back(std::move(*it)); + } return std::make_shared( leaf_node(index)->hash, index, std::move(path), as_of); @@ -1221,9 +1301,13 @@ namespace merkle leaf_nodes.size() + uninserted_leaf_nodes.size(), bytes); serialise_uint64_t(num_flushed, bytes); for (auto& n : leaf_nodes) + { n->hash.serialise(bytes); + } for (auto& n : uninserted_leaf_nodes) + { n->hash.serialise(bytes); + } if (!empty()) { @@ -1237,12 +1321,16 @@ namespace merkle std::vector extras; walk_to(min_index(), false, [&extras](Node*& n, bool go_right) { if (go_right) + { extras.push_back(n->left); + } return true; }); for (size_t i = extras.size() - 1; i != SIZE_MAX; i--) + { extras.at(i)->hash.serialise(bytes); + } } } @@ -1258,12 +1346,16 @@ namespace merkle if ( (from < min_index() || max_index() < from) || (to < min_index() || max_index() < to) || from > to) + { throw std::runtime_error("invalid leaf indices"); + } serialise_uint64_t(to - from + 1, bytes); serialise_uint64_t(from, bytes); for (size_t i = from; i <= to; i++) + { leaf(i).serialise(bytes); + } if (!empty()) { @@ -1277,12 +1369,16 @@ namespace merkle std::vector extras; walk_to(from, false, [&extras](Node*& n, bool go_right) { if (go_right) + { extras.push_back(n->left); + } return true; }); for (size_t i = extras.size() - 1; i != SIZE_MAX; i--) + { extras.at(i)->hash.serialise(bytes); + } } } @@ -1304,7 +1400,9 @@ namespace merkle delete (_root); leaf_nodes.clear(); for (auto n : uninserted_leaf_nodes) + { delete (n); + } uninserted_leaf_nodes.clear(); insertion_stack.clear(); hashing_stack.clear(); @@ -1322,13 +1420,14 @@ namespace merkle leaf_nodes.push_back(n); } - std::vector level = leaf_nodes, next_level; + std::vector level = leaf_nodes; + std::vector next_level; size_t it = num_flushed; uint8_t level_no = 0; while (it != 0 || level.size() > 1) { // Restore extra hashes on the left edge of the tree - if (it & 0x01) + if ((it & 0x01) != 0U) { Hash h(bytes, position); MERKLECPP_TRACE(MERKLECPP_TOUT << "+";); @@ -1348,9 +1447,13 @@ namespace merkle for (size_t i = 0; i < level.size(); i += 2) { if (i + 1 >= level.size()) + { next_level.push_back(level.at(i)); + } else + { next_level.push_back(Node::make(level.at(i), level.at(i + 1))); + } } level.swap(next_level); @@ -1392,13 +1495,16 @@ namespace merkle { 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()) + { return uninserted_leaf_nodes .at(index - num_flushed - leaf_nodes.size()) ->hash; - else - return leaf_nodes.at(index - num_flushed)->hash; + } + return leaf_nodes.at(index - num_flushed)->hash; } /// @brief Number of leaves in the tree @@ -1443,7 +1549,9 @@ namespace merkle size_t size() { if (!uninserted_leaf_nodes.empty()) + { insert_leaves(); + } return _root ? _root->size : 0; } @@ -1458,7 +1566,9 @@ namespace merkle { walk_to(min_index(), false, [&num_extras](Node*&, bool go_right) { if (go_right) + { num_extras++; + } return true; }); } @@ -1476,7 +1586,9 @@ namespace merkle size_t num_extras = 0; walk_to(from, false, [&num_extras](Node*&, bool go_right) { if (go_right) + { num_extras++; + } return true; }); @@ -1513,7 +1625,7 @@ namespace merkle size_t num_past_paths = 0; /// @brief String representation of the statistics - std::string to_string() const + [[nodiscard]] std::string to_string() const { std::stringstream stream; stream << "num_insert=" << num_insert << " num_hash=" << num_hash @@ -1533,17 +1645,18 @@ namespace merkle { static const std::string dirty_hash(2 * num_bytes, '?'); std::stringstream stream; - std::vector level, next_level; + std::vector level; + std::vector next_level; if (num_leaves() == 0) { - stream << "" << std::endl; + stream << "" << '\n'; return stream.str(); } if (!_root) { - stream << "No root." << std::endl; + stream << "No root." << '\n'; } else { @@ -1557,12 +1670,16 @@ namespace merkle stream << (n->dirty ? dirty_hash : n->hash.to_string(num_bytes)); stream << "(" << n->size << "," << (unsigned)n->height << ")"; if (n->left) + { next_level.push_back(n->left); + } if (n->right) + { next_level.push_back(n->right); + } stream << " "; } - stream << std::endl << std::flush; + stream << '\n' << std::flush; std::swap(level, next_level); next_level.clear(); } @@ -1594,14 +1711,14 @@ namespace merkle private: /// @brief The structure of elements on the insertion stack - typedef struct + using InsertionStackElement = struct { /// @brief The tree node to insert Node* n; /// @brief Flag to indicate whether @p n should be inserted into the /// left or the right subtree of the current position in the tree. bool left; - } InsertionStackElement; + }; /// @brief The insertion stack /// @note To avoid actual recursion, this holds the stack/continuation for @@ -1625,12 +1742,15 @@ namespace merkle { MERKLECPP_TRACE(MERKLECPP_TOUT << "> leaf_node " << index << std::endl;); if (index >= num_leaves()) + { throw std::runtime_error("leaf index out of bounds"); + } if (index - num_flushed >= leaf_nodes.size()) + { return uninserted_leaf_nodes.at( index - num_flushed - leaf_nodes.size()); - else - return leaf_nodes.at(index - num_flushed); + } + return leaf_nodes.at(index - num_flushed); } /// @brief Computes the hash of a tree node @@ -1654,12 +1774,20 @@ namespace merkle assert((n->left && n->right) || (!n->left && !n->right)); if (n->left && n->left->dirty) + { hashing_stack.push_back(n->left); + } else if (n->right && n->right->dirty) + { hashing_stack.push_back(n->right); + } else { assert(n->left && n->right); + if (!n->left || !n->right) + { + throw std::runtime_error("unexpected null child node"); + } HASH_FUNCTION(n->left->hash, n->right->hash, n->hash); statistics.num_hash++; MERKLECPP_TRACE( @@ -1680,7 +1808,9 @@ namespace merkle { insert_leaves(true); if (num_leaves() == 0) + { throw std::runtime_error("empty tree does not have a root"); + } assert(_root); assert(_root->invariant()); if (_root->dirty) @@ -1711,23 +1841,21 @@ namespace merkle insertion_stack.back().n = result; return; } + + assert(n->left && n->right); + insertion_stack.push_back(InsertionStackElement()); + InsertionStackElement& se = insertion_stack.back(); + se.n = n; + n->dirty = true; + if (!n->left->is_full()) + { + se.left = true; + n = n->left; + } else { - assert(n->left && n->right); - insertion_stack.push_back(InsertionStackElement()); - InsertionStackElement& se = insertion_stack.back(); - se.n = n; - n->dirty = true; - if (!n->left->is_full()) - { - se.left = true; - n = n->left; - } - else - { - se.left = false; - n = n->right; - } + se.left = false; + n = n->right; } } } @@ -1760,9 +1888,13 @@ namespace merkle insertion_stack.pop_back(); if (left) + { n->left = result; + } else + { n->right = result; + } n->dirty = true; n->update_sizes(); @@ -1793,7 +1925,9 @@ namespace merkle << std::endl;); leaf_nodes.push_back(n); if (insertion_stack.empty() && !root) + { root = n; + } else { continue_insertion_stack(root, n); @@ -1814,11 +1948,15 @@ namespace merkle // Potential future improvement: make this go fast when there are many // leaves to insert. for (auto& n : uninserted_leaf_nodes) + { insert_leaf(_root, n); + } uninserted_leaf_nodes.clear(); } if (complete && !insertion_stack.empty()) + { _root = process_insertion_stack(); + } } }; @@ -1851,28 +1989,37 @@ namespace merkle uint32_t cws[64] = {0}; - for (int i=0; i < 16; i++) - cws[i] = convert_endianness(((int32_t *)block)[i]); + for (int i=0; i < 16; i++) { + cws[i] = convert_endianness(reinterpret_cast(block)[i]); +} for (int i = 16; i < 64; i++) { - uint32_t t16 = cws[i - 16]; - uint32_t t15 = cws[i - 15]; - uint32_t t7 = cws[i - 7]; - uint32_t t2 = cws[i - 2]; - uint32_t s1 = (t2 >> 17 | t2 << 15) ^ ((t2 >> 19 | t2 << 13) ^ t2 >> 10); - uint32_t s0 = (t15 >> 7 | t15 << 25) ^ ((t15 >> 18 | t15 << 14) ^ t15 >> 3); + uint32_t const t16 = cws[i - 16]; + uint32_t const t15 = cws[i - 15]; + uint32_t const t7 = cws[i - 7]; + uint32_t const t2 = cws[i - 2]; + uint32_t const s1 = (t2 >> 17 | t2 << 15) ^ ((t2 >> 19 | t2 << 13) ^ t2 >> 10); + uint32_t const s0 = (t15 >> 7 | t15 << 25) ^ ((t15 >> 18 | t15 << 14) ^ t15 >> 3); cws[i] = (s1 + t7 + s0 + t16); } uint32_t h[8]; - for (int i=0; i < 8; i++) + for (int i=0; i < 8; i++) { h[i] = s[i]; +} for (int i=0; i < 64; i++) { - uint32_t a0 = h[0], b0 = h[1], c0 = h[2], d0 = h[3], e0 = h[4], f0 = h[5], g0 = h[6], h03 = h[7]; - uint32_t w = cws[i]; - uint32_t t1 = h03 + ((e0 >> 6 | e0 << 26) ^ ((e0 >> 11 | e0 << 21) ^ (e0 >> 25 | e0 << 7))) + ((e0 & f0) ^ (~e0 & g0)) + constants[i] + w; - uint32_t t2 = ((a0 >> 2 | a0 << 30) ^ ((a0 >> 13 | a0 << 19) ^ (a0 >> 22 | a0 << 10))) + ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0))); + const uint32_t a0 = h[0]; + const uint32_t b0 = h[1]; + const uint32_t c0 = h[2]; + const uint32_t d0 = h[3]; + const uint32_t e0 = h[4]; + const uint32_t f0 = h[5]; + const uint32_t g0 = h[6]; + const uint32_t h03 = h[7]; + uint32_t const w = cws[i]; + uint32_t const t1 = h03 + ((e0 >> 6 | e0 << 26) ^ ((e0 >> 11 | e0 << 21) ^ (e0 >> 25 | e0 << 7))) + ((e0 & f0) ^ (~e0 & g0)) + constants[i] + w; + uint32_t const t2 = ((a0 >> 2 | a0 << 30) ^ ((a0 >> 13 | a0 << 19) ^ (a0 >> 22 | a0 << 10))) + ((a0 & b0) ^ ((a0 & c0) ^ (b0 & c0))); h[0] = t1 + t2; h[1] = a0; h[2] = b0; @@ -1883,8 +2030,9 @@ namespace merkle h[7] = g0; } - for (int i=0; i < 8; i++) - ((uint32_t*)out.bytes)[i] = convert_endianness(s[i] + h[i]); + for (int i=0; i < 8; i++) { + reinterpret_cast(out.bytes)[i] = convert_endianness(s[i] + h[i]); +} } // clang-format on @@ -1976,11 +2124,11 @@ namespace merkle #endif /// @brief Type of hashes in the default tree type - typedef HashT<32> Hash; + using Hash = HashT<32>; /// @brief Type of paths in the default tree type - typedef PathT<32, sha256_compress> Path; + using Path = PathT<32, sha256_compress>; /// @brief Default tree with default hash size and function - typedef TreeT<32, sha256_compress> Tree; + using Tree = TreeT<32, sha256_compress>; }; diff --git a/test/demo_tree.cpp b/test/demo_tree.cpp index 2707072..05d6f87 100644 --- a/test/demo_tree.cpp +++ b/test/demo_tree.cpp @@ -13,7 +13,7 @@ #include -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { @@ -26,21 +26,25 @@ int main() // Insert a number of hashes into the tree merkle::Tree mt; for (auto h : hashes) + { mt.insert(h); - merkle::Tree::Hash root = mt.root(); - std::cout << mt.to_string(PRINT_HASH_SIZE) << std::endl; + } + const merkle::Tree::Hash root = mt.root(); + std::cout << mt.to_string(PRINT_HASH_SIZE) << '\n'; // Extract some paths - std::cout << "Paths: " << std::endl; + std::cout << "Paths: " << '\n'; for (size_t i = mt.min_index(); i <= mt.max_index(); i++) { mt.flush_to(i); auto path = mt.path(i); std::cout << "P" << std::setw(2) << std::setfill('0') << i << ": " - << path->to_string(PRINT_HASH_SIZE) << " " << std::endl; + << path->to_string(PRINT_HASH_SIZE) << " " << '\n'; if (!path->verify(root)) - throw std::runtime_error("root hash mismatch"); - std::vector chk = *path; + { + throw std::runtime_error("root hash mismatch"); + } + const std::vector chk = *path; } // Serialise, then deserialise the tree @@ -48,9 +52,11 @@ int main() mt.serialise(buffer); merkle::Tree dmt(buffer); if (mt.root() != dmt.root()) - throw std::runtime_error("root hash mismatch"); + { + throw std::runtime_error("root hash mismatch"); + } - std::cout << std::endl; + std::cout << '\n'; } #ifdef HAVE_OPENSSL @@ -59,7 +65,9 @@ int main() /// SNIPPET_START: OpenSSL-SHA256 merkle::TreeT<32, merkle::sha256_openssl> tree; for (auto h : hashes) + { tree.insert(h); + } auto root = tree.root(); auto path = tree.path(hashes.size() - 1); assert(path->verify(root)); @@ -70,12 +78,12 @@ int main() } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/flush.cpp b/test/flush.cpp index d751126..89c88bf 100644 --- a/test/flush.cpp +++ b/test/flush.cpp @@ -9,14 +9,14 @@ #include #include -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; try { @@ -26,25 +26,26 @@ int main() const size_t max_flushes = 16; #else const size_t num_trees = 128; - const size_t max_num_leaves = 128 * 1024; + const size_t max_num_leaves = static_cast(128) * 1024; const size_t max_flushes = 64; #endif - size_t total_leaves = 0, total_flushes = 0; + size_t total_leaves = 0; + size_t total_flushes = 0; for (size_t k = 0; k < num_trees && !timed_out(timeout, test_start_time); k++) { - size_t num_leaves = - (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_leaves = + static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); total_leaves += num_leaves; auto hashes = make_hashes(num_leaves); merkle::Tree mt; - for (size_t i = 0; i < hashes.size(); i++) + for (auto& hash : hashes) { - mt.insert(hashes[i]); + mt.insert(hash); if ((std::rand() / (double)RAND_MAX) > 0.95) { mt.flush_to(random_index(mt)); @@ -57,25 +58,27 @@ int main() mt.flush_to(random_index(mt)); total_flushes++; if (mt.min_index() == mt.max_index()) + { break; + } } - if ((k && k % 1000 == 0) || k == num_trees - 1) + if ((k != 0 && k % 1000 == 0) || k == num_trees - 1) { std::cout << k << " trees, " << total_leaves << " leaves, " << total_flushes << " flushes" - << ": OK." << std::endl; + << ": OK." << '\n'; } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/partial_serialisation.cpp b/test/partial_serialisation.cpp index 3a0c3de..e8b43fe 100644 --- a/test/partial_serialisation.cpp +++ b/test/partial_serialisation.cpp @@ -12,14 +12,14 @@ #include "util.h" -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; try { @@ -29,19 +29,21 @@ int main() const size_t max_num_subtrees = 32; #else const size_t num_trees = 256; - const size_t max_num_leaves = 128 * 1024; + const size_t max_num_leaves = static_cast(128) * 1024; const size_t max_num_subtrees = 256; #endif - size_t total_leaves = 0, total_flushes = 0, total_retractions = 0, - total_subtrees = 0; + size_t total_leaves = 0; + size_t total_flushes = 0; + size_t total_retractions = 0; + size_t total_subtrees = 0; for (size_t k = 0; k < num_trees && !timed_out(timeout, test_start_time); k++) { - std::map past_roots; - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); - size_t num_subtrees = (size_t)( + const std::map past_roots; + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_subtrees = static_cast( 1 + (std::rand() / (double)RAND_MAX) * max_num_subtrees); total_leaves += num_leaves; auto hashes = make_hashes(num_leaves); @@ -76,7 +78,9 @@ int main() size_t from = random_index(mt); size_t to = random_index(mt); if (from > to) + { std::swap(from, to); + } // Serialise std::vector buffer; @@ -98,10 +102,10 @@ int main() mt2.num_leaves() != to + 1 || mt2.min_index() != from || !root_ok || !path_ok || !paths_equal || !size_ok) { - std::cout << "before:" << std::endl - << mt.to_string(PRINT_HASH_SIZE) << std::endl; - std::cout << "after:" << std::endl - << mt2.to_string(PRINT_HASH_SIZE) << std::endl; + std::cout << "before:" << '\n' + << mt.to_string(PRINT_HASH_SIZE) << '\n'; + std::cout << "after:" << '\n' + << mt2.to_string(PRINT_HASH_SIZE) << '\n'; throw std::runtime_error("tree properties mismatch"); } @@ -114,21 +118,21 @@ int main() std::cout << k + 1 << " trees, " << total_leaves << " leaves, " << total_flushes << " flushes, " << total_retractions << " retractions, " << total_subtrees << " subtrees" - << ": OK." << std::endl; + << ": OK." << '\n'; } } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; - std::cout << "(seed=" << seed << ")" << std::endl; + std::cout << "Error: " << ex.what() << '\n'; + std::cout << "(seed=" << seed << ")" << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; - std::cout << "(seed=" << seed << ")" << std::endl; + std::cout << "Error" << '\n'; + std::cout << "(seed=" << seed << ")" << '\n'; return 1; } diff --git a/test/past_paths.cpp b/test/past_paths.cpp index 5dda986..6553b91 100644 --- a/test/past_paths.cpp +++ b/test/past_paths.cpp @@ -10,7 +10,7 @@ #include "util.h" -#define PSZ 3 +constexpr size_t PSZ = 3; std::shared_ptr past_root_spec( const merkle::Tree& mt, size_t index, size_t as_of) @@ -19,8 +19,8 @@ std::shared_ptr past_root_spec( tmt.retract_to(as_of); tmt.root(); #ifdef MERKLECPP_TRACE_ENABLED - MERKLECPP_TOUT << "Retracted tree:" << std::endl; - MERKLECPP_TOUT << tmt.to_string(PSZ) << std::endl; + MERKLECPP_TOUT << "Retracted tree:" << '\n'; + MERKLECPP_TOUT << tmt.to_string(PSZ) << '\n'; #endif auto root = tmt.root(); auto result = tmt.path(index); @@ -28,12 +28,12 @@ std::shared_ptr past_root_spec( return result; } -int main(int argc, char** argv) +int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; std::srand((unsigned)seed); @@ -42,33 +42,37 @@ int main(int argc, char** argv) #ifndef NDEBUG const size_t num_trees = 24; const size_t max_num_paths = 128; - const size_t max_num_leaves = 16 * 1024; + const size_t max_num_leaves = static_cast(16) * 1024; #else const size_t num_trees = 128; const size_t max_num_paths = 1024; - const size_t max_num_leaves = 64 * 1024; + const size_t max_num_leaves = static_cast(64) * 1024; #endif - size_t total_paths = 0, total_leaves = 0, total_flushed_nodes = 0; + size_t total_paths = 0; + size_t total_leaves = 0; + size_t total_flushed_nodes = 0; auto hashes = make_hashes(max_num_leaves); bool is_timed_out = false; for (size_t l = 0; l < num_trees && !is_timed_out; l++) { - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); - size_t num_paths = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_paths); + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_paths = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_paths); total_leaves += num_leaves; total_paths += num_paths; merkle::Tree mt; for (size_t i = 0; i < num_leaves; i++) + { mt.insert(hashes[i]); + } #ifdef MERKLECPP_TRACE_ENABLED - MERKLECPP_TOUT << "Tree: " << std::endl; - MERKLECPP_TOUT << mt.to_string(PSZ) << std::endl; + MERKLECPP_TOUT << "Tree: " << '\n'; + MERKLECPP_TOUT << mt.to_string(PSZ) << '\n'; #endif for (size_t m = 0; @@ -78,31 +82,35 @@ int main(int argc, char** argv) size_t index = random_index(mt); size_t as_of = random_index(mt); if (index > as_of) + { std::swap(index, as_of); + } auto past_path_spec = past_root_spec(mt, index, as_of); auto past_root_spec = past_path_spec->root(); if ((std::rand() / (double)RAND_MAX) > 0.95) + { if (index / 10 > mt.min_index()) { - size_t before = mt.min_index(); + const size_t before = mt.min_index(); mt.flush_to(index / 2); total_flushed_nodes += mt.min_index() - before; } + } #ifdef MERKLECPP_TRACE_ENABLED - MERKLECPP_TOUT << std::endl; - MERKLECPP_TOUT << "past_root_spec: " << std::endl; + MERKLECPP_TOUT << '\n'; + MERKLECPP_TOUT << "past_root_spec: " << '\n'; MERKLECPP_TOUT << "Past path (spec) from " << index << " as_of " << as_of << ": " << past_path_spec->to_string(PSZ) - << std::endl; + << '\n'; MERKLECPP_TOUT << "Computed root: " << past_root_spec->to_string(PSZ) - << std::endl; - MERKLECPP_TOUT << std::endl; + << '\n'; + MERKLECPP_TOUT << '\n'; - MERKLECPP_TOUT << "Flushed tree: " << std::endl; - MERKLECPP_TOUT << mt.to_string(PSZ) << std::endl; + MERKLECPP_TOUT << "Flushed tree: " << '\n'; + MERKLECPP_TOUT << mt.to_string(PSZ) << '\n'; #endif auto past_root = mt.past_root(as_of); @@ -111,26 +119,34 @@ int main(int argc, char** argv) #ifdef MERKLECPP_TRACE_ENABLED MERKLECPP_TOUT << "Past root: " << past_root->to_string(PSZ) - << std::endl; + << '\n'; MERKLECPP_TOUT << "Past path: " << past_path->to_string(PSZ) - << std::endl; + << '\n'; MERKLECPP_TOUT << "Computed root: " << pp_root->to_string(PSZ) - << std::endl; + << '\n'; #endif if (*past_path_spec != *past_path) + { throw std::runtime_error("path mismatch"); + } if (*pp_root != *past_root) + { throw std::runtime_error("path root mismatch"); + } if (!past_path->verify(*past_root)) + { throw std::runtime_error("path verification failed"); + } if (m == num_paths - 1) + { std::cout << (l + 1) << " trees, " << total_leaves << " leaves, " << total_flushed_nodes << " flushed, " << total_paths - << " past paths: OK." << std::endl; + << " past paths: OK." << '\n'; + } is_timed_out = timed_out(timeout, test_start_time); } @@ -138,14 +154,14 @@ int main(int argc, char** argv) } catch (std::exception& ex) { - std::cout << "Seed: " << seed << std::endl; - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Seed: " << seed << '\n'; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Seed: " << seed << std::endl; - std::cout << "Error" << std::endl; + std::cout << "Seed: " << seed << '\n'; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/past_root.cpp b/test/past_root.cpp index 41bbcdb..8f11467 100644 --- a/test/past_root.cpp +++ b/test/past_root.cpp @@ -12,14 +12,14 @@ #include "util.h" -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; std::srand((unsigned)seed); @@ -30,16 +30,17 @@ int main() const size_t max_num_leaves = 8 * 1024; #else const size_t num_trees = 128; - const size_t max_num_leaves = 32 * 1024; + const size_t max_num_leaves = static_cast(32) * 1024; #endif - size_t total_leaves = 0, total_roots = 0; + size_t total_leaves = 0; + size_t total_roots = 0; for (size_t k = 0; k < num_trees && !timed_out(timeout, test_start_time); k++) { std::map past_roots; - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); total_leaves += num_leaves; auto hashes = make_hashes(num_leaves); @@ -50,14 +51,18 @@ int main() { mt.insert(hashes[i]); if ((std::rand() / (double)RAND_MAX) > 0.95) + { past_roots[i] = mt.root(); + } } } // Build new tree without taking roots merkle::Tree mt; for (auto& h : hashes) + { mt.insert(h); + } // Extract and check past roots for (auto& kv : past_roots) @@ -68,27 +73,27 @@ int main() { std::cout << pr->to_string(PRINT_HASH_SIZE) << " != " << kv.second.to_string(PRINT_HASH_SIZE) - << std::endl; + << '\n'; throw std::runtime_error("past root hash mismatch"); } } - if ((k && k % 1000 == 999) || k == num_trees - 1) + if ((k != 0 && k % 1000 == 999) || k == num_trees - 1) { std::cout << k + 1 << " trees, " << total_leaves << " leaves, " << total_roots << " roots" - << ": OK." << std::endl; + << ": OK." << '\n'; } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/paths.cpp b/test/paths.cpp index 03ddb79..77624fb 100644 --- a/test/paths.cpp +++ b/test/paths.cpp @@ -10,34 +10,35 @@ #include "util.h" -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; try { #ifndef NDEBUG const size_t num_trees = 64; const size_t max_num_paths = 32; - const size_t max_num_leaves = 64 * 1024; + const size_t max_num_leaves = static_cast(64) * 1024; #else const size_t num_trees = 256; const size_t max_num_paths = 128; - const size_t max_num_leaves = 64 * 1024; + const size_t max_num_leaves = static_cast(64) * 1024; #endif - size_t total_paths = 0, total_leaves = 0; + size_t total_paths = 0; + size_t total_leaves = 0; for (size_t l = 0; l < num_trees && !timed_out(timeout, test_start_time); l++) { - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); - size_t num_paths = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_paths); + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_paths = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_paths); total_leaves += num_leaves; total_paths += num_paths; @@ -46,34 +47,40 @@ int main() merkle::Tree mt; for (auto h : hashes) + { mt.insert(h); - merkle::Tree::Hash root = mt.root(); + } + const merkle::Tree::Hash root = mt.root(); for (size_t p = 0; p < num_paths && !timed_out(timeout, test_start_time); p++) { - size_t i = (size_t)((std::rand() / (double)(RAND_MAX)) * (num_leaves - 1)); + const auto i = static_cast((std::rand() / static_cast(RAND_MAX)) * static_cast(num_leaves - 1)); auto path = mt.path(i); if (!path->verify(root)) + { throw std::runtime_error("path verification failed"); + } std::vector serialised_path; path->serialise(serialised_path); if (path->serialised_size() != serialised_path.size()) + { throw std::runtime_error("serialised_size() != serialised_path.size()"); + } } } std::cout << num_trees << " trees, " << total_leaves << " leaves, " - << total_paths << " paths: OK." << std::endl; + << total_paths << " paths: OK." << '\n'; } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/retract.cpp b/test/retract.cpp index 093b8b9..613c561 100644 --- a/test/retract.cpp +++ b/test/retract.cpp @@ -10,14 +10,14 @@ #include "util.h" -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; try { @@ -27,16 +27,17 @@ int main() const size_t max_retractions = 16; #else const size_t num_trees = 256; - const size_t max_num_leaves = 256 * 1024; + const size_t max_num_leaves = static_cast(256) * 1024; const size_t max_retractions = 64; #endif - size_t total_leaves = 0, total_retractions = 0; + size_t total_leaves = 0; + size_t total_retractions = 0; for (size_t k = 0; k < num_trees && !timed_out(timeout, test_start_time); k++) { - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); total_leaves += num_leaves; auto hashes = make_hashes(num_leaves); @@ -50,9 +51,12 @@ int main() mt.retract_to(mt.max_index() - 1); total_retractions++; mt.insert(hashes[i]); + const auto max_before = mt.max_index(); mt.retract_to(mt.max_index()); - if (mt.max_index() != i) - std::runtime_error("invalid max index"); + if (mt.max_index() != max_before) + { + throw std::runtime_error("retract_to(max_index()) changed max_index"); + } } if ((std::rand() / (double)RAND_MAX) > 0.95) @@ -67,25 +71,27 @@ int main() mt.retract_to(random_index(mt)); total_retractions++; if (mt.min_index() == mt.max_index()) + { break; + } } - if ((k && k % 1000 == 0) || k == num_trees - 1) + if ((k != 0 && k % 1000 == 0) || k == num_trees - 1) { std::cout << k << " trees, " << total_leaves << " leaves, " << total_retractions << " retractions" - << ": OK." << std::endl; + << ": OK." << '\n'; } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/serialisation.cpp b/test/serialisation.cpp index 1133bf8..fe878c4 100644 --- a/test/serialisation.cpp +++ b/test/serialisation.cpp @@ -12,14 +12,14 @@ #include "util.h" -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { auto test_start_time = std::chrono::high_resolution_clock::now(); - double timeout = get_timeout(); - auto seed = std::time(0); - std::cout << "seed=" << seed << " timeout=" << timeout << std::endl; + const double timeout = get_timeout(); + auto seed = std::time(nullptr); + std::cout << "seed=" << seed << " timeout=" << timeout << '\n'; try { @@ -28,16 +28,18 @@ int main() const size_t max_num_leaves = 32 * 1024; #else const size_t num_trees = 256; - const size_t max_num_leaves = 128 * 1024; + const size_t max_num_leaves = static_cast(128) * 1024; #endif - size_t total_leaves = 0, total_flushes = 0, total_retractions = 0; + size_t total_leaves = 0; + size_t total_flushes = 0; + size_t total_retractions = 0; for (size_t k = 0; k < num_trees && !timed_out(timeout, test_start_time); k++) { - std::map past_roots; - size_t num_leaves = (size_t)(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); + const std::map past_roots; + const auto num_leaves = static_cast(1 + (std::rand() / (double)RAND_MAX) * max_num_leaves); total_leaves += num_leaves; auto hashes = make_hashes(num_leaves); @@ -79,32 +81,32 @@ int main() mt.serialised_size() != mt2.serialised_size() || mt.size() != mt2.size()) { - std::cout << "before:" << std::endl - << mt.to_string(PRINT_HASH_SIZE) << std::endl; - std::cout << "after:" << std::endl - << mt2.to_string(PRINT_HASH_SIZE) << std::endl; + std::cout << "before:" << '\n' + << mt.to_string(PRINT_HASH_SIZE) << '\n'; + std::cout << "after:" << '\n' + << mt2.to_string(PRINT_HASH_SIZE) << '\n'; throw std::runtime_error("tree properties mismatch"); } - if ((k && k % 1000 == 999) || k == num_trees - 1) + if ((k != 0 && k % 1000 == 999) || k == num_trees - 1) { std::cout << k + 1 << " trees, " << total_leaves << " leaves, " << total_flushes << " flushes, " << total_retractions << " retractions" - << ": OK." << std::endl; + << ": OK." << '\n'; } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; - std::cout << "(seed=" << seed << ")" << std::endl; + std::cout << "Error: " << ex.what() << '\n'; + std::cout << "(seed=" << seed << ")" << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; - std::cout << "(seed=" << seed << ")" << std::endl; + std::cout << "Error" << '\n'; + std::cout << "(seed=" << seed << ")" << '\n'; return 1; } diff --git a/test/serialise_to_file.cpp b/test/serialise_to_file.cpp index c049c69..3f2dde4 100644 --- a/test/serialise_to_file.cpp +++ b/test/serialise_to_file.cpp @@ -14,7 +14,7 @@ #include -#define PRINT_HASH_SIZE 3 +constexpr size_t PRINT_HASH_SIZE = 3; int main() { @@ -25,9 +25,11 @@ int main() auto hashes = make_hashes(num_leaves); merkle::Tree tree1; for (auto h : hashes) + { tree1.insert(h); + } auto root1 = tree1.root(); - std::cout << "ROOT1=" << root1.to_string() << std::endl; + std::cout << "ROOT1=" << root1.to_string() << '\n'; { // Write a new file if it doesn't exist. @@ -37,8 +39,11 @@ int main() std::vector bytes; tree1.serialise(bytes); std::ofstream f("tree.bytes", std::ofstream::binary); - for (char b : bytes) - f.write(&b, 1); + for (auto b : bytes) + { + const auto ch = static_cast(b); + f.write(&ch, 1); + } f.close(); fi.close(); } @@ -50,7 +55,7 @@ int main() { merkle::Tree tree2; std::vector bytes; - char t; + char t = 0; while (!f.eof()) { f.read(&t, 1); @@ -59,20 +64,22 @@ int main() tree2.deserialise(bytes); f.close(); auto root2 = tree2.root(); - std::cout << "ROOT2=" << root2.to_string() << std::endl; + std::cout << "ROOT2=" << root2.to_string() << '\n'; if (root1 != root2) + { throw std::runtime_error("root hash mismatch"); + } } } } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; } diff --git a/test/time_large_trees.cpp b/test/time_large_trees.cpp index ed83083..2624211 100644 --- a/test/time_large_trees.cpp +++ b/test/time_large_trees.cpp @@ -12,7 +12,7 @@ #include -#define HSZ 32 +constexpr size_t HSZ = 32; int main() { @@ -22,7 +22,7 @@ int main() 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 num_leaves = static_cast(16) * 1024 * 1024; const size_t root_interval = 1024; #endif @@ -35,16 +35,18 @@ int main() { 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(stop - start) - .count() / + const double seconds = + static_cast(std::chrono::duration_cast(stop - start) + .count()) / 1e9; std::cout << "NEW: " << mt.statistics.to_string() << " in " << seconds - << " sec" << std::endl; + << " sec" << '\n'; #ifdef HAVE_OPENSSL { @@ -66,7 +68,7 @@ int main() .count() / 1e9; std::cout << "SHA384: " << mt384.statistics.to_string() << " in " - << seconds384 << " sec" << std::endl; + << seconds384 << " sec" << '\n'; } { @@ -88,7 +90,7 @@ int main() .count() / 1e9; std::cout << "SHA512: " << mt512.statistics.to_string() << " in " - << seconds512 << " sec" << std::endl; + << seconds512 << " sec" << '\n'; } #endif @@ -121,7 +123,7 @@ int main() std::cout << "EC :" << " num_insert=" << ec_hashes.size() << " num_root=" << num_ec_roots << " in " << seconds << " sec" - << std::endl; + << '\n'; for (auto h : ec_hashes) mt_free_hash(h); @@ -131,12 +133,12 @@ int main() } catch (std::exception& ex) { - std::cout << "Error: " << ex.what() << std::endl; + std::cout << "Error: " << ex.what() << '\n'; return 1; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error" << '\n'; return 1; }