4
4
"bytes"
5
5
"encoding/base64"
6
6
"encoding/binary"
7
+ "errors"
7
8
"fmt"
8
9
"os"
9
10
@@ -15,6 +16,10 @@ import (
15
16
"github.com/spf13/cobra"
16
17
)
17
18
19
+ var (
20
+ errNoPathFound = fmt .Errorf ("no matching derivation path found" )
21
+ )
22
+
18
23
type signPSBTCommand struct {
19
24
Psbt string
20
25
FromRawPsbtFile string
@@ -134,93 +139,117 @@ func (c *signPSBTCommand) Execute(_ *cobra.Command, _ []string) error {
134
139
func signPsbt (rootKey * hdkeychain.ExtendedKey ,
135
140
packet * psbt.Packet , signer * lnd.Signer ) error {
136
141
137
- // Check that we have an input with a derivation path that belongs to
138
- // the root key.
139
- derivationPath , inputIndex , err := findMatchingDerivationPath (
140
- rootKey , packet ,
141
- )
142
- if err != nil {
143
- return fmt .Errorf ("could not find matching derivation path: %w" ,
144
- err )
145
- }
142
+ for inputIndex := range packet .Inputs {
143
+ pIn := & packet .Inputs [inputIndex ]
146
144
147
- if len (derivationPath ) < 5 {
148
- return fmt .Errorf ("invalid derivation path, expected at least " +
149
- "5 elements, got %d" , len (derivationPath ))
150
- }
145
+ // Check that we have an input with a derivation path that
146
+ // belongs to the root key.
147
+ derivationPath , err := findMatchingDerivationPath (rootKey , pIn )
148
+ if errors .Is (err , errNoPathFound ) {
149
+ log .Infof ("No matching derivation path found for " +
150
+ "input %d, skipping" , inputIndex )
151
+ continue
152
+ }
153
+ if err != nil {
154
+ return fmt .Errorf ("could not find matching derivation " +
155
+ "path: %w" , err )
156
+ }
151
157
152
- localKey , err := lnd .DeriveChildren (rootKey , derivationPath )
153
- if err != nil {
154
- return fmt .Errorf ("could not derive local key: %w" , err )
155
- }
158
+ if len (derivationPath ) < 5 {
159
+ return fmt .Errorf ("invalid derivation path, expected " +
160
+ "at least 5 elements, got %d" ,
161
+ len (derivationPath ))
162
+ }
156
163
157
- if packet .Inputs [inputIndex ].WitnessUtxo == nil {
158
- return fmt .Errorf ("invalid PSBT, input %d is missing witness " +
159
- "UTXO" , inputIndex )
160
- }
161
- utxo := packet .Inputs [inputIndex ].WitnessUtxo
162
-
163
- // The signing is a bit different for P2WPKH, we need to specify the
164
- // pk script as the witness script.
165
- var witnessScript []byte
166
- if txscript .IsPayToWitnessPubKeyHash (utxo .PkScript ) {
167
- witnessScript = utxo .PkScript
168
- } else {
169
- if len (packet .Inputs [inputIndex ].WitnessScript ) == 0 {
164
+ localKey , err := lnd .DeriveChildren (rootKey , derivationPath )
165
+ if err != nil {
166
+ return fmt .Errorf ("could not derive local key: %w" , err )
167
+ }
168
+
169
+ if pIn .WitnessUtxo == nil {
170
170
return fmt .Errorf ("invalid PSBT, input %d is missing " +
171
- "witness script" , inputIndex )
171
+ "witness UTXO" , inputIndex )
172
+ }
173
+ utxo := pIn .WitnessUtxo
174
+
175
+ // The signing is a bit different for P2WPKH, we need to specify
176
+ // the pk script as the witness script.
177
+ var witnessScript []byte
178
+ if txscript .IsPayToWitnessPubKeyHash (utxo .PkScript ) {
179
+ witnessScript = utxo .PkScript
180
+ } else {
181
+ if len (pIn .WitnessScript ) == 0 {
182
+ return fmt .Errorf ("invalid PSBT, input %d is " +
183
+ "missing witness script" , inputIndex )
184
+ }
185
+ witnessScript = pIn .WitnessScript
172
186
}
173
- witnessScript = packet .Inputs [inputIndex ].WitnessScript
174
- }
175
187
176
- localPrivateKey , err := localKey .ECPrivKey ()
177
- if err != nil {
178
- return fmt .Errorf ("error getting private key: %w" , err )
179
- }
180
- err = signer .AddPartialSignatureForPrivateKey (
181
- packet , localPrivateKey , utxo , witnessScript , inputIndex ,
182
- )
183
- if err != nil {
184
- return fmt .Errorf ("error adding partial signature: %w" , err )
188
+ localPrivateKey , err := localKey .ECPrivKey ()
189
+ if err != nil {
190
+ return fmt .Errorf ("error getting private key: %w" , err )
191
+ }
192
+
193
+ // Do we already have a partial signature for our key?
194
+ localPubKey := localPrivateKey .PubKey ().SerializeCompressed ()
195
+ haveSig := false
196
+ for _ , partialSig := range pIn .PartialSigs {
197
+ if bytes .Equal (partialSig .PubKey , localPubKey ) {
198
+ haveSig = true
199
+ }
200
+ }
201
+ if haveSig {
202
+ log .Infof ("Already have a partial signature for input " +
203
+ "%d and local key %x, skipping" , inputIndex ,
204
+ localPubKey )
205
+ continue
206
+ }
207
+
208
+ err = signer .AddPartialSignatureForPrivateKey (
209
+ packet , localPrivateKey , utxo , witnessScript ,
210
+ inputIndex ,
211
+ )
212
+ if err != nil {
213
+ return fmt .Errorf ("error adding partial signature: %w" ,
214
+ err )
215
+ }
185
216
}
186
217
187
218
return nil
188
219
}
189
220
190
221
func findMatchingDerivationPath (rootKey * hdkeychain.ExtendedKey ,
191
- packet * psbt.Packet ) ([]uint32 , int , error ) {
222
+ pIn * psbt.PInput ) ([]uint32 , error ) {
192
223
193
224
pubKey , err := rootKey .ECPubKey ()
194
225
if err != nil {
195
- return nil , 0 , fmt .Errorf ("error getting public key: %w" , err )
226
+ return nil , fmt .Errorf ("error getting public key: %w" , err )
196
227
}
197
228
198
229
pubKeyHash := btcutil .Hash160 (pubKey .SerializeCompressed ())
199
230
fingerprint := binary .LittleEndian .Uint32 (pubKeyHash [:4 ])
200
231
201
- for idx , input := range packet .Inputs {
202
- if len (input .Bip32Derivation ) == 0 {
203
- continue
204
- }
232
+ if len (pIn .Bip32Derivation ) == 0 {
233
+ return nil , errNoPathFound
234
+ }
205
235
206
- for _ , derivation := range input .Bip32Derivation {
207
- // A special case where there is only a single
208
- // derivation path and the master key fingerprint is not
209
- // set, we assume we are the correct signer... This
210
- // might not be correct, but we have no way of knowing.
211
- if derivation .MasterKeyFingerprint == 0 &&
212
- len (input .Bip32Derivation ) == 1 {
236
+ for _ , derivation := range pIn .Bip32Derivation {
237
+ // A special case where there is only a single derivation path
238
+ // and the master key fingerprint is not set, we assume we are
239
+ // the correct signer... This might not be correct, but we have
240
+ // no way of knowing.
241
+ if derivation .MasterKeyFingerprint == 0 &&
242
+ len (pIn .Bip32Derivation ) == 1 {
213
243
214
- return derivation .Bip32Path , idx , nil
215
- }
244
+ return derivation .Bip32Path , nil
245
+ }
216
246
217
- // The normal case, where a derivation path has the
218
- // master fingerprint set.
219
- if derivation .MasterKeyFingerprint == fingerprint {
220
- return derivation .Bip32Path , idx , nil
221
- }
247
+ // The normal case, where a derivation path has the master
248
+ // fingerprint set.
249
+ if derivation .MasterKeyFingerprint == fingerprint {
250
+ return derivation .Bip32Path , nil
222
251
}
223
252
}
224
253
225
- return nil , 0 , fmt . Errorf ( "no matching derivation path found" )
254
+ return nil , errNoPathFound
226
255
}
0 commit comments