hsmd: create an hsm variant to sign a bolt12 invoice using a tweak on our key.

The current interface, if given a tweak, uses a *different secret key*
and tweaks it.  This was an early experiment: we will switch to using
a secret tweak for invoice_requests like we do for invoice path ids.

To make sure there's no funny business, *hsmd* hashes to form the
tweak (i.e. no zero tweaks!).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-08-01 09:33:35 +09:30
parent 09401e34b6
commit e8a38f111d
5 changed files with 84 additions and 0 deletions

View File

@ -26,6 +26,7 @@
* v5 with dev_preinit: b93e18534a468a4aa9f7015db42e9c363c32aeee5f9146b36dc953ebbdc3d33c
* v5 with preapprove_check: 0ed6dd4ea2c02b67c51b1420b3d07ab2227a4c06ce7e2942d946967687e9baf7
* v6 no secret from get_per_commitment_point: 0cad1790beb3473d64355f4cb4f64daa80c28c8a241998b7ef0223385d7ffff9
* v6 with sign_bolt12_2 (tweak using node id): 8fcb731279a10af3f95aeb8be1da6b2ced76a1984afa18c5f46a03515d70ea0e
*/
#define HSM_MIN_VERSION 5
#define HSM_MAX_VERSION 6

View File

@ -26,6 +26,7 @@ HSMD_COMMON_OBJS := \
common/base32.o \
common/bigsize.o \
common/bip32.o \
common/bolt12_id.o \
common/bolt12_merkle.o \
common/channel_id.o \
common/daemon.o \

View File

@ -691,6 +691,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SIGN_MESSAGE:
case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER:
case WIRE_HSMD_SIGN_BOLT12:
case WIRE_HSMD_SIGN_BOLT12_2:
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_KEYSEND:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
@ -746,6 +747,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SIGN_MESSAGE_REPLY:
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_SIGN_BOLT12_2_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:

View File

@ -378,6 +378,21 @@ msgdata,hsmd_sign_bolt12,publictweak,u8,publictweaklen
msgtype,hsmd_sign_bolt12_reply,125
msgdata,hsmd_sign_bolt12_reply,sig,bip340sig,
# Sign a bolt12-style merkle hash (modern)
msgtype,hsmd_sign_bolt12_2,41
msgdata,hsmd_sign_bolt12_2,messagename,wirestring,
msgdata,hsmd_sign_bolt12_2,fieldname,wirestring,
msgdata,hsmd_sign_bolt12_2,merkleroot,sha256,
# This is for signing with an alias (temporary key), used if *publictweak* not empty.
# derive_secret with info, then tweak privkey with SHA256(derived_secret || publictweak).
msgdata,hsmd_sign_bolt12_2,infolen,u16,
msgdata,hsmd_sign_bolt12_2,info,u8,infolen
msgdata,hsmd_sign_bolt12_2,publictweaklen,u16,
msgdata,hsmd_sign_bolt12_2,publictweak,u8,publictweaklen
msgtype,hsmd_sign_bolt12_2_reply,141
msgdata,hsmd_sign_bolt12_2_reply,sig,bip340sig,
# Sign an option_will_fund offer hash
msgtype,hsmd_sign_option_will_fund_offer,26
msgdata,hsmd_sign_option_will_fund_offer,funding_pubkey,pubkey,

Can't render this file because it contains an unexpected character in line 169 and column 43.

View File

@ -3,6 +3,7 @@
#include <ccan/array_size/array_size.h>
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
#include <ccan/tal/str/str.h>
#include <common/bolt12_id.h>
#include <common/bolt12_merkle.h>
#include <common/hash_u5.h>
#include <common/key_derive.h>
@ -136,6 +137,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_SIGN_MESSAGE:
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:
case WIRE_HSMD_SIGN_BOLT12:
case WIRE_HSMD_SIGN_BOLT12_2:
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_KEYSEND:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
@ -181,6 +183,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_SIGN_MESSAGE_REPLY:
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_SIGN_BOLT12_2_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
@ -783,6 +786,64 @@ static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in)
return towire_hsmd_sign_bolt12_reply(NULL, &sig);
}
/*~ lightningd asks us to sign a bolt12 (e.g. offer): modern version */
static u8 *handle_sign_bolt12_2(struct hsmd_client *c, const u8 *msg_in)
{
char *messagename, *fieldname;
struct sha256 merkle, sha;
struct bip340sig sig;
secp256k1_keypair kp;
u8 *info;
u8 *tweakmessage;
if (!fromwire_hsmd_sign_bolt12_2(tmpctx, msg_in,
&messagename, &fieldname, &merkle,
&info, &tweakmessage))
return hsmd_status_malformed_request(c, msg_in);
sighash_from_merkle(messagename, fieldname, &merkle, &sha);
if (tweakmessage) {
struct secret base_secret;
struct sha256 tweak;
struct privkey tweakedkey;
/* See handle_derive_secret: this gives a base secret. */
hkdf_sha256(&base_secret, sizeof(base_secret), NULL, 0,
&secretstuff.derived_secret,
sizeof(secretstuff.derived_secret),
info, tal_bytelen(info));
/* This is simply SHA256(secret || tweakmessage) */
bolt12_alias_tweak(&base_secret,
tweakmessage, tal_bytelen(tweakmessage),
&tweak);
node_key(&tweakedkey, NULL);
if (secp256k1_ec_seckey_tweak_add(secp256k1_ctx,
tweakedkey.secret.data,
tweak.u.u8) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Couldn't tweak key.");
if (secp256k1_keypair_create(secp256k1_ctx, &kp,
tweakedkey.secret.data) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed to derive tweaked keypair");
} else {
node_schnorrkey(&kp);
}
if (!secp256k1_schnorrsig_sign32(secp256k1_ctx, sig.u8,
sha.u.u8,
&kp,
NULL)) {
return hsmd_status_bad_request_fmt(c, msg_in,
"Failed to sign bolt12");
}
return towire_hsmd_sign_bolt12_2_reply(NULL, &sig);
}
/*~ lightningd asks us to approve an invoice. This stub implementation
* is overriden by fully validating signers that need to track invoice
* payments. */
@ -2075,6 +2136,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
return handle_sign_option_will_fund_offer(client, msg);
case WIRE_HSMD_SIGN_BOLT12:
return handle_sign_bolt12(client, msg);
case WIRE_HSMD_SIGN_BOLT12_2:
return handle_sign_bolt12_2(client, msg);
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
return handle_preapprove_invoice(client, msg);
@ -2167,6 +2230,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
case WIRE_HSMD_SIGN_MESSAGE_REPLY:
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_SIGN_BOLT12_2_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
@ -2197,6 +2261,7 @@ u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
WIRE_HSMD_CHECK_OUTPOINT,
WIRE_HSMD_FORGET_CHANNEL,
WIRE_HSMD_REVOKE_COMMITMENT_TX,
WIRE_HSMD_SIGN_BOLT12_2,
WIRE_HSMD_PREAPPROVE_INVOICE_CHECK,
WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK,
};