Switched base58 to use libbase58.

This commit is contained in:
Christian Decker 2016-07-29 11:36:18 +02:00 committed by Rusty Russell
parent f086e44358
commit 1f4a056009
2 changed files with 36 additions and 236 deletions

View File

@ -177,7 +177,7 @@ CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations
CDEBUGFLAGS := -g -fstack-protector
CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I secp256k1/include/ -I . $(FEATURES)
LDLIBS := -lcrypto -lprotobuf-c -lgmp -lsodium
LDLIBS := -lcrypto -lprotobuf-c -lgmp -lsodium -lbase58
$(PROGRAMS): CFLAGS+=-I.
default: $(PROGRAMS) daemon-all

View File

@ -11,149 +11,28 @@
#include <assert.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/tal/str/str.h>
#include <openssl/bn.h>
#include <secp256k1.h>
#include <string.h>
#include <libbase58.h>
static const char enc_16[] = "0123456789abcdef";
static const char enc_58[] =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
static char encode_char(unsigned long val, const char *enc)
static bool my_sha256(void *digest, const void *data, size_t datasz)
{
assert(val < strlen(enc));
return enc[val];
}
static int decode_char(char c, const char *enc)
{
const char *pos = strchr(enc, c);
if (!pos)
return -1;
return pos - enc;
}
/*
* Encode a byte sequence as a base58-encoded string. This is a bit
* weird: returns pointer into buf (or NULL if wouldn't fit).
*/
static char *encode_base58(char *buf, size_t buflen,
const u8 *data, size_t data_len)
{
char *p;
BIGNUM bn;
/* Convert to a bignum. */
BN_init(&bn);
BN_bin2bn(data, data_len, &bn);
/* Add NUL terminator */
if (!buflen) {
p = NULL;
goto out;
}
p = buf + buflen;
*(--p) = '\0';
/* Fill from the back, using a series of divides. */
while (!BN_is_zero(&bn)) {
int rem = BN_div_word(&bn, 58);
if (--p < buf) {
p = NULL;
goto out;
}
*p = encode_char(rem, enc_58);
}
/* Now, this is really weird. We pad with zeroes, but not at
* base 58, but in terms of zero bytes. This means that some
* encodings are shorter than others! */
while (data_len && *data == '\0') {
if (--p < buf) {
p = NULL;
goto out;
}
*p = encode_char(0, enc_58);
data_len--;
data++;
}
out:
BN_free(&bn);
return p;
}
/*
* Decode a base_n-encoded string into a byte sequence.
*/
bool raw_decode_base_n(BIGNUM *bn, const char *src, size_t len, int base)
{
const char *enc;
BN_zero(bn);
assert(base == 16 || base == 58);
switch (base) {
case 16:
enc = enc_16;
break;
case 58:
enc = enc_58;
break;
}
while (len) {
char current = *src;
if (base == 16)
current = tolower(current); /* TODO: Not in ccan. */
int val = decode_char(current, enc);
if (val < 0) {
BN_free(bn);
return false;
}
BN_mul_word(bn, base);
BN_add_word(bn, val);
src++;
len--;
}
sha256(digest, data, datasz);
return true;
}
/*
* Decode a base58-encoded string into a byte sequence.
*/
bool raw_decode_base58(BIGNUM *bn, const char *src, size_t len)
{
return raw_decode_base_n(bn, src, len, 58);
}
void base58_get_checksum(u8 csum[4], const u8 buf[], size_t buflen)
{
struct sha256_double sha_result;
/* Form checksum, using double SHA2 (as per bitcoin standard) */
sha256_double(&sha_result, buf, buflen);
/* Use first four bytes of that as the checksum. */
memcpy(csum, sha_result.sha.u.u8, 4);
}
static char *to_base58(const tal_t *ctx, u8 version,
const struct ripemd160 *rmd)
{
u8 buf[1 + sizeof(*rmd) + 4];
char out[BASE58_ADDR_MAX_LEN + 2], *p;
char out[BASE58_ADDR_MAX_LEN + 1];
size_t outlen = sizeof(out);
buf[0] = version;
memcpy(buf+1, rmd, sizeof(*rmd));
/* Append checksum */
base58_get_checksum(buf + 1 + sizeof(*rmd), buf, 1 + sizeof(*rmd));
p = encode_base58(out, BASE58_ADDR_MAX_LEN, buf, sizeof(buf));
return tal_strdup(ctx, p);
b58_sha256_impl = my_sha256;
if (!b58check_enc(out, &outlen, version, rmd, sizeof(*rmd))) {
return NULL;
}else{
return tal_strdup(ctx, out);
}
}
char *bitcoin_to_base58(const tal_t *ctx, bool test_net,
@ -173,30 +52,15 @@ static bool from_base58(u8 *version,
const char *base58, size_t base58_len)
{
u8 buf[1 + sizeof(*rmd) + 4];
BIGNUM bn;
size_t len;
u8 csum[4];
BN_init(&bn);
if (!raw_decode_base58(&bn, base58, base58_len))
return false;
len = BN_num_bytes(&bn);
if (len > sizeof(buf))
return false;
memset(buf, 0, sizeof(buf));
BN_bn2bin(&bn, buf + sizeof(buf) - len);
BN_free(&bn);
b58_sha256_impl = my_sha256;
size_t buflen = sizeof(buf);
b58tobin(buf, &buflen, base58, base58_len);
int r = b58check(buf, sizeof(buf), base58, base58_len);
*version = buf[0];
base58_get_checksum(csum, buf, 1 + sizeof(*rmd));
if (memcmp(csum, buf + 1 + sizeof(*rmd), sizeof(csum)) != 0)
return false;
memcpy(rmd, buf+1, sizeof(*rmd));
return true;
memcpy(rmd, buf + 1, sizeof(*rmd));
return r > 0;
}
bool bitcoin_from_base58(bool *test_net,
@ -235,124 +99,60 @@ bool p2sh_from_base58(bool *test_net,
return true;
}
/* buf already contains version and ripemd160. Append checksum and encode */
char *base58_with_check(char dest[BASE58_ADDR_MAX_LEN],
u8 buf[1 + sizeof(struct ripemd160) + 4])
{
/* Append checksum */
base58_get_checksum(buf + 1 + sizeof(struct ripemd160),
buf, 1 + sizeof(struct ripemd160));
/* Now encode. */
return encode_base58(dest, BASE58_ADDR_MAX_LEN, buf,
1 + sizeof(struct ripemd160) + 4);
}
bool ripemd_from_base58(u8 *version,
struct ripemd160 *ripemd160,
const char *base58)
{
u8 buf[1 + sizeof(*ripemd160) + 4];
u8 csum[4];
BIGNUM bn;
size_t len;
/* Too long? Check here before doing arithmetic. */
if (strlen(base58) > BASE58_ADDR_MAX_LEN - 1)
return false;
BN_init(&bn);
/* Fails if it contains invalid characters. */
if (!raw_decode_base58(&bn, base58, strlen(base58)))
return false;
/* Too big? */
len = BN_num_bytes(&bn);
if (len > sizeof(buf)) {
BN_free(&bn);
return false;
}
/* Fill start with zeroes. */
memset(buf, 0, sizeof(buf) - len);
BN_bn2bin(&bn, buf + sizeof(buf) - len);
BN_free(&bn);
/* Check checksum is correct. */
base58_get_checksum(csum, buf, sizeof(buf));
if (memcmp(csum, buf + 1 + sizeof(*ripemd160), 4) != 0)
return false;
*version = buf[0];
memcpy(ripemd160, buf + 1, sizeof(*ripemd160));
return true;
return from_base58(version, ripemd160, base58, strlen(base58));
}
char *key_to_base58(const tal_t *ctx, bool test_net, const struct privkey *key)
{
u8 buf[1 + 32 + 1 + 4];
char out[BASE58_KEY_MAX_LEN + 2], *p;
buf[0] = test_net ? 239 : 128;
memcpy(buf + 1, key->secret, sizeof(key->secret));
u8 buf[32 + 1];
char out[BASE58_KEY_MAX_LEN + 2];
u8 version = test_net ? 239 : 128;
size_t outlen = sizeof(out);
memcpy(buf, key->secret, sizeof(key->secret));
/* Mark this as a compressed key. */
buf[1 + 32] = 1;
buf[32] = 1;
/* Append checksum */
base58_get_checksum(buf + 1 + 32 + 1, buf, 1 + 32 + 1);
p = encode_base58(out, BASE58_KEY_MAX_LEN, buf, sizeof(buf));
return tal_strdup(ctx, p);
b58check_enc(out, &outlen, version, buf, sizeof(buf));
return tal_strdup(ctx, out);
}
bool key_from_base58(secp256k1_context *secpctx,
const char *base58, size_t base58_len,
bool *test_net, struct privkey *priv, struct pubkey *key)
{
// 1 byte version, 32 byte private key, 1 byte compressed, 4 byte checksum
u8 keybuf[1 + 32 + 1 + 4];
u8 csum[4];
BIGNUM bn;
size_t keylen;
BN_init(&bn);
if (!raw_decode_base58(&bn, base58, base58_len))
size_t keybuflen = sizeof(keybuf);
b58tobin(keybuf, &keybuflen, base58, base58_len);
if (b58check(keybuf, sizeof(keybuf), base58, base58_len) < 0)
return false;
keylen = BN_num_bytes(&bn);
if (keylen != 1 + 32 + 1 + 4)
goto fail_free_bn;
BN_bn2bin(&bn, keybuf);
base58_get_checksum(csum, keybuf, keylen - sizeof(csum));
if (memcmp(csum, keybuf + keylen - sizeof(csum), sizeof(csum)) != 0)
goto fail_free_bn;
/* Byte after key should be 1 to represent a compressed key. */
if (keybuf[1 + 32] != 1)
goto fail_free_bn;
return false;
if (keybuf[0] == 128)
*test_net = false;
else if (keybuf[0] == 239)
*test_net = true;
else
goto fail_free_bn;
return false;
/* Copy out secret. */
memcpy(priv->secret, keybuf + 1, sizeof(priv->secret));
if (!secp256k1_ec_seckey_verify(secpctx, priv->secret))
goto fail_free_bn;
return false;
/* Get public key, too. */
if (!pubkey_from_privkey(secpctx, priv, key))
goto fail_free_bn;
return false;
BN_free(&bn);
return true;
fail_free_bn:
BN_free(&bn);
return false;
}