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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-10-17 11:05:31 +10:30
parent 987adb9718
commit bed905a394
14 changed files with 76 additions and 94 deletions

View File

@@ -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);

View File

@@ -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) */

View File

@@ -1,4 +1,5 @@
#include "config.h"
#include <assert.h>
#include <bitcoin/chainparams.h>
#include <ccan/tal/str/str.h>
#include <common/bech32_util.h>
@@ -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,

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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. */

View File

@@ -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;
}

View File

@@ -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.");

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)),

View File

@@ -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");
}

View File

@@ -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,