diff --git a/base58.c b/base58.c index aaefa3548..4ed2a3b31 100644 --- a/base58.c +++ b/base58.c @@ -32,8 +32,8 @@ int base58_encode_check(const uint8_t *data, int len, char *str) case 78: // xpub/xprv 78 outlen = 111; break; - case 34: // WIF privkey 1+32 - outlen = 51; + case 34: // WIF privkey 1+32+1 + outlen = 52; break; case 21: // address 1+20 outlen = 34; @@ -57,9 +57,20 @@ int base58_encode_check(const uint8_t *data, int len, char *str) mydata[i] = rem * 4 + (tmp / 58); rem = tmp % 58; } - str[outlen - 1 - j] = code[rem]; + str[j] = code[rem]; + } + // remove duplicite 1s at the end + while (outlen > 1 && str[outlen - 1] == code[0] && str[outlen - 2] == code[0]) { + outlen--; } str[outlen] = 0; + char s; + // reverse string + for (i = 0; i < outlen / 2; i++) { + s = str[i]; + str[i] = str[outlen - 1 - i]; + str[outlen - 1 - i] = s; + } return outlen; } @@ -83,8 +94,8 @@ int base58_decode_check(const char *str, uint8_t *data) case 111: // xpub/xprv outlen = 78; break; - case 51: // WIF privkey - outlen = 34; + case 52: // WIF privkey + outlen = 35; break; case 27: // address case 28: diff --git a/ecdsa.c b/ecdsa.c index e1dbbe86c..31128d122 100644 --- a/ecdsa.c +++ b/ecdsa.c @@ -31,6 +31,7 @@ #include "ripemd160.h" #include "hmac.h" #include "ecdsa.h" +#include "base58.h" // cp2 = cp1 + cp2 void point_add(const curve_point *cp1, curve_point *cp2) @@ -347,79 +348,25 @@ void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr) { - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - char *p = addr, s; - uint8_t a[32], b[21]; - uint32_t r; - bignum256 c; - int i, l; - - b[0] = version; - ecdsa_get_pubkeyhash(pub_key, b + 1); - - sha256_Raw(b, 21, a); - sha256_Raw(a, 32, a); - - memcpy(a + 28, a, 4); // checksum - memset(a, 0, 7); // zeroes - memcpy(a + 7, b, 21); // version || ripemd160(sha256(pubkey)) - - bn_read_be(a, &c); - - while (!bn_is_zero(&c)) { - bn_divmod58(&c, &r); - *p = code[r]; - p++; - } - - i = 7; - while (a[i] == 0) { - *p = code[0]; - p++; i++; - } - - *p = 0; - - l = strlen(addr); + uint8_t data[21]; + data[0] = version; + ecdsa_get_pubkeyhash(pub_key, data + 1); + base58_encode_check(data, 21, addr); +} - for (i = 0; i < l / 2; i++) { - s = addr[i]; - addr[i] = addr[l - 1 - i]; - addr[l - 1 - i] = s; - } +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif) +{ + uint8_t data[34]; + data[0] = version; + memcpy(data + 1, priv_key, 32); + data[33 ] = 0x01; + base58_encode_check(data, 34, wif); } int ecdsa_address_decode(const char *addr, uint8_t *out) { if (!addr) return 0; - const char code[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - bignum256 num; - uint8_t buf[32], check[32]; - bn_zero(&num); - uint32_t k; - size_t i; - for (i = 0; i < strlen(addr); i++) { - bn_muli(&num, 58); - for (k = 0; k <= strlen(code); k++) { - if (code[k] == 0) { // char not found -> invalid address - return 0; - } - if (addr[i] == code[k]) { - bn_addi(&num, k); - break; - } - } - } - bn_write_be(&num, buf); - // compute address hash - sha256_Raw(buf + 7, 21, check); - sha256_Raw(check, 32, check); - // check if valid - if (memcmp(buf + 7 + 21, check, 4) != 0) { - return 0; - } - memcpy(out, buf + 7, 21); - return 1; + return base58_decode_check(addr, out) == 21; } void uncompress_coords(uint8_t odd, const bignum256 *x, bignum256 *y) diff --git a/ecdsa.h b/ecdsa.h index b7f59b350..3e2dede55 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -45,6 +45,7 @@ void ecdsa_get_public_key33(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_public_key65(const uint8_t *priv_key, uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); void ecdsa_get_address(const uint8_t *pub_key, uint8_t version, char *addr); +void ecdsa_get_wif(const uint8_t *priv_key, uint8_t version, char *wif); int ecdsa_address_decode(const char *addr, uint8_t *out); int ecdsa_read_pubkey(const uint8_t *pub_key, curve_point *pub); int ecdsa_verify(const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len); diff --git a/tests.c b/tests.c index 90c1df2d5..0ba3fac39 100644 --- a/tests.c +++ b/tests.c @@ -728,6 +728,25 @@ START_TEST(test_address) } END_TEST +START_TEST(test_wif) +{ + uint8_t priv_key[32]; + char wif[53]; + + memcpy(priv_key, fromhex("1111111111111111111111111111111111111111111111111111111111111111"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cN9spWsvaxA8taS7DFMxnk1yJD2gaF2PX1npuTpy3vuZFJdwavaw"); + + memcpy(priv_key, fromhex("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "L4ezQvyC6QoBhxB4GVs9fAPhUKtbaXYUn8YTqoeXwbevQq4U92vN"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cV1ysqy3XUVSsPeKeugH2Utm6ZC1EyeArAgvxE73SiJvfa6AJng7"); + + memcpy(priv_key, fromhex("47f7616ea6f9b923076625b4488115de1ef1187f760e65f89eb6f4f7ff04b012"), 32); + ecdsa_get_wif(priv_key, 0x80, wif); ck_assert_str_eq(wif, "KydbzBtk6uc7M6dXwEgTEH2sphZxSPbmDSz6kUUHi4eUpSQuhEbq"); + ecdsa_get_wif(priv_key, 0xEF, wif); ck_assert_str_eq(wif, "cPzbT6tbXyJNWY6oKeVabbXwSvsN6qhTHV8ZrtvoDBJV5BRY1G5Q"); +} +END_TEST + START_TEST(test_address_decode) { int res; @@ -867,6 +886,10 @@ Suite *test_suite(void) tcase_add_test(tc, test_address_decode); suite_add_tcase(s, tc); + tc = tcase_create("wif"); + tcase_add_test(tc, test_wif); + suite_add_tcase(s, tc); + tc = tcase_create("ecdsa_der"); tcase_add_test(tc, test_ecdsa_der); suite_add_tcase(s, tc);