lightning-hsmtool: fix dumponchaindescriptors for mnemonic hsm_secrets.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: `lightning-hsmtool`: handle mnemonic hsm_secret files (nodes created >= v25.12).
This commit is contained in:
Rusty Russell
2026-01-13 22:52:03 +10:30
parent 9c6430c076
commit d2123a94a5
2 changed files with 51 additions and 18 deletions

View File

@@ -1651,7 +1651,10 @@ def test_hsmtool_all_commands_work_with_mnemonic_formats(node_factory):
(["getnodeid", hsm_path], "03653e90c1ce4660fd8505dd6d643356e93cfe202af109d382787639dd5890e87d"),
(["getsecret", hsm_path], "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"),
(["makerune", hsm_path], "6VkrWMI2hm2a2UTkg-EyUrrBJN0RcuPB80I1pCVkTD89MA=="),
(["dumponchaindescriptors", hsm_path], "wpkh(xpub661MyMwAqRbcG9kjo3mdWQuSDbtdJzsd3K2mvifyeUMF3GhLcBAfELqjuxCvxUkYqQVe6rJ9SzmpipoUedb5MD79MJaLL8RME2A3J3Fw6Zd/0/0/*)#2jtshmk0\nsh(wpkh(xpub661MyMwAqRbcG9kjo3mdWQuSDbtdJzsd3K2mvifyeUMF3GhLcBAfELqjuxCvxUkYqQVe6rJ9SzmpipoUedb5MD79MJaLL8RME2A3J3Fw6Zd/0/0/*))#u6am4was\ntr(xpub661MyMwAqRbcG9kjo3mdWQuSDbtdJzsd3K2mvifyeUMF3GhLcBAfELqjuxCvxUkYqQVe6rJ9SzmpipoUedb5MD79MJaLL8RME2A3J3Fw6Zd/0/0/*)#v9hf4756"),
(["dumponchaindescriptors", hsm_path],
"wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#hjszq0wk\n"
"sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*))#u0t3u3xz\n"
"tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#8e7pq23w"),
]
for cmd_args, expected_output in test_commands:

View File

@@ -477,29 +477,60 @@ static void derive_to_remote(const struct unilateral_close_info *info, const cha
fmt_pubkey(tmpctx, info->commitment_point));
printf("privkey : %s\n", fmt_secret(tmpctx, &privkey.secret));
}
static void dumponchaindescriptors(const char *hsm_secret_path,
const u32 version, bool show_secrets)
{
struct secret hsm_secret;
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
u32 salt = 0;
struct ext_key master_extkey;
char *enc_xkey, *descriptor;
struct descriptor_checksum checksum;
struct hsm_secret *hsms = load_hsm_secret(tmpctx, hsm_secret_path);
/* Extract first 32 bytes for legacy compatibility */
memcpy(hsm_secret.data, hsms->secret_data, 32);
const char *path;
/* The root seed is derived from hsm_secret using hkdf.. */
do {
hkdf_sha256(bip32_seed, sizeof(bip32_seed),
&salt, sizeof(salt),
&hsm_secret, sizeof(hsm_secret),
"bip32 seed", strlen("bip32 seed"));
salt++;
/* ..Which is used to derive m/ */
} while (bip32_key_from_seed(bip32_seed, sizeof(bip32_seed),
version, 0, &master_extkey) != WALLY_OK);
/* For BIP 86, we derive from subkey: m/86'/0'/0' */
if (use_bip86_derivation(tal_bytelen(hsms->secret_data))) {
/* First create the master key from the seed */
struct ext_key master_key, bip86_base;
u32 base_path[3];
base_path[0] = 86 | 0x80000000; /* 86' */
base_path[1] = 0x80000000; /* 0' */
base_path[2] = 0x80000000; /* 0' */
if (bip32_key_from_seed(hsms->secret_data, tal_bytelen(hsms->secret_data),
version, 0, &master_key) != WALLY_OK) {
errx(ERROR_LIBWALLY,
"Failed to create master key from BIP32 seed");
}
/* Derive the BIP86 base key */
if (bip32_key_from_parent_path(&master_key, base_path, 3, BIP32_FLAG_KEY_PRIVATE, &bip86_base) != WALLY_OK) {
errx(ERROR_LIBWALLY,
"Failed to derive BIP86 base key");
}
master_extkey = bip86_base;
/* Remaining path is 0/ */
path = "0";
} else {
struct secret hsm_secret;
/* Extract first 32 bytes for legacy compatibility */
memcpy(hsm_secret.data, hsms->secret_data, 32);
/* The root seed is derived from hsm_secret using hkdf.. */
do {
hkdf_sha256(bip32_seed, sizeof(bip32_seed),
&salt, sizeof(salt),
&hsm_secret, sizeof(hsm_secret),
"bip32 seed", strlen("bip32 seed"));
salt++;
/* ..Which is used to derive m/ */
} while (bip32_key_from_seed(bip32_seed, sizeof(bip32_seed),
version, 0, &master_extkey) != WALLY_OK);
/* Remaining path is 0/0/ */
path = "0/0";
}
if (show_secrets) {
if (bip32_key_to_base58(&master_extkey, BIP32_FLAG_KEY_PRIVATE,
@@ -513,20 +544,19 @@ static void dumponchaindescriptors(const char *hsm_secret_path,
/* Now we format the descriptor strings (we only ever create P2TR, P2WPKH, and
* P2SH-P2WPKH outputs). */
descriptor = tal_fmt(NULL, "wpkh(%s/0/0/*)", enc_xkey);
descriptor = tal_fmt(NULL, "wpkh(%s/%s/*)", enc_xkey, path);
if (!descriptor_checksum(descriptor, strlen(descriptor), &checksum))
errx(ERROR_LIBWALLY, "Can't derive descriptor checksum for wpkh");
printf("%s#%s\n", descriptor, checksum.csum);
tal_free(descriptor);
descriptor = tal_fmt(NULL, "sh(wpkh(%s/0/0/*))", enc_xkey);
descriptor = tal_fmt(NULL, "sh(wpkh(%s/%s/*))", enc_xkey, path);
if (!descriptor_checksum(descriptor, strlen(descriptor), &checksum))
errx(ERROR_LIBWALLY, "Can't derive descriptor checksum for sh(wpkh)");
printf("%s#%s\n", descriptor, checksum.csum);
tal_free(descriptor);
descriptor = tal_fmt(NULL, "tr(%s/0/0/*)", enc_xkey);
descriptor = tal_fmt(NULL, "tr(%s/%s/*)", enc_xkey, path);
if (!descriptor_checksum(descriptor, strlen(descriptor), &checksum))
errx(ERROR_LIBWALLY, "Can't derive descriptor checksum for tr");
printf("%s#%s\n", descriptor, checksum.csum);