diff --git a/bitcoin/address.c b/bitcoin/address.c index d1dbe22c7..a5aad53bd 100644 --- a/bitcoin/address.c +++ b/bitcoin/address.c @@ -6,6 +6,6 @@ void bitcoin_address(const struct pubkey *key, struct bitcoin_address *addr) { struct sha256 h; - sha256(&h, key->key, pubkey_len(key)); + sha256(&h, key->der, pubkey_derlen(key)); ripemd160(&addr->addr, h.u.u8, sizeof(h)); } diff --git a/bitcoin/base58.c b/bitcoin/base58.c index 9ec28d3d2..6c29a4d03 100644 --- a/bitcoin/base58.c +++ b/bitcoin/base58.c @@ -275,7 +275,6 @@ bool key_from_base58(const char *base58, size_t base58_len, bool compressed; secp256k1_context *secpctx; size_t keylen; - secp256k1_pubkey pubkey; BN_init(&bn); if (!raw_decode_base58(&bn, base58, base58_len)) @@ -312,19 +311,11 @@ bool key_from_base58(const char *base58, size_t base58_len, if (!secp256k1_ec_seckey_verify(secpctx, priv->secret)) goto fail_free_secpctx; - /* Get public key, too. */ - /* FIXME: Don't convert. */ - if (!secp256k1_ec_pubkey_create(secpctx, &pubkey, priv->secret)) + /* Get public key, too, since we know if it's compressed. */ + if (!pubkey_from_privkey(priv, key, + compressed ? SECP256K1_EC_COMPRESSED : 0)) goto fail_free_secpctx; - memset(key, 0, sizeof(*key)); - if (!secp256k1_ec_pubkey_serialize(secpctx, key->key, &keylen, - &pubkey, - compressed - ? SECP256K1_EC_COMPRESSED : 0)) - goto fail_free_secpctx; - assert(keylen == pubkey_len(key)); - BN_free(&bn); secp256k1_context_destroy(secpctx); return true; diff --git a/bitcoin/pubkey.c b/bitcoin/pubkey.c index ee9ae4550..f922b8707 100644 --- a/bitcoin/pubkey.c +++ b/bitcoin/pubkey.c @@ -1,6 +1,7 @@ #include #include #include "pubkey.h" +#include "privkey.h" /* Must agree on key validity with bitcoin! Stolen from bitcoin/src/pubkey.h's * GetLen: @@ -18,29 +19,76 @@ static unsigned int GetLen(unsigned char chHeader) return 0; } -bool pubkey_valid(const u8 *first_char, size_t len) +size_t pubkey_derlen(const struct pubkey *key) { - if (len < 1) - return false; - return (len == GetLen(*first_char)); -} - -size_t pubkey_len(const struct pubkey *key) -{ - size_t len = GetLen(key->key[0]); + size_t len = GetLen(key->der[0]); assert(len); return len; } -bool pubkey_from_hexstr(const char *str, struct pubkey *key) +bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key) { - size_t slen = strlen(str), dlen; - dlen = hex_data_size(slen); + secp256k1_context *secpctx = secp256k1_context_create(0); - if (dlen != 33 && dlen != 65) - return false; - if (!hex_decode(str, slen, key->key, dlen)) - return false; - return GetLen(key->key[0]) == dlen; + if (len > sizeof(key->der)) + goto fail_free_secpctx; + + memcpy(key->der, der, len); + if (!secp256k1_ec_pubkey_parse(secpctx, &key->pubkey, key->der, len)) + goto fail_free_secpctx; + + secp256k1_context_destroy(secpctx); + return true; + +fail_free_secpctx: + secp256k1_context_destroy(secpctx); + return false; +} + +/* Pubkey from privkey */ +bool pubkey_from_privkey(const struct privkey *privkey, + struct pubkey *key, + unsigned int compressed_flags) +{ + secp256k1_context *secpctx; + size_t outlen; + + secpctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + if (!secp256k1_ec_pubkey_create(secpctx, &key->pubkey, privkey->secret)) + goto fail_free_secpctx; + + if (!secp256k1_ec_pubkey_serialize(secpctx, key->der, &outlen, + &key->pubkey, compressed_flags)) + goto fail_free_secpctx; + assert(outlen == pubkey_derlen(key)); + + secp256k1_context_destroy(secpctx); + return true; + +fail_free_secpctx: + secp256k1_context_destroy(secpctx); + return false; +} + +bool pubkey_from_hexstr(const char *derstr, struct pubkey *key) +{ + size_t slen = strlen(derstr), dlen; + unsigned char der[65]; + + dlen = hex_data_size(slen); + if (dlen > sizeof(der)) + return false; + + if (!hex_decode(derstr, slen, der, dlen)) + return false; + + return pubkey_from_der(der, dlen, key); +} + +bool pubkey_eq(const struct pubkey *a, const struct pubkey *b) +{ + return pubkey_derlen(a) == pubkey_derlen(b) + && memcmp(a->der, b->der, pubkey_derlen(a)) == 0; } diff --git a/bitcoin/pubkey.h b/bitcoin/pubkey.h index 50cb9aa18..b75831348 100644 --- a/bitcoin/pubkey.h +++ b/bitcoin/pubkey.h @@ -2,18 +2,31 @@ #define LIGHTNING_BITCOIN_PUBKEY_H #include #include +#include "secp256k1.h" + +struct privkey; struct pubkey { - u8 key[65]; + /* DER-encoded key (as hashed by bitcoin, for addresses) */ + u8 der[65]; + /* Unpacked pubkey (as used by libsecp256k1 internally) */ + secp256k1_pubkey pubkey; }; -/* 33 or 65 bytes? */ -size_t pubkey_len(const struct pubkey *key); +/* Convert from hex string of DER (scriptPubKey from validateaddress) */ +bool pubkey_from_hexstr(const char *derstr, struct pubkey *key); -/* Convert from hex string (scriptPubKey from validateaddress) */ -bool pubkey_from_hexstr(const char *str, struct pubkey *key); +/* Pubkey from privkey */ +bool pubkey_from_privkey(const struct privkey *privkey, + struct pubkey *key, + unsigned int compressed_flags); -/* For conversion routines in protobuf_convert.c */ -bool pubkey_valid(const u8 *first_char, size_t len); +/* Pubkey from DER encoding. */ +bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key); +/* How many bytes of key->der are valid. */ +size_t pubkey_derlen(const struct pubkey *key); + +/* Are these keys equal? */ +bool pubkey_eq(const struct pubkey *a, const struct pubkey *b); #endif /* LIGHTNING_PUBKEY_H */ diff --git a/bitcoin/script.c b/bitcoin/script.c index 75701c563..937e2e369 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -94,7 +94,7 @@ static void add_number(u8 **script, u32 num) static void add_push_key(u8 **scriptp, const struct pubkey *key) { - add_push_bytes(scriptp, key->key, pubkey_len(key)); + add_push_bytes(scriptp, key->der, pubkey_derlen(key)); } static void add_push_sig(u8 **scriptp, const struct bitcoin_signature *sig) @@ -128,10 +128,10 @@ static void add_push_le32(u8 **scriptp, u32 val) static bool key_less(const struct pubkey *a, const struct pubkey *b) { /* Shorter one wins. */ - if (pubkey_len(a) != pubkey_len(b)) - return pubkey_len(a) < pubkey_len(b); + if (pubkey_derlen(a) != pubkey_derlen(b)) + return pubkey_derlen(a) < pubkey_derlen(b); - return memcmp(a->key, b->key, pubkey_len(a)) < 0; + return memcmp(a->der, b->der, pubkey_derlen(a)) < 0; } /* tal_count() gives the length of the script. */ diff --git a/bitcoin/signature.c b/bitcoin/signature.c index fbdaaa75d..698d10842 100644 --- a/bitcoin/signature.c +++ b/bitcoin/signature.c @@ -152,26 +152,18 @@ static bool check_signed_hash(const struct sha256_double *hash, { int ret; secp256k1_context *secpctx; - /* FIXME: Don't convert here! */ - secp256k1_pubkey pubkey; secpctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); if (!secpctx) return false; - if (!secp256k1_ec_pubkey_parse(secpctx, &pubkey, key->key, - pubkey_len(key))) { - secp256k1_context_destroy(secpctx); - return false; - } - #ifdef USE_SCHNORR ret = secp256k1_schnorr_verify(secpctx, (unsigned char *)signature, - hash->sha.u.u8, &pubkey); + hash->sha.u.u8, &key->pubkey); #else ret = secp256k1_ecdsa_verify(secpctx, (secp256k1_ecdsa_signature *)signature, - hash->sha.u.u8, &pubkey); + hash->sha.u.u8, &key->pubkey); #endif secp256k1_context_destroy(secpctx); diff --git a/protobuf_convert.c b/protobuf_convert.c index 288508199..8ec27a6bc 100644 --- a/protobuf_convert.c +++ b/protobuf_convert.c @@ -41,22 +41,20 @@ bool proto_to_signature(const Signature *pb, struct signature *sig) BitcoinPubkey *pubkey_to_proto(const tal_t *ctx, const struct pubkey *key) { BitcoinPubkey *p = tal(ctx, BitcoinPubkey); + struct pubkey check; bitcoin_pubkey__init(p); - p->key.len = pubkey_len(key); - p->key.data = tal_dup_arr(p, u8, key->key, p->key.len, 0); + p->key.len = pubkey_derlen(key); + p->key.data = tal_dup_arr(p, u8, key->der, p->key.len, 0); - assert(pubkey_valid(p->key.data, p->key.len)); + assert(pubkey_from_der(p->key.data, p->key.len, &check)); + assert(pubkey_eq(&check, key)); return p; } bool proto_to_pubkey(const BitcoinPubkey *pb, struct pubkey *key) { - if (!pubkey_valid(pb->key.data, pb->key.len)) - return false; - - memcpy(key->key, pb->key.data, pb->key.len); - return true; + return pubkey_from_der(pb->key.data, pb->key.len, key); } Sha256Hash *sha256_to_proto(const tal_t *ctx, const struct sha256 *hash) diff --git a/test-cli/close-channel.c b/test-cli/close-channel.c index b3d0f9e22..fa2f29021 100644 --- a/test-cli/close-channel.c +++ b/test-cli/close-channel.c @@ -79,8 +79,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->commit_key, &pubkey2)) errx(1, "Invalid o1 commit pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit pubkey"); diff --git a/test-cli/create-commit-spend-tx.c b/test-cli/create-commit-spend-tx.c index 79755044d..7b49563da 100644 --- a/test-cli/create-commit-spend-tx.c +++ b/test-cli/create-commit-spend-tx.c @@ -77,8 +77,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->final_key, &pubkey2)) errx(1, "Invalid o1 final pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->final_key, &pubkey2)) errx(1, "Invalid o2 final pubkey"); diff --git a/test-cli/create-commit-tx.c b/test-cli/create-commit-tx.c index f8bf64c44..527c5827a 100644 --- a/test-cli/create-commit-tx.c +++ b/test-cli/create-commit-tx.c @@ -60,8 +60,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->commit_key, &pubkey2)) errx(1, "Invalid o1 commit pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit pubkey"); diff --git a/test-cli/create-htlc-spend-tx.c b/test-cli/create-htlc-spend-tx.c index 82b46baf0..0979f0c27 100644 --- a/test-cli/create-htlc-spend-tx.c +++ b/test-cli/create-htlc-spend-tx.c @@ -99,11 +99,9 @@ int main(int argc, char *argv[]) if (!proto_to_pubkey(o2->final_key, &pubkey2)) errx(1, "Invalid o2 final pubkey"); - if (pubkey_len(&key) == pubkey_len(&pubkey1) - && memcmp(key.key, pubkey1.key, pubkey_len(&pubkey1)) == 0) { + if (pubkey_eq(&key, &pubkey1)) { own_commit_tx = true; - } else if (pubkey_len(&key) == pubkey_len(&pubkey2) - && memcmp(key.key, pubkey2.key, pubkey_len(&pubkey2)) == 0) { + } else if (pubkey_eq(&key, &pubkey2)) { own_commit_tx = false; } else errx(1, "Privkey doesn't match either key"); diff --git a/test-cli/create-steal-tx.c b/test-cli/create-steal-tx.c index 70a633907..99ab6fd21 100644 --- a/test-cli/create-steal-tx.c +++ b/test-cli/create-steal-tx.c @@ -77,8 +77,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->final_key, &pubkey2)) errx(1, "Invalid o1 final pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->final_key, &pubkey2)) errx(1, "Invalid o2 final pubkey"); diff --git a/test-cli/update-channel-accept.c b/test-cli/update-channel-accept.c index 2baa7a7fc..482983a44 100644 --- a/test-cli/update-channel-accept.c +++ b/test-cli/update-channel-accept.c @@ -74,8 +74,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->commit_key, &pubkey2)) errx(1, "Invalid o1 commit pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit pubkey"); diff --git a/test-cli/update-channel-signature.c b/test-cli/update-channel-signature.c index fbad4dbbf..81bf7a5a7 100644 --- a/test-cli/update-channel-signature.c +++ b/test-cli/update-channel-signature.c @@ -77,8 +77,7 @@ int main(int argc, char *argv[]) /* Get pubkeys */ if (!proto_to_pubkey(o1->commit_key, &pubkey2)) errx(1, "Invalid o1 commit pubkey"); - if (pubkey_len(&pubkey1) != pubkey_len(&pubkey2) - || memcmp(pubkey1.key, pubkey2.key, pubkey_len(&pubkey2)) != 0) + if (!pubkey_eq(&pubkey1, &pubkey2)) errx(1, "o1 pubkey != this privkey"); if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit pubkey");