diff --git a/address.c b/address.c index 2fb8b32dd..5882e5c3e 100644 --- a/address.c +++ b/address.c @@ -52,3 +52,19 @@ bool address_check_prefix(const uint8_t *addr, uint32_t address_type) } return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); } + +#if USE_ETHEREUM +#include "sha3.h" + +void ethereum_address_checksum(const uint8_t *addr, char *address) +{ + const char *hexU = "0123456789ABCDEF", *hexL = "0123456789abcdef"; + uint8_t hash[32]; + keccak_256(addr, 20, hash); + for (int i = 0; i < 40; i++) { + const char *t = (hash[i / 8] & (1 << (7 - i % 8))) ? hexU : hexL; + address[i] = (i % 2 == 0) ? t[(addr[i / 2] >> 4) & 0xF] : t[addr[i / 2] & 0xF]; + } + address[40] = 0; +} +#endif diff --git a/address.h b/address.h index bd96d61f5..62ce887f0 100644 --- a/address.h +++ b/address.h @@ -31,5 +31,8 @@ size_t address_prefix_bytes_len(uint32_t address_type); void address_write_prefix_bytes(uint32_t address_type, uint8_t *out); bool address_check_prefix(const uint8_t *addr, uint32_t address_type); +#if USE_ETHEREUM +void ethereum_address_checksum(const uint8_t *addr, char *address); +#endif #endif diff --git a/test_check.c b/test_check.c index aaecb11f9..6f43c49f9 100644 --- a/test_check.c +++ b/test_check.c @@ -55,6 +55,7 @@ #include "ed25519-keccak.h" #include "script.h" #include "rfc6979.h" +#include "address.h" /* * This is a clever trick to make Valgrind's Memcheck verify code @@ -3077,6 +3078,25 @@ START_TEST(test_ethereum_pubkeyhash) } END_TEST +START_TEST(test_ethereum_address) +{ + uint8_t addr[20]; + char address[41]; + + memcpy(addr, fromhex("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "Cd2a3d9f938e13Cd947eC05ABC7fe734df8DD826"); + + memcpy(addr, fromhex("9ca0e998df92c5351cecbbb6dba82ac2266f7e0c"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "9Ca0e998dF92c5351cEcbBb6Dba82Ac2266f7e0C"); + + memcpy(addr, fromhex("cb16d0e54450cdd2368476e762b09d147972b637"), 20); + ethereum_address_checksum(addr, address); + ck_assert_str_eq(address, "cB16D0E54450Cdd2368476E762B09D147972b637"); +} +END_TEST + START_TEST(test_multibyte_address) { uint8_t priv_key[32]; @@ -3225,6 +3245,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); + tc = tcase_create("ethereum_address"); + tcase_add_test(tc, test_ethereum_address); + suite_add_tcase(s, tc); + tc = tcase_create("wif"); tcase_add_test(tc, test_wif); suite_add_tcase(s, tc);