@@ -9,9 +9,12 @@ import (
99 "os"
1010 "time"
1111
12+ "github.com/btcsuite/btcd/btcec/v2"
1213 "github.com/btcsuite/btcd/btcutil"
1314 "github.com/btcsuite/btcd/wire"
15+ "github.com/lightninglabs/chantools/cln"
1416 "github.com/lightninglabs/chantools/lnd"
17+ "github.com/lightningnetwork/lnd/keychain"
1518 "github.com/spf13/cobra"
1619)
1720
@@ -25,6 +28,8 @@ type zombieRecoveryPrepareKeysCommand struct {
2528
2629 NumKeys uint32
2730
31+ HsmSecret string
32+
2833 rootKey * rootKey
2934 cmd * cobra.Command
3035}
@@ -58,6 +63,12 @@ correct ones for the matched channels.`,
5863 & cc .NumKeys , "num_keys" , numMultisigKeys , "the number of " +
5964 "multisig keys to derive" ,
6065 )
66+ cc .cmd .Flags ().StringVar (
67+ & cc .HsmSecret , "hsm_secret" , "" , "the hex encoded HSM secret " +
68+ "to use for deriving the multisig keys for a CLN " +
69+ "node; obtain by running 'xxd -p -c32 " +
70+ "~/.lightning/bitcoin/hsm_secret'" ,
71+ )
6172
6273 cc .rootKey = newRootKey (cc .cmd , "deriving the multisig keys" )
6374
@@ -67,12 +78,7 @@ correct ones for the matched channels.`,
6778func (c * zombieRecoveryPrepareKeysCommand ) Execute (_ * cobra.Command ,
6879 _ []string ) error {
6980
70- extendedKey , err := c .rootKey .read ()
71- if err != nil {
72- return fmt .Errorf ("error reading root key: %w" , err )
73- }
74-
75- err = lnd .CheckAddress (
81+ err := lnd .CheckAddress (
7682 c .PayoutAddr , chainParams , false , "payout" , lnd .AddrTypeP2WKH ,
7783 lnd .AddrTypeP2TR ,
7884 )
@@ -98,26 +104,68 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
98104 return errors .New ("invalid match file, node info missing" )
99105 }
100106
101- _ , pubKey , _ , err := lnd .DeriveKey (
102- extendedKey , lnd .IdentityPath (chainParams ), chainParams ,
103- )
107+ // Derive the keys for the node type, depending on the input flags.
108+ var signer lnd.ChannelSigner
109+ switch {
110+ case c .HsmSecret != "" :
111+ secretBytes , err := hex .DecodeString (c .HsmSecret )
112+ if err != nil {
113+ return fmt .Errorf ("error decoding HSM secret: %w" , err )
114+ }
115+
116+ var hsmSecret [32 ]byte
117+ copy (hsmSecret [:], secretBytes )
118+
119+ signer = & cln.Signer {
120+ HsmSecret : hsmSecret ,
121+ }
122+
123+ default :
124+ extendedKey , err := c .rootKey .read ()
125+ if err != nil {
126+ return fmt .Errorf ("error reading root key: %w" , err )
127+ }
128+ signer = & lnd.Signer {
129+ ExtendedKey : extendedKey ,
130+ ChainParams : chainParams ,
131+ }
132+ }
133+
134+ nodePrivKey , err := signer .FetchPrivateKey (& keychain.KeyDescriptor {
135+ KeyLocator : keychain.KeyLocator {
136+ Family : keychain .KeyFamilyNodeKey ,
137+ },
138+ })
104139 if err != nil {
105- return fmt .Errorf ("error deriving identity pubkey: %w" , err )
140+ return fmt .Errorf ("error deriving identity private key: %w" ,
141+ err )
106142 }
107143
144+ pubKey := nodePrivKey .PubKey ()
108145 pubKeyStr := hex .EncodeToString (pubKey .SerializeCompressed ())
109- var nodeInfo * nodeInfo
146+ var ourNodeInfo , theirNodeInfo * nodeInfo
110147 switch {
111148 case match .Node1 .PubKey != pubKeyStr && match .Node2 .PubKey != pubKeyStr :
112- return fmt .Errorf ("derived pubkey %s from seed but that key " +
113- "was not found in the match file %s" , pubKeyStr ,
149+ return fmt .Errorf ("derived pubkey %s from seed but that " +
150+ "key was not found in the match file %s" , pubKeyStr ,
114151 c .MatchFile )
115152
116153 case match .Node1 .PubKey == pubKeyStr :
117- nodeInfo = match .Node1
154+ ourNodeInfo = match .Node1
155+ theirNodeInfo = match .Node2
118156
119157 default :
120- nodeInfo = match .Node2
158+ ourNodeInfo = match .Node2
159+ theirNodeInfo = match .Node1
160+ }
161+
162+ theirNodeKeyBytes , err := hex .DecodeString (theirNodeInfo .PubKey )
163+ if err != nil {
164+ return fmt .Errorf ("error decoding peer pubkey: %w" , err )
165+ }
166+ theirNodeKey , err := btcec .ParsePubKey (theirNodeKeyBytes )
167+ if err != nil {
168+ return fmt .Errorf ("error parsing peer pubkey: %w" , err )
121169 }
122170
123171 // If there are any Simple Taproot channels, we need to generate some
@@ -132,6 +180,12 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
132180
133181 _ , isP2TR := addr .(* btcutil.AddressTaproot )
134182 if isP2TR {
183+ lndSigner , ok := signer .(* lnd.Signer )
184+ if ! ok {
185+ return errors .New ("taproot channels not " +
186+ "supported for CLN " )
187+ }
188+
135189 chanPoint , err := wire .NewOutPointFromString (
136190 matchChannel .ChanPoint ,
137191 )
@@ -147,12 +201,13 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
147201 }
148202
149203 nonces , err := lnd .GenerateMuSig2Nonces (
150- extendedKey , randomness , chanPoint , chainParams ,
204+ lndSigner .ExtendedKey , randomness , chanPoint ,
205+ chainParams ,
151206 nil ,
152207 )
153208 if err != nil {
154- return fmt .Errorf ("error generating MuSig2 " +
155- "nonces: %w" , err )
209+ return fmt .Errorf ("error generating " +
210+ "MuSig2 nonces: %w" , err )
156211 }
157212
158213 matchChannel .MuSig2NonceRandomness = hex .EncodeToString (
@@ -166,21 +221,25 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
166221
167222 // Derive all 2500 keys now, this might take a while.
168223 for index := range c .NumKeys {
169- _ , pubKey , _ , err := lnd .DeriveKey (
170- extendedKey , lnd .MultisigPath (chainParams , int (index )),
171- chainParams ,
172- )
224+ privKey , err := signer .FetchPrivateKey (& keychain.KeyDescriptor {
225+ PubKey : theirNodeKey ,
226+ KeyLocator : keychain.KeyLocator {
227+ Family : keychain .KeyFamilyMultiSig ,
228+ Index : index ,
229+ },
230+ })
173231 if err != nil {
174- return fmt .Errorf ("error deriving multisig pubkey: %w" ,
175- err )
232+ return fmt .Errorf ("error deriving funding private " +
233+ "key: %w" , err )
176234 }
177235
178- nodeInfo .MultisigKeys = append (
179- nodeInfo .MultisigKeys ,
180- hex .EncodeToString (pubKey .SerializeCompressed ()),
236+ fundingPubKey := privKey .PubKey ()
237+ ourNodeInfo .MultisigKeys = append (
238+ ourNodeInfo .MultisigKeys ,
239+ hex .EncodeToString (fundingPubKey .SerializeCompressed ()),
181240 )
182241 }
183- nodeInfo .PayoutAddr = c .PayoutAddr
242+ ourNodeInfo .PayoutAddr = c .PayoutAddr
184243
185244 // Write the result back into a new file.
186245 matchBytes , err := json .MarshalIndent (match , "" , " " )
0 commit comments