Skip to content

Commit 93f9334

Browse files
committed
Add derivations for all types from BIP86 base
1 parent 8114f26 commit 93f9334

15 files changed

Lines changed: 158 additions & 259 deletions

File tree

bitcoin/tx.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,6 @@ size_t bitcoin_tx_input_witness_weight(enum utxotype utxotype)
940940
/* In practice, these predate anchors, so: */
941941
return 1 + 1 + bitcoin_tx_input_sig_weight();
942942
case UTXO_P2TR:
943-
case UTXO_P2TR_BIP86:
944943
return 1 + 64;
945944
}
946945
abort();

bitcoin/tx.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ enum utxotype {
5757
UTXO_P2WSH_FROM_CLOSE = 3,
5858
/* "p2tr" addresses. */
5959
UTXO_P2TR = 4,
60-
/* "bip86" addresses (P2TR with BIP86 derivation). */
61-
UTXO_P2TR_BIP86 = 5,
6260
};
6361

6462
struct bitcoin_tx_output *new_tx_output(const tal_t *ctx,

common/utxo.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ const char *utxotype_to_str(enum utxotype utxotype)
4747
return "p2wsh_from_close";
4848
case UTXO_P2TR:
4949
return "p2tr";
50-
case UTXO_P2TR_BIP86:
51-
return "p2tr_bip86";
5250
}
5351
abort();
5452
}

contrib/msggen/msggen/schema.json

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25994,13 +25994,12 @@
2599425994
"addresstype": {
2599525995
"type": "string",
2599625996
"description": [
25997-
"It specifies the type of address wanted; currently *bech32* (e.g. `tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg` on bitcoin testnet or `bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej` on bitcoin mainnet), *p2tr* taproot addresses, or *bip86* for BIP86-derived taproot addresses. The special value *all* generates all known address types for the same underlying key."
25997+
"It specifies the type of address wanted; currently *bech32* (e.g. `tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg` on bitcoin testnet or `bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej` on bitcoin mainnet) or *p2tr* taproot addresses. For wallets created from a mnemonic, addresses are derived using BIP86 derivation. The special value *all* generates both address types for the same underlying key."
2599825998
],
2599925999
"default": "*bech32* address",
2600026000
"enum": [
2600126001
"bech32",
2600226002
"p2tr",
26003-
"bip86",
2600426003
"all"
2600526004
]
2600626005
}
@@ -26014,7 +26013,7 @@
2601426013
"added": "v23.08",
2601526014
"type": "string",
2601626015
"description": [
26017-
"The taproot address (returned for both 'p2tr' and 'bip86' addresstype)."
26016+
"The taproot address (returned for 'p2tr' addresstype)."
2601826017
]
2601926018
},
2602026019
"bech32": {
@@ -26062,18 +26061,6 @@
2606226061
"response": {
2606326062
"p2tr": "bcrt1p2gppccw6ywewmg74qqxxmqfdpjds3rpr0mf22y9tm9xcc0muggwsea9nkf"
2606426063
}
26065-
},
26066-
{
26067-
"request": {
26068-
"id": "example:newaddr#3",
26069-
"method": "newaddr",
26070-
"params": {
26071-
"addresstype": "bip86"
26072-
}
26073-
},
26074-
"response": {
26075-
"p2tr": "bcrt1p2gppccw6ywewmg74qqxxmqfdpjds3rpr0mf22y9tm9xcc0muggwsea9nkf"
26076-
}
2607726064
}
2607826065
]
2607926066
},

doc/schemas/newaddr.json

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717
"addresstype": {
1818
"type": "string",
1919
"description": [
20-
"It specifies the type of address wanted; currently *bech32* (e.g. `tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg` on bitcoin testnet or `bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej` on bitcoin mainnet), *p2tr* taproot addresses, or *bip86* for BIP86-derived taproot addresses. The special value *all* generates all known address types for the same underlying key."
20+
"It specifies the type of address wanted; currently *bech32* (e.g. `tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg` on bitcoin testnet or `bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej` on bitcoin mainnet) or *p2tr* taproot addresses. For wallets created from a mnemonic, addresses are derived using BIP86 derivation. The special value *all* generates both address types for the same underlying key."
2121
],
2222
"default": "*bech32* address",
2323
"enum": [
2424
"bech32",
2525
"p2tr",
26-
"bip86",
2726
"all"
2827
]
2928
}
@@ -37,7 +36,7 @@
3736
"added": "v23.08",
3837
"type": "string",
3938
"description": [
40-
"The taproot address (returned for both 'p2tr' and 'bip86' addresstype)."
39+
"The taproot address (returned for 'p2tr' addresstype)."
4140
]
4241
},
4342
"bech32": {
@@ -85,18 +84,6 @@
8584
"response": {
8685
"p2tr": "bcrt1p2gppccw6ywewmg74qqxxmqfdpjds3rpr0mf22y9tm9xcc0muggwsea9nkf"
8786
}
88-
},
89-
{
90-
"request": {
91-
"id": "example:newaddr#3",
92-
"method": "newaddr",
93-
"params": {
94-
"addresstype": "bip86"
95-
}
96-
},
97-
"response": {
98-
"p2tr": "bcrt1p2gppccw6ywewmg74qqxxmqfdpjds3rpr0mf22y9tm9xcc0muggwsea9nkf"
99-
}
10087
}
10188
]
10289
}

