diff --git a/ecdsa.c b/ecdsa.c index 2b0f00cbd0..310dad3256 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -27,6 +27,7 @@ #include #include +#include "address.h" #include "bignum.h" #include "rand.h" #include "sha2.h" @@ -881,40 +882,17 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, uint8_t *addr_raw) { - if (version <= 0xFF) { - addr_raw[0] = version; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 1); - } else if (version <= 0xFFFF) { - addr_raw[0] = version >> 8; - addr_raw[1] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 2); - } else if (version <= 0xFFFFFF) { - addr_raw[0] = version >> 16; - addr_raw[1] = (version >> 8) & 0xFF; - addr_raw[2] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 3); - } else { - addr_raw[0] = version >> 24; - addr_raw[1] = (version >> 16) & 0xFF; - addr_raw[2] = (version >> 8) & 0xFF; - addr_raw[3] = version & 0xFF; - ecdsa_get_pubkeyhash(pub_key, addr_raw + 4); - } + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, addr_raw); + ecdsa_get_pubkeyhash(pub_key, addr_raw + prefix_len); } void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int addrsize) { uint8_t raw[MAX_ADDR_RAW_SIZE]; + size_t prefix_len = address_prefix_bytes_len(version); ecdsa_get_address_raw(pub_key, version, raw); - if (version <= 0xFF) { - base58_encode_check(raw, 21, addr, addrsize); - } else if (version <= 0xFFFF) { - base58_encode_check(raw, 22, addr, addrsize); - } else if (version <= 0xFFFFFF) { - base58_encode_check(raw, 23, addr, addrsize); - } else { - base58_encode_check(raw, 24, addr, addrsize); - } + base58_encode_check(raw, 20 + prefix_len, addr, addrsize); // not as important to clear this one, but we might as well MEMSET_BZERO(raw, sizeof(raw)); } @@ -922,35 +900,11 @@ void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, char *addr, int void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wifsize) { uint8_t wif_raw[MAX_WIF_RAW_SIZE]; - - if (version <= 0xFF) { - wif_raw[0] = version; - memcpy(wif_raw + 1, priv_key, 32); - wif_raw[33] = 0x01; - base58_encode_check(wif_raw, 1 + 32 + 1, wif, wifsize); - } else if (version <= 0xFFFF) { - wif_raw[0] = version >> 8; - wif_raw[1] = version & 0xFF; - memcpy(wif_raw + 2, priv_key, 32); - wif_raw[34] = 0x01; - base58_encode_check(wif_raw, 2 + 32 + 1, wif, wifsize); - } else if (version <= 0xFFFFFF) { - wif_raw[0] = version >> 16; - wif_raw[1] = (version >> 8) & 0xFF; - wif_raw[2] = version & 0xFF; - memcpy(wif_raw + 3, priv_key, 32); - wif_raw[35] = 0x01; - base58_encode_check(wif_raw, 3 + 32 + 1, wif, wifsize); - } else { - wif_raw[0] = version >> 24; - wif_raw[1] = (version >> 16) & 0xFF; - wif_raw[2] = (version >> 8) & 0xFF; - wif_raw[3] = version & 0xFF; - memcpy(wif_raw + 4, priv_key, 32); - wif_raw[36] = 0x01; - base58_encode_check(wif_raw, 4 + 32 + 1, wif, wifsize); - } - + size_t prefix_len = address_prefix_bytes_len(version); + address_write_prefix_bytes(version, wif_raw); + memcpy(wif_raw + prefix_len, priv_key, 32); + wif_raw[prefix_len + 32] = 0x01; + base58_encode_check(wif_raw, prefix_len + 32 + 1, wif, wifsize); // private keys running around our stack can cause trouble MEMSET_BZERO(wif_raw, sizeof(wif_raw)); } @@ -958,15 +912,9 @@ void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, char *wif, int wif int ecdsa_address_decode(const char *addr, uint32_t version, uint8_t *out) { if (!addr) return 0; - if (version <= 0xFF) { - return base58_decode_check(addr, out, 21) == 21 && out[0] == (version & 0xFF); - } else if (version <= 0xFFFF) { - return base58_decode_check(addr, out, 22) == 22 && out[0] == ((version >> 8) & 0xFF) && out[1] == (version & 0xFF); - } else if (version <= 0xFFFFFF) { - return base58_decode_check(addr, out, 23) == 23 && out[0] == ((version >> 16) & 0xFF) && out[1] == ((version >> 8) & 0xFF) && out[2] == (version & 0xFF); - } else { - return base58_decode_check(addr, out, 24) == 24 && out[0] == (version >> 24) && out[1] == ((version >> 16) & 0xFF) && out[2] == ((version >> 8) & 0xFF) && out[3] == (version & 0xFF); - } + int prefix_len = address_prefix_bytes_len(version); + return base58_decode_check(addr, out, 20 + prefix_len) == 20 + prefix_len + && address_check_prefix(out, version); } void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y) diff --git a/tests.c b/tests.c index 2c917dcdd6..fd1ef94ccc 100644 --- a/tests.c +++ b/tests.c @@ -2799,6 +2799,65 @@ START_TEST(test_ethereum_pubkeyhash) } END_TEST +START_TEST(test_multibyte_address) +{ + uint8_t priv_key[32]; + char wif[57]; + uint8_t pub_key[33]; + char address[40]; + uint8_t decode[24]; + int res; + + memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); + ecdsa_get_wif(priv_key, 0, wif, sizeof(wif)); ck_assert_str_eq(wif, "13QtoXmbhELWcrwD9YA9KzvXy5rTaptiNuFR8L8ArpBNn4xmQj4N"); + ecdsa_get_wif(priv_key, 0x12, wif, sizeof(wif)); ck_assert_str_eq(wif, "3hrF6SFnqzpzABB36uGDf8dJSuUCcMmoJrTmCWMshRkBr2Vx86qJ"); + ecdsa_get_wif(priv_key, 0x1234, wif, sizeof(wif)); ck_assert_str_eq(wif, "CtPTF9awbVbfDWGepGdVhB3nBhr4HktUGya8nf8dLxgC8tbqBreB9"); + ecdsa_get_wif(priv_key, 0x123456, wif, sizeof(wif)); ck_assert_str_eq(wif, "uTrDevVQt5QZgoL3iJ1cPWHaCz7ZMBncM7QXZfCegtxiMHqBvWoYJa"); + ecdsa_get_wif(priv_key, 0x12345678, wif, sizeof(wif)); ck_assert_str_eq(wif, "4zZWMzv1SVbs95pmLXWrXJVp9ntPEam1mfwb6CXBLn9MpWNxLg9huYgv"); + ecdsa_get_wif(priv_key, 0xffffffff, wif, sizeof(wif)); ck_assert_str_eq(wif, "y9KVfV1RJXcTxpVjeuh6WYWh8tMwnAUeyUwDEiRviYdrJ61njTmnfUjE"); + + memcpy(pub_key, fromhex("0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71"), 33); + ecdsa_get_address(pub_key, 0, address, sizeof(address)); ck_assert_str_eq(address, "1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8"); + ecdsa_get_address(pub_key, 0x12, address, sizeof(address)); ck_assert_str_eq(address, "8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq"); + ecdsa_get_address(pub_key, 0x1234, address, sizeof(address)); ck_assert_str_eq(address, "ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV"); + ecdsa_get_address(pub_key, 0x123456, address, sizeof(address)); ck_assert_str_eq(address, "3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq"); + ecdsa_get_address(pub_key, 0x12345678, address, sizeof(address)); ck_assert_str_eq(address, "BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44"); + ecdsa_get_address(pub_key, 0xffffffff, address, sizeof(address)); ck_assert_str_eq(address, "3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT"); + + + res = ecdsa_address_decode("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8", 0, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("0079fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("8SCrMR2yYF7ciqoDbav7VLLTsVx5dTVPPq", 0x12, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("1279fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("ZLH8q1UgMPg8o2s1MD55YVMpPV7vqms9kiV", 0x1234, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("123479fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3ThqvsQVFnbiF66NwHtfe2j6AKn75DpLKpQSq", 0x123456, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("12345679fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x12345678, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("1234567879fbfc3f34e7745860d76137da68f362380c606c"), 21); + res = ecdsa_address_decode("3diW7paWGJyZRLGqMJZ55DMfPExob8QxQHkrfYT", 0xffffffff, decode); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq(decode, fromhex("ffffffff79fbfc3f34e7745860d76137da68f362380c606c"), 21); + + // wrong length + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x123456, decode); + ck_assert_int_eq(res, 0); + + // wrong address prefix + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL44", 0x22345678, decode); + ck_assert_int_eq(res, 0); + + // wrong checksum + res = ecdsa_address_decode("BrsGxAHga3VbopvSnb3gmLvMBhJNCGuDxBZL45", 0x12345678, decode); + ck_assert_int_eq(res, 0); +} +END_TEST + // define test suite and cases Suite *test_suite(void) { @@ -2965,6 +3024,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_ethereum_pubkeyhash); suite_add_tcase(s, tc); + tc = tcase_create("multibyte_addresse"); + tcase_add_test(tc, test_multibyte_address); + suite_add_tcase(s, tc); + return s; }