diff --git a/.gitmodules b/.gitmodules index 8a25db68..d9c387a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,3 @@ url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git branch = develop ignore = dirty -[submodule "libraries/vendor/SHA3IUF"] - path = libraries/vendor/SHA3IUF - url = https://github.com/brainhub/SHA3IUF.git - branch = master diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index df872464..f28a6cee 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -5,7 +5,7 @@ add_subdirectory( egenesis ) add_subdirectory( fc ) add_subdirectory( net ) add_subdirectory( plugins ) +add_subdirectory( sha3 ) add_subdirectory( time ) add_subdirectory( utilities ) -add_subdirectory( vendor ) add_subdirectory( wallet ) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index ca995c10..687532a1 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -22,6 +22,7 @@ add_library( peerplays_sidechain ethereum/decoders.cpp ethereum/transaction.cpp ethereum/types.cpp + ethereum/utils.cpp hive/asset.cpp hive/operations.cpp hive/transaction.cpp @@ -41,11 +42,9 @@ endif() unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) -target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} ) -target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin zmq ${SHA3IUF_libraries} ) -target_include_directories( peerplays_sidechain PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${SHA3IUF_include_dirs}" ) +target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq ) +target_include_directories( peerplays_sidechain + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) install( TARGETS peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp index fcf468ce..02f334f5 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -1,5 +1,224 @@ #include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +//! rlp_decoder + +namespace { +const signed char p_util_hexdigit[256] = + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +} + +std::vector rlp_decoder::decode(const std::string &str) { + size_t consumed = 0; + const auto raw_vec = parse_hex(str); + const std::vector rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed); + std::vector result_array; + for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) { + result_array.emplace_back(bytes2hex(rlp)); + } + return result_array; +} + +std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) { + std::vector rlp_result; + + consumed = 0; + + const unsigned char *end = raw + len; + const size_t prefixlen = 1; + unsigned char ch = *raw; + + if (len < 1) { + return rlp_result; + } + + // Case 1: [prefix is 1-byte data buffer] + if (ch <= 0x7f) { + const unsigned char *tok_start = raw; + const unsigned char *tok_end = tok_start + prefixlen; + FC_ASSERT(tok_end <= end); + + // parsing done; assign data buffer value. + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back(buf.cbegin(), buf.cend()); + + consumed = buf.size(); + } + // Case 2: [prefix, including buffer length][data] + else if ((ch >= 0x80) && (ch <= 0xb7)) { + const size_t blen = ch - 0x80; + const size_t expected = prefixlen + blen; + + if (len < expected) + return std::vector{}; + + const unsigned char *tok_start = raw + 1; + const unsigned char *tok_end = tok_start + blen; + FC_ASSERT(tok_end <= end); + + // require minimal encoding + if ((blen == 1) && (tok_start[0] <= 0x7f)) + return std::vector{}; + + // parsing done; assign data buffer value. + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back(buf.cbegin(), buf.cend()); + + consumed = expected; + } + // Case 3: [prefix][buffer length][data] + else if ((ch >= 0xb8) && (ch <= 0xbf)) { + const size_t uintlen = ch - 0xb7; + size_t expected = prefixlen + uintlen; + + if (len < expected) + return std::vector{}; + + FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + return std::vector{}; + + // read buffer length + const uint64_t slen = to_int(tok_start, uintlen); + + // validate buffer length, including possible addition overflows. + expected = prefixlen + uintlen + slen; + if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len)) + return std::vector{}; + + // parsing done; assign data buffer value. + tok_start = raw + prefixlen + uintlen; + const unsigned char *tok_end = tok_start + slen; + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back(buf.cbegin(), buf.cend()); + + consumed = expected; + } + // Case 4: [prefix][list] + else if ((ch >= 0xc0) && (ch <= 0xf7)) { + const size_t payloadlen = ch - 0xc0; + const size_t expected = prefixlen + payloadlen; + + // read list payload + const auto array = decode_array(raw, len, 0, payloadlen); + rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend()); + + consumed = expected; + } + // Case 5: [prefix][list length][list] + else { + FC_ASSERT((ch >= 0xf8) && (ch <= 0xff)); + + const size_t uintlen = ch - 0xf7; + const size_t expected = prefixlen + uintlen; + + if (len < expected) + return std::vector{}; + + FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + return std::vector{}; + + // read list length + const size_t payloadlen = to_int(tok_start, uintlen); + + // special requirement for non-immediate length + if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen)) + return std::vector{}; + + // read list payload + const auto array = decode_array(raw, len, uintlen, payloadlen); + rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend()); + + consumed = prefixlen + uintlen + payloadlen; + } + + return rlp_result; +} + +std::vector rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) { + std::vector rlp_result; + const size_t prefixlen = 1; + + // validate list length, including possible addition overflows. + const size_t expected = prefixlen + uintlen + payloadlen; + if ((expected > len) || (payloadlen > len)) + return std::vector{}; + + size_t child_len = payloadlen; + const unsigned char *list_ent = raw + prefixlen + uintlen; + + // recursively read until payloadlen bytes parsed, or error + while (child_len > 0) { + size_t child_consumed = 0; + + const auto val = decode_rlp(list_ent, child_len, child_consumed); + rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend()); + + list_ent += child_consumed; + child_len -= child_consumed; + } + + return rlp_result; +} + +uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) { + if (len == 0) + return 0; + else if (len == 1) + return *raw; + else + return (raw[len - 1]) + (to_int(raw, len - 1) * 256); +} + +std::vector rlp_decoder::parse_hex(const std::string &str) { + return parse_hex(str.c_str()); +} + +std::vector rlp_decoder::parse_hex(const char *psz) { + // convert hex dump to vector + std::vector vch; + while (true) { + while (isspace(*psz)) + psz++; + signed char c = hex_digit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = hex_digit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +signed char rlp_decoder::hex_digit(char c) { + return p_util_hexdigit[(unsigned char)c]; +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 4359a605..ad42088b 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -1,5 +1,102 @@ #include +#include +#include +#include + +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +//! base_encoder +std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) { + return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); +} + +std::string base_encoder::encode_address(const std::string &value) { + return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); +} + +std::string base_encoder::encode_string(const std::string &value) { + std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str(); + data += boost::algorithm::hex(value) + std::string((64 - value.size() * 2 % 64), '0'); + return data; +} + +//! update_owners_encoder +std::string update_owners_encoder::encode(const std::vector> &owners_weights, const std::string &object_id) const { + std::string data = "0x" + function_signature; + data += base_encoder::encode_uint256(64); + data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32); + data += base_encoder::encode_uint256(owners_weights.size()); + for (const auto &owner : owners_weights) { + data += base_encoder::encode_address(owner.first); + data += base_encoder::encode_uint256(owner.second); + } + data += base_encoder::encode_string(object_id); + + return data; +} + +//! withdrawal_encoder +std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const { + std::string data = "0x" + function_signature; + data += base_encoder::encode_address(to); + data += base_encoder::encode_uint256(amount); + data += base_encoder::encode_uint256(32 * 3); + data += base_encoder::encode_string(object_id); + + return data; +} + +//! rlp_encoder +std::string rlp_encoder::encode(const std::string &s) { + return encode_rlp(hex2bytes(s)); +} + +std::string rlp_encoder::encode_length(int len, int offset) { + if (len < 56) { + std::string temp; + temp = (char)(len + offset); + return temp; + } else { + const std::string hexLength = to_hex(len); + const int lLength = hexLength.size() / 2; + const std::string fByte = to_hex(offset + 55 + lLength); + return hex2bytes(fByte + hexLength); + } +} + +std::string rlp_encoder::hex2bytes(const std::string &s) { + std::string dest; + dest.resize(s.size() / 2); + hex2bin(s.c_str(), &dest[0]); + return dest; +} + +std::string rlp_encoder::encode_rlp(const std::string &s) { + if (s.size() == 1 && (unsigned char)s[0] < 128) + return s; + else + return encode_length(s.size(), 128) + s; +} + +int rlp_encoder::char2int(char input) { + if (input >= '0' && input <= '9') + return input - '0'; + if (input >= 'A' && input <= 'F') + return input - 'A' + 10; + if (input >= 'a' && input <= 'f') + return input - 'a' + 10; + + return -1; +} + +void rlp_encoder::hex2bin(const char *src, char *target) { + while (*src && src[1]) { + *(target++) = char2int(*src) * 16 + char2int(src[1]); + src += 2; + } +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 9bf3bf02..668e9639 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,22 +1,158 @@ #include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { -std::string transaction::sign(std::string private_key) { - v = "signed"; - r = "transaction"; - s = "signed-transaction"; - return v + "|" + r + "|" + s; +const secp256k1_context *eth_context() { + static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + return ctx; } -std::string transaction::serialize() { - return "serialized-transaction"; +//! transaction + +const transaction &transaction::sign(const std::string &private_key) const { + return *this; } -void transaction::deserialize(std::string raw_tx) { - block_hash = "1"; - block_number = "2"; - hash = "3"; +std::string transaction::serialize() const { + boost::property_tree::ptree pt; + pt.put("from", from); + pt.put("to", to); + pt.put("data", data); + + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, pt); + return ss.str(); +} + +void transaction::deserialize(const std::string &raw_tx) { + std::stringstream ss_tx(raw_tx); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + + if (tx_json.count("from")) + from = tx_json.get("from"); + if (tx_json.count("to")) + to = tx_json.get("to"); + if (tx_json.count("data")) + data = tx_json.get("data"); +} + +//! raw_transaction + +signed_transaction raw_transaction::sign(const std::string &private_key) const { + //! Prepare signed transaction + signed_transaction tr; + tr.nonce = nonce; + tr.gas_price = gas_price; + tr.gas_limit = gas_limit; + tr.to = to; + tr.value = value; + tr.data = data; + + //! Calculate keccak hash of transaction + bytes hash; + hash.resize(32); + const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); + keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); + + const bytes priv_key = parse_hex(private_key); + + int recid = 0; + secp256k1_ecdsa_recoverable_signature sig; + FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL)); + fc::ecc::compact_signature result; + FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); + + bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; + bytes r; + for (int i = 1; i < 33; i++) + r.emplace_back((char)result.at(i)); + bytes s; + for (int i = 33; i < 65; i++) + s.emplace_back((char)result.at(i)); + + tr.v = fc::to_hex((char *)&v[0], v.size()); + tr.r = fc::to_hex((char *)&r[0], r.size()); + tr.s = fc::to_hex((char *)&s[0], s.size()); + + return tr; +} + +std::string raw_transaction::serialize() const { + rlp_encoder encoder; + const std::string serialized = encoder.encode(remove_0x(nonce)) + + encoder.encode(remove_0x(gas_price)) + + encoder.encode(remove_0x(gas_limit)) + + encoder.encode(remove_0x(to)) + + encoder.encode(remove_0x(value)) + + encoder.encode(remove_0x(data)) + + encoder.encode(remove_0x(chain_id)) + + encoder.encode("") + + encoder.encode(""); + + return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); +} + +void raw_transaction::deserialize(const std::string &raw_tx) { + rlp_decoder decoder; + const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); + + nonce = add_0x(rlp_array.at(0)); + gas_price = add_0x(rlp_array.at(1)); + gas_limit = add_0x(rlp_array.at(2)); + to = add_0x(rlp_array.at(3)); + value = add_0x(rlp_array.at(4)); + data = add_0x(rlp_array.at(5)); + chain_id = add_0x(rlp_array.at(6)); +} + +//! signed_transaction + +std::string signed_transaction::serialize() const { + rlp_encoder encoder; + const std::string serialized = encoder.encode(remove_0x(nonce)) + + encoder.encode(remove_0x(gas_price)) + + encoder.encode(remove_0x(gas_limit)) + + encoder.encode(remove_0x(to)) + + encoder.encode(remove_0x(value)) + + encoder.encode(remove_0x(data)) + + encoder.encode(remove_0x(v)) + + encoder.encode(remove_0x(r)) + + encoder.encode(remove_0x(s)); + + return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); +} + +void signed_transaction::deserialize(const std::string &raw_tx) { + rlp_decoder decoder; + const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); + + nonce = add_0x(rlp_array.at(0)); + gas_price = add_0x(rlp_array.at(1)); + gas_limit = add_0x(rlp_array.at(2)); + to = add_0x(rlp_array.at(3)); + value = add_0x(rlp_array.at(4)); + data = add_0x(rlp_array.at(5)); + v = add_0x(rlp_array.at(6)); + r = add_0x(rlp_array.at(7)); + s = add_0x(rlp_array.at(8)); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp new file mode 100644 index 00000000..ce64e1ae --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -0,0 +1,52 @@ +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +bytes parse_hex(const std::string &str) { + bytes vec(str.size() / 2); + fc::from_hex(str, vec.data(), vec.size()); + return vec; +} + +std::string bytes2hex(const std::string &s) { + std::string dest; + for (const auto &i : s) + dest += uchar2Hex((unsigned char)i); + + return dest; +} + +std::string uchar2Hex(unsigned char n) { + std::string dest; + dest.resize(2); + sprintf(&dest[0], "%X", n); + + if (n < (unsigned char)16) { + dest[1] = dest[0]; + dest[0] = '0'; + } + + return dest; +} + +std::string add_0x(const std::string &s) { + if (s.size() > 1) { + if (s.substr(0, 2) == "0x") + return s; + } + + return "0x" + s; +} + +std::string remove_0x(const std::string &s) { + if (s.size() > 1) { + if (s.substr(0, 2) == "0x") + return s.substr(2); + } + + return s; +} + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp index b9a7e927..9edb6ae3 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp @@ -5,4 +5,24 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { +class rlp_decoder { +private: + enum RLP_constants { + RLP_maxUintLen = 8, + RLP_bufferLenStart = 0x80, + RLP_listStart = 0xc0, + }; + +public: + static std::vector decode(const std::string &str); + +private: + static std::vector decode_rlp(const unsigned char *raw, size_t len, size_t &consumed); + static std::vector decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen); + static uint64_t to_int(const unsigned char *raw, size_t len); + static std::vector parse_hex(const std::string &str); + static std::vector parse_hex(const char *psz); + static signed char hex_digit(char c); +}; + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp index 43fc38dc..1ff97978 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp @@ -1,11 +1,45 @@ #pragma once +#include #include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { -class ethereum_function_call_encoder { +class base_encoder { +public: + static std::string encode_uint256(boost::multiprecision::uint256_t value); + static std::string encode_address(const std::string &value); + static std::string encode_string(const std::string &value); +}; + +class update_owners_encoder { +public: + const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) + + std::string encode(const std::vector> &owners_weights, const std::string &object_id) const; +}; + +class withdrawal_encoder { +public: + const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string) + + std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const; +}; + +class rlp_encoder { +public: + static std::string encode(const std::string &s); + static std::string encode_length(int len, int offset); + static std::string hex2bytes(const std::string &s); + +private: + static std::string encode_rlp(const std::string &s); + static int char2int(char input); + static void hex2bin(const char *src, char *target); +}; + +/*class ethereum_function_call_encoder { public: enum operation_t { OPERATION_CALL, @@ -34,6 +68,6 @@ public: private: ethereum_function_call_encoder m_ethereum_function_call_encoder; -}; +};*/ }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 1ce9497e..c112206b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -6,32 +6,54 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -class transaction { +class base_transaction { + virtual std::string serialize() const = 0; + virtual void deserialize(const std::string &raw_tx) = 0; +}; + +class transaction : base_transaction { public: - std::string block_hash; - std::string block_number; std::string from; - std::string gas; - std::string gas_price; - std::string max_fee_per_gas; - std::string max_priority_fee_per_gas; - std::string hash; - std::string input; - std::string nonce; std::string to; - std::string transaction_index; + std::string data; + + const transaction &sign(const std::string &private_key) const; + + virtual std::string serialize() const override; + virtual void deserialize(const std::string &raw_tx) override; +}; + +class signed_transaction; +class raw_transaction : base_transaction { +public: + std::string nonce; + std::string gas_price; + std::string gas_limit; + std::string to; std::string value; - std::string type; - std::vector access_list; + std::string data; std::string chain_id; + + signed_transaction sign(const std::string &private_key) const; + + virtual std::string serialize() const override; + virtual void deserialize(const std::string &raw_tx) override; +}; + +class signed_transaction : base_transaction { +public: + std::string nonce; + std::string gas_price; + std::string gas_limit; + std::string to; + std::string value; + std::string data; std::string v; std::string r; std::string s; - std::string sign(std::string private_key); - - std::string serialize(); - void deserialize(std::string raw_tx); + virtual std::string serialize() const override; + virtual void deserialize(const std::string &raw_tx) override; }; }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp index def91947..963244fa 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp @@ -7,4 +7,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { typedef uint64_t chain_id_type; typedef uint64_t network_id_type; +using bytes = std::vector; + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp new file mode 100644 index 00000000..b4461713 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +bytes parse_hex(const std::string &str); + +std::string bytes2hex(const std::string &s); + +std::string uchar2Hex(unsigned char n); + +std::string add_0x(const std::string &s); + +std::string remove_0x(const std::string &s); + +template +std::string to_hex(const T &val) { + std::stringstream stream; + stream << std::hex << val; + std::string result(stream.str()); + if (result.size() % 2) + result = "0" + result; + return result; +} + +template +T from_hex(const std::string &s) { + T val; + std::stringstream stream; + stream << std::hex << s; + stream >> val; + + return val; +} + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp index 681ceaed..3944d0a2 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp @@ -19,9 +19,18 @@ public: std::string eth_get_block_by_number(std::string block_number, bool full_block); std::string eth_get_logs(std::string wallet_contract_address); std::string net_version(); + std::string eth_get_transaction_count(const std::string ¶ms); + std::string eth_gas_price(); std::string get_chain_id(); std::string get_network_id(); + std::string get_nonce(const std::string &address); + std::string get_gas_price(); + std::string get_gas_limit(); + + std::string eth_send_transaction(const std::string ¶ms); + std::string eth_send_raw_transaction(const std::string ¶ms); + std::string eth_get_transaction_receipt(const std::string ¶ms); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { @@ -49,14 +58,11 @@ private: ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; - std::string create_primary_wallet_address(const std::vector &son_pubkeys); - - std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); + std::string create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id); std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); std::string sign_transaction(const sidechain_transaction_object &sto); - std::string send_transaction(const sidechain_transaction_object &sto); uint64_t last_block_received; fc::future _listener_task; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 58d22b00..52d401cb 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -3,8 +3,7 @@ #include #include -#include -#include +#include #include #include @@ -17,8 +16,11 @@ #include #include #include +#include #include -#include +#include + +#define SEND_RAW_TRANSACTION 1 namespace graphene { namespace peerplays_sidechain { @@ -45,6 +47,14 @@ std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } +std::string ethereum_rpc_client::eth_get_transaction_count(const std::string ¶ms) { + return send_post_request("eth_getTransactionCount", params, debug_rpc_calls); +} + +std::string ethereum_rpc_client::eth_gas_price() { + return send_post_request("eth_gasPrice", "", debug_rpc_calls); +} + std::string ethereum_rpc_client::get_chain_id() { std::string reply_str = net_version(); return retrieve_value_from_reply(reply_str, ""); @@ -55,6 +65,43 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } +std::string ethereum_rpc_client::get_nonce(const std::string &address) { + std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]"); + const auto nonce_val = ethereum::from_hex(retrieve_value_from_reply(reply_str, "")); + return nonce_val == 0 ? ethereum::add_0x("0") : ethereum::add_0x(ethereum::to_hex(nonce_val)); +} + +std::string ethereum_rpc_client::get_gas_price() { + std::string reply_str = eth_gas_price(); + return retrieve_value_from_reply(reply_str, ""); +} + +std::string ethereum_rpc_client::get_gas_limit() { + std::string reply_str = eth_get_block_by_number("latest", false); + if (!reply_str.empty()) { + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.count("result")) { + std::string gas_limit_s = json.get("result.gasLimit"); + return gas_limit_s; + } + } + return std::string{}; +} + +std::string ethereum_rpc_client::eth_send_transaction(const std::string ¶ms) { + return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); +} + +std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string ¶ms) { + return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls); +} + +std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string ¶ms) { + return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); +} + sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -146,80 +193,45 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto swo = idx.find(swo_id); if (swo != idx.end()) { - //auto active_sons = gpo.active_sons; - //vector wallet_sons = swo->sons; - // - //bool son_sets_equal = (active_sons.size() == wallet_sons.size()); - // - //if (son_sets_equal) { - // for (size_t i = 0; i < active_sons.size(); i++) { - // son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); - // } - //} - // - //if (son_sets_equal) { - // address_ok = (op_obj_idx_0.get().address == wallet_account_name); - //} - // - //if (po.proposed_transaction.operations.size() >= 2) { - // object_id_type object_id = op_obj_idx_1.get().object_id; - // std::string op_tx_str = op_obj_idx_1.get().transaction; - // - // const auto &st_idx = database.get_index_type().indices().get(); - // const auto st = st_idx.find(object_id); - // if (st == st_idx.end()) { - // - // std::string tx_str = ""; - // - // if (object_id.is()) { - // const auto &idx = database.get_index_type().indices().get(); - // const auto swo = idx.find(object_id); - // if (swo != idx.end()) { - // - // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); - // hive::signed_transaction op_trx; - // fc::raw::unpack(ss_trx, op_trx, 1000); - // - // fc::flat_map account_auths; - // uint32_t total_weight = 0; - // for (const auto &wallet_son : wallet_sons) { - // total_weight = total_weight + wallet_son.weight; - // account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; - // } - // - // std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); - // - // hive::authority active; - // active.weight_threshold = total_weight * 2 / 3 + 1; - // active.account_auths = account_auths; - // - // hive::account_update_operation auo; - // auo.account = wallet_account_name; - // auo.active = active; - // auo.memo_key = op_trx.operations[0].get().memo_key; - // - // hive::signed_transaction htrx; - // htrx.ref_block_num = op_trx.ref_block_num; - // htrx.ref_block_prefix = op_trx.ref_block_prefix; - // htrx.set_expiration(op_trx.expiration); - // - // htrx.operations.push_back(auo); - // - // std::stringstream ss; - // fc::raw::pack(ss, htrx, 1000); - // tx_str = boost::algorithm::hex(ss.str()); - // } - // } - // - // transaction_ok = (op_tx_str == tx_str); - // } - //} else { - // transaction_ok = true; - //} - } + auto active_sons = gpo.active_sons; + vector wallet_sons = swo->sons; - address_ok = true; - transaction_ok = true; + bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + + if (son_sets_equal) { + for (size_t i = 0; i < active_sons.size(); i++) { + son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + } + } + + if (son_sets_equal) { + address_ok = (op_obj_idx_0.get().address == wallet_contract_address); + } + + if (po.proposed_transaction.operations.size() >= 2) { + object_id_type object_id = op_obj_idx_1.get().object_id; + std::string op_tx_str = op_obj_idx_1.get().transaction; + + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + tx_str = create_primary_wallet_transaction(gpo.active_sons, object_id.operator std::string()); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } else { + transaction_ok = true; + } + } should_approve = address_ok && transaction_ok; @@ -298,81 +310,48 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto &idx = database.get_index_type().indices().get(); const auto swwo = idx.find(swwo_id); if (swwo != idx.end()) { + uint32_t swwo_block_num = swwo->block_num; + std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - //uint32_t swwo_block_num = swwo->block_num; - //std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; - //uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - // - //const auto &block = database.fetch_block_by_number(swwo_block_num); - // - //for (const auto &tx : block->transactions) { - // if (tx.id().str() == swwo_peerplays_transaction_id) { - // operation op = tx.operations[swwo_op_idx]; - // transfer_operation t_op = op.get(); - // - // price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; - // asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - // - // process_ok = (t_op.to == gpo.parameters.son_account()) && - // (swwo->peerplays_from == t_op.from) && - // (swwo->peerplays_asset == peerplays_asset); - // break; - // } - //} - // - //object_id_type object_id = op_obj_idx_1.get().object_id; - //std::string op_tx_str = op_obj_idx_1.get().transaction; - // - //const auto &st_idx = database.get_index_type().indices().get(); - //const auto st = st_idx.find(object_id); - //if (st == st_idx.end()) { - // - // std::string tx_str = ""; - // - // if (object_id.is()) { - // const auto &idx = database.get_index_type().indices().get(); - // const auto swwo = idx.find(object_id); - // if (swwo != idx.end()) { - // - // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); - // hive::signed_transaction op_trx; - // fc::raw::unpack(ss_trx, op_trx, 1000); - // - // uint64_t symbol = 0; - // if (swwo->withdraw_currency == "HBD") { - // symbol = hive::asset::hbd_symbol_ser; - // } - // if (swwo->withdraw_currency == "HIVE") { - // symbol = hive::asset::hive_symbol_ser; - // } - // - // hive::transfer_operation t_op; - // t_op.from = wallet_account_name; - // t_op.to = swwo->withdraw_address; - // t_op.amount.amount = swwo->withdraw_amount; - // t_op.amount.symbol = symbol; - // t_op.memo = ""; - // - // hive::signed_transaction htrx; - // htrx.ref_block_num = op_trx.ref_block_num; - // htrx.ref_block_prefix = op_trx.ref_block_prefix; - // htrx.set_expiration(op_trx.expiration); - // - // htrx.operations.push_back(t_op); - // - // std::stringstream ss; - // fc::raw::pack(ss, htrx, 1000); - // tx_str = boost::algorithm::hex(ss.str()); - // } - // } - // - // transaction_ok = (op_tx_str == tx_str); - //} + const auto &block = database.fetch_block_by_number(swwo_block_num); + + for (const auto &tx : block->transactions) { + if (tx.id().str() == swwo_peerplays_transaction_id) { + operation op = tx.operations[swwo_op_idx]; + transfer_operation t_op = op.get(); + + price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + + process_ok = (t_op.to == gpo.parameters.son_account()) && + (swwo->peerplays_from == t_op.from) && + (swwo->peerplays_asset == peerplays_asset); + break; + } + } + + object_id_type object_id = op_obj_idx_1.get().object_id; + std::string op_tx_str = op_obj_idx_1.get().transaction; + + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(object_id); + if (swwo != idx.end()) { + tx_str = create_withdrawal_transaction(*swwo); + } + } + + transaction_ok = (op_tx_str == tx_str); + } } - process_ok = true; - transaction_ok = true; - should_approve = process_ok && transaction_ok; break; @@ -416,79 +395,62 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) } void sidechain_net_handler_ethereum::process_primary_wallet() { - //const auto &swi = database.get_index_type().indices().get(); - //const auto &active_sw = swi.rbegin(); - //if (active_sw != swi.rend()) { - // - // if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - // (active_sw->addresses.at(sidechain_type::ethereum).empty())) { - // - // if (proposal_exists(chain::operation::tag::value, active_sw->id)) { - // return; - // } - // - // const chain::global_property_object &gpo = database.get_global_properties(); - // - // auto active_sons = gpo.active_sons; - // string reply_str = create_primary_wallet_address(active_sons); - // - // std::stringstream active_pw_ss(reply_str); - // - // boost::property_tree::ptree active_pw_pt; - // boost::property_tree::read_json(active_pw_ss, active_pw_pt); - // if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - // if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { - // return; - // } - // - // proposal_create_operation proposal_op; - // proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - // uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - // proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - // - // std::stringstream res; - // boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - // - // son_wallet_update_operation swu_op; - // swu_op.payer = gpo.parameters.son_account(); - // swu_op.son_wallet_id = active_sw->id; - // swu_op.sidechain = sidechain_type::ethereum; - // swu_op.address = res.str(); - // - // proposal_op.proposed_ops.emplace_back(swu_op); - // - // const auto &prev_sw = std::next(active_sw); - // if (prev_sw != swi.rend()) { - // std::string new_pw_address = active_pw_pt.get("result.address"); - // std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address); - // if (!tx_str.empty()) { - // sidechain_transaction_create_operation stc_op; - // stc_op.payer = gpo.parameters.son_account(); - // stc_op.object_id = prev_sw->id; - // stc_op.sidechain = sidechain; - // stc_op.transaction = tx_str; - // stc_op.signers = prev_sw->sons; - // proposal_op.proposed_ops.emplace_back(stc_op); - // } - // } - // - // signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - // try { - // trx.validate(); - // database.push_transaction(trx, database::validation_steps::skip_block_size_check); - // if (plugin.app().p2p_node()) - // plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - // plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); - // } catch (fc::exception &e) { - // elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); - // return; - // } - // } - // } - //} + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { + + if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } + + if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + return; + } + + const chain::global_property_object &gpo = database.get_global_properties(); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain_type::ethereum; + swu_op.address = wallet_contract_address; + proposal_op.proposed_ops.emplace_back(swu_op); + + std::string tx_str = create_primary_wallet_transaction(gpo.active_sons, active_sw->id.operator std::string()); + if (!tx_str.empty()) { + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = active_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + } + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } } void sidechain_net_handler_ethereum::process_sidechain_addresses() { + int temp = 0; } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { @@ -578,19 +540,93 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const } std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { - return send_transaction(sto); + boost::property_tree::ptree pt; + boost::property_tree::ptree pt_array; + for (const auto &signature : sto.signatures) { + const auto &transaction = signature.second; + + //! Check if we have this signed transaction, if not, don't send it + if(transaction.empty()) + continue; + +#ifdef SEND_RAW_TRANSACTION + const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); +#else + const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); +#endif + + std::stringstream ss_tx(sidechain_transaction); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + if (tx_json.count("result") && !tx_json.count("error")) { + boost::property_tree::ptree node; + node.put("transaction", transaction); + node.put("transaction_receipt", tx_json.get("result")); + pt_array.push_back(std::make_pair("", node)); + } else { + //! Fixme + //! How should we proceed with error in eth_send_transaction + elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction)); + return std::string{}; //! Return empty string, as we have error in sending + } + } + pt.add_child("result_array", pt_array); + + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, pt); + return ss.str(); } bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return true; + std::stringstream ss(sto.sidechain_transaction); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + if (!json.count("result_array")) { + return false; + } + + size_t count = 0; + for (const auto &entry : json.get_child("result_array")) { + const std::string receipt = rpc_client->eth_get_transaction_receipt(entry.second.get("transaction_receipt")); + + std::stringstream ss_receipt(receipt); + boost::property_tree::ptree json_receipt; + boost::property_tree::read_json(ss_receipt, json_receipt); + + if (json_receipt.get("result") == "null") { + wlog("Block is not minted yet for transaction ${id}", ("id", sto.id)); + return false; + } + + if ("0x1" == json_receipt.get("result.status")) { + count += 1; + //! Fixme - compare data somehow? + //if( sto.transaction == entry_receipt.second.get("data") ) { + //} + } + } + + //! Check that we have all transactions + if (count != json.get_child("result_array").size()) { + wlog("Not all receipts received for transaction ${id}", ("id", sto.id)); + return false; + } else + return true; + + return false; } -std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector &son_pubkeys) { - return "Primary Wallet Address"; -} +std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id) { + std::vector> owners_weights; + for (auto &son : son_pubkeys) { + FC_ASSERT(son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for son: ${son_id}", ("son_id", son.son_id)); + const std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); + } -std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return "Primary-Wallet-Transaction"; + ethereum::update_owners_encoder encoder; + return encoder.encode(owners_weights, object_id); } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -598,16 +634,35 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return "Withdrawal-Transaction"; + ethereum::withdrawal_encoder encoder; + return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); - return "Transaction-Signature-" + key; -} + const auto ¤t_son = plugin.get_current_son_object(); + FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); -std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) { - return "Transaction-ID"; + const auto &public_key = current_son.sidechain_public_keys.at(sidechain); + +#ifdef SEND_RAW_TRANSACTION + ethereum::raw_transaction raw_tr; + raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key)); + raw_tr.gas_price = rpc_client->get_gas_price(); + raw_tr.gas_limit = rpc_client->get_gas_limit(); + raw_tr.to = wallet_contract_address; + raw_tr.value = ""; + raw_tr.data = sto.transaction; + raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); + + const auto sign_tr = raw_tr.sign(get_private_key(public_key)); + return sign_tr.serialize(); +#else + ethereum::transaction sign_transaction; + sign_transaction.data = sto.transaction; + sign_transaction.to = wallet_contract_address; + sign_transaction.from = "0x" + public_key; + return sign_transaction.sign(get_private_key(public_key)).serialize(); +#endif } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { diff --git a/libraries/sha3/CMakeLists.txt b/libraries/sha3/CMakeLists.txt new file mode 100644 index 00000000..c790323e --- /dev/null +++ b/libraries/sha3/CMakeLists.txt @@ -0,0 +1,16 @@ +file(GLOB HEADERS "include/sha3/*.h") + +add_library( sha3 + memzero.c + sha3.c +) + +target_include_directories( sha3 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include ) +target_compile_definitions( sha3 PUBLIC USE_KECCAK=1 ) + +install( TARGETS + sha3 + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/libraries/sha3/include/sha3/memzero.h b/libraries/sha3/include/sha3/memzero.h new file mode 100644 index 00000000..1e744c12 --- /dev/null +++ b/libraries/sha3/include/sha3/memzero.h @@ -0,0 +1,16 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +void memzero(void* const pnt, const size_t len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/libraries/sha3/include/sha3/sha3.h b/libraries/sha3/include/sha3/sha3.h new file mode 100644 index 00000000..881e806c --- /dev/null +++ b/libraries/sha3/include/sha3/sha3.h @@ -0,0 +1,88 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * 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. + * + * 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. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX *ctx); +void sha3_256_Init(SHA3_CTX *ctx); +void sha3_384_Init(SHA3_CTX *ctx); +void sha3_512_Init(SHA3_CTX *ctx); +void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX *ctx, unsigned char* result); + +#if USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); +#endif + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ diff --git a/libraries/sha3/memzero.c b/libraries/sha3/memzero.c new file mode 100644 index 00000000..32aa140f --- /dev/null +++ b/libraries/sha3/memzero.c @@ -0,0 +1,75 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined(__NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) { +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; + size_t i = (size_t)0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif + + // explicitly mark the memory as overwritten for the Clang MemorySanitizer + // this is only included at compile time if MemorySanitizer is enabled and + // should not come with any downsides during regular builds +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset(pnt, 0, len); +#endif +#endif +} diff --git a/libraries/sha3/sha3.c b/libraries/sha3/sha3.c new file mode 100644 index 00000000..172728eb --- /dev/null +++ b/libraries/sha3/sha3.c @@ -0,0 +1,397 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * 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. + * + * 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. Use this program at your own risk! + */ + +#include +#include + +#include +#include + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((long)(p)))) // [wallet-core] pointer/numerical type, for MacOS SDK 12.3 +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), + I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), + I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), + I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), + I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) +}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX *ctx, unsigned bits) +{ + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memzero(ctx, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) +{ + unsigned int x = 0; + uint64_t C[5] = {0}, D[5] = {0}; + + for (x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for (x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) +{ + uint64_t A1 = 0; + A1 = A[1]; + A[ 1] = A[ 6]; + A[ 6] = A[ 9]; + A[ 9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[ 2]; + A[ 2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[ 4]; + A[ 4] = A[24]; + A[24] = A[21]; + A[21] = A[ 8]; + A[ 8] = A[16]; + A[16] = A[ 5]; + A[ 5] = A[ 3]; + A[ 3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[ 7]; + A[ 7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) +{ + int i = 0; + for (i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t *state) +{ + int round = 0; + for (round = 0; round < NumberOfRounds; round++) + { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[ 1] = ROTL64(state[ 1], 1); + state[ 2] = ROTL64(state[ 2], 62); + state[ 3] = ROTL64(state[ 3], 28); + state[ 4] = ROTL64(state[ 4], 27); + state[ 5] = ROTL64(state[ 5], 36); + state[ 6] = ROTL64(state[ 6], 44); + state[ 7] = ROTL64(state[ 7], 6); + state[ 8] = ROTL64(state[ 8], 55); + state[ 9] = ROTL64(state[ 9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) +{ + /* expanded loop */ + hash[ 0] ^= le2me_64(block[ 0]); + hash[ 1] ^= le2me_64(block[ 1]); + hash[ 2] ^= le2me_64(block[ 2]); + hash[ 3] ^= le2me_64(block[ 3]); + hash[ 4] ^= le2me_64(block[ 4]); + hash[ 5] ^= le2me_64(block[ 5]); + hash[ 6] ^= le2me_64(block[ 6]); + hash[ 7] ^= le2me_64(block[ 7]); + hash[ 8] ^= le2me_64(block[ 8]); + /* if not sha3-512 */ + if (block_size > 72) { + hash[ 9] ^= le2me_64(block[ 9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if (block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if (block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if (block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) +{ + size_t idx = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if (idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while (size >= block_size) { + uint64_t *aligned_message_block = NULL; + if (IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +#if USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} +#endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} diff --git a/libraries/vendor/CMakeLists.txt b/libraries/vendor/CMakeLists.txt deleted file mode 100755 index 6047e95e..00000000 --- a/libraries/vendor/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -PROJECT( SHA3IUF ) - -include(ExternalProject) - -ExternalProject_Add(project_SHA3IUF - PREFIX ${CMAKE_CURRENT_BINARY_DIR} - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF - CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build - BUILD_COMMAND make - INSTALL_COMMAND true - BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} - LOG_BUILD ON -) - -ExternalProject_Get_Property(project_SHA3IUF binary_dir) -add_library(SHA3IUF STATIC IMPORTED) -message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}") -set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}) -set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF) - -add_dependencies(SHA3IUF project_SHA3IUF) -install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib ) - -set(SHA3IUF_libraries sha3 CACHE INTERNAL "") -set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "") -set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "") diff --git a/libraries/vendor/SHA3IUF b/libraries/vendor/SHA3IUF deleted file mode 160000 index fc850475..00000000 --- a/libraries/vendor/SHA3IUF +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fc8504750a5c2174a1874094dd05e6a0d8797753