hsmd/hsmd.c

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,12 @@ static void create_hsm(int fd, const char *passphrase)
309309
char *mnemonic = NULL;
310310
struct sha256 seed_hash;
311311

312-
status_debug("HSM: Starting create_hsm with passphrase=%s", passphrase ? "provided" : "none");
313312

314313
/* Initialize wally tal context for libwally operations */
315314

316-
status_debug("HSM: Initialized wally tal context");
317315

318316
/* Generate random entropy for new mnemonic */
319317
randombytes_buf(entropy, sizeof(entropy));
320-
status_debug("HSM: Generated random entropy");
321318

322319

323320
/* Generate mnemonic from entropy */
@@ -330,7 +327,6 @@ static void create_hsm(int fd, const char *passphrase)
330327
hsmd_send_init_reply_failure(HSM_SECRET_ERR_SEED_DERIVATION_FAILED, STATUS_FAIL_INTERNAL_ERROR,
331328
"Failed to generate mnemonic from entropy");
332329
}
333-
status_debug("HSM: Generated mnemonic from entropy");
334330

335331
if (!mnemonic) {
336332
unlink_noerr("hsm_secret");
@@ -344,7 +340,6 @@ static void create_hsm(int fd, const char *passphrase)
344340
hsmd_send_init_reply_failure(HSM_SECRET_ERR_SEED_DERIVATION_FAILED, STATUS_FAIL_INTERNAL_ERROR,
345341
"Failed to derive seed hash from mnemonic");
346342
}
347-
status_debug("HSM: Derived seed hash from mnemonic");
348343

349344
/* Create hsm_secret format: seed_hash (32 bytes) + mnemonic */
350345
hsm_secret_len = PASSPHRASE_HASH_LEN + strlen(mnemonic);
@@ -354,7 +349,6 @@ static void create_hsm(int fd, const char *passphrase)
354349
memcpy(hsm_secret_data, &seed_hash, PASSPHRASE_HASH_LEN);
355350
/* Copy mnemonic after seed hash */
356351
memcpy(hsm_secret_data + PASSPHRASE_HASH_LEN, mnemonic, strlen(mnemonic));
357-
status_debug("HSM: Created hsm_secret data structure");
358352

359353
/* Derive the actual secret from mnemonic + passphrase for our global hsm_secret */
360354
u8 bip32_seed[BIP39_SEED_LEN_512];
@@ -368,7 +362,6 @@ static void create_hsm(int fd, const char *passphrase)
368362
hsmd_send_init_reply_failure(HSM_SECRET_ERR_SEED_DERIVATION_FAILED, STATUS_FAIL_INTERNAL_ERROR,
369363
"Failed to derive seed from mnemonic");
370364
}
371-
status_debug("HSM: Derived BIP32 seed from mnemonic");
372365

373366
/* Store the full BIP32 seed */
374367
hsm_secret.secret_data = tal_dup_arr(tmpctx, u8, bip32_seed, bip32_seed_len, 0);
@@ -383,7 +376,6 @@ static void create_hsm(int fd, const char *passphrase)
383376
status_failed(STATUS_FAIL_INTERNAL_ERROR,
384377
"writing: %s", strerror(errno));
385378
}
386-
status_debug("HSM: Successfully wrote hsm_secret to file");
387379
}
388380

389381
/*~ We store our root secret in a "hsm_secret" file (like all of Core Lightning,
@@ -400,14 +392,12 @@ static void maybe_create_new_hsm(const char *passphrase)
400392
if (fd < 0) {
401393
/* If this is not the first time we've run, it will exist. */
402394
if (errno == EEXIST) {
403-
status_debug("HSM: hsm_secret file already exists, skipping creation");
404395
return;
405396
}
406397
status_failed(STATUS_FAIL_INTERNAL_ERROR,
407398
"creating: %s", strerror(errno));
408399
}
409400

410-
status_debug("HSM: Creating new hsm_secret file");
411401

