diff --git a/eosio.unregd/abieos_numeric.hpp b/eosio.unregd/abieos_numeric.hpp new file mode 100644 index 0000000..e82a8bc --- /dev/null +++ b/eosio.unregd/abieos_numeric.hpp @@ -0,0 +1,84 @@ +// copyright defined in abieos/LICENSE.txt + +#include +#include +#include +#include +#include +#include +//#include "ripemd160.hpp" + +namespace abieos { + +const char base58_chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +bool map_initialized = false; +std::array base58_map{{0}}; +auto get_base58_map() { + if(!map_initialized) { + for (unsigned i = 0; i < base58_map.size(); ++i) + base58_map[i] = -1; + for (unsigned i = 0; i < sizeof(base58_chars); ++i) + base58_map[base58_chars[i]] = i; + map_initialized = true; + } + return base58_map; +} + +template +std::array base58_to_binary(std::string_view s) { + std::array result{{0}}; + for (auto& src_digit : s) { + int carry = get_base58_map()[src_digit]; + if (carry < 0) + eosio_assert(0, "invalid base-58 value"); + for (auto& result_byte : result) { + int x = result_byte * 58 + carry; + result_byte = x; + carry = x >> 8; + } + if (carry) + eosio_assert(0, "base-58 value is out of range"); + } + std::reverse(result.begin(), result.end()); + return result; +} + +enum class key_type : uint8_t { + k1 = 0, + r1 = 1, +}; + +struct public_key { + key_type type{}; + std::array data{}; +}; + + +template +Key string_to_key(std::string_view s, key_type type, const char (&suffix)[suffix_size]) { + static const auto size = std::tuple_size::value; + auto whole = base58_to_binary(s); + Key result{type}; + memcpy(result.data.data(), whole.data(), result.data.size()); + return result; +} + + +public_key string_to_public_key(std::string_view s) { + if (s.size() >= 3 && s.substr(0, 3) == "EOS") { + auto whole = base58_to_binary<37>(s.substr(3)); + public_key key{key_type::k1}; + static_assert(whole.size() == key.data.size() + 4, "Error: whole.size() != key.data.size() + 4"); + memcpy(key.data.data(), whole.data(), key.data.size()); + return key; + } else if (s.size() >= 7 && s.substr(0, 7) == "PUB_R1_") { + return string_to_key(s.substr(7), key_type::r1, "R1"); + } else { + eosio_assert(0, "unrecognized public key format"); + } + return public_key{}; +} + +} // namespace abieos + diff --git a/eosio.unregd/eosio.unregd.abi b/eosio.unregd/eosio.unregd.abi index 43b0a49..23ddbaa 100644 --- a/eosio.unregd/eosio.unregd.abi +++ b/eosio.unregd/eosio.unregd.abi @@ -1,5 +1,5 @@ { - "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-07-19T06:16:39", + "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-08-28T10:54:52", "version": "eosio::abi/1.0", "types": [{ "new_type_name": "ethereum_address", @@ -42,7 +42,7 @@ "type": "string" },{ "name": "eos_pubkey", - "type": "public_key" + "type": "string" } ] } diff --git a/eosio.unregd/eosio.unregd.cpp b/eosio.unregd/eosio.unregd.cpp index 1e5ea3d..8041977 100644 --- a/eosio.unregd/eosio.unregd.cpp +++ b/eosio.unregd/eosio.unregd.cpp @@ -24,7 +24,7 @@ void unregd::add(const ethereum_address& ethereum_address, const asset& balance) /** * Register an EOS account using the stored information (address/balance) verifying an ETH signature */ -void unregd::regaccount(const bytes& signature, const string& account, const eosio::public_key& eos_pubkey) { +void unregd::regaccount(const bytes& signature, const string& account, const string& eos_pubkey_str) { eosio_assert(signature.size() == 66, "Invalid signature"); eosio_assert(account.size() == 12, "Invalid account length"); @@ -40,18 +40,29 @@ void unregd::regaccount(const bytes& signature, const string& account, const eos // Verify that the account does not exists eosio_assert(!is_account(naccount), "Account already exists"); - // Calculate message hash based on current TX block num/prefix - char* message = (char*)malloc(64); - sprintf(message, "%u,%u", tapos_block_num(), tapos_block_prefix()); + // Rebuild signed message based on current TX block num/prefix, pubkey and name + const abieos::public_key eos_pubkey = abieos::string_to_public_key(eos_pubkey_str); - checksum256 digest; - sha256(message, strlen(message), &digest); + char tmpmsg[128]; + sprintf(tmpmsg, "%u,%u,%s,%s", tapos_block_num(), tapos_block_prefix(), + eos_pubkey_str.c_str(), account.c_str()); + + //Add prefix and length of signed message + char message[128]; + sprintf(message, "%s%s%d%s", "\x19", "Ethereum Signed Message:\n", strlen(tmpmsg), tmpmsg); + + //Calculate sha3 hash of message + sha3_ctx shactx; + checksum256 msghash; + rhash_keccak_256_init(&shactx); + rhash_keccak_update(&shactx, (const uint8_t*)message, strlen(message)); + rhash_keccak_final(&shactx, msghash.hash); // Recover compressed pubkey from signature - uint8_t* pubkey = (uint8_t*)malloc(64); - uint8_t* compressed_pubkey = (uint8_t*)malloc(34); + uint8_t pubkey[64]; + uint8_t compressed_pubkey[34]; auto res = recover_key( - &digest, + &msghash, signature.data(), signature.size(), (char*)compressed_pubkey, @@ -64,15 +75,13 @@ void unregd::regaccount(const bytes& signature, const string& account, const eos uECC_decompress(compressed_pubkey+1, pubkey, uECC_secp256k1()); // Calculate ETH address based on decompressed pubkey - sha3_ctx* shactx = (sha3_ctx*)malloc(sizeof(sha3_ctx)); - - checksum256 msghash; - rhash_keccak_256_init(shactx); - rhash_keccak_update(shactx, pubkey, 64); - rhash_keccak_final(shactx, msghash.hash); + checksum256 pubkeyhash; + rhash_keccak_256_init(&shactx); + rhash_keccak_update(&shactx, pubkey, 64); + rhash_keccak_final(&shactx, pubkeyhash.hash); - uint8_t* eth_address = (uint8_t*)malloc(20); - memcpy(eth_address, msghash.hash + 12, 20); + uint8_t eth_address[20]; + memcpy(eth_address, pubkeyhash.hash + 12, 20); // Verify that the ETH address exists in the "addresses" eosio.unregd contract table addresses_index addresses(_self, _self); @@ -90,7 +99,9 @@ void unregd::regaccount(const bytes& signature, const string& account, const eos auto amount_to_purchase_8kb_of_RAM = buyrambytes(8*1024); // Build authority with the pubkey passed as parameter - auto auth = authority{1,{{eos_pubkey,1}},{},{}}; + const auto auth = authority{ + 1, {{{(uint8_t)eos_pubkey.type, eos_pubkey.data} , 1}}, {}, {} + }; // Issue to eosio.unregd the necesary EOS to buy 8K of RAM INLINE_ACTION_SENDER(call::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, diff --git a/eosio.unregd/eosio.unregd.hpp b/eosio.unregd/eosio.unregd.hpp index 0da5d05..0e35c38 100644 --- a/eosio.unregd/eosio.unregd.hpp +++ b/eosio.unregd/eosio.unregd.hpp @@ -15,6 +15,7 @@ #include "sha3/byte_order.c" #include "sha3/sha3.c" +#include "abieos_numeric.hpp" #define uECC_SUPPORTS_secp160r1 0 #define uECC_SUPPORTS_secp192r1 0 #define uECC_SUPPORTS_secp224r1 0 @@ -51,7 +52,7 @@ class unregd : public contract { // Actions void add(const ethereum_address& ethereum_address, const asset& balance); - void regaccount(const bytes& signature, const string& account, const eosio::public_key& eos_pubkey); + void regaccount(const bytes& signature, const string& account, const string& eos_pubkey); private: static uint8_t hex_char_to_uint(char character) {