9
9
"os"
10
10
"time"
11
11
12
+ "github.com/btcsuite/btcd/btcec/v2"
13
+ "github.com/lightninglabs/chantools/cln"
12
14
"github.com/lightninglabs/chantools/lnd"
13
15
"github.com/spf13/cobra"
14
16
)
@@ -23,6 +25,8 @@ type zombieRecoveryPrepareKeysCommand struct {
23
25
24
26
NumKeys uint32
25
27
28
+ HsmSecret string
29
+
26
30
rootKey * rootKey
27
31
cmd * cobra.Command
28
32
}
@@ -56,6 +60,12 @@ correct ones for the matched channels.`,
56
60
& cc .NumKeys , "num_keys" , numMultisigKeys , "the number of " +
57
61
"multisig keys to derive" ,
58
62
)
63
+ cc .cmd .Flags ().StringVar (
64
+ & cc .HsmSecret , "hsm_secret" , "" , "the hex encoded HSM secret " +
65
+ "to use for deriving the multisig keys for a CLN " +
66
+ "node; obtain by running 'xxd -p -c32 " +
67
+ "~/.lightning/bitcoin/hsm_secret'" ,
68
+ )
59
69
60
70
cc .rootKey = newRootKey (cc .cmd , "deriving the multisig keys" )
61
71
@@ -65,12 +75,7 @@ correct ones for the matched channels.`,
65
75
func (c * zombieRecoveryPrepareKeysCommand ) Execute (_ * cobra.Command ,
66
76
_ []string ) error {
67
77
68
- extendedKey , err := c .rootKey .read ()
69
- if err != nil {
70
- return fmt .Errorf ("error reading root key: %w" , err )
71
- }
72
-
73
- _ , err = lnd .GetP2WPKHScript (c .PayoutAddr , chainParams )
78
+ _ , err := lnd .GetP2WPKHScript (c .PayoutAddr , chainParams )
74
79
if err != nil {
75
80
return errors .New ("invalid payout address, must be P2WPKH" )
76
81
}
@@ -93,19 +98,51 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
93
98
return errors .New ("invalid match file, node info missing" )
94
99
}
95
100
101
+ // Derive the keys for the node type, depending on the input flags.
102
+ var pubKeyStr string
103
+ switch {
104
+ case c .HsmSecret != "" :
105
+ pubKeyStr , err = c .clnDeriveKeys (match )
106
+ default :
107
+ pubKeyStr , err = c .lndDeriveKeys (match )
108
+ }
109
+ if err != nil {
110
+ return err
111
+ }
112
+
113
+ // Write the result back into a new file.
114
+ matchBytes , err := json .MarshalIndent (match , "" , " " )
115
+ if err != nil {
116
+ return err
117
+ }
118
+
119
+ fileName := fmt .Sprintf ("results/preparedkeys-%s-%s.json" ,
120
+ time .Now ().Format ("2006-01-02" ), pubKeyStr )
121
+ log .Infof ("Writing result to %s" , fileName )
122
+ return os .WriteFile (fileName , matchBytes , 0644 )
123
+ }
124
+
125
+ func (c * zombieRecoveryPrepareKeysCommand ) lndDeriveKeys (match * match ) (string ,
126
+ error ) {
127
+
128
+ extendedKey , err := c .rootKey .read ()
129
+ if err != nil {
130
+ return "" , fmt .Errorf ("error reading root key: %w" , err )
131
+ }
132
+
96
133
_ , pubKey , _ , err := lnd .DeriveKey (
97
134
extendedKey , lnd .IdentityPath (chainParams ), chainParams ,
98
135
)
99
136
if err != nil {
100
- return fmt .Errorf ("error deriving identity pubkey: %w" , err )
137
+ return "" , fmt .Errorf ("error deriving identity pubkey: %w" , err )
101
138
}
102
139
103
140
pubKeyStr := hex .EncodeToString (pubKey .SerializeCompressed ())
104
141
var nodeInfo * nodeInfo
105
142
switch {
106
143
case match .Node1 .PubKey != pubKeyStr && match .Node2 .PubKey != pubKeyStr :
107
- return fmt .Errorf ("derived pubkey %s from seed but that key " +
108
- "was not found in the match file %s" , pubKeyStr ,
144
+ return "" , fmt .Errorf ("derived pubkey %s from seed but that " +
145
+ "key was not found in the match file %s" , pubKeyStr ,
109
146
c .MatchFile )
110
147
111
148
case match .Node1 .PubKey == pubKeyStr :
@@ -122,8 +159,8 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
122
159
chainParams ,
123
160
)
124
161
if err != nil {
125
- return fmt .Errorf ("error deriving multisig pubkey: %w" ,
126
- err )
162
+ return "" , fmt .Errorf ("error deriving multisig " +
163
+ "pubkey: %w" , err )
127
164
}
128
165
129
166
nodeInfo .MultisigKeys = append (
@@ -133,14 +170,67 @@ func (c *zombieRecoveryPrepareKeysCommand) Execute(_ *cobra.Command,
133
170
}
134
171
nodeInfo .PayoutAddr = c .PayoutAddr
135
172
136
- // Write the result back into a new file.
137
- matchBytes , err := json .MarshalIndent (match , "" , " " )
173
+ return pubKeyStr , nil
174
+ }
175
+
176
+ func (c * zombieRecoveryPrepareKeysCommand ) clnDeriveKeys (match * match ) (string ,
177
+ error ) {
178
+
179
+ secretBytes , err := hex .DecodeString (c .HsmSecret )
138
180
if err != nil {
139
- return err
181
+ return "" , fmt . Errorf ( "error decoding HSM secret: %w" , err )
140
182
}
141
183
142
- fileName := fmt .Sprintf ("results/preparedkeys-%s-%s.json" ,
143
- time .Now ().Format ("2006-01-02" ), pubKeyStr )
144
- log .Infof ("Writing result to %s" , fileName )
145
- return os .WriteFile (fileName , matchBytes , 0644 )
184
+ var hsmSecret [32 ]byte
185
+ copy (hsmSecret [:], secretBytes )
186
+
187
+ nodePubKey , err := cln .NodeKey (hsmSecret )
188
+ if err != nil {
189
+ return "" , fmt .Errorf ("error deriving node pubkey: %w" , err )
190
+ }
191
+
192
+ pubKeyStr := hex .EncodeToString (nodePubKey .SerializeCompressed ())
193
+ var ourNodeInfo , theirNodeInfo * nodeInfo
194
+ switch {
195
+ case match .Node1 .PubKey != pubKeyStr && match .Node2 .PubKey != pubKeyStr :
196
+ return "" , fmt .Errorf ("derived pubkey %s from seed but that " +
197
+ "key was not found in the match file %s" , pubKeyStr ,
198
+ c .MatchFile )
199
+
200
+ case match .Node1 .PubKey == pubKeyStr :
201
+ ourNodeInfo = match .Node1
202
+ theirNodeInfo = match .Node2
203
+
204
+ default :
205
+ ourNodeInfo = match .Node2
206
+ theirNodeInfo = match .Node1
207
+ }
208
+
209
+ theirNodeKeyBytes , err := hex .DecodeString (theirNodeInfo .PubKey )
210
+ if err != nil {
211
+ return "" , fmt .Errorf ("error decoding peer pubkey: %w" , err )
212
+ }
213
+ theirNodeKey , err := btcec .ParsePubKey (theirNodeKeyBytes )
214
+ if err != nil {
215
+ return "" , fmt .Errorf ("error parsing peer pubkey: %w" , err )
216
+ }
217
+
218
+ // Derive all 2500 keys now, this might take a while.
219
+ for index := range c .NumKeys {
220
+ pubKey , err := cln .FundingKey (
221
+ hsmSecret , theirNodeKey , uint64 (index ),
222
+ )
223
+ if err != nil {
224
+ return "" , fmt .Errorf ("error deriving multisig " +
225
+ "pubkey: %w" , err )
226
+ }
227
+
228
+ ourNodeInfo .MultisigKeys = append (
229
+ ourNodeInfo .MultisigKeys ,
230
+ hex .EncodeToString (pubKey .SerializeCompressed ()),
231
+ )
232
+ }
233
+ ourNodeInfo .PayoutAddr = c .PayoutAddr
234
+
235
+ return pubKeyStr , nil
146
236
}
0 commit comments