From bed905a394dee7f7584628b6389b3f202fd0112b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 17 Oct 2022 11:05:31 +1030 Subject: [PATCH] lightningd: use 33 byte pubkeys internally. We still use 32 bytes on the wire, but internally don't use x-only. Signed-off-by: Rusty Russell --- bitcoin/pubkey.c | 31 +++++++++++++++++-------------- bitcoin/pubkey.h | 5 +++-- common/bolt12.c | 8 +++----- common/bolt12_merkle.c | 14 ++++++++++---- common/gossmap.c | 11 +++++------ common/json_stream.c | 8 +++++--- common/node_id.c | 4 ++-- devtools/bolt12-cli.c | 6 +----- hsmd/libhsmd.c | 18 +++++++++--------- lightningd/offer.c | 18 +++++------------- plugins/fetchinvoice.c | 30 ++++++++++++------------------ plugins/offers.c | 4 +--- plugins/offers_inv_hook.c | 7 ++----- plugins/offers_invreq_hook.c | 6 +----- 14 files changed, 76 insertions(+), 94 deletions(-) diff --git a/bitcoin/pubkey.c b/bitcoin/pubkey.c index 00ce2f139..90b30350f 100644 --- a/bitcoin/pubkey.c +++ b/bitcoin/pubkey.c @@ -128,34 +128,37 @@ void towire_pubkey(u8 **pptr, const struct pubkey *pubkey) void fromwire_point32(const u8 **cursor, size_t *max, struct point32 *point32) { - u8 raw[32]; + u8 raw[33]; + struct pubkey pk; - if (!fromwire(cursor, max, raw, sizeof(raw))) + raw[0] = SECP256K1_TAG_PUBKEY_EVEN; + if (!fromwire(cursor, max, raw + 1, sizeof(raw) - 1)) return; - if (secp256k1_xonly_pubkey_parse(secp256k1_ctx, - &point32->pubkey, - raw) != 1) { + if (!pubkey_from_der(raw, sizeof(raw), &pk)) { SUPERVERBOSE("not a valid point"); fromwire_fail(cursor, max); - } + } else + point32->pubkey = pk.pubkey; } void towire_point32(u8 **pptr, const struct point32 *point32) { - u8 output[32]; + u8 output[33]; + struct pubkey pk; - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, - &point32->pubkey); - towire(pptr, output, sizeof(output)); + pk.pubkey = point32->pubkey; + pubkey_to_der(output, &pk); + towire(pptr, output + 1, sizeof(output) - 1); } static char *point32_to_hexstr(const tal_t *ctx, const struct point32 *point32) { - u8 output[32]; + u8 output[33]; + struct pubkey pk; - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, - &point32->pubkey); - return tal_hexstr(ctx, output, sizeof(output)); + pk.pubkey = point32->pubkey; + pubkey_to_der(output, &pk); + return tal_hexstr(ctx, output + 1, sizeof(output) - 1); } REGISTER_TYPE_TO_STRING(point32, point32_to_hexstr); diff --git a/bitcoin/pubkey.h b/bitcoin/pubkey.h index 3eb52add0..c5d4ffc6d 100644 --- a/bitcoin/pubkey.h +++ b/bitcoin/pubkey.h @@ -19,11 +19,12 @@ struct pubkey { /* Define pubkey_eq (no padding) */ STRUCTEQ_DEF(pubkey, 0, pubkey.data); +/* FIXME: This is for the deprecated offers: it's represented x-only there */ struct point32 { /* Unpacked pubkey (as used by libsecp256k1 internally) */ - secp256k1_xonly_pubkey pubkey; + secp256k1_pubkey pubkey; }; -/* Define pubkey_eq (no padding) */ +/* Define point32_eq (no padding) */ STRUCTEQ_DEF(point32, 0, pubkey.data); /* Convert from hex string of DER (scriptPubKey from validateaddress) */ diff --git a/common/bolt12.c b/common/bolt12.c index ec1569c90..50de689b2 100644 --- a/common/bolt12.c +++ b/common/bolt12.c @@ -1,4 +1,5 @@ #include "config.h" +#include #include #include #include @@ -80,11 +81,8 @@ bool bolt12_check_signature(const struct tlv_field *fields, merkle_tlv(fields, &m); sighash_from_merkle(messagename, fieldname, &m, &shash); - return secp256k1_schnorrsig_verify(secp256k1_ctx, - sig->u8, - shash.u.u8, - sizeof(shash.u.u8), - &key->pubkey) == 1; + + return check_schnorr_sig(&shash, &key->pubkey, sig); } static char *check_signature(const tal_t *ctx, diff --git a/common/bolt12_merkle.c b/common/bolt12_merkle.c index 591685e4e..76b8e4ab4 100644 --- a/common/bolt12_merkle.c +++ b/common/bolt12_merkle.c @@ -220,17 +220,23 @@ void sighash_from_merkle(const char *messagename, } /* We use the SHA(pubkey | publictweak); so reader cannot figure out the - * tweak and derive the base key */ + * tweak and derive the base key. + * + * Since key used to be x-only, we don't hash first byte! + */ void payer_key_tweak(const struct point32 *bolt12, const u8 *publictweak, size_t publictweaklen, struct sha256 *tweak) { - u8 rawkey[32]; + u8 rawkey[PUBKEY_CMPR_LEN]; struct sha256_ctx sha; + struct pubkey pk; + + pk.pubkey = bolt12->pubkey; + pubkey_to_der(rawkey, &pk); - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, rawkey, &bolt12->pubkey); sha256_init(&sha); - sha256_update(&sha, rawkey, sizeof(rawkey)); + sha256_update(&sha, rawkey + 1, sizeof(rawkey) - 1); sha256_update(&sha, memcheck(publictweak, publictweaklen), publictweaklen); diff --git a/common/gossmap.c b/common/gossmap.c index b5d326938..9fb2a1a2b 100644 --- a/common/gossmap.c +++ b/common/gossmap.c @@ -1296,12 +1296,11 @@ void gossmap_guess_node_id(const struct gossmap *map, const struct point32 *point32, struct node_id *id) { - id->k[0] = SECP256K1_TAG_PUBKEY_EVEN; - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, - id->k + 1, - &point32->pubkey); + struct pubkey pk; + pk.pubkey = point32->pubkey; + node_id_from_pubkey(id, &pk); - /* If we don't find this, let's assume it's odd. */ + /* If we don't find this, let's assume it's the alternate. */ if (!gossmap_find_node(map, id)) - id->k[0] = SECP256K1_TAG_PUBKEY_ODD; + id->k[0] |= 1; } diff --git a/common/json_stream.c b/common/json_stream.c index 5e9401c62..ec1cfe7a1 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -419,10 +419,12 @@ void json_add_point32(struct json_stream *response, const char *fieldname, const struct point32 *key) { - u8 output[32]; + struct pubkey pk; + u8 der[PUBKEY_CMPR_LEN]; - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, output, &key->pubkey); - json_add_hex(response, fieldname, output, sizeof(output)); + pk.pubkey = key->pubkey; + pubkey_to_der(der, &pk); + json_add_hex(response, fieldname, der + 1, sizeof(der) - 1); } void json_add_bip340sig(struct json_stream *response, diff --git a/common/node_id.c b/common/node_id.c index d130dcff4..1582d0981 100644 --- a/common/node_id.c +++ b/common/node_id.c @@ -31,8 +31,8 @@ bool point32_from_node_id(struct point32 *key, const struct node_id *id) struct pubkey k; if (!pubkey_from_node_id(&k, id)) return false; - return secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, &key->pubkey, - NULL, &k.pubkey) == 1; + key->pubkey = k.pubkey; + return true; } /* It's valid if we can convert to a real pubkey. */ diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index 9b082f847..800be2ec9 100644 --- a/devtools/bolt12-cli.c +++ b/devtools/bolt12-cli.c @@ -318,11 +318,7 @@ static bool print_signature(const char *messagename, merkle_tlv(fields, &m); sighash_from_merkle(messagename, fieldname, &m, &shash); - if (secp256k1_schnorrsig_verify(secp256k1_ctx, - sig->u8, - shash.u.u8, - sizeof(shash.u.u8), - &node_id->pubkey) != 1) { + if (!check_schnorr_sig(&shash, &node_id->pubkey, sig)) { fprintf(stderr, "%s: INVALID\n", fieldname); return false; } diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index aedb6021f..4fca594ba 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -238,11 +238,11 @@ static void node_schnorrkey(secp256k1_keypair *node_keypair, "Failed to derive keypair"); if (node_id32) { - if (secp256k1_keypair_xonly_pub(secp256k1_ctx, - &node_id32->pubkey, - NULL, node_keypair) != 1) + if (secp256k1_keypair_pub(secp256k1_ctx, + &node_id32->pubkey, + node_keypair) != 1) hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed to derive xonly pub"); + "Failed to derive keypair pub"); } } @@ -638,9 +638,9 @@ static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in) struct point32 bolt12; struct sha256 tweak; - if (secp256k1_keypair_xonly_pub(secp256k1_ctx, - &bolt12.pubkey, NULL, - &secretstuff.bolt12) != 1) + if (secp256k1_keypair_pub(secp256k1_ctx, + &bolt12.pubkey, + &secretstuff.bolt12) != 1) hsmd_status_failed( STATUS_FAIL_INTERNAL_ERROR, "Could not derive bolt12 public key."); @@ -1772,8 +1772,8 @@ u8 *hsmd_init(struct secret hsm_secret, node_id_from_pubkey(&node_id, &key); /* We also give it the base key for bolt12 payerids */ - if (secp256k1_keypair_xonly_pub(secp256k1_ctx, &bolt12.pubkey, NULL, - &secretstuff.bolt12) != 1) + if (secp256k1_keypair_pub(secp256k1_ctx, &bolt12.pubkey, + &secretstuff.bolt12) != 1) hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could derive bolt12 public key."); diff --git a/lightningd/offer.c b/lightningd/offer.c index bd54cc465..b66a4184c 100644 --- a/lightningd/offer.c +++ b/lightningd/offer.c @@ -75,8 +75,7 @@ static void hsm_sign_b12(struct lightningd *ld, /* Now we sanity-check! */ sighash_from_merkle(messagename, fieldname, merkle, &sighash); - if (secp256k1_schnorrsig_verify(secp256k1_ctx, sig->u8, - sighash.u.u8, sizeof(sighash.u.u8), &key->pubkey) != 1) + if (!check_schnorr_sig(&sighash, &key->pubkey, sig)) fatal("HSM gave bad signature %s for pubkey %s", type_to_string(tmpctx, struct bip340sig, sig), type_to_string(tmpctx, struct point32, key)); @@ -397,21 +396,14 @@ static bool payer_key(struct lightningd *ld, struct point32 *key) { struct sha256 tweakhash; - secp256k1_pubkey tweaked; payer_key_tweak(&ld->bolt12_base, public_tweak, public_tweak_len, &tweakhash); - /* Tweaking gives a not-x-only pubkey, must then convert. */ - if (secp256k1_xonly_pubkey_tweak_add(secp256k1_ctx, - &tweaked, - &ld->bolt12_base.pubkey, - tweakhash.u.u8) != 1) - return false; - - return secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, - &key->pubkey, - NULL, &tweaked) == 1; + key->pubkey = ld->bolt12_base.pubkey; + return secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, + &key->pubkey, + tweakhash.u.u8) == 1; } static struct command_result *json_createinvoicerequest(struct command *cmd, diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 8c587d60d..b7682efff 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -217,8 +217,7 @@ static struct command_result *handle_invreq_response(struct command *cmd, sighash_from_merkle("invoice", "signature", &merkle, &sighash); if (!inv->signature - || secp256k1_schnorrsig_verify(secp256k1_ctx, inv->signature->u8, - sighash.u.u8, sizeof(sighash.u.u8), &inv->node_id->pubkey) != 1) { + || !check_schnorr_sig(&sighash, &inv->node_id->pubkey, inv->signature)) { badfield = "signature"; goto badinv; } @@ -576,11 +575,13 @@ static void node_id_from_point32(struct node_id *nid, const struct point32 *node32_id, enum nodeid_parity parity) { + struct pubkey pk; assert(parity == SECP256K1_TAG_PUBKEY_EVEN || parity == SECP256K1_TAG_PUBKEY_ODD); + + pk.pubkey = node32_id->pubkey; + node_id_from_pubkey(nid, &pk); nid->k[0] = parity; - secp256k1_xonly_pubkey_serialize(secp256k1_ctx, nid->k+1, - &node32_id->pubkey); } /* Create path to node which can carry onion messages (including @@ -1075,9 +1076,9 @@ force_payer_secret(struct command *cmd, invreq->payer_key = tal(invreq, struct point32); /* Docs say this only happens if arguments are invalid! */ - if (secp256k1_keypair_xonly_pub(secp256k1_ctx, - &invreq->payer_key->pubkey, NULL, - &kp) != 1) + if (secp256k1_keypair_pub(secp256k1_ctx, + &invreq->payer_key->pubkey, + &kp) != 1) plugin_err(cmd->plugin, "secp256k1_keypair_pub failed on %s?", type_to_string(tmpctx, struct secret, payer_secret)); @@ -1585,13 +1586,7 @@ static struct command_result *json_sendinvoice(struct command *cmd, * - MUST set `description` the same as the offer. */ sent->inv->node_id = tal(sent->inv, struct point32); - - /* This only fails if pubkey is invalid. */ - if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, - &sent->inv->node_id->pubkey, - NULL, - &local_id.pubkey)) - abort(); + sent->inv->node_id->pubkey = local_id.pubkey; sent->inv->description = tal_dup_talarr(sent->inv, char, sent->offer->description); @@ -1754,12 +1749,11 @@ static struct command_result *json_rawrequest(struct command *cmd, NULL)) return command_param_failed(); - /* Skip over 02/03 in node_id */ - if (!secp256k1_xonly_pubkey_parse(secp256k1_ctx, - &node_id32.pubkey, - node_id->k + 1)) + if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &node_id32.pubkey, + node_id->k, sizeof(node_id->k))) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Invalid nodeid"); + /* This is how long we'll wait for a reply for. */ sent->wait_timeout = *timeout; sent->cmd = cmd; diff --git a/plugins/offers.c b/plugins/offers.c index cfe3309cf..6cce43f80 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -926,9 +926,7 @@ static const char *init(struct plugin *p, rpc_scan(p, "getinfo", take(json_out_obj(NULL, NULL, NULL)), "{id:%}", JSON_SCAN(json_to_pubkey, &k)); - if (secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, &id.pubkey, - NULL, &k.pubkey) != 1) - abort(); + id.pubkey = k.pubkey; rpc_scan(p, "listconfigs", take(json_out_obj(NULL, NULL, NULL)), diff --git a/plugins/offers_inv_hook.c b/plugins/offers_inv_hook.c index 680307bee..a4f151f44 100644 --- a/plugins/offers_inv_hook.c +++ b/plugins/offers_inv_hook.c @@ -382,11 +382,8 @@ struct command_result *handle_invoice(struct command *cmd, merkle_tlv(inv->inv->fields, &m); sighash_from_merkle("invoice", "signature", &m, &shash); - if (secp256k1_schnorrsig_verify(secp256k1_ctx, - inv->inv->signature->u8, - shash.u.u8, - sizeof(shash.u.u8), - &inv->inv->node_id->pubkey) != 1) { + if (!check_schnorr_sig(&shash, &inv->inv->node_id->pubkey, + inv->inv->signature)) { return fail_inv(cmd, inv, "Bad signature"); } diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index 17eb2c688..b59586d9d 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -432,11 +432,7 @@ static bool check_payer_sig(struct command *cmd, merkle_tlv(invreq->fields, &merkle); sighash_from_merkle("invoice_request", "signature", &merkle, &sighash); - return secp256k1_schnorrsig_verify(secp256k1_ctx, - sig->u8, - sighash.u.u8, - sizeof(sighash.u.u8), - &payer_key->pubkey) == 1; + return check_schnorr_sig(&sighash, &payer_key->pubkey, sig); } static struct command_result *invreq_amount_by_quantity(struct command *cmd,