Skip to content
This repository has been archived by the owner on Mar 5, 2020. It is now read-only.

Commit

Permalink
- Signed message now includes pubkey and account name
Browse files Browse the repository at this point in the history
- Use sha3 for message hash
  • Loading branch information
elmato committed Aug 28, 2018
1 parent 3f99a20 commit dcea8ff
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 21 deletions.
84 changes: 84 additions & 0 deletions eosio.unregd/abieos_numeric.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// copyright defined in abieos/LICENSE.txt

#include <algorithm>
#include <array>
#include <stdexcept>
#include <stdint.h>
#include <string>
#include <string_view>
//#include "ripemd160.hpp"

namespace abieos {

const char base58_chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

bool map_initialized = false;
std::array<int8_t, 256> 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 <size_t size>
std::array<uint8_t, size> base58_to_binary(std::string_view s) {
std::array<uint8_t, size> 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<char, 33> data{};
};


template <typename Key, int suffix_size>
Key string_to_key(std::string_view s, key_type type, const char (&suffix)[suffix_size]) {
static const auto size = std::tuple_size<decltype(Key::data)>::value;
auto whole = base58_to_binary<size + 4>(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<public_key>(s.substr(7), key_type::r1, "R1");
} else {
eosio_assert(0, "unrecognized public key format");
}
return public_key{};
}

} // namespace abieos

4 changes: 2 additions & 2 deletions eosio.unregd/eosio.unregd.abi
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -42,7 +42,7 @@
"type": "string"
},{
"name": "eos_pubkey",
"type": "public_key"
"type": "string"
}
]
}
Expand Down
47 changes: 29 additions & 18 deletions eosio.unregd/eosio.unregd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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,
Expand All @@ -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);
Expand All @@ -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)}},
Expand Down
3 changes: 2 additions & 1 deletion eosio.unregd/eosio.unregd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit dcea8ff

Please sign in to comment.