From e9cc8644b6a927a7a79c0a93f73c1b7acb3532e4 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Wed, 21 Apr 2021 20:45:12 +0200 Subject: [PATCH] libhsmd: Migrate handle_get_output_scriptpubkey --- hsmd/hsmd.c | 29 +--------------------- hsmd/libhsmd.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 29 deletions(-) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 7988ebcd1..d7125bf7c 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -1557,31 +1557,6 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, take(towire_hsmd_sign_withdrawal_reply(NULL, psbt))); } -static struct io_plan *handle_get_output_scriptpubkey(struct io_conn *conn, - struct client *c, - const u8 *msg_in) -{ - struct pubkey pubkey; - struct privkey privkey; - struct unilateral_close_info info; - u8 *scriptPubkey; - - info.commitment_point = NULL; - if (!fromwire_hsmd_get_output_scriptpubkey(tmpctx, msg_in, - &info.channel_id, - &info.peer_id, - &info.commitment_point)) - return bad_req(conn, c, msg_in); - - hsm_unilateral_close_privkey(&privkey, &info); - pubkey_from_privkey(&privkey, &pubkey); - scriptPubkey = scriptpubkey_p2wpkh(tmpctx, &pubkey); - - return req_reply(conn, c, - take(towire_hsmd_get_output_scriptpubkey_reply(NULL, - scriptPubkey))); -} - /*~ It's optional for nodes to send node_announcement, but it lets us set our * favourite color and cool alias! Plus other minor details like how to * connect to us. */ @@ -1721,9 +1696,6 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_CLIENT_HSMFD: return pass_client_hsmfd(conn, c, c->msg_in); - case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: - return handle_get_output_scriptpubkey(conn, c, c->msg_in); - case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ: return handle_cannouncement_sig(conn, c, c->msg_in); @@ -1770,6 +1742,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_SIGN_BOLT12: case WIRE_HSMD_ECDH_REQ: case WIRE_HSMD_CHECK_FUTURE_SECRET: + case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: /* Hand off to libhsmd for processing */ return req_reply(conn, c, take(hsmd_handle_client_message( diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 8d09ad0e9..929d11ec2 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -1,6 +1,8 @@ +#include #include #include #include +#include #include #include @@ -258,6 +260,45 @@ static void get_channel_seed(const struct node_id *peer_id, u64 dbid, info, strlen(info)); } +/*~ For almost every wallet tx we use the BIP32 seed, but not for onchain + * unilateral closes from a peer: they (may) have an output to us using a + * public key based on the channel basepoints. It's a bit spammy to spend + * those immediately just to make the wallet simpler, and we didn't appreciate + * the problem when we designed the protocol for commitment transaction keys. + * + * So we store just enough about the channel it came from (which may be + * long-gone) to regenerate the keys here. That has the added advantage that + * the secrets themselves stay within the HSM. */ +static void hsm_unilateral_close_privkey(struct privkey *dst, + struct unilateral_close_info *info) +{ + struct secret channel_seed; + struct basepoints basepoints; + struct secrets secrets; + + get_channel_seed(&info->peer_id, info->channel_id, &channel_seed); + derive_basepoints(&channel_seed, NULL, &basepoints, &secrets, NULL); + + /* BOLT #3: + * + * If `option_static_remotekey` or `option_anchor_outputs` is + * negotiated, the `remotepubkey` is simply the remote node's + * `payment_basepoint`, otherwise it is calculated as above using the + * remote node's `payment_basepoint`. + */ + /* In our UTXO representation, this is indicated by a NULL + * commitment_point. */ + if (!info->commitment_point) + dst->secret = secrets.payment_basepoint_secret; + else if (!derive_simple_privkey(&secrets.payment_basepoint_secret, + &basepoints.payment, + info->commitment_point, + dst)) { + hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Deriving unilateral_close_privkey"); + } +} + /*~ lightningd asks us to sign a message. I tweeted the spec * in https://twitter.com/rusty_twit/status/1182102005914800128: * @@ -495,6 +536,29 @@ static u8 *handle_check_future_secret(struct hsmd_client *c, const u8 *msg_in) NULL, secret_eq_consttime(&secret, &suggested)); } +static u8 *handle_get_output_scriptpubkey(struct hsmd_client *c, + const u8 *msg_in) +{ + struct pubkey pubkey; + struct privkey privkey; + struct unilateral_close_info info; + u8 *scriptPubkey; + + info.commitment_point = NULL; + if (!fromwire_hsmd_get_output_scriptpubkey(tmpctx, msg_in, + &info.channel_id, + &info.peer_id, + &info.commitment_point)) + return hsmd_status_malformed_request(c, msg_in); + + hsm_unilateral_close_privkey(&privkey, &info); + pubkey_from_privkey(&privkey, &pubkey); + scriptPubkey = scriptpubkey_p2wpkh(tmpctx, &pubkey); + + return towire_hsmd_get_output_scriptpubkey_reply(NULL, + scriptPubkey); +} + u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, const u8 *msg) { @@ -521,7 +585,6 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, switch (t) { case WIRE_HSMD_INIT: case WIRE_HSMD_CLIENT_HSMFD: - case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ: case WIRE_HSMD_CUPDATE_SIG_REQ: case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ: @@ -538,6 +601,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, /* Not implemented yet. Should not have been passed here yet. */ return hsmd_status_bad_request_fmt(client, msg, "Not implemented yet."); + case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: + return handle_get_output_scriptpubkey(client, msg); case WIRE_HSMD_CHECK_FUTURE_SECRET: return handle_check_future_secret(client, msg); case WIRE_HSMD_ECDH_REQ: