bolt12: change our payer_key calculation.

It was very tied to x-only keys; we could support it in a backwards
compatibility mode for a while, but getting refunds or proving old
pre-finalization invoices is not worth spending time on.

Changelog-EXPERIMENTAL: offers: old `payer_key` proofs won't work.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-10-17 11:06:41 +10:30
parent 4e39b3ff3d
commit 7745513c51
3 changed files with 29 additions and 38 deletions

View file

@ -221,8 +221,6 @@ 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.
*
* Since key used to be x-only, we don't hash first byte!
*/
void payer_key_tweak(const struct pubkey *bolt12,
const u8 *publictweak, size_t publictweaklen,
@ -234,7 +232,7 @@ void payer_key_tweak(const struct pubkey *bolt12,
pubkey_to_der(rawkey, bolt12);
sha256_init(&sha);
sha256_update(&sha, rawkey + 1, sizeof(rawkey) - 1);
sha256_update(&sha, rawkey, sizeof(rawkey));
sha256_update(&sha,
memcheck(publictweak, publictweaklen),
publictweaklen);

View file

@ -28,7 +28,7 @@ struct secret *dev_force_bip32_seed;
struct {
struct secret hsm_secret;
struct ext_key bip32;
secp256k1_keypair bolt12;
struct secret bolt12;
struct secret derived_secret;
} secretstuff;
@ -636,26 +636,29 @@ static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in)
node_schnorrkey(&kp, NULL);
} else {
/* If we're tweaking key, we use bolt12 key */
struct privkey tweakedkey;
struct pubkey bolt12;
struct sha256 tweak;
if (secp256k1_keypair_pub(secp256k1_ctx,
&bolt12.pubkey,
&secretstuff.bolt12) != 1)
hsmd_status_failed(
STATUS_FAIL_INTERNAL_ERROR,
"Could not derive bolt12 public key.");
if (secp256k1_ec_pubkey_create(secp256k1_ctx, &bolt12.pubkey,
secretstuff.bolt12.data) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could derive bolt12 public key.");
payer_key_tweak(&bolt12, publictweak, tal_bytelen(publictweak),
&tweak);
kp = secretstuff.bolt12;
tweakedkey.secret = secretstuff.bolt12;
if (secp256k1_ec_seckey_tweak_add(secp256k1_ctx,
tweakedkey.secret.data,
tweak.u.u8) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could tweak bolt12 key.");
if (secp256k1_keypair_xonly_tweak_add(secp256k1_ctx,
&kp,
tweak.u.u8) != 1) {
return hsmd_status_bad_request_fmt(
c, msg_in, "Failed to get tweak key");
}
if (secp256k1_keypair_create(secp256k1_ctx, &kp,
tweakedkey.secret.data) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed to derive bolt12 keypair");
}
if (!secp256k1_schnorrsig_sign32(secp256k1_ctx, sig.u8,
@ -1759,10 +1762,8 @@ u8 *hsmd_init(struct secret hsm_secret,
/* libwally says: The private key with prefix byte 0; remove it
* for libsecp256k1. */
if (secp256k1_keypair_create(secp256k1_ctx, &secretstuff.bolt12,
child_extkey.priv_key+1) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't derive bolt12 keypair");
memcpy(&secretstuff.bolt12, child_extkey.priv_key+1,
sizeof(secretstuff.bolt12));
/* Now we can consider ourselves initialized, and we won't get
* upset if we get a non-init message. */
@ -1773,19 +1774,11 @@ 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_pub(secp256k1_ctx, &bolt12.pubkey,
&secretstuff.bolt12) != 1)
if (secp256k1_ec_pubkey_create(secp256k1_ctx, &bolt12.pubkey,
secretstuff.bolt12.data) != 1)
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could derive bolt12 public key.");
/* For compatibility, we have to invert y-odd keys */
u8 raw[PUBKEY_CMPR_LEN];
pubkey_to_der(raw, &bolt12);
if (raw[0] == SECP256K1_TAG_PUBKEY_ODD) {
raw[0] = SECP256K1_TAG_PUBKEY_EVEN;
pubkey_from_der(raw, sizeof(raw), &bolt12);
}
/*~ We derive a secret for onion_message's self_id so we can tell
* if it used a path we created (i.e. do not leak our public id!) */
hkdf_sha256(&onion_reply_secret, sizeof(onion_reply_secret),

View file

@ -5329,13 +5329,13 @@ def test_payerkey(node_factory):
"""payerkey calculation should not change across releases!"""
nodes = node_factory.get_nodes(7)
expected_keys = ["ed648d8c53c73eb4ef97f3e9586ecfd86e2628037dd91e96ecdc469467dcc1b2",
"ee90e2adcf0e12c5dd1d802af792a4f4b18fd3926a9cc325ffe181bab1c48661",
"17b9ecb1870b5d3896e88247fcb592833fbee8abb5e89673d16560b0ed38f5c6",
"d37f723b611c15b7af394984aea84837d85371ba9eee95364b3c9f89a086f7bf",
"b33482c9753af9deb6df365cf834eccaab7afb24d080caaf87a57010f78f5817",
"f1d699068e3d276eddf9fc4caa0955604a34ee9b9b6529a1ec2eacebb82eb11e",
"4ef73851fe22604e9b7034f548bcb79583ec503983879c56963b9a40fc854758"]
expected_keys = ["294ec1cd3f100947fe859d71a42cb87932e36e7771abf2d50b02a7a92be8e4d5",
"6a4a3b6b0c694da6f14629ca5140713fc703591a6d8aae5c79ba9b5556fc5723",
"defd2b1f3004b0145351f469f34512c6fa4d02fe891a977bafdb34fe7b73ea48",
"eccb00c0a3c760465bb69a6297d7cfa5bcbd989d5a88e435bd8d6e4c723013cd",
"1b4bfa652f0df7498d734b0ca888b4e3b07f59e1a974ec7d4a9d6046e8e5ab92",
"fc91d60b061e517f9182e3e40ea14c27df520c51db204f1409ff50e5cf9a5e4d",
"a3bbda0137722ba62207b9d3e5e6cc2a11e58480f801892093e01383aacb7fb2"]
for n, k in zip(nodes, expected_keys):
b12 = n.rpc.createinvoicerequest('lnr1qvsqvgnwgcg35z6ee2h3yczraddm72xrfua9uve2rlrm9deu7xyfzrcyyrjjthf4rh99n7equvlrzrlalcacxj4y9hgzxc79yrntrth6mp3nkvssy5mac4pkfq2m3gq4ttajwh097s')['bolt12']