From 86176e8d0a4922b3af31c3255d5239a9a3790ee6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 9 Dec 2020 14:27:50 +1030 Subject: [PATCH] hsmd: code to sign a bolt12 merkle root. Signed-off-by: Rusty Russell --- hsmd/Makefile | 4 +++ hsmd/hsmd.c | 73 ++++++++++++++++++++++++++++++++++++++++++++- hsmd/hsmd_wire.csv | 10 +++++++ hsmd/hsmd_wiregen.c | 53 +++++++++++++++++++++++++++++++- hsmd/hsmd_wiregen.h | 14 ++++++++- 5 files changed, 151 insertions(+), 3 deletions(-) diff --git a/hsmd/Makefile b/hsmd/Makefile index 772aacf88..397f732b1 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -42,6 +42,10 @@ HSMD_COMMON_OBJS := \ common/utxo.o \ common/version.o +ifeq ($(EXPERIMENTAL_FEATURES),1) +HSMD_COMMON_OBJS += common/bolt12_merkle.o +endif + lightningd/lightning_hsmd: $(HSMD_OBJS) $(HSMD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) -include hsmd/test/Makefile diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 34774e9c6..8f42a5164 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -25,6 +25,9 @@ #include #include #include +#if EXPERIMENTAL_FEATURES +#include +#endif #include #include #include @@ -43,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -313,7 +317,7 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) /* If caller specifies NULL, they don't want the results. */ if (node_privkey == NULL) node_privkey = &unused_s; - else if (node_id == NULL) + if (node_id == NULL) node_id = &unused_k; /*~ So, there is apparently a 1 in 2^127 chance that a random value is @@ -343,6 +347,33 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) #endif } +#if EXPERIMENTAL_FEATURES +/*~ This returns the secret and/or public x-only key for this node. */ +static void node_schnorrkey(secp256k1_keypair *node_keypair, + struct pubkey32 *node_id32) +{ + secp256k1_keypair unused_kp; + struct privkey node_privkey; + + if (!node_keypair) + node_keypair = &unused_kp; + + node_key(&node_privkey, NULL); + if (secp256k1_keypair_create(secp256k1_ctx, node_keypair, + node_privkey.secret.data) != 1) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to derive keypair"); + + if (node_id32) { + if (secp256k1_keypair_xonly_pub(secp256k1_ctx, + &node_id32->pubkey, + NULL, node_keypair) != 1) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to derive xonly pub"); + } +} +#endif + /*~ This secret is the basis for all per-channel secrets: the per-channel seeds * will be generated by mixing in the dbid and the peer node_id. */ static void hsm_channel_secret_base(struct secret *channel_seed_base) @@ -1790,6 +1821,36 @@ static struct io_plan *handle_sign_message(struct io_conn *conn, take(towire_hsmd_sign_message_reply(NULL, &rsig))); } +#if EXPERIMENTAL_FEATURES +/*~ lightningd asks us to sign a bolt12 (e.g. offer). */ +static struct io_plan *handle_sign_bolt12(struct io_conn *conn, + struct client *c, + const u8 *msg_in) +{ + char *messagename, *fieldname; + struct sha256 merkle, sha; + struct bip340sig sig; + secp256k1_keypair node_kp; + + if (!fromwire_hsmd_sign_bolt12(tmpctx, msg_in, + &messagename, &fieldname, &merkle)) + return bad_req(conn, c, msg_in); + + sighash_from_merkle(messagename, fieldname, &merkle, &sha); + + node_schnorrkey(&node_kp, NULL); + if (!secp256k1_schnorrsig_sign(secp256k1_ctx, sig.u8, + sha.u.u8, + &node_kp, + NULL, NULL)) { + return bad_req_fmt(conn, c, msg_in, "Failed to sign bolt12"); + } + + return req_reply(conn, c, + take(towire_hsmd_sign_bolt12_reply(NULL, &sig))); +} +#endif + #if DEVELOPER static struct io_plan *handle_memleak(struct io_conn *conn, struct client *c, @@ -1871,6 +1932,7 @@ static bool check_client_capabilities(struct client *client, case WIRE_HSMD_DEV_MEMLEAK: case WIRE_HSMD_SIGN_MESSAGE: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: + case WIRE_HSMD_SIGN_BOLT12: return (client->capabilities & HSM_CAP_MASTER) != 0; /*~ These are messages sent by the HSM so we should never receive them. */ @@ -1893,6 +1955,7 @@ static bool check_client_capabilities(struct client *client, case WIRE_HSMD_DEV_MEMLEAK_REPLY: case WIRE_HSMD_SIGN_MESSAGE_REPLY: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: + case WIRE_HSMD_SIGN_BOLT12_REPLY: break; } return false; @@ -1975,6 +2038,13 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_SIGN_MESSAGE: return handle_sign_message(conn, c, c->msg_in); + + case WIRE_HSMD_SIGN_BOLT12: +#if EXPERIMENTAL_FEATURES + return handle_sign_bolt12(conn, c, c->msg_in); +#else + break; +#endif #if DEVELOPER case WIRE_HSMD_DEV_MEMLEAK: return handle_memleak(conn, c, c->msg_in); @@ -1998,6 +2068,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_DEV_MEMLEAK_REPLY: case WIRE_HSMD_SIGN_MESSAGE_REPLY: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: + case WIRE_HSMD_SIGN_BOLT12_REPLY: break; } diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index 6b147043c..ee2381175 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -198,3 +198,13 @@ msgdata,hsmd_get_output_scriptpubkey,commitment_point,?pubkey, msgtype,hsmd_get_output_scriptpubkey_reply,124 msgdata,hsmd_get_output_scriptpubkey_reply,script_len,u16, msgdata,hsmd_get_output_scriptpubkey_reply,script,u8,script_len + +# Sign a bolt12-style merkle hash +msgtype,hsmd_sign_bolt12,25 +msgdata,hsmd_sign_bolt12,messagename,wirestring, +msgdata,hsmd_sign_bolt12,fieldname,wirestring, +msgdata,hsmd_sign_bolt12,merkleroot,sha256, + +msgtype,hsmd_sign_bolt12_reply,125 +msgdata,hsmd_sign_bolt12_reply,sig,bip340sig, + diff --git a/hsmd/hsmd_wiregen.c b/hsmd/hsmd_wiregen.c index aa58612a2..a5e47b70a 100644 --- a/hsmd/hsmd_wiregen.c +++ b/hsmd/hsmd_wiregen.c @@ -60,6 +60,8 @@ const char *hsmd_wire_name(int e) case WIRE_HSMD_SIGN_MESSAGE_REPLY: return "WIRE_HSMD_SIGN_MESSAGE_REPLY"; case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: return "WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY"; case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: return "WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY"; + case WIRE_HSMD_SIGN_BOLT12: return "WIRE_HSMD_SIGN_BOLT12"; + case WIRE_HSMD_SIGN_BOLT12_REPLY: return "WIRE_HSMD_SIGN_BOLT12_REPLY"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -108,6 +110,8 @@ bool hsmd_wire_is_defined(u16 type) case WIRE_HSMD_SIGN_MESSAGE_REPLY:; case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:; case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:; + case WIRE_HSMD_SIGN_BOLT12:; + case WIRE_HSMD_SIGN_BOLT12_REPLY:; return true; } return false; @@ -1214,4 +1218,51 @@ bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const void *p fromwire_u8_array(&cursor, &plen, *script, script_len); return cursor != NULL; } -// SHA256STAMP:02b3951c8bdb27997f5a30ebcf2e174cb99d6089d889b94da925fd674fca653f + +/* WIRE: HSMD_SIGN_BOLT12 */ +/* Sign a bolt12-style merkle hash */ +u8 *towire_hsmd_sign_bolt12(const tal_t *ctx, const wirestring *messagename, const wirestring *fieldname, const struct sha256 *merkleroot) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_HSMD_SIGN_BOLT12); + towire_wirestring(&p, messagename); + towire_wirestring(&p, fieldname); + towire_sha256(&p, merkleroot); + + return memcheck(p, tal_count(p)); +} +bool fromwire_hsmd_sign_bolt12(const tal_t *ctx, const void *p, wirestring **messagename, wirestring **fieldname, struct sha256 *merkleroot) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_BOLT12) + return false; + *messagename = fromwire_wirestring(ctx, &cursor, &plen); + *fieldname = fromwire_wirestring(ctx, &cursor, &plen); + fromwire_sha256(&cursor, &plen, merkleroot); + return cursor != NULL; +} + +/* WIRE: HSMD_SIGN_BOLT12_REPLY */ +u8 *towire_hsmd_sign_bolt12_reply(const tal_t *ctx, const struct bip340sig *sig) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_HSMD_SIGN_BOLT12_REPLY); + towire_bip340sig(&p, sig); + + return memcheck(p, tal_count(p)); +} +bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_BOLT12_REPLY) + return false; + fromwire_bip340sig(&cursor, &plen, sig); + return cursor != NULL; +} +// SHA256STAMP:cb033b99e13d9bdd06582a34132ba7cd311f4cf074298da1addcdad06b3fdf8f diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index a8ed4966d..17ec54d3e 100644 --- a/hsmd/hsmd_wiregen.h +++ b/hsmd/hsmd_wiregen.h @@ -76,6 +76,9 @@ enum hsmd_wire { /* lightningd needs to get a scriptPubkey for a utxo with closeinfo */ WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY = 24, WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY = 124, + /* Sign a bolt12-style merkle hash */ + WIRE_HSMD_SIGN_BOLT12 = 25, + WIRE_HSMD_SIGN_BOLT12_REPLY = 125, }; const char *hsmd_wire_name(int e); @@ -269,6 +272,15 @@ bool fromwire_hsmd_get_output_scriptpubkey(const tal_t *ctx, const void *p, u64 u8 *towire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const u8 *script); bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const void *p, u8 **script); +/* WIRE: HSMD_SIGN_BOLT12 */ +/* Sign a bolt12-style merkle hash */ +u8 *towire_hsmd_sign_bolt12(const tal_t *ctx, const wirestring *messagename, const wirestring *fieldname, const struct sha256 *merkleroot); +bool fromwire_hsmd_sign_bolt12(const tal_t *ctx, const void *p, wirestring **messagename, wirestring **fieldname, struct sha256 *merkleroot); + +/* WIRE: HSMD_SIGN_BOLT12_REPLY */ +u8 *towire_hsmd_sign_bolt12_reply(const tal_t *ctx, const struct bip340sig *sig); +bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig); + #endif /* LIGHTNING_HSMD_HSMD_WIREGEN_H */ -// SHA256STAMP:02b3951c8bdb27997f5a30ebcf2e174cb99d6089d889b94da925fd674fca653f +// SHA256STAMP:cb033b99e13d9bdd06582a34132ba7cd311f4cf074298da1addcdad06b3fdf8f