multi: make derivekey CLN compatible

This commit is contained in:
Oliver Gugger 2025-07-06 14:27:16 +02:00
parent 168d1cb348
commit 99724b6f2d
No known key found for this signature in database
GPG key ID: 8E4256593F177720
4 changed files with 90 additions and 19 deletions

View file

@ -484,7 +484,7 @@ Legend:
| [compactdb](doc/chantools_compactdb.md) | Run database compaction manually to reclaim space |
| [createwallet](doc/chantools_createwallet.md) | :pencil: Create a new lnd compatible wallet.db file from an existing seed or by generating a new one |
| [deletepayments](doc/chantools_deletepayments.md) | Remove ALL payments from a `channel.db` file to reduce size |
| [derivekey](doc/chantools_derivekey.md) | :pencil: Derive a single private/public key from `lnd`'s seed, use to test seed |
| [derivekey](doc/chantools_derivekey.md) | :pencil: (**CLN**) Derive a single private/public key from `lnd`'s seed, use to test seed |
| [doublespendinputs](doc/chantools_doublespendinputs.md) | :pencil: Tries to double spend the given inputs by deriving the private for the address and sweeping the funds to the given address |
| [dropchannelgraph](doc/chantools_dropchannelgraph.md) | ( :warning: ) Completely drop the channel graph from a `channel.db` to force re-sync (not recommended while channels are open!) |
| [dropgraphzombies](doc/chantools_dropgraphzombies.md) | Drop all zombie channels from a `channel.db` to force a graph re-sync |

View file

@ -1,10 +1,13 @@
package main
import (
"encoding/hex"
"errors"
"fmt"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/lightninglabs/chantools/cln"
"github.com/lightninglabs/chantools/lnd"
"github.com/spf13/cobra"
)
@ -27,6 +30,8 @@ type deriveKeyCommand struct {
Neuter bool
Identity bool
HsmSecret string
rootKey *rootKey
cmd *cobra.Command
}
@ -53,8 +58,14 @@ chantools derivekey --identity`,
"only public key(s)",
)
cc.cmd.Flags().BoolVar(
&cc.Identity, "identity", false, "derive the lnd "+
"identity_pubkey",
&cc.Identity, "identity", false, "derive the node's identity "+
"public key",
)
cc.cmd.Flags().StringVar(
&cc.HsmSecret, "hsm_secret", "", "the hex encoded HSM secret "+
"to use for deriving the multisig keys for a CLN "+
"node; obtain by running 'xxd -p -c32 "+
"~/.lightning/bitcoin/hsm_secret'",
)
cc.rootKey = newRootKey(cc.cmd, "decrypting the backup")
@ -63,6 +74,40 @@ chantools derivekey --identity`,
}
func (c *deriveKeyCommand) Execute(_ *cobra.Command, _ []string) error {
if c.HsmSecret != "" {
if c.Path != "" {
return errors.New("cannot specify --path with " +
"--hsm_secret, only identity key can be " +
"derived")
}
secretBytes, err := hex.DecodeString(c.HsmSecret)
if err != nil {
return fmt.Errorf("error decoding HSM secret: %w", err)
}
var hsmSecret [32]byte
copy(hsmSecret[:], secretBytes)
nodePubKey, _, err := cln.NodeKey(hsmSecret)
if err != nil {
return fmt.Errorf("error deriving node key from HSM: "+
"%w", err)
}
result := fmt.Sprintf(
"Node identity public key: %x",
nodePubKey.SerializeCompressed(),
)
fmt.Println(result)
// For the tests, also log as trace level which is disabled by
// default.
log.Tracef(result)
return nil
}
extendedKey, err := c.rootKey.read()
if err != nil {
return fmt.Errorf("error reading root key: %w", err)

View file

@ -99,8 +99,9 @@ func TestDeriveKeyXprv(t *testing.T) {
err := derive.Execute(nil, nil)
require.NoError(t, err)
h.assertLogContains("cQcdieZy2d1TAdCsa5MjmHJs2gdHcD7x22nDbhJyVTUa3Ax" +
"5KB3w")
h.assertLogContains(
"cQcdieZy2d1TAdCsa5MjmHJs2gdHcD7x22nDbhJyVTUa3Ax5KB3w",
)
}
func TestDeriveKeyXpub(t *testing.T) {
@ -120,8 +121,10 @@ func TestDeriveKeyXpub(t *testing.T) {
err := derive.Execute(nil, nil)
require.NoError(t, err)
h.assertLogContains("03dc8655d58bd4fd4326863fe34bd5cdddbefaa3b042571" +
"05eb1ab99aa05e01c2a")
h.assertLogContains(
"03dc8655d58bd4fd4326863fe34bd5cdddbefaa3b04257105eb1ab99aa05e" +
"01c2a",
)
}
func TestDeriveKeyXpubNoNeuter(t *testing.T) {
@ -140,6 +143,27 @@ func TestDeriveKeyXpubNoNeuter(t *testing.T) {
err := derive.Execute(nil, nil)
require.NoError(t, err)
h.assertLogContains("03dc8655d58bd4fd4326863fe34bd5cdddbefaa3b042571" +
"05eb1ab99aa05e01c2a")
h.assertLogContains(
"03dc8655d58bd4fd4326863fe34bd5cdddbefaa3b04257105eb1ab99aa05e" +
"01c2a",
)
}
func TestDeriveKeyHsmSecret(t *testing.T) {
h := newHarness(t)
// Derive a specific key from the serialized root key.
derive := &deriveKeyCommand{
Identity: true,
HsmSecret: "471a115fb8edd6281f883ac82509fb0f30707e590d895f683" +
"2d781f1639c07ff",
}
err := derive.Execute(nil, nil)
require.NoError(t, err)
h.assertLogContains(
"03508beb59d2ec4772cd7b143bbef0fdac204b240747e82bc5fe58bd0418" +
"4f35a3",
)
}

View file

@ -23,21 +23,23 @@ chantools derivekey --identity
### Options
```
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
-h, --help help for derivekey
--identity derive the lnd identity_pubkey
--neuter don't output private key(s), only public key(s)
--path string BIP32 derivation path to derive; must start with "m/"
--rootkey string BIP32 HD root key of the wallet to use for decrypting the backup; leave empty to prompt for lnd 24 word aezeed
--walletdb string read the seed/master root key to use for decrypting the backup from an lnd wallet.db file instead of asking for a seed or providing the --rootkey flag
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
-h, --help help for derivekey
--hsm_secret string the hex encoded HSM secret to use for deriving the multisig keys for a CLN node; obtain by running 'xxd -p -c32 ~/.lightning/bitcoin/hsm_secret'
--identity derive the node's identity public key
--neuter don't output private key(s), only public key(s)
--path string BIP32 derivation path to derive; must start with "m/"
--rootkey string BIP32 HD root key of the wallet to use for decrypting the backup; leave empty to prompt for lnd 24 word aezeed
--walletdb string read the seed/master root key to use for decrypting the backup from an lnd wallet.db file instead of asking for a seed or providing the --rootkey flag
```
### Options inherited from parent commands
```
-r, --regtest Indicates if regtest parameters should be used
-s, --signet Indicates if the public signet parameters should be used
-t, --testnet Indicates if testnet parameters should be used
--nologfile If set, no log file will be created. This is useful for testing purposes where we don't want to create a log file.
-r, --regtest Indicates if regtest parameters should be used
-s, --signet Indicates if the public signet parameters should be used
-t, --testnet Indicates if testnet parameters should be used
```
### SEE ALSO