412402
/*~ Store the seed in clear. New hsm_secret files will use mnemonic format
413403
* with passphrases, not encrypted 32-byte secrets. */
@@ -472,7 +462,6 @@ static void load_hsm(const char *passphrase)
472462
passphrase, &err);
473463
tal_wally_end(tmpctx);
474464
if (!hsms) {
475-
status_debug("HSM: Failed to load hsm_secret: %s", hsm_secret_error_str(err));
476465
hsmd_send_init_reply_failure(err, STATUS_FAIL_INTERNAL_ERROR,
477466
"Failed to load hsm_secret: %s", hsm_secret_error_str(err));
478467
}
@@ -490,6 +479,7 @@ static void load_hsm(const char *passphrase)
490479
if (hsms->mnemonic) {
491480
hsm_secret.mnemonic = tal_strdup(NULL, hsms->mnemonic);
492481
}
482+
493483
}
494484

495485
/*~ We have a pre-init call in developer mode, to set dev flags */
@@ -512,8 +502,6 @@ static struct io_plan *preinit_hsm(struct io_conn *conn,
512502
if (tlv->warn_on_overgrind)
513503
dev_warn_on_overgrind = *tlv->warn_on_overgrind;
514504

515-
status_debug("preinit: dev_fail_preapprove = %u, dev_no_preapprove_check = %u, dev_warn_on_overgrind = %u",
516-
dev_fail_preapprove, dev_no_preapprove_check, dev_warn_on_overgrind);
517505
/* We don't send a reply, just read next */
518506
return client_read_next(conn, c);
519507
}
@@ -591,7 +579,7 @@ static struct io_plan *init_hsm(struct io_conn *conn,
591579
/* This was tallocated off NULL, and memleak complains if we don't free it */
592580
tal_free(tlvs);
593581
return req_reply(conn, c, hsmd_init(hsm_secret.secret_data, hsm_secret.secret_len, hsmd_mutual_version,
594-
bip32_key_version));
582+
bip32_key_version, hsm_secret.type));
595583
}
596584

597585
/*~ Since we process requests then service them in strict order, and because
@@ -645,7 +633,6 @@ static struct io_plan *pass_client_hsmfd(struct io_conn *conn,
645633
status_failed(STATUS_FAIL_INTERNAL_ERROR, "creating fds: %s",
646634
strerror(errno));
647635

648-
status_debug("new_client: %"PRIu64, dbid);
649636
new_client(c, c->chainparams, &id, dbid, capabilities, fds[0]);
650637

651638
/*~ We stash this in a global, because we need to get both the fd and

hsmd/hsmd_wire.csv

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ msgdata,hsmd_init_reply_v4,hsm_capabilities,u32,num_hsm_capabilities
4646
msgdata,hsmd_init_reply_v4,node_id,node_id,
4747
msgdata,hsmd_init_reply_v4,bip32,ext_key,
4848
msgdata,hsmd_init_reply_v4,bolt12,pubkey,
49+
msgdata,hsmd_init_reply_v4,tlvs,hsmd_init_reply_v4_tlvs,
50+
# TLV to indicate HSM secret type
51+
tlvtype,hsmd_init_reply_v4_tlvs,hsm_secret_type,1
52+
tlvdata,hsmd_init_reply_v4_tlvs,hsm_secret_type,hsm_type,u8,
4953

5054
# HSM initialization failure response
5155
msgtype,hsmd_init_reply_failure,115

hsmd/libhsmd.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
23872387
}
23882388

23892389
u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
2390-
struct bip32_key_version bip32_key_version)
2390+
struct bip32_key_version bip32_key_version, u8 hsm_secret_type)
23912391
{
23922392
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
23932393
struct pubkey key, bolt12;
@@ -2546,10 +2546,15 @@ u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
25462546
* And version is 4: we offer limited compatibility (or at least,
25472547
* incompatibility detection) with alternate implementations.
25482548
*/
2549+
/* Create TLV with HSM secret type */
2550+
struct tlv_hsmd_init_reply_v4_tlvs *tlvs = tlv_hsmd_init_reply_v4_tlvs_new(tmpctx);
2551+
tlvs->hsm_secret_type = tal(tlvs, u8);
2552+
*tlvs->hsm_secret_type = hsm_secret_type;
2553+
25492554
return take(towire_hsmd_init_reply_v4(
25502555
NULL, hsmd_version, caps,
25512556
&node_id, &secretstuff.bip32,
2552-
&bolt12));
2557+
&bolt12, tlvs));
25532558
}
25542559

25552560
/* BIP86 key derivation functions moved from hsmd.c */

hsmd/libhsmd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct hsmd_client {
4848
* `lightningd`.
4949
*/
5050
u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
51-
struct bip32_key_version bip32_key_version);
51+
struct bip32_key_version bip32_key_version, u8 hsm_secret_type);
5252

