From 8fc590747b37983632abc238abc15e642a349bc0 Mon Sep 17 00:00:00 2001 From: Marcos Pernambuco Motta <1091485+mpernambuco@users.noreply.github.com> Date: Thu, 9 Jan 2025 19:58:55 -0300 Subject: [PATCH] feat!: replace keccak with sha256 --- CHANGELOG.md | 1 + src/Makefile | 14 +- src/back-merkle-tree.h | 4 +- src/cartesi/proof.lua | 6 +- src/clua-cartesi.cpp | 43 +++- src/complete-merkle-tree.h | 4 +- src/full-merkle-tree.h | 4 +- src/machine-hasher.h | 28 +++ src/machine-merkle-tree.h | 7 +- src/merkle-tree-hash.cpp | 6 +- src/pristine-merkle-tree.h | 4 +- src/sha-256-hasher.h | 66 ++++++ tests/lua/cartesi/tests/util.lua | 32 +-- tests/lua/machine-bind.lua | 2 +- tests/misc/Makefile | 2 +- tests/misc/test-merkle-tree-hash.cpp | 4 +- tests/misc/test-utils.h | 10 +- third-party/SHA256/LICENSE | 23 ++ third-party/SHA256/sha256.c | 328 +++++++++++++++++++++++++++ third-party/SHA256/sha256.h | 52 +++++ uarch/Makefile | 4 +- 21 files changed, 597 insertions(+), 47 deletions(-) create mode 100644 src/machine-hasher.h create mode 100644 src/sha-256-hasher.h create mode 100644 third-party/SHA256/LICENSE create mode 100644 third-party/SHA256/sha256.c create mode 100644 third-party/SHA256/sha256.h diff --git a/CHANGELOG.md b/CHANGELOG.md index d109b477c..536479195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a "--jobs" option to "uarch-riscv-tests.lua" test - add-created-files.diff should now be applied with `-p1` - Improved send_cmio_response bounds checking +- keccak hash algorithm replaced by sha-256 ### Fixed - Fixed --skip-root-hash-store not skipping root hash computation when using the cli diff --git a/src/Makefile b/src/Makefile index 5f66b62d7..24e4cd177 100644 --- a/src/Makefile +++ b/src/Makefile @@ -157,6 +157,7 @@ WARNS=-Wall -Wextra -Wpedantic INCS+= \ -I../third-party/llvm-flang-uint128 \ -I../third-party/tiny_sha3 \ + -I../third-party/SHA256 \ -I../third-party/nlohmann-json \ -I../third-party/downloads \ $(BOOST_INC) @@ -212,6 +213,9 @@ endif # The SHA3 is third party library we always want to compile with O3 SHA3_CFLAGS=-O3 +# The SHA256 is third party library we always want to compile with O3 +SHA256_CFLAGS=-O3 + # Optimization flags for the interpreter ifneq (,$(filter yes,$(relwithdebinfo) $(release))) ifneq (,$(filter gcc,$(CC))) @@ -375,7 +379,8 @@ LIBCARTESI_OBJS:= \ uarch-pristine-state-hash.o \ uarch-pristine-hash.o \ send-cmio-response.o \ - replay-step-state-access-interop.o + replay-step-state-access-interop.o \ + sha256.o CARTESI_CLUA_OBJS:= \ clua.o \ @@ -394,7 +399,8 @@ LIBCARTESI_MERKLE_TREE_OBJS:= \ back-merkle-tree.o \ pristine-merkle-tree.o \ complete-merkle-tree.o \ - full-merkle-tree.o + full-merkle-tree.o \ + sha256.o MERKLE_TREE_HASH_OBJS:= \ merkle-tree-hash.o @@ -554,6 +560,10 @@ jsonrpc-discover.cpp: jsonrpc-discover.json sha3.o: ../third-party/tiny_sha3/sha3.c $(CC) $(CFLAGS) $(SHA3_CFLAGS) -c -o $@ $< +sha256.o: ../third-party/SHA256/sha256.c + $(CC) $(CFLAGS) $(SHA256_CFLAGS) -c -o $@ $< + + uarch-pristine-ram.o: $(UARCH_PRISTINE_RAM_C) $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/back-merkle-tree.h b/src/back-merkle-tree.h index fd1902b80..ab5840b70 100644 --- a/src/back-merkle-tree.h +++ b/src/back-merkle-tree.h @@ -20,7 +20,7 @@ #include #include -#include "keccak-256-hasher.h" +#include "machine-hasher.h" #include "merkle-tree-proof.h" #include "pristine-merkle-tree.h" @@ -40,7 +40,7 @@ namespace cartesi { class back_merkle_tree { public: /// \brief Hasher class. - using hasher_type = keccak_256_hasher; + using hasher_type = machine_hasher_type; /// \brief Storage for a hash. using hash_type = hasher_type::hash_type; diff --git a/src/cartesi/proof.lua b/src/cartesi/proof.lua index 2e661824b..3369df43a 100644 --- a/src/cartesi/proof.lua +++ b/src/cartesi/proof.lua @@ -13,7 +13,7 @@ function _M.roll_hash_up_tree(proof, target_hash) else first, second = hash, proof.sibling_hashes[i] end - hash = cartesi.keccak(first, second) + hash = cartesi.hash(first, second) end return hash end @@ -26,7 +26,7 @@ end function _M.word_slice_assert(root_hash, proof, word) assert(proof.log2_target_size == 3, "not a word proof") assert(root_hash == proof.root_hash, "proof root_hash mismatch") - assert(cartesi.keccak(word) == proof.target_hash, "proof target_hash mismatch") + assert(cartesi.hash(word) == proof.target_hash, "proof target_hash mismatch") assert(_M.roll_hash_up_tree(proof, proof.target_hash) == root_hash, "node not in tree") end @@ -37,7 +37,7 @@ end function _M.word_splice_assert(root_hash, proof, old_word, new_word, new_root_hash) _M.word_slice_assert(root_hash, proof, old_word) - assert(_M.roll_hash_up_tree(proof, cartesi.keccak(new_word)) == new_root_hash, "new root hash mismatch") + assert(_M.roll_hash_up_tree(proof, cartesi.hash(new_word)) == new_root_hash, "new root hash mismatch") end return _M diff --git a/src/clua-cartesi.cpp b/src/clua-cartesi.cpp index 9d513edaf..becc34d66 100644 --- a/src/clua-cartesi.cpp +++ b/src/clua-cartesi.cpp @@ -92,6 +92,46 @@ static int cartesi_mod_keccak(lua_State *L) { return 1; } +/// \brief This is the cartesi.keccak() function implementation. +/// \param L Lua state. +static int cartesi_mod_sha256(lua_State *L) { + using namespace cartesi; + sha_256_hasher h; + sha_256_hasher::hash_type hash; + if (lua_gettop(L) > 2) { + luaL_argerror(L, 3, "too many arguments"); + } + if (lua_gettop(L) < 1) { + luaL_argerror(L, 1, "too few arguments"); + } + if (lua_isinteger(L, 1) != 0) { + if (lua_gettop(L) > 1) { + luaL_argerror(L, 2, "too many arguments"); + } + uint64_t word = luaL_checkinteger(L, 1); + h.begin(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + h.add_data(reinterpret_cast(&word), sizeof(word)); + h.end(hash); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + lua_pushlstring(L, reinterpret_cast(hash.data()), hash.size()); + return 1; + } + h.begin(); + size_t len1 = 0; + const char *hash1 = luaL_checklstring(L, 1, &len1); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + h.add_data(reinterpret_cast(hash1), len1); + size_t len2 = 0; + const char *hash2 = luaL_optlstring(L, 2, "", &len2); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + h.add_data(reinterpret_cast(hash2), len2); + h.end(hash); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + lua_pushlstring(L, reinterpret_cast(hash.data()), hash.size()); + return 1; +} + static int cartesi_mod_tobase64(lua_State *L) try { size_t size = 0; const char *data = luaL_checklstring(L, 1, &size); @@ -147,7 +187,8 @@ static int cartesi_mod_new(lua_State *L) try { /// \brief Contents of the cartesi module table. static const auto cartesi_mod = clua_make_luaL_Reg_array({ - {"keccak", cartesi_mod_keccak}, + {"hash", cartesi_mod_sha256}, + {"keccak", cartesi_mod_keccak}, // <--- remove this. Use lua keccak256 for the test-cmio.lua {"tobase64", cartesi_mod_tobase64}, {"frombase64", cartesi_mod_frombase64}, {"tojson", cartesi_mod_tojson}, diff --git a/src/complete-merkle-tree.h b/src/complete-merkle-tree.h index 6dc8bcf88..3c19d785f 100644 --- a/src/complete-merkle-tree.h +++ b/src/complete-merkle-tree.h @@ -21,7 +21,7 @@ #include #include -#include "keccak-256-hasher.h" +#include "machine-hasher.h" #include "merkle-tree-proof.h" #include "meta.h" #include "pristine-merkle-tree.h" @@ -39,7 +39,7 @@ namespace cartesi { class complete_merkle_tree { public: /// \brief Hasher class. - using hasher_type = keccak_256_hasher; + using hasher_type = machine_hasher_type; /// \brief Storage for a hash. using hash_type = hasher_type::hash_type; diff --git a/src/full-merkle-tree.h b/src/full-merkle-tree.h index 1dbfa9713..81a3372c1 100644 --- a/src/full-merkle-tree.h +++ b/src/full-merkle-tree.h @@ -20,7 +20,7 @@ #include #include -#include "keccak-256-hasher.h" +#include "machine-hasher.h" #include "merkle-tree-proof.h" #include "pristine-merkle-tree.h" @@ -34,7 +34,7 @@ namespace cartesi { class full_merkle_tree { public: /// \brief Hasher class. - using hasher_type = keccak_256_hasher; + using hasher_type = machine_hasher_type; /// \brief Storage for a hash. using hash_type = hasher_type::hash_type; diff --git a/src/machine-hasher.h b/src/machine-hasher.h new file mode 100644 index 000000000..1f1587b37 --- /dev/null +++ b/src/machine-hasher.h @@ -0,0 +1,28 @@ +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with this program (see COPYING). If not, see . +// + +#ifndef MACHINE_HASHER_H +#define MACHINE_HASHER_H + +#include "sha-256-hasher.h" + +namespace cartesi { + +using machine_hasher_type = sha_256_hasher; + +} + +#endif diff --git a/src/machine-merkle-tree.h b/src/machine-merkle-tree.h index 71293fed5..c2f2db09e 100644 --- a/src/machine-merkle-tree.h +++ b/src/machine-merkle-tree.h @@ -28,7 +28,7 @@ #include #include -#include "keccak-256-hasher.h" +#include "machine-hasher.h" #include "merkle-tree-proof.h" #include "pristine-merkle-tree.h" @@ -51,7 +51,8 @@ namespace cartesi { /// original data whenever needed and never stored. /// Pages are divided into *words* that cover LOG2_WORD_SIZE /// bits of address space. -/// Tree leaves contain Keccak-256 hashes of individual words. +/// Tree leaves contain hashes of individual words. +// The hashing algorithm is provided hasher_type, defined in machine-hasher.h. /// /// Tree contents are updated page-by-page using calls to /// machine_merkle_tree#begin_update, machine_merkle_tree#update_page, ..., @@ -112,7 +113,7 @@ class machine_merkle_tree final { } /// \brief Hasher class. - using hasher_type = keccak_256_hasher; + using hasher_type = machine_hasher_type; /// \brief Storage for a hash. using hash_type = hasher_type::hash_type; diff --git a/src/merkle-tree-hash.cpp b/src/merkle-tree-hash.cpp index 3531de036..8fa75b35a 100644 --- a/src/merkle-tree-hash.cpp +++ b/src/merkle-tree-hash.cpp @@ -26,11 +26,11 @@ #include "back-merkle-tree.h" #include "i-hasher.h" -#include "keccak-256-hasher.h" +#include "machine-hasher.h" #include "unique-c-ptr.h" using namespace cartesi; -using hasher_type = keccak_256_hasher; +using hasher_type = machine_hasher_type; using hash_type = hasher_type::hash_type; /// \brief Checks if string matches prefix and captures remaninder @@ -175,7 +175,7 @@ the hash of the data in the range. The Merkle tree root hash is simply the node hash corresponding to the entire 2^log2_root_size range. -The hash function used is Keccak-256. +The hash function used is machine_hasher_type, defined in machine-hasher.h. Options: diff --git a/src/pristine-merkle-tree.h b/src/pristine-merkle-tree.h index d3230f600..c641a62cd 100644 --- a/src/pristine-merkle-tree.h +++ b/src/pristine-merkle-tree.h @@ -20,7 +20,7 @@ #include #include -#include "keccak-256-hasher.h" +#include "machine-hasher.h" /// \file /// \brief Pristine Merkle tree interface. @@ -31,7 +31,7 @@ namespace cartesi { class pristine_merkle_tree { public: /// \brief Hasher class. - using hasher_type = keccak_256_hasher; + using hasher_type = machine_hasher_type; /// \brief Storage for a hash. using hash_type = hasher_type::hash_type; diff --git a/src/sha-256-hasher.h b/src/sha-256-hasher.h new file mode 100644 index 000000000..8fe472329 --- /dev/null +++ b/src/sha-256-hasher.h @@ -0,0 +1,66 @@ +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License along +// with this program (see COPYING). If not, see . +// + +#ifndef SHA256_HASHER_H +#define SHA256_HASHER_H + +#include + +#include "i-hasher.h" + +extern "C" { +#include "sha256.h" +} + +namespace cartesi { + +class sha_256_hasher final : public i_hasher> { + sha256_context m_ctx{}; + + friend i_hasher>; + + void do_begin() { + sha256_init(&m_ctx); + } + + void do_add_data(const unsigned char *data, size_t length) { + sha256_hash(&m_ctx, data, length); + } + + void do_end(hash_type &hash) { + sha256_done(&m_ctx, hash.data()); + } + +public: + /// \brief Default constructor + sha_256_hasher() = default; + + /// \brief Default destructor + ~sha_256_hasher() = default; + + /// \brief No copy constructor + sha_256_hasher(const sha_256_hasher &) = delete; + /// \brief No move constructor + sha_256_hasher(sha_256_hasher &&) = delete; + /// \brief No copy assignment + sha_256_hasher &operator=(const sha_256_hasher &) = delete; + /// \brief No move assignment + sha_256_hasher &operator=(sha_256_hasher &&) = delete; +}; + +} // namespace cartesi + +#endif diff --git a/tests/lua/cartesi/tests/util.lua b/tests/lua/cartesi/tests/util.lua index c98e13138..d75041966 100644 --- a/tests/lua/cartesi/tests/util.lua +++ b/tests/lua/cartesi/tests/util.lua @@ -32,16 +32,16 @@ local test_util = { tests_uarch_path = adjust_path(assert(os.getenv("CARTESI_TESTS_UARCH_PATH"))), } -local zero_keccak_hash_table = { +local zero_hash_table = { "", "", } do - local hash = cartesi.keccak(string.rep("\0", 1 << WORD_LOG2_SIZE)) + local hash = cartesi.hash(string.rep("\0", 1 << WORD_LOG2_SIZE)) for i = WORD_LOG2_SIZE, ROOT_LOG2_SIZE - 1 do - zero_keccak_hash_table[i] = hash - hash = cartesi.keccak(hash, hash) + zero_hash_table[i] = hash + hash = cartesi.hash(hash, hash) end end @@ -93,7 +93,7 @@ function back_merkle_tree_meta.__index:push_back(new_leaf_hash) for i = 0, depth do if self.m_leaf_count & (0x01 << i) ~= 0x0 then local left = self.m_context[i] - right = cartesi.keccak(left, right) + right = cartesi.hash(left, right) else self.m_context[i] = right break @@ -118,12 +118,12 @@ function back_merkle_tree_meta.__index:pad_back(new_leaf_count) -- is our smallest tree at depth j? if (self.m_leaf_count & j_span) ~= 0x0 then -- if so, we can add 2^j pristine leaves directly - local right = zero_keccak_hash_table[self.m_log2_leaf_size + j] + local right = zero_hash_table[self.m_log2_leaf_size + j] for i = j, depth do local i_span = 0x1 << i if (self.m_leaf_count & i_span) ~= 0x0 then local left = self.m_context[i] - right = cartesi.keccak(left, right) + right = cartesi.hash(left, right) else self.m_context[i] = right -- next outer loop starts again from where inner loop left off @@ -141,7 +141,7 @@ function back_merkle_tree_meta.__index:pad_back(new_leaf_count) for i = 0, depth do local i_span = 0x1 << i if (new_leaf_count & i_span) ~= 0x0 then - self.m_context[i] = zero_keccak_hash_table[self.m_log2_leaf_size + i] + self.m_context[i] = zero_hash_table[self.m_log2_leaf_size + i] new_leaf_count = new_leaf_count - i_span self.m_leaf_count = self.m_leaf_count + i_span end @@ -152,14 +152,14 @@ function back_merkle_tree_meta.__index:get_root_hash() assert(self.m_leaf_count <= self.m_max_leaves, "too many leaves") local depth = self.m_log2_root_size - self.m_log2_leaf_size if self.m_leaf_count < self.m_max_leaves then - local root = zero_keccak_hash_table[self.m_log2_leaf_size] + local root = zero_hash_table[self.m_log2_leaf_size] for i = 0, depth - 1 do if (self.m_leaf_count & (0x01 << i)) ~= 0 then local left = self.m_context[i] - root = cartesi.keccak(left, root) + root = cartesi.hash(left, root) else - local right = zero_keccak_hash_table[self.m_log2_leaf_size + i] - root = cartesi.keccak(root, right) + local right = zero_hash_table[self.m_log2_leaf_size + i] + root = cartesi.hash(root, right) end end return root @@ -216,7 +216,7 @@ function test_util.check_proof(proof) else first, second = hash, proof.sibling_hashes[log2_size - proof.log2_target_size + 1] end - hash = cartesi.keccak(first, second) + hash = cartesi.hash(first, second) end return hash == proof.root_hash end @@ -233,14 +233,14 @@ end local function merkle_hash(data, start, log2_size) if log2_size == PAGE_LOG2_SIZE and data:sub(start + 1, start + PAGE_SIZE) == ZERO_PAGE then - return zero_keccak_hash_table[PAGE_LOG2_SIZE] + return zero_hash_table[PAGE_LOG2_SIZE] elseif log2_size > WORD_LOG2_SIZE then local child_log2_size = log2_size - 1 local left = merkle_hash(data, start, child_log2_size) local right = merkle_hash(data, start + (1 << child_log2_size), child_log2_size) - return cartesi.keccak(left, right) + return cartesi.hash(left, right) else - return cartesi.keccak(data:sub(start + 1, start + (1 << WORD_LOG2_SIZE))) + return cartesi.hash(data:sub(start + 1, start + (1 << WORD_LOG2_SIZE))) end end diff --git a/tests/lua/machine-bind.lua b/tests/lua/machine-bind.lua index a8c9d87ce..325e15435 100755 --- a/tests/lua/machine-bind.lua +++ b/tests/lua/machine-bind.lua @@ -1263,7 +1263,7 @@ do_test("Dump of log produced by send_cmio_response should match", function(mach -- luacheck: push no max line length local expected_dump = "begin send cmio response\n" .. " 1: read iflags.Y@0x2f8(760): 0x1(1)\n" - .. ' 2: write cmio rx buffer@0x60000000(1610612736): hash:"290decd9"(2^5 bytes) -> hash:"555b1f6d"(2^5 bytes)\n' + .. ' 2: write cmio rx buffer@0x60000000(1610612736): hash:"66687aad"(2^5 bytes) -> hash:"e6fe5964"(2^5 bytes)\n' .. " 3: write htif.fromhost@0x330(816): 0x0(0) -> 0x70000000a(30064771082)\n" .. " 4: write iflags.Y@0x2f8(760): 0x1(1) -> 0x0(0)\n" .. "end send cmio response\n" diff --git a/tests/misc/Makefile b/tests/misc/Makefile index f4a2eeffb..8be86cef4 100644 --- a/tests/misc/Makefile +++ b/tests/misc/Makefile @@ -94,7 +94,7 @@ CLANG_TIDY_HEADER_FILTER=$(CURDIR)/($(subst $(SPACE),|,$(LINTER_HEADERS))) CLANG_FORMAT=clang-format CLANG_FORMAT_FILES:=$(wildcard *.cpp) $(wildcard *.h) -INCS=-I../../src -I../../third-party/tiny_sha3 -I../../third-party/nlohmann-json -I../../third-party/downloads +INCS=-I../../src -I../../third-party/SHA256 -I../../third-party/nlohmann-json -I../../third-party/downloads WARNS=-Wall -Wpedantic CXXFLAGS+=-O2 -g -std=gnu++20 -fvisibility=hidden $(INCS) $(UBFLAGS) $(WARNS) diff --git a/tests/misc/test-merkle-tree-hash.cpp b/tests/misc/test-merkle-tree-hash.cpp index 7fb3918f1..f09e50a52 100644 --- a/tests/misc/test-merkle-tree-hash.cpp +++ b/tests/misc/test-merkle-tree-hash.cpp @@ -30,12 +30,12 @@ #include #include #include -#include +#include #include #include using namespace cartesi; -using hasher_type = keccak_256_hasher; +using hasher_type = machine_hasher_type; using hash_type = hasher_type::hash_type; namespace { diff --git a/tests/misc/test-utils.h b/tests/misc/test-utils.h index 9fc017d64..7aeb55e7b 100644 --- a/tests/misc/test-utils.h +++ b/tests/misc/test-utils.h @@ -18,11 +18,11 @@ #include "json-util.h" #include -#include #include +#include #include -using hash_type = cartesi::keccak_256_hasher::hash_type; +using hash_type = cartesi::machine_hasher_type::hash_type; // Calculate root hash for data buffer of log2_size namespace detail { @@ -31,7 +31,7 @@ constexpr int WORD_LOG2_SIZE = 5; constexpr int MERKLE_PAGE_LOG2_SIZE = 12; constexpr int MERKLE_PAGE_SIZE = (UINT64_C(1) << MERKLE_PAGE_LOG2_SIZE); -static hash_type merkle_hash(cartesi::keccak_256_hasher &h, const std::string_view &data, int log2_size) { +static hash_type merkle_hash(cartesi::machine_hasher_type &h, const std::string_view &data, int log2_size) { hash_type result; if (log2_size > WORD_LOG2_SIZE) { --log2_size; @@ -60,7 +60,7 @@ static hash_type merkle_hash(const std::string_view &data, int log2_size) { if ((UINT64_C(1) << log2_size) != data.size()) { throw std::invalid_argument("log2_size does not match data size"); } - cartesi::keccak_256_hasher h; + cartesi::machine_hasher_type h; return detail::merkle_hash(h, data, log2_size); } @@ -69,7 +69,7 @@ static hash_type calculate_proof_root_hash(const cartesi::machine_merkle_tree::p memcpy(hash.data(), proof.get_target_hash().data(), sizeof(cm_hash)); for (int log2_size = static_cast(proof.get_log2_target_size()); log2_size < static_cast(proof.get_log2_root_size()); ++log2_size) { - cartesi::keccak_256_hasher h; + cartesi::machine_hasher_type h; auto bit = (proof.get_target_address() & (UINT64_C(1) << log2_size)); hash_type first; hash_type second; diff --git a/third-party/SHA256/LICENSE b/third-party/SHA256/LICENSE new file mode 100644 index 000000000..701cbba11 --- /dev/null +++ b/third-party/SHA256/LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +Copyright (c) 2022 Ilia Levin (ilia@levin.sg) + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third-party/SHA256/sha256.c b/third-party/SHA256/sha256.c new file mode 100644 index 000000000..9f7bf2fcf --- /dev/null +++ b/third-party/SHA256/sha256.c @@ -0,0 +1,328 @@ +//usr/bin/env clang -Ofast -Wall -Wextra -pedantic ${0} -o ${0%%.c*} $* ;exit $? +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#include "sha256.h" + +#ifndef _cbmc_ +#define __CPROVER_assume(...) do {} while(0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define FN_ static inline __attribute__((const)) + +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +// ----------------------------------------------------------------------------- +FN_ uint8_t _shb(uint32_t x, uint32_t n) +{ + return ((x >> (n & 31)) & 0xff); +} // _shb + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _shw(uint32_t x, uint32_t n) +{ + return ((x << (n & 31)) & 0xffffffff); +} // _shw + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _r(uint32_t x, uint8_t n) +{ + return ((x >> n) | _shw(x, 32 - n)); +} // _r + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ ((~x) & z)); +} // _Ch + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ma(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} // _Ma + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _S0(uint32_t x) +{ + return (_r(x, 2) ^ _r(x, 13) ^ _r(x, 22)); +} // _S0 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _S1(uint32_t x) +{ + return (_r(x, 6) ^ _r(x, 11) ^ _r(x, 25)); +} // _S1 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _G0(uint32_t x) +{ + return (_r(x, 7) ^ _r(x, 18) ^ (x >> 3)); +} // _G0 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _G1(uint32_t x) +{ + return (_r(x, 17) ^ _r(x, 19) ^ (x >> 10)); +} // _G1 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _word(uint8_t *c) +{ + return (_shw(c[0], 24) | _shw(c[1], 16) | _shw(c[2], 8) | (c[3])); +} // _word + + +// ----------------------------------------------------------------------------- +static void _addbits(sha256_context *ctx, uint32_t n) +{ + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + + if (ctx->bits[0] > (0xffffffff - n)) { + ctx->bits[1] = (ctx->bits[1] + 1) & 0xFFFFFFFF; + } + ctx->bits[0] = (ctx->bits[0] + n) & 0xFFFFFFFF; +} // _addbits + + +// ----------------------------------------------------------------------------- +static void _hash(sha256_context *ctx) +{ + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + + register uint32_t a, b, c, d, e, f, g, h; + uint32_t t[2]; + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + f = ctx->hash[5]; + g = ctx->hash[6]; + h = ctx->hash[7]; + + for (uint32_t i = 0; i < 64; i++) { + if (i < 16) { + ctx->W[i] = _word(&ctx->buf[_shw(i, 2)]); + } else { + ctx->W[i] = _G1(ctx->W[i - 2]) + ctx->W[i - 7] + + _G0(ctx->W[i - 15]) + ctx->W[i - 16]; + } + + t[0] = h + _S1(e) + _Ch(e, f, g) + K[i] + ctx->W[i]; + t[1] = _S0(a) + _Ma(a, b, c); + h = g; + g = f; + f = e; + e = d + t[0]; + d = c; + c = b; + b = a; + a = t[0] + t[1]; + } + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} // _hash + + +// ----------------------------------------------------------------------------- +void sha256_init(sha256_context *ctx) +{ + if (ctx != NULL) { + ctx->bits[0] = ctx->bits[1] = ctx->len = 0; + ctx->hash[0] = 0x6a09e667; + ctx->hash[1] = 0xbb67ae85; + ctx->hash[2] = 0x3c6ef372; + ctx->hash[3] = 0xa54ff53a; + ctx->hash[4] = 0x510e527f; + ctx->hash[5] = 0x9b05688c; + ctx->hash[6] = 0x1f83d9ab; + ctx->hash[7] = 0x5be0cd19; + } +} // sha256_init + + +// ----------------------------------------------------------------------------- +void sha256_hash(sha256_context *ctx, const void *data, size_t len) +{ + const uint8_t *bytes = (const uint8_t *)data; + + if ((ctx != NULL) && (bytes != NULL) && (ctx->len < sizeof(ctx->buf))) { + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(bytes)); + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + for (size_t i = 0; i < len; i++) { + ctx->buf[ctx->len++] = bytes[i]; + if (ctx->len == sizeof(ctx->buf)) { + _hash(ctx); + _addbits(ctx, sizeof(ctx->buf) * 8); + ctx->len = 0; + } + } + } +} // sha256_hash + + +// ----------------------------------------------------------------------------- +void sha256_done(sha256_context *ctx, uint8_t *hash) +{ + register uint32_t i, j; + + if (ctx != NULL) { + j = ctx->len % sizeof(ctx->buf); + ctx->buf[j] = 0x80; + for (i = j + 1; i < sizeof(ctx->buf); i++) { + ctx->buf[i] = 0x00; + } + + if (ctx->len > 55) { + _hash(ctx); + for (j = 0; j < sizeof(ctx->buf); j++) { + ctx->buf[j] = 0x00; + } + } + + _addbits(ctx, ctx->len * 8); + ctx->buf[63] = _shb(ctx->bits[0], 0); + ctx->buf[62] = _shb(ctx->bits[0], 8); + ctx->buf[61] = _shb(ctx->bits[0], 16); + ctx->buf[60] = _shb(ctx->bits[0], 24); + ctx->buf[59] = _shb(ctx->bits[1], 0); + ctx->buf[58] = _shb(ctx->bits[1], 8); + ctx->buf[57] = _shb(ctx->bits[1], 16); + ctx->buf[56] = _shb(ctx->bits[1], 24); + _hash(ctx); + + if (hash != NULL) { + for (i = 0, j = 24; i < 4; i++, j -= 8) { + hash[i + 0] = _shb(ctx->hash[0], j); + hash[i + 4] = _shb(ctx->hash[1], j); + hash[i + 8] = _shb(ctx->hash[2], j); + hash[i + 12] = _shb(ctx->hash[3], j); + hash[i + 16] = _shb(ctx->hash[4], j); + hash[i + 20] = _shb(ctx->hash[5], j); + hash[i + 24] = _shb(ctx->hash[6], j); + hash[i + 28] = _shb(ctx->hash[7], j); + } + } + } +} // sha256_done + + +// ----------------------------------------------------------------------------- +void sha256(const void *data, size_t len, uint8_t *hash) +{ + sha256_context ctx; + + sha256_init(&ctx); + sha256_hash(&ctx, data, len); + sha256_done(&ctx, hash); +} // sha256 + + +#if 0 +#pragma mark - Self Test +#endif +#ifdef SHA256_SELF_TEST__ +#include +#include + +int main(void) +{ + char *buf[] = { + "", + "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", + + "abc", + "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad", + + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1", + + "The quick brown fox jumps over the lazy dog", + "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592", + + "The quick brown fox jumps over the lazy cog", // avalanche effect test + "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be", + + "bhn5bjmoniertqea40wro2upyflkydsibsk8ylkmgbvwi420t44cq034eou1szc1k0mk46oeb7ktzmlxqkbte2sy", + "9085df2f 02e0cc45 5928d0f5 1b27b4bf 1d9cd260 a66ed1fd a11b0a3f f5756d99" + }; + const size_t tests_total = sizeof(buf) / sizeof(buf[0]); + uint8_t hash[SHA256_SIZE_BYTES]; + + if (0 != (tests_total % 2)) { + return printf("invalid tests\n"); + } + + for (size_t i = 0; i < tests_total; i += 2) { + sha256(buf[i], strlen(buf[i]), hash); + printf("input = '%s'\ndigest: %s\nresult: ", buf[i], buf[i + 1]); + for (size_t j = 0; j < SHA256_SIZE_BYTES; j++) { + printf("%02x%s", hash[j], ((j % 4) == 3) ? " " : ""); + } + printf("\n\n"); + } + + return 0; +} // main + +#endif // def SHA256_SELF_TEST__ + +#ifdef __cplusplus +} +#endif diff --git a/third-party/SHA256/sha256.h b/third-party/SHA256/sha256.h new file mode 100644 index 000000000..6df116bc3 --- /dev/null +++ b/third-party/SHA256/sha256.h @@ -0,0 +1,52 @@ +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#ifndef SHA256_H_ +#define SHA256_H_ + +#include +#include + +#define SHA256_SIZE_BYTES (32) + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + uint8_t buf[64]; + uint32_t hash[8]; + uint32_t bits[2]; + uint32_t len; + uint32_t rfu__; + uint32_t W[64]; +} sha256_context; + +void sha256_init(sha256_context *ctx); +void sha256_hash(sha256_context *ctx, const void *data, size_t len); +void sha256_done(sha256_context *ctx, uint8_t *hash); + +void sha256(const void *data, size_t len, uint8_t *hash); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/uarch/Makefile b/uarch/Makefile index cd80e391c..f497f7ab7 100644 --- a/uarch/Makefile +++ b/uarch/Makefile @@ -19,7 +19,7 @@ else HOST_CXX := g++ endif -HOST_CFLAGS := -I$(THIRD_PARTY_DIR)/tiny_sha3 -I$(EMULATOR_SRC_DIR) +HOST_CFLAGS := -I$(THIRD_PARTY_DIR)/SHA256 -I$(EMULATOR_SRC_DIR) CC := $(TOOLCHAIN_PREFIX)gcc LD := $(TOOLCHAIN_PREFIX)ld @@ -81,7 +81,7 @@ COMPUTE_UARCH_CPP_SOURCES=\ $(EMULATOR_SRC_DIR)/complete-merkle-tree.cpp \ $(EMULATOR_SRC_DIR)/full-merkle-tree.cpp COMPUTE_UARCH_C_SOURCES=\ - $(THIRD_PARTY_DIR)/tiny_sha3/sha3.c \ + $(THIRD_PARTY_DIR)/SHA256/sha256.c \ uarch-pristine-ram.c UARCH_OBJS = $(patsubst %.c,%.uarch_c.o,$(patsubst %.cpp,%.uarch_cpp.o,$(UARCH_SOURCES)))