Merge branch 'feature/son-for-ethereum' of https://gitlab.com/PBSA/peerplays into feature/son-for-ethereum

This commit is contained in:
serkixenos 2022-08-29 23:11:01 +02:00
commit 4458965649
21 changed files with 1542 additions and 302 deletions

4
.gitmodules vendored
View file

@ -7,7 +7,3 @@
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
branch = develop branch = develop
ignore = dirty ignore = dirty
[submodule "libraries/vendor/SHA3IUF"]
path = libraries/vendor/SHA3IUF
url = https://github.com/brainhub/SHA3IUF.git
branch = master

View file

@ -5,7 +5,7 @@ add_subdirectory( egenesis )
add_subdirectory( fc ) add_subdirectory( fc )
add_subdirectory( net ) add_subdirectory( net )
add_subdirectory( plugins ) add_subdirectory( plugins )
add_subdirectory( sha3 )
add_subdirectory( time ) add_subdirectory( time )
add_subdirectory( utilities ) add_subdirectory( utilities )
add_subdirectory( vendor )
add_subdirectory( wallet ) add_subdirectory( wallet )

View file

@ -22,6 +22,7 @@ add_library( peerplays_sidechain
ethereum/decoders.cpp ethereum/decoders.cpp
ethereum/transaction.cpp ethereum/transaction.cpp
ethereum/types.cpp ethereum/types.cpp
ethereum/utils.cpp
hive/asset.cpp hive/asset.cpp
hive/operations.cpp hive/operations.cpp
hive/transaction.cpp hive/transaction.cpp
@ -41,11 +42,9 @@ endif()
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} ) target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq )
target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin zmq ${SHA3IUF_libraries} ) target_include_directories( peerplays_sidechain
target_include_directories( peerplays_sidechain PUBLIC PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${SHA3IUF_include_dirs}" )
install( TARGETS install( TARGETS
peerplays_sidechain peerplays_sidechain

View file

@ -1,5 +1,224 @@
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp> #include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <fc/exception/exception.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum { 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<std::string> rlp_decoder::decode(const std::string &str) {
size_t consumed = 0;
const auto raw_vec = parse_hex(str);
const std::vector<std::string> rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed);
std::vector<std::string> 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<std::string> rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) {
std::vector<std::string> 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<unsigned char> 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<std::string>{};
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<std::string>{};
// parsing done; assign data buffer value.
const std::vector<unsigned char> 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<std::string>{};
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<std::string>{};
// 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<std::string>{};
// parsing done; assign data buffer value.
tok_start = raw + prefixlen + uintlen;
const unsigned char *tok_end = tok_start + slen;
const std::vector<unsigned char> 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<std::string>{};
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<std::string>{};
// 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<std::string>{};
// 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<std::string> rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) {
std::vector<std::string> 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<std::string>{};
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<unsigned char> rlp_decoder::parse_hex(const std::string &str) {
return parse_hex(str.c_str());
}
std::vector<unsigned char> rlp_decoder::parse_hex(const char *psz) {
// convert hex dump to vector
std::vector<unsigned char> 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 }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,5 +1,102 @@
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp> #include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <stdlib.h>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum { 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<std::pair<std::string, uint16_t>> &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 }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,22 +1,158 @@
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp> #include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <secp256k1_recovery.h>
#include <sha3/sha3.h>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum { namespace graphene { namespace peerplays_sidechain { namespace ethereum {
std::string transaction::sign(std::string private_key) { const secp256k1_context *eth_context() {
v = "signed"; static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
r = "transaction"; return ctx;
s = "signed-transaction";
return v + "|" + r + "|" + s;
} }
std::string transaction::serialize() { //! transaction
return "serialized-transaction";
const transaction &transaction::sign(const std::string &private_key) const {
return *this;
} }
void transaction::deserialize(std::string raw_tx) { std::string transaction::serialize() const {
block_hash = "1"; boost::property_tree::ptree pt;
block_number = "2"; pt.put("from", from);
hash = "3"; 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<std::string>("from");
if (tx_json.count("to"))
to = tx_json.get<std::string>("to");
if (tx_json.count("data"))
data = tx_json.get<std::string>("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<int>(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 }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -0,0 +1,52 @@
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#include <fc/crypto/hex.hpp>
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

View file

@ -5,4 +5,24 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum { 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<std::string> decode(const std::string &str);
private:
static std::vector<std::string> decode_rlp(const unsigned char *raw, size_t len, size_t &consumed);
static std::vector<std::string> 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<unsigned char> parse_hex(const std::string &str);
static std::vector<unsigned char> parse_hex(const char *psz);
static signed char hex_digit(char c);
};
}}} // namespace graphene::peerplays_sidechain::ethereum }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,11 +1,45 @@
#pragma once #pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
namespace graphene { namespace peerplays_sidechain { namespace ethereum { 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<std::pair<std::string, uint16_t>> &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: public:
enum operation_t { enum operation_t {
OPERATION_CALL, OPERATION_CALL,
@ -34,6 +68,6 @@ public:
private: private:
ethereum_function_call_encoder m_ethereum_function_call_encoder; ethereum_function_call_encoder m_ethereum_function_call_encoder;
}; };*/
}}} // namespace graphene::peerplays_sidechain::ethereum }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -6,32 +6,54 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum { 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: public:
std::string block_hash;
std::string block_number;
std::string from; 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 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 value;
std::string type; std::string data;
std::vector<std::string> access_list;
std::string chain_id; 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 v;
std::string r; std::string r;
std::string s; std::string s;
std::string sign(std::string private_key); virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
std::string serialize();
void deserialize(std::string raw_tx);
}; };
}}} // namespace graphene::peerplays_sidechain::ethereum }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -7,4 +7,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum {
typedef uint64_t chain_id_type; typedef uint64_t chain_id_type;
typedef uint64_t network_id_type; typedef uint64_t network_id_type;
using bytes = std::vector<char>;
}}} // namespace graphene::peerplays_sidechain::ethereum }}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -0,0 +1,37 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
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 <typename T>
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 <typename T>
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

View file

@ -19,9 +19,18 @@ public:
std::string eth_get_block_by_number(std::string block_number, bool full_block); 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 eth_get_logs(std::string wallet_contract_address);
std::string net_version(); std::string net_version();
std::string eth_get_transaction_count(const std::string &params);
std::string eth_gas_price();
std::string get_chain_id(); std::string get_chain_id();
std::string get_network_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 &params);
std::string eth_send_raw_transaction(const std::string &params);
std::string eth_get_transaction_receipt(const std::string &params);
}; };
class sidechain_net_handler_ethereum : public sidechain_net_handler { class sidechain_net_handler_ethereum : public sidechain_net_handler {
@ -49,14 +58,11 @@ private:
ethereum::chain_id_type chain_id; ethereum::chain_id_type chain_id;
ethereum::network_id_type network_id; ethereum::network_id_type network_id;
std::string create_primary_wallet_address(const std::vector<son_info> &son_pubkeys); std::string create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id);
std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
std::string sign_transaction(const sidechain_transaction_object &sto); std::string sign_transaction(const sidechain_transaction_object &sto);
std::string send_transaction(const sidechain_transaction_object &sto);
uint64_t last_block_received; uint64_t last_block_received;
fc::future<void> _listener_task; fc::future<void> _listener_task;

View file

@ -3,8 +3,7 @@
#include <algorithm> #include <algorithm>
#include <thread> #include <thread>
#include <boost/algorithm/hex.hpp> #include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
@ -17,8 +16,11 @@
#include <graphene/chain/sidechain_transaction_object.hpp> #include <graphene/chain/sidechain_transaction_object.hpp>
#include <graphene/chain/son_info.hpp> #include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp> #include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp> #include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <graphene/utilities/key_conversion.hpp> #include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#define SEND_RAW_TRANSACTION 1
namespace graphene { namespace peerplays_sidechain { 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); return send_post_request("net_version", "", debug_rpc_calls);
} }
std::string ethereum_rpc_client::eth_get_transaction_count(const std::string &params) {
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 ethereum_rpc_client::get_chain_id() {
std::string reply_str = net_version(); std::string reply_str = net_version();
return retrieve_value_from_reply(reply_str, ""); 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"); 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<boost::multiprecision::uint256_t>(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<std::string>("result.gasLimit");
return gas_limit_s;
}
}
return std::string{};
}
std::string ethereum_rpc_client::eth_send_transaction(const std::string &params) {
return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string &params) {
return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string &params) {
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_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) { sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::ethereum; 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); const auto swo = idx.find(swo_id);
if (swo != idx.end()) { if (swo != idx.end()) {
//auto active_sons = gpo.active_sons; auto active_sons = gpo.active_sons;
//vector<son_info> wallet_sons = swo->sons; vector<son_info> 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<son_wallet_update_operation>().address == wallet_account_name);
//}
//
//if (po.proposed_transaction.operations.size() >= 2) {
// object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
// std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
//
// const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
// const auto st = st_idx.find(object_id);
// if (st == st_idx.end()) {
//
// std::string tx_str = "";
//
// if (object_id.is<son_wallet_id_type>()) {
// const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
// 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<std::string, uint16_t> 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<hive::account_update_operation>().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;
//}
}
address_ok = true; bool son_sets_equal = (active_sons.size() == wallet_sons.size());
transaction_ok = true;
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<son_wallet_update_operation>().address == wallet_contract_address);
}
if (po.proposed_transaction.operations.size() >= 2) {
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (object_id.is<son_wallet_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
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 && should_approve = address_ok &&
transaction_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<son_wallet_withdraw_index>().indices().get<by_id>(); const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto swwo = idx.find(swwo_id); const auto swwo = idx.find(swwo_id);
if (swwo != idx.end()) { 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; const auto &block = database.fetch_block_by_number(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)); for (const auto &tx : block->transactions) {
// if (tx.id().str() == swwo_peerplays_transaction_id) {
//const auto &block = database.fetch_block_by_number(swwo_block_num); operation op = tx.operations[swwo_op_idx];
// transfer_operation t_op = op.get<transfer_operation>();
//for (const auto &tx : block->transactions) {
// if (tx.id().str() == swwo_peerplays_transaction_id) { price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate;
// operation op = tx.operations[swwo_op_idx]; asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount);
// transfer_operation t_op = op.get<transfer_operation>();
// process_ok = (t_op.to == gpo.parameters.son_account()) &&
// price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate; (swwo->peerplays_from == t_op.from) &&
// asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); (swwo->peerplays_asset == peerplays_asset);
// break;
// 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<sidechain_transaction_create_operation>().object_id;
// } std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
//}
// const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
//object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id; const auto st = st_idx.find(object_id);
//std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction; if (st == st_idx.end()) {
//
//const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>(); std::string tx_str = "";
//const auto st = st_idx.find(object_id);
//if (st == st_idx.end()) { if (object_id.is<son_wallet_withdraw_id_type>()) {
// const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
// std::string tx_str = ""; const auto swwo = idx.find(object_id);
// if (swwo != idx.end()) {
// if (object_id.is<son_wallet_withdraw_id_type>()) { tx_str = create_withdrawal_transaction(*swwo);
// const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>(); }
// const auto swwo = idx.find(object_id); }
// if (swwo != idx.end()) {
// transaction_ok = (op_tx_str == tx_str);
// 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);
//}
} }
process_ok = true;
transaction_ok = true;
should_approve = process_ok && should_approve = process_ok &&
transaction_ok; transaction_ok;
break; break;
@ -416,79 +395,62 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
} }
void sidechain_net_handler_ethereum::process_primary_wallet() { void sidechain_net_handler_ethereum::process_primary_wallet() {
//const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>(); const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
//const auto &active_sw = swi.rbegin(); const auto &active_sw = swi.rbegin();
//if (active_sw != swi.rend()) { if (active_sw != swi.rend()) {
//
// if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) ||
// (active_sw->addresses.at(sidechain_type::ethereum).empty())) { (active_sw->addresses.at(sidechain_type::ethereum).empty())) {
//
// if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) { if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
// return; return;
// } }
//
// const chain::global_property_object &gpo = database.get_global_properties(); if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
// return;
// auto active_sons = gpo.active_sons; }
// string reply_str = create_primary_wallet_address(active_sons);
// const chain::global_property_object &gpo = database.get_global_properties();
// std::stringstream active_pw_ss(reply_str); proposal_create_operation proposal_op;
// proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
// boost::property_tree::ptree active_pw_pt; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
// boost::property_tree::read_json(active_pw_ss, active_pw_pt); proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
// if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
// if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) { son_wallet_update_operation swu_op;
// return; swu_op.payer = gpo.parameters.son_account();
// } swu_op.son_wallet_id = active_sw->id;
// swu_op.sidechain = sidechain_type::ethereum;
// proposal_create_operation proposal_op; swu_op.address = wallet_contract_address;
// proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; proposal_op.proposed_ops.emplace_back(swu_op);
// 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::string tx_str = create_primary_wallet_transaction(gpo.active_sons, active_sw->id.operator std::string());
// if (!tx_str.empty()) {
// std::stringstream res; sidechain_transaction_create_operation stc_op;
// boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); stc_op.payer = gpo.parameters.son_account();
// stc_op.object_id = active_sw->id;
// son_wallet_update_operation swu_op; stc_op.sidechain = sidechain;
// swu_op.payer = gpo.parameters.son_account(); stc_op.transaction = tx_str;
// swu_op.son_wallet_id = active_sw->id; stc_op.signers = gpo.active_sons;
// swu_op.sidechain = sidechain_type::ethereum; proposal_op.proposed_ops.emplace_back(stc_op);
// swu_op.address = res.str(); }
//
// proposal_op.proposed_ops.emplace_back(swu_op); signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
// try {
// const auto &prev_sw = std::next(active_sw); trx.validate();
// if (prev_sw != swi.rend()) { database.push_transaction(trx, database::validation_steps::skip_block_size_check);
// std::string new_pw_address = active_pw_pt.get<std::string>("result.address"); if (plugin.app().p2p_node())
// std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address); plugin.app().p2p_node()->broadcast(net::trx_message(trx));
// if (!tx_str.empty()) { plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
// sidechain_transaction_create_operation stc_op; } catch (fc::exception &e) {
// stc_op.payer = gpo.parameters.son_account(); elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
// stc_op.object_id = prev_sw->id; return;
// 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<chain::son_wallet_update_operation>::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() { void sidechain_net_handler_ethereum::process_sidechain_addresses() {
int temp = 0;
} }
bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { 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) { 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<std::string>("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) { 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<std::string>("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<std::string>("result") == "null") {
wlog("Block is not minted yet for transaction ${id}", ("id", sto.id));
return false;
}
if ("0x1" == json_receipt.get<std::string>("result.status")) {
count += 1;
//! Fixme - compare data somehow?
//if( sto.transaction == entry_receipt.second.get<std::string>("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_info> &son_pubkeys) { std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) {
return "Primary Wallet Address"; std::vector<std::pair<std::string, uint16_t>> 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) { ethereum::update_owners_encoder encoder;
return "Primary-Wallet-Transaction"; return encoder.encode(owners_weights, object_id);
} }
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { 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) { 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 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)); const auto &current_son = plugin.get_current_son_object();
return "Transaction-Signature-" + key; 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) { const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
return "Transaction-ID";
#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() { void sidechain_net_handler_ethereum::schedule_ethereum_listener() {

View file

@ -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
)

View file

@ -0,0 +1,16 @@
#ifndef __MEMZERO_H__
#define __MEMZERO_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void memzero(void* const pnt, const size_t len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View file

@ -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 <rhash.admin@gmail.com>
*
* 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 <stdint.h>
#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__ */

75
libraries/sha3/memzero.c Normal file
View file

@ -0,0 +1,75 @@
#ifndef __STDC_WANT_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface.
#endif
#include <string.h>
#ifdef _WIN32
#include <Windows.h>
#endif
#ifdef __unix__
#include <strings.h>
#include <sys/param.h>
#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
}

397
libraries/sha3/sha3.c Normal file
View file

@ -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 <rhash.admin@gmail.com>
*
* 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 <assert.h>
#include <string.h>
#include <sha3/sha3.h>
#include <sha3/memzero.h>
#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);
}

View file

@ -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 "")

@ -1 +0,0 @@
Subproject commit fc8504750a5c2174a1874094dd05e6a0d8797753