5353
struct hsmd_client *hsmd_client_new_main(const tal_t *ctx, u64 capabilities,
5454
void *extra);

lightningd/hsm_control.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,12 @@ struct ext_key *hsm_init(struct lightningd *ld)
151151
}
152152

153153
/* Check for successful init reply */
154+
struct tlv_hsmd_init_reply_v4_tlvs *tlvs;
154155
if (fromwire_hsmd_init_reply_v4(ld, msg,
155156
&hsm_version,
156157
&ld->hsm_capabilities,
157158
&ld->our_nodeid, bip32_base,
158-
&unused)) {
159+
&unused, &tlvs)) {
159160
/* nothing to do. */
160161
} else {
161162
/* Unknown message type */
@@ -193,20 +194,43 @@ struct ext_key *hsm_init(struct lightningd *ld)
193194
fatal("--experimental-splicing needs HSM capable of signing splices!");
194195
}
195196

196-
/* Try to get BIP86 base key from HSM (works only for mnemonic secrets) */
197-
ld->bip86_base = tal(ld, struct ext_key);
198-
msg = towire_hsmd_derive_bip86_key(NULL, 0, false);
199-
const u8 *reply = hsm_sync_req(tmpctx, ld, take(msg));
200-
if (fromwire_hsmd_derive_bip86_key_reply(reply, ld->bip86_base)) {
201-
/* BIP86 derivation succeeded - we have a mnemonic-based secret */
202-
log_info(ld->log, "Using BIP86 for new addresses, BIP32 for channels (mnemonic HSM secret)");
203-
/* Keep bip32_base for channel operations, database, etc. */
197+
/* Check if we have a mnemonic-based HSM secret from TLV */
198+
bool is_mnemonic_secret = false;
199+
if (tlvs && tlvs->hsm_secret_type) {
200+
u8 secret_type = *tlvs->hsm_secret_type;
201+
log_info(ld->log, "DEBUG: HSM secret type from TLV: %u", secret_type);
202+
is_mnemonic_secret = (secret_type == 2 || secret_type == 3); /* HSM_SECRET_MNEMONIC_NO_PASS or HSM_SECRET_MNEMONIC_WITH_PASS */
204203
} else {
205-
/* BIP86 derivation failed - we have a legacy secret */
204+
log_info(ld->log, "DEBUG: No HSM secret type TLV found, assuming legacy secret");
205+
}
206+
207+
if (is_mnemonic_secret) {
208+
/* Try to get BIP86 base key from HSM (works only for mnemonic secrets) */
209+
ld->bip86_base = tal(ld, struct ext_key);
210+
msg = towire_hsmd_derive_bip86_key(NULL, 0, false);
211+
const u8 *reply = hsm_sync_req(tmpctx, ld, take(msg));
212+
log_info(ld->log, "DEBUG: Attempting BIP86 derivation from HSM (mnemonic secret)");
213+
if (fromwire_hsmd_derive_bip86_key_reply(reply, ld->bip86_base)) {
214+
/* BIP86 derivation succeeded */
215+
log_info(ld->log, "DEBUG: BIP86 derivation succeeded, bip86_base is set");
216+
log_info(ld->log, "Using BIP86 for new addresses, BIP32 for channels (mnemonic HSM secret)");
217+
/* Keep bip32_base for channel operations, database, etc. */
218+
} else {
219+
/* BIP86 derivation failed unexpectedly */
220+
log_info(ld->log, "DEBUG: BIP86 derivation failed unexpectedly for mnemonic secret");
221+
ld->bip86_base = tal_free(ld->bip86_base);
222+
}
223+
} else {
224+
/* Legacy HSM secret - don't attempt BIP86 derivation */
225+
log_info(ld->log, "DEBUG: Legacy HSM secret detected, skipping BIP86 derivation");
206226
log_info(ld->log, "Using BIP32 derivation for all operations (legacy HSM secret)");
207-
ld->bip86_base = tal_free(ld->bip86_base);
208-
/* bip32_base was already set by the HSM init reply */
227+
ld->bip86_base = NULL;
209228
}
229+
log_info(ld->log, "DEBUG: Final bip86_base state: %s", ld->bip86_base ? "NOT NULL" : "NULL");
230+
231+
/* Free the TLV structure to prevent memory leak */
232+
if (tlvs)
233+
tal_free(tlvs);
210234

211235
/* This is equivalent to makesecret("bolt12-invoice-base") */
212236
msg = towire_hsmd_derive_secret(NULL, tal_dup_arr(tmpctx, u8,

0 commit comments

Comments
 (0)