From 6c2bf868c50764b88b68045dd9392ebb570b218c Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 22 Aug 2022 16:02:58 +0300 Subject: [PATCH] Fix signing of eth transaction. Calculate `v` value --- .../peerplays_sidechain/ethereum/encoders.cpp | 16 +-- .../ethereum/transaction.cpp | 111 ++++++------------ .../peerplays_sidechain/ethereum/utils.cpp | 20 ++++ .../peerplays_sidechain/ethereum/encoders.hpp | 1 - .../peerplays_sidechain/ethereum/utils.hpp | 26 ++++ 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 456a1be6..90b05fd2 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -4,6 +4,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { //! base_encoder @@ -71,9 +73,9 @@ std::string rlp_encoder::encode_length(int len, int offset) } else { - const std::string hexLength = int2Hex(len); + const std::string hexLength = to_hex(len); const int lLength = hexLength.size()/2; - const std::string fByte = int2Hex(offset+55+lLength); + const std::string fByte = to_hex(offset+55+lLength); return hex2bytes(fByte+hexLength); } } @@ -94,16 +96,6 @@ std::string rlp_encoder::encode_rlp(const std::string& s) return encode_length(s.size(), 128) + s; } -std::string rlp_encoder::int2Hex(int n) -{ - std::stringstream stream; - stream << std::hex << n; - std::string result( stream.str() ); - if(result.size() % 2) - result = "0"+result; - return result; -} - int rlp_encoder::char2int(char input) { if(input >= '0' && input <= '9') diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 5ca8c81d..268256ae 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -18,36 +18,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -namespace -{ - -int is_even(char last_char) -{ - switch (last_char) - { - case '0': - return 1; - case '2': - return 1; - case '4': - return 1; - case '6': - return 1; - case '8': - return 1; - case 'A': - return 1; - case 'C': - return 1; - case 'E': - return 1; - default: - return -1; - } -} - -} - const secp256k1_context *eth_context() { static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); return ctx; @@ -107,12 +77,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const const bytes priv_key = parse_hex(private_key); - secp256k1_ecdsa_signature sign; - FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr)); - + 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_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign)); + 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)); @@ -120,12 +91,6 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const for(int i = 33; i < 65; i++) s.emplace_back((char) result.at(i)); - bytes v; - if(is_even(r.back())) - v = {37}; - else - v = {38}; - 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()); @@ -136,13 +101,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const std::string raw_transaction::serialize() const { rlp_encoder encoder; - const std::string serialized = encoder.encode(nonce) + - encoder.encode(gas_price) + - encoder.encode(gas_limit) + - encoder.encode(to) + - encoder.encode(value) + - encoder.encode(data) + - encoder.encode(chain_id) + + 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(""); @@ -155,13 +120,13 @@ void raw_transaction::deserialize(const std::string& raw_tx) const auto rlp_array = decoder.decode(raw_tx); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); - nonce = rlp_array.at(0); - gas_price = rlp_array.at(1); - gas_limit = rlp_array.at(2); - to = rlp_array.at(3); - value = rlp_array.at(4); - data = rlp_array.at(5); - chain_id = rlp_array.at(6); + 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 @@ -169,15 +134,15 @@ void raw_transaction::deserialize(const std::string& raw_tx) std::string signed_transaction::serialize() const { rlp_encoder encoder; - const std::string serialized = encoder.encode(nonce) + - encoder.encode(gas_price) + - encoder.encode(gas_limit) + - encoder.encode(to) + - encoder.encode(value) + - encoder.encode(data) + - encoder.encode(v) + - encoder.encode(r) + - encoder.encode(s); + 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 bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); } @@ -188,15 +153,15 @@ void signed_transaction::deserialize(const std::string& raw_tx) const auto rlp_array = decoder.decode(raw_tx); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); - nonce = rlp_array.at(0); - gas_price = rlp_array.at(1); - gas_limit = rlp_array.at(2); - to = rlp_array.at(3); - value = rlp_array.at(4); - data = rlp_array.at(5); - v = rlp_array.at(6); - r = rlp_array.at(7); - s = rlp_array.at(8); + 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 index 0bfe136a..04861b88 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -34,4 +34,24 @@ std::string uchar2Hex(unsigned char n) 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/encoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp index 8c92b2fe..d3652199 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 @@ -35,7 +35,6 @@ public: private: static std::string encode_rlp(const std::string& s); - static std::string int2Hex(int n); static int char2int(char input); static void hex2bin(const char* src, char* target); }; 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 index 4a2e33d1..519ed4a1 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -10,4 +10,30 @@ 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