• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 9935147745

15 Jul 2024 07:07AM UTC coverage: 49.819% (+0.6%) from 49.268%
9935147745

Pull #8900

github

guggero
Makefile: add GOCC variable
Pull Request #8900: Makefile: add GOCC variable

93876 of 188433 relevant lines covered (49.82%)

2.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.35
/lnwallet/rpcwallet/rpcwallet.go
1
package rpcwallet
2

3
import (
4
        "bytes"
5
        "context"
6
        "crypto/sha256"
7
        "crypto/x509"
8
        "errors"
9
        "fmt"
10
        "os"
11
        "time"
12

13
        "github.com/btcsuite/btcd/btcec/v2"
14
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
15
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
16
        "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
17
        "github.com/btcsuite/btcd/btcutil"
18
        "github.com/btcsuite/btcd/btcutil/hdkeychain"
19
        "github.com/btcsuite/btcd/btcutil/psbt"
20
        "github.com/btcsuite/btcd/chaincfg"
21
        "github.com/btcsuite/btcd/txscript"
22
        "github.com/btcsuite/btcd/wire"
23
        "github.com/btcsuite/btcwallet/waddrmgr"
24
        basewallet "github.com/btcsuite/btcwallet/wallet"
25
        "github.com/lightningnetwork/lnd/input"
26
        "github.com/lightningnetwork/lnd/keychain"
27
        "github.com/lightningnetwork/lnd/lncfg"
28
        "github.com/lightningnetwork/lnd/lnrpc/signrpc"
29
        "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
30
        "github.com/lightningnetwork/lnd/lnwallet"
31
        "github.com/lightningnetwork/lnd/lnwallet/btcwallet"
32
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
33
        "github.com/lightningnetwork/lnd/lnwire"
34
        "github.com/lightningnetwork/lnd/macaroons"
35
        "google.golang.org/grpc"
36
        "google.golang.org/grpc/codes"
37
        "google.golang.org/grpc/credentials"
38
        "google.golang.org/grpc/status"
39
        "gopkg.in/macaroon.v2"
40
)
41

42
var (
43
        // ErrRemoteSigningPrivateKeyNotAvailable is the error that is returned
44
        // if an operation is requested from the RPC wallet that is not
45
        // supported in remote signing mode.
46
        ErrRemoteSigningPrivateKeyNotAvailable = errors.New("deriving " +
47
                "private key is not supported by RPC based key ring")
48
)
49

50
// RPCKeyRing is an implementation of the SecretKeyRing interface that uses a
51
// local watch-only wallet for keeping track of addresses and transactions but
52
// delegates any signing or ECDH operations to a remote node through RPC.
53
type RPCKeyRing struct {
54
        // WalletController is the embedded wallet controller of the watch-only
55
        // base wallet. We need to overwrite/shadow certain of the implemented
56
        // methods to make sure we can mirror them to the remote wallet.
57
        lnwallet.WalletController
58

59
        watchOnlyKeyRing keychain.SecretKeyRing
60

61
        netParams *chaincfg.Params
62

63
        rpcTimeout time.Duration
64

65
        signerClient signrpc.SignerClient
66
        walletClient walletrpc.WalletKitClient
67
}
68

69
var _ keychain.SecretKeyRing = (*RPCKeyRing)(nil)
70
var _ input.Signer = (*RPCKeyRing)(nil)
71
var _ keychain.MessageSignerRing = (*RPCKeyRing)(nil)
72
var _ lnwallet.WalletController = (*RPCKeyRing)(nil)
73

74
// NewRPCKeyRing creates a new remote signing secret key ring that uses the
75
// given watch-only base wallet to keep track of addresses and transactions but
76
// delegates any signing or ECDH operations to the remove signer through RPC.
77
func NewRPCKeyRing(watchOnlyKeyRing keychain.SecretKeyRing,
78
        watchOnlyWalletController lnwallet.WalletController,
79
        remoteSigner *lncfg.RemoteSigner,
80
        netParams *chaincfg.Params) (*RPCKeyRing, error) {
4✔
81

4✔
82
        rpcConn, err := connectRPC(
4✔
83
                remoteSigner.RPCHost, remoteSigner.TLSCertPath,
4✔
84
                remoteSigner.MacaroonPath, remoteSigner.Timeout,
4✔
85
        )
4✔
86
        if err != nil {
4✔
87
                return nil, fmt.Errorf("error connecting to the remote "+
×
88
                        "signing node through RPC: %v", err)
×
89
        }
×
90

91
        return &RPCKeyRing{
4✔
92
                WalletController: watchOnlyWalletController,
4✔
93
                watchOnlyKeyRing: watchOnlyKeyRing,
4✔
94
                netParams:        netParams,
4✔
95
                rpcTimeout:       remoteSigner.Timeout,
4✔
96
                signerClient:     signrpc.NewSignerClient(rpcConn),
4✔
97
                walletClient:     walletrpc.NewWalletKitClient(rpcConn),
4✔
98
        }, nil
4✔
99
}
100

101
// NewAddress returns the next external or internal address for the
102
// wallet dictated by the value of the `change` parameter. If change is
103
// true, then an internal address should be used, otherwise an external
104
// address should be returned. The type of address returned is dictated
105
// by the wallet's capabilities, and may be of type: p2sh, p2wkh,
106
// p2wsh, etc. The account parameter must be non-empty as it determines
107
// which account the address should be generated from.
108
func (r *RPCKeyRing) NewAddress(addrType lnwallet.AddressType, change bool,
109
        account string) (btcutil.Address, error) {
4✔
110

4✔
111
        return r.WalletController.NewAddress(addrType, change, account)
4✔
112
}
4✔
113

114
// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to
115
// the specified outputs. In the case the wallet has insufficient funds, or the
116
// outputs are non-standard, a non-nil error will be returned.
117
//
118
// NOTE: This method requires the global coin selection lock to be held.
119
//
120
// NOTE: This is a part of the WalletController interface.
121
//
122
// NOTE: This method only signs with BIP49/84 keys.
123
func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
124
        feeRate chainfee.SatPerKWeight, minConfs int32, label string,
125
        strategy basewallet.CoinSelectionStrategy) (*wire.MsgTx, error) {
4✔
126

4✔
127
        tx, err := r.WalletController.SendOutputs(
4✔
128
                outputs, feeRate, minConfs, label, strategy,
4✔
129
        )
4✔
130
        if err != nil && err != basewallet.ErrTxUnsigned {
4✔
131
                return nil, err
×
132
        }
×
133
        if err == nil {
4✔
134
                // This shouldn't happen since our wallet controller is watch-
×
135
                // only and can't sign the TX.
×
136
                return tx, nil
×
137
        }
×
138

139
        // We know at this point that we only have inputs from our own wallet.
140
        // So we can just compute the input script using the remote signer.
141
        outputFetcher := lnwallet.NewWalletPrevOutputFetcher(r.WalletController)
4✔
142
        for i, txIn := range tx.TxIn {
8✔
143
                signDesc := input.SignDescriptor{
4✔
144
                        HashType: txscript.SigHashAll,
4✔
145
                        SigHashes: txscript.NewTxSigHashes(
4✔
146
                                tx, outputFetcher,
4✔
147
                        ),
4✔
148
                        PrevOutputFetcher: outputFetcher,
4✔
149
                }
4✔
150

4✔
151
                // We can only sign this input if it's ours, so we'll ask the
4✔
152
                // watch-only wallet if it can map this outpoint into a coin we
4✔
153
                // own. If not, then we can't continue because our wallet state
4✔
154
                // is out of sync.
4✔
155
                info, err := r.WalletController.FetchInputInfo(
4✔
156
                        &txIn.PreviousOutPoint,
4✔
157
                )
4✔
158
                if err != nil {
4✔
159
                        return nil, fmt.Errorf("error looking up utxo: %w", err)
×
160
                }
×
161

162
                if txscript.IsPayToTaproot(info.PkScript) {
8✔
163
                        signDesc.HashType = txscript.SigHashDefault
4✔
164
                }
4✔
165

166
                // Now that we know the input is ours, we'll populate the
167
                // signDesc with the per input unique information.
168
                signDesc.Output = &wire.TxOut{
4✔
169
                        Value:    int64(info.Value),
4✔
170
                        PkScript: info.PkScript,
4✔
171
                }
4✔
172
                signDesc.InputIndex = i
4✔
173

4✔
174
                // Finally, we'll sign the input as is, and populate the input
4✔
175
                // with the witness and sigScript (if needed).
4✔
176
                inputScript, err := r.ComputeInputScript(tx, &signDesc)
4✔
177
                if err != nil {
4✔
178
                        return nil, err
×
179
                }
×
180

181
                txIn.SignatureScript = inputScript.SigScript
4✔
182
                txIn.Witness = inputScript.Witness
4✔
183
        }
184

185
        return tx, r.WalletController.PublishTransaction(tx, label)
4✔
186
}
187

188
// SignPsbt expects a partial transaction with all inputs and outputs fully
189
// declared and tries to sign all unsigned inputs that have all required fields
190
// (UTXO information, BIP32 derivation information, witness or sig scripts) set.
191
// If no error is returned, the PSBT is ready to be given to the next signer or
192
// to be finalized if lnd was the last signer.
193
//
194
// NOTE: This RPC only signs inputs (and only those it can sign), it does not
195
// perform any other tasks (such as coin selection, UTXO locking or
196
// input/output/fee value validation, PSBT finalization). Any input that is
197
// incomplete will be skipped.
198
func (r *RPCKeyRing) SignPsbt(packet *psbt.Packet) ([]uint32, error) {
4✔
199
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
200
        defer cancel()
4✔
201

4✔
202
        var buf bytes.Buffer
4✔
203
        if err := packet.Serialize(&buf); err != nil {
4✔
204
                return nil, fmt.Errorf("error serializing PSBT: %w", err)
×
205
        }
×
206

207
        resp, err := r.walletClient.SignPsbt(ctxt, &walletrpc.SignPsbtRequest{
4✔
208
                FundedPsbt: buf.Bytes(),
4✔
209
        })
4✔
210
        if err != nil {
4✔
211
                considerShutdown(err)
×
212
                return nil, fmt.Errorf("error signing PSBT in remote signer "+
×
213
                        "instance: %v", err)
×
214
        }
×
215

216
        signedPacket, err := psbt.NewFromRawBytes(
4✔
217
                bytes.NewReader(resp.SignedPsbt), false,
4✔
218
        )
4✔
219
        if err != nil {
4✔
220
                return nil, fmt.Errorf("error parsing signed PSBT: %w", err)
×
221
        }
×
222

223
        // The caller expects the packet to be modified instead of a new
224
        // instance to be returned. So we just overwrite all fields in the
225
        // original packet.
226
        packet.UnsignedTx = signedPacket.UnsignedTx
4✔
227
        packet.Inputs = signedPacket.Inputs
4✔
228
        packet.Outputs = signedPacket.Outputs
4✔
229
        packet.Unknowns = signedPacket.Unknowns
4✔
230

4✔
231
        return resp.SignedInputs, nil
4✔
232
}
233

234
// FinalizePsbt expects a partial transaction with all inputs and outputs fully
235
// declared and tries to sign all inputs that belong to the specified account.
236
// Lnd must be the last signer of the transaction. That means, if there are any
237
// unsigned non-witness inputs or inputs without UTXO information attached or
238
// inputs without witness data that do not belong to lnd's wallet, this method
239
// will fail. If no error is returned, the PSBT is ready to be extracted and the
240
// final TX within to be broadcast.
241
//
242
// NOTE: This method does NOT publish the transaction after it's been
243
// finalized successfully.
244
//
245
// NOTE: This is a part of the WalletController interface.
246
//
247
// NOTE: We need to overwrite this method because we need to redirect the call
248
// to ComputeInputScript to the RPC key ring's implementation. If we forward
249
// the call to the default WalletController implementation, we get an error
250
// since that wallet is watch-only. If we forward the call to the remote signer,
251
// we get an error because the signer doesn't know the UTXO information required
252
// in ComputeInputScript.
253
//
254
// TODO(guggero): Refactor btcwallet to accept ComputeInputScript as a function
255
// parameter in FinalizePsbt so we can get rid of this code duplication.
256
func (r *RPCKeyRing) FinalizePsbt(packet *psbt.Packet, _ string) error {
4✔
257
        // Let's check that this is actually something we can and want to sign.
4✔
258
        // We need at least one input and one output. In addition each
4✔
259
        // input needs nonWitness Utxo or witness Utxo data specified.
4✔
260
        err := psbt.InputsReadyToSign(packet)
4✔
261
        if err != nil {
4✔
262
                return err
×
263
        }
×
264

265
        // Go through each input that doesn't have final witness data attached
266
        // to it already and try to sign it. We do expect that we're the last
267
        // ones to sign. If there is any input without witness data that we
268
        // cannot sign because it's not our UTXO, this will be a hard failure.
269
        tx := packet.UnsignedTx
4✔
270
        prevOutFetcher := basewallet.PsbtPrevOutputFetcher(packet)
4✔
271
        sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
4✔
272
        for idx, txIn := range tx.TxIn {
8✔
273
                in := packet.Inputs[idx]
4✔
274

4✔
275
                // We can only sign if we have UTXO information available. We
4✔
276
                // can just continue here as a later step will fail with a more
4✔
277
                // precise error message.
4✔
278
                if in.WitnessUtxo == nil && in.NonWitnessUtxo == nil {
4✔
279
                        continue
×
280
                }
281

282
                // Skip this input if it's got final witness data attached.
283
                if len(in.FinalScriptWitness) > 0 {
4✔
284
                        continue
×
285
                }
286

287
                // We can only sign this input if it's ours, so we try to map it
288
                // to a coin we own. If we can't, then we'll continue as it
289
                // isn't our input.
290
                utxo, err := r.FetchInputInfo(&txIn.PreviousOutPoint)
4✔
291
                if err != nil {
4✔
292
                        continue
×
293
                }
294
                fullTx := utxo.PrevTx
4✔
295
                signDesc := &input.SignDescriptor{
4✔
296
                        KeyDesc: keychain.KeyDescriptor{},
4✔
297
                        Output: &wire.TxOut{
4✔
298
                                Value:    int64(utxo.Value),
4✔
299
                                PkScript: utxo.PkScript,
4✔
300
                        },
4✔
301
                        HashType:          in.SighashType,
4✔
302
                        SigHashes:         sigHashes,
4✔
303
                        InputIndex:        idx,
4✔
304
                        PrevOutputFetcher: prevOutFetcher,
4✔
305
                }
4✔
306

4✔
307
                // Find out what UTXO we are signing. Wallets _should_ always
4✔
308
                // provide the full non-witness UTXO for segwit v0.
4✔
309
                var signOutput *wire.TxOut
4✔
310
                if in.NonWitnessUtxo != nil {
8✔
311
                        prevIndex := txIn.PreviousOutPoint.Index
4✔
312
                        signOutput = in.NonWitnessUtxo.TxOut[prevIndex]
4✔
313

4✔
314
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
4✔
315
                                return fmt.Errorf("found UTXO %#v but it "+
×
316
                                        "doesn't match PSBT's input %v",
×
317
                                        signDesc.Output, signOutput)
×
318
                        }
×
319

320
                        if fullTx.TxHash() != txIn.PreviousOutPoint.Hash {
4✔
321
                                return fmt.Errorf("found UTXO tx %v but it "+
×
322
                                        "doesn't match PSBT's input %v",
×
323
                                        fullTx.TxHash(),
×
324
                                        txIn.PreviousOutPoint.Hash)
×
325
                        }
×
326
                }
327

328
                // Fall back to witness UTXO only for older wallets.
329
                if in.WitnessUtxo != nil {
8✔
330
                        signOutput = in.WitnessUtxo
4✔
331

4✔
332
                        if !psbt.TxOutsEqual(signDesc.Output, signOutput) {
4✔
333
                                return fmt.Errorf("found UTXO %#v but it "+
×
334
                                        "doesn't match PSBT's input %v",
×
335
                                        signDesc.Output, signOutput)
×
336
                        }
×
337
                }
338

339
                // Do the actual signing in ComputeInputScript which in turn
340
                // will invoke the remote signer.
341
                script, err := r.ComputeInputScript(tx, signDesc)
4✔
342
                if err != nil {
4✔
343
                        return fmt.Errorf("error computing input script for "+
×
344
                                "input %d: %v", idx, err)
×
345
                }
×
346

347
                // Serialize the witness format from the stack representation to
348
                // the wire representation.
349
                var witnessBytes bytes.Buffer
4✔
350
                err = psbt.WriteTxWitness(&witnessBytes, script.Witness)
4✔
351
                if err != nil {
4✔
352
                        return fmt.Errorf("error serializing witness: %w", err)
×
353
                }
×
354
                packet.Inputs[idx].FinalScriptWitness = witnessBytes.Bytes()
4✔
355
                packet.Inputs[idx].FinalScriptSig = script.SigScript
4✔
356
        }
357

358
        // Make sure the PSBT itself thinks it's finalized and ready to be
359
        // broadcast.
360
        err = psbt.MaybeFinalizeAll(packet)
4✔
361
        if err != nil {
4✔
362
                return fmt.Errorf("error finalizing PSBT: %w", err)
×
363
        }
×
364

365
        return nil
4✔
366
}
367

368
// DeriveNextKey attempts to derive the *next* key within the key family
369
// (account in BIP43) specified. This method should return the next external
370
// child within this branch.
371
//
372
// NOTE: This method is part of the keychain.KeyRing interface.
373
func (r *RPCKeyRing) DeriveNextKey(
374
        keyFam keychain.KeyFamily) (keychain.KeyDescriptor, error) {
4✔
375

4✔
376
        return r.watchOnlyKeyRing.DeriveNextKey(keyFam)
4✔
377
}
4✔
378

379
// DeriveKey attempts to derive an arbitrary key specified by the passed
380
// KeyLocator. This may be used in several recovery scenarios, or when manually
381
// rotating something like our current default node key.
382
//
383
// NOTE: This method is part of the keychain.KeyRing interface.
384
func (r *RPCKeyRing) DeriveKey(
385
        keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, error) {
4✔
386

4✔
387
        return r.watchOnlyKeyRing.DeriveKey(keyLoc)
4✔
388
}
4✔
389

390
// ECDH performs a scalar multiplication (ECDH-like operation) between the
391
// target key descriptor and remote public key. The output returned will be the
392
// sha256 of the resulting shared point serialized in compressed format. If k is
393
// our private key, and P is the public key, we perform the following operation:
394
//
395
//        sx := k*P
396
//        s := sha256(sx.SerializeCompressed())
397
//
398
// NOTE: This method is part of the keychain.ECDHRing interface.
399
func (r *RPCKeyRing) ECDH(keyDesc keychain.KeyDescriptor,
400
        pubKey *btcec.PublicKey) ([32]byte, error) {
4✔
401

4✔
402
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
403
        defer cancel()
4✔
404

4✔
405
        key := [32]byte{}
4✔
406
        req := &signrpc.SharedKeyRequest{
4✔
407
                EphemeralPubkey: pubKey.SerializeCompressed(),
4✔
408
                KeyDesc: &signrpc.KeyDescriptor{
4✔
409
                        KeyLoc: &signrpc.KeyLocator{
4✔
410
                                KeyFamily: int32(keyDesc.Family),
4✔
411
                                KeyIndex:  int32(keyDesc.Index),
4✔
412
                        },
4✔
413
                },
4✔
414
        }
4✔
415

4✔
416
        if keyDesc.Index == 0 && keyDesc.PubKey != nil {
8✔
417
                req.KeyDesc.RawKeyBytes = keyDesc.PubKey.SerializeCompressed()
4✔
418
        }
4✔
419

420
        resp, err := r.signerClient.DeriveSharedKey(ctxt, req)
4✔
421
        if err != nil {
4✔
422
                considerShutdown(err)
×
423
                return key, fmt.Errorf("error deriving shared key in remote "+
×
424
                        "signer instance: %v", err)
×
425
        }
×
426

427
        copy(key[:], resp.SharedKey)
4✔
428
        return key, nil
4✔
429
}
430

431
// SignMessage attempts to sign a target message with the private key described
432
// in the key locator. If the target private key is unable to be found, then an
433
// error will be returned. The actual digest signed is the single or double
434
// SHA-256 of the passed message.
435
//
436
// NOTE: This method is part of the keychain.MessageSignerRing interface.
437
func (r *RPCKeyRing) SignMessage(keyLoc keychain.KeyLocator,
438
        msg []byte, doubleHash bool) (*ecdsa.Signature, error) {
4✔
439

4✔
440
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
441
        defer cancel()
4✔
442

4✔
443
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
444
                Msg: msg,
4✔
445
                KeyLoc: &signrpc.KeyLocator{
4✔
446
                        KeyFamily: int32(keyLoc.Family),
4✔
447
                        KeyIndex:  int32(keyLoc.Index),
4✔
448
                },
4✔
449
                DoubleHash: doubleHash,
4✔
450
        })
4✔
451
        if err != nil {
4✔
452
                considerShutdown(err)
×
453
                return nil, fmt.Errorf("error signing message in remote "+
×
454
                        "signer instance: %v", err)
×
455
        }
×
456

457
        wireSig, err := lnwire.NewSigFromECDSARawSignature(resp.Signature)
4✔
458
        if err != nil {
4✔
459
                return nil, fmt.Errorf("unable to create sig: %w", err)
×
460
        }
×
461
        sig, err := wireSig.ToSignature()
4✔
462
        if err != nil {
4✔
463
                return nil, fmt.Errorf("unable to parse sig: %w", err)
×
464
        }
×
465
        ecdsaSig, ok := sig.(*ecdsa.Signature)
4✔
466
        if !ok {
4✔
467
                return nil, fmt.Errorf("unexpected signature type: %T", sig)
×
468
        }
×
469

470
        return ecdsaSig, nil
4✔
471
}
472

473
// SignMessageCompact signs the given message, single or double SHA256 hashing
474
// it first, with the private key described in the key locator and returns the
475
// signature in the compact, public key recoverable format.
476
//
477
// NOTE: This method is part of the keychain.MessageSignerRing interface.
478
func (r *RPCKeyRing) SignMessageCompact(keyLoc keychain.KeyLocator,
479
        msg []byte, doubleHash bool) ([]byte, error) {
4✔
480

4✔
481
        if keyLoc.Family != keychain.KeyFamilyNodeKey {
4✔
482
                return nil, fmt.Errorf("error compact signing with key "+
×
483
                        "locator %v, can only sign with node key", keyLoc)
×
484
        }
×
485

486
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
487
        defer cancel()
4✔
488

4✔
489
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
490
                Msg: msg,
4✔
491
                KeyLoc: &signrpc.KeyLocator{
4✔
492
                        KeyFamily: int32(keyLoc.Family),
4✔
493
                        KeyIndex:  int32(keyLoc.Index),
4✔
494
                },
4✔
495
                DoubleHash: doubleHash,
4✔
496
                CompactSig: true,
4✔
497
        })
4✔
498
        if err != nil {
4✔
499
                considerShutdown(err)
×
500
                return nil, fmt.Errorf("error signing message in remote "+
×
501
                        "signer instance: %v", err)
×
502
        }
×
503

504
        // The signature in the response is zbase32 encoded, so we need to
505
        // decode it before returning.
506
        return resp.Signature, nil
4✔
507
}
508

509
// SignMessageSchnorr attempts to sign a target message with the private key
510
// described in the key locator. If the target private key is unable to be
511
// found, then an error will be returned. The actual digest signed is the
512
// single or double SHA-256 of the passed message.
513
//
514
// NOTE: This method is part of the keychain.MessageSignerRing interface.
515
func (r *RPCKeyRing) SignMessageSchnorr(keyLoc keychain.KeyLocator,
516
        msg []byte, doubleHash bool, taprootTweak []byte,
517
        tag []byte) (*schnorr.Signature, error) {
4✔
518

4✔
519
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
520
        defer cancel()
4✔
521

4✔
522
        resp, err := r.signerClient.SignMessage(ctxt, &signrpc.SignMessageReq{
4✔
523
                Msg: msg,
4✔
524
                KeyLoc: &signrpc.KeyLocator{
4✔
525
                        KeyFamily: int32(keyLoc.Family),
4✔
526
                        KeyIndex:  int32(keyLoc.Index),
4✔
527
                },
4✔
528
                DoubleHash:         doubleHash,
4✔
529
                SchnorrSig:         true,
4✔
530
                SchnorrSigTapTweak: taprootTweak,
4✔
531
                Tag:                tag,
4✔
532
        })
4✔
533
        if err != nil {
4✔
534
                considerShutdown(err)
×
535
                return nil, fmt.Errorf("error signing message in remote "+
×
536
                        "signer instance: %w", err)
×
537
        }
×
538

539
        sigParsed, err := schnorr.ParseSignature(resp.Signature)
4✔
540
        if err != nil {
4✔
541
                return nil, fmt.Errorf("can't parse schnorr signature: %w",
×
542
                        err)
×
543
        }
×
544
        return sigParsed, nil
4✔
545
}
546

547
// DerivePrivKey attempts to derive the private key that corresponds to the
548
// passed key descriptor.  If the public key is set, then this method will
549
// perform an in-order scan over the key set, with a max of MaxKeyRangeScan
550
// keys. In order for this to work, the caller MUST set the KeyFamily within the
551
// partially populated KeyLocator.
552
//
553
// NOTE: This method is part of the keychain.SecretKeyRing interface.
554
func (r *RPCKeyRing) DerivePrivKey(_ keychain.KeyDescriptor) (*btcec.PrivateKey,
555
        error) {
×
556

×
557
        // This operation is not supported with remote signing. There should be
×
558
        // no need for invoking this method unless a channel backup (SCB) file
×
559
        // for pre-0.13.0 channels are attempted to be restored. In that case
×
560
        // it is recommended to restore the channels using a node with the full
×
561
        // seed available.
×
562
        return nil, ErrRemoteSigningPrivateKeyNotAvailable
×
563
}
×
564

565
// SignOutputRaw generates a signature for the passed transaction
566
// according to the data within the passed SignDescriptor.
567
//
568
// NOTE: The resulting signature should be void of a sighash byte.
569
//
570
// NOTE: This method is part of the input.Signer interface.
571
//
572
// NOTE: This method only signs with BIP1017 (internal) keys!
573
func (r *RPCKeyRing) SignOutputRaw(tx *wire.MsgTx,
574
        signDesc *input.SignDescriptor) (input.Signature, error) {
4✔
575

4✔
576
        // Forward the call to the remote signing instance. This call is only
4✔
577
        // ever called for signing witness (p2pkh or p2wsh) inputs and never
4✔
578
        // nested witness inputs, so the sigScript is always nil.
4✔
579
        return r.remoteSign(tx, signDesc, nil)
4✔
580
}
4✔
581

582
// ComputeInputScript generates a complete InputIndex for the passed
583
// transaction with the signature as defined within the passed
584
// SignDescriptor. This method should be capable of generating the
585
// proper input script for both regular p2wkh output and p2wkh outputs
586
// nested within a regular p2sh output.
587
//
588
// NOTE: This method will ignore any tweak parameters set within the
589
// passed SignDescriptor as it assumes a set of typical script
590
// templates (p2wkh, np2wkh, BIP0086 p2tr, etc).
591
//
592
// NOTE: This method is part of the input.Signer interface.
593
func (r *RPCKeyRing) ComputeInputScript(tx *wire.MsgTx,
594
        signDesc *input.SignDescriptor) (*input.Script, error) {
4✔
595

4✔
596
        addr, witnessProgram, sigScript, err := r.WalletController.ScriptForOutput(
4✔
597
                signDesc.Output,
4✔
598
        )
4✔
599
        if err != nil {
4✔
600
                return nil, err
×
601
        }
×
602
        signDesc.WitnessScript = witnessProgram
4✔
603

4✔
604
        // If this is a p2tr address, then it must be a BIP0086 key spend if we
4✔
605
        // are coming through this path (instead of SignOutputRaw).
4✔
606
        switch addr.AddrType() {
4✔
607
        case waddrmgr.TaprootPubKey:
4✔
608
                signDesc.SignMethod = input.TaprootKeySpendBIP0086SignMethod
4✔
609
                signDesc.WitnessScript = nil
4✔
610

4✔
611
                sig, err := r.remoteSign(tx, signDesc, nil)
4✔
612
                if err != nil {
4✔
613
                        return nil, fmt.Errorf("error signing with remote"+
×
614
                                "instance: %v", err)
×
615
                }
×
616

617
                rawSig := sig.Serialize()
4✔
618
                if signDesc.HashType != txscript.SigHashDefault {
4✔
619
                        rawSig = append(rawSig, byte(signDesc.HashType))
×
620
                }
×
621

622
                return &input.Script{
4✔
623
                        Witness: wire.TxWitness{
4✔
624
                                rawSig,
4✔
625
                        },
4✔
626
                }, nil
4✔
627

628
        case waddrmgr.TaprootScript:
×
629
                return nil, fmt.Errorf("computing input script for taproot " +
×
630
                        "script address not supported")
×
631
        }
632

633
        // Let's give the TX to the remote instance now, so it can sign the
634
        // input.
635
        sig, err := r.remoteSign(tx, signDesc, witnessProgram)
4✔
636
        if err != nil {
4✔
637
                return nil, fmt.Errorf("error signing with remote instance: %w",
×
638
                        err)
×
639
        }
×
640

641
        // ComputeInputScript currently is only used for P2WKH and NP2WKH
642
        // addresses. So the last item on the stack is always the compressed
643
        // public key.
644
        return &input.Script{
4✔
645
                Witness: wire.TxWitness{
4✔
646
                        append(sig.Serialize(), byte(signDesc.HashType)),
4✔
647
                        addr.PubKey().SerializeCompressed(),
4✔
648
                },
4✔
649
                SigScript: sigScript,
4✔
650
        }, nil
4✔
651
}
652

653
// MuSig2CreateSession creates a new MuSig2 signing session using the local
654
// key identified by the key locator. The complete list of all public keys of
655
// all signing parties must be provided, including the public key of the local
656
// signing key. If nonces of other parties are already known, they can be
657
// submitted as well to reduce the number of method calls necessary later on.
658
func (r *RPCKeyRing) MuSig2CreateSession(bipVersion input.MuSig2Version,
659
        keyLoc keychain.KeyLocator, pubKeys []*btcec.PublicKey,
660
        tweaks *input.MuSig2Tweaks, otherNonces [][musig2.PubNonceSize]byte,
661
        localNonces *musig2.Nonces) (*input.MuSig2SessionInfo, error) {
4✔
662

4✔
663
        apiVersion, err := signrpc.MarshalMuSig2Version(bipVersion)
4✔
664
        if err != nil {
4✔
665
                return nil, err
×
666
        }
×
667

668
        // We need to serialize all data for the RPC call. We can do that by
669
        // putting everything directly into the request struct.
670
        req := &signrpc.MuSig2SessionRequest{
4✔
671
                KeyLoc: &signrpc.KeyLocator{
4✔
672
                        KeyFamily: int32(keyLoc.Family),
4✔
673
                        KeyIndex:  int32(keyLoc.Index),
4✔
674
                },
4✔
675
                AllSignerPubkeys: make([][]byte, len(pubKeys)),
4✔
676
                Tweaks: make(
4✔
677
                        []*signrpc.TweakDesc, len(tweaks.GenericTweaks),
4✔
678
                ),
4✔
679
                OtherSignerPublicNonces: make([][]byte, len(otherNonces)),
4✔
680
                Version:                 apiVersion,
4✔
681
        }
4✔
682
        for idx, pubKey := range pubKeys {
8✔
683
                switch bipVersion {
4✔
684
                case input.MuSig2Version040:
4✔
685
                        req.AllSignerPubkeys[idx] = schnorr.SerializePubKey(
4✔
686
                                pubKey,
4✔
687
                        )
4✔
688

689
                case input.MuSig2Version100RC2:
4✔
690
                        req.AllSignerPubkeys[idx] = pubKey.SerializeCompressed()
4✔
691
                }
692
        }
693
        for idx, genericTweak := range tweaks.GenericTweaks {
4✔
694
                req.Tweaks[idx] = &signrpc.TweakDesc{
×
695
                        Tweak:   genericTweak.Tweak[:],
×
696
                        IsXOnly: genericTweak.IsXOnly,
×
697
                }
×
698
        }
×
699
        for idx, nonce := range otherNonces {
8✔
700
                req.OtherSignerPublicNonces[idx] = make([]byte, len(nonce))
4✔
701
                copy(req.OtherSignerPublicNonces[idx], nonce[:])
4✔
702
        }
4✔
703
        if tweaks.HasTaprootTweak() {
8✔
704
                req.TaprootTweak = &signrpc.TaprootTweakDesc{
4✔
705
                        KeySpendOnly: tweaks.TaprootBIP0086Tweak,
4✔
706
                        ScriptRoot:   tweaks.TaprootTweak,
4✔
707
                }
4✔
708
        }
4✔
709

710
        if localNonces != nil {
8✔
711
                req.PregeneratedLocalNonce = localNonces.SecNonce[:]
4✔
712
        }
4✔
713

714
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
715
        defer cancel()
4✔
716

4✔
717
        resp, err := r.signerClient.MuSig2CreateSession(ctxt, req)
4✔
718
        if err != nil {
4✔
719
                considerShutdown(err)
×
720
                return nil, fmt.Errorf("error creating MuSig2 session in "+
×
721
                        "remote signer instance: %v", err)
×
722
        }
×
723

724
        // De-Serialize all the info back into our native struct.
725
        info := &input.MuSig2SessionInfo{
4✔
726
                Version:       bipVersion,
4✔
727
                TaprootTweak:  tweaks.HasTaprootTweak(),
4✔
728
                HaveAllNonces: resp.HaveAllNonces,
4✔
729
        }
4✔
730
        copy(info.SessionID[:], resp.SessionId)
4✔
731
        copy(info.PublicNonce[:], resp.LocalPublicNonces)
4✔
732

4✔
733
        info.CombinedKey, err = schnorr.ParsePubKey(resp.CombinedKey)
4✔
734
        if err != nil {
4✔
735
                return nil, fmt.Errorf("error parsing combined key: %w", err)
×
736
        }
×
737

738
        if tweaks.HasTaprootTweak() {
8✔
739
                info.TaprootInternalKey, err = schnorr.ParsePubKey(
4✔
740
                        resp.TaprootInternalKey,
4✔
741
                )
4✔
742
                if err != nil {
4✔
743
                        return nil, fmt.Errorf("error parsing internal key: %w",
×
744
                                err)
×
745
                }
×
746
        }
747

748
        return info, nil
4✔
749
}
750

751
// MuSig2RegisterNonces registers one or more public nonces of other signing
752
// participants for a session identified by its ID. This method returns true
753
// once we have all nonces for all other signing participants.
754
func (r *RPCKeyRing) MuSig2RegisterNonces(sessionID input.MuSig2SessionID,
755
        pubNonces [][musig2.PubNonceSize]byte) (bool, error) {
4✔
756

4✔
757
        // We need to serialize all data for the RPC call. We can do that by
4✔
758
        // putting everything directly into the request struct.
4✔
759
        req := &signrpc.MuSig2RegisterNoncesRequest{
4✔
760
                SessionId:               sessionID[:],
4✔
761
                OtherSignerPublicNonces: make([][]byte, len(pubNonces)),
4✔
762
        }
4✔
763
        for idx, nonce := range pubNonces {
8✔
764
                req.OtherSignerPublicNonces[idx] = make([]byte, len(nonce))
4✔
765
                copy(req.OtherSignerPublicNonces[idx], nonce[:])
4✔
766
        }
4✔
767

768
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
769
        defer cancel()
4✔
770

4✔
771
        resp, err := r.signerClient.MuSig2RegisterNonces(ctxt, req)
4✔
772
        if err != nil {
4✔
773
                considerShutdown(err)
×
774
                return false, fmt.Errorf("error registering MuSig2 nonces in "+
×
775
                        "remote signer instance: %v", err)
×
776
        }
×
777

778
        return resp.HaveAllNonces, nil
4✔
779
}
780

781
// MuSig2Sign creates a partial signature using the local signing key
782
// that was specified when the session was created. This can only be
783
// called when all public nonces of all participants are known and have
784
// been registered with the session. If this node isn't responsible for
785
// combining all the partial signatures, then the cleanup parameter
786
// should be set, indicating that the session can be removed from memory
787
// once the signature was produced.
788
func (r *RPCKeyRing) MuSig2Sign(sessionID input.MuSig2SessionID,
789
        msg [sha256.Size]byte, cleanUp bool) (*musig2.PartialSignature, error) {
4✔
790

4✔
791
        // We need to serialize all data for the RPC call. We can do that by
4✔
792
        // putting everything directly into the request struct.
4✔
793
        req := &signrpc.MuSig2SignRequest{
4✔
794
                SessionId:     sessionID[:],
4✔
795
                MessageDigest: msg[:],
4✔
796
                Cleanup:       cleanUp,
4✔
797
        }
4✔
798

4✔
799
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
800
        defer cancel()
4✔
801

4✔
802
        resp, err := r.signerClient.MuSig2Sign(ctxt, req)
4✔
803
        if err != nil {
8✔
804
                considerShutdown(err)
4✔
805
                return nil, fmt.Errorf("error signing MuSig2 session in "+
4✔
806
                        "remote signer instance: %v", err)
4✔
807
        }
4✔
808

809
        partialSig, err := input.DeserializePartialSignature(
4✔
810
                resp.LocalPartialSignature,
4✔
811
        )
4✔
812
        if err != nil {
4✔
813
                return nil, fmt.Errorf("error parsing partial signature from "+
×
814
                        "remote signer: %v", err)
×
815
        }
×
816

817
        return partialSig, nil
4✔
818
}
819

820
// MuSig2CombineSig combines the given partial signature(s) with the
821
// local one, if it already exists. Once a partial signature of all
822
// participants is registered, the final signature will be combined and
823
// returned.
824
func (r *RPCKeyRing) MuSig2CombineSig(sessionID input.MuSig2SessionID,
825
        partialSigs []*musig2.PartialSignature) (*schnorr.Signature, bool,
826
        error) {
4✔
827

4✔
828
        // We need to serialize all data for the RPC call. We can do that by
4✔
829
        // putting everything directly into the request struct.
4✔
830
        req := &signrpc.MuSig2CombineSigRequest{
4✔
831
                SessionId:              sessionID[:],
4✔
832
                OtherPartialSignatures: make([][]byte, len(partialSigs)),
4✔
833
        }
4✔
834
        for idx, partialSig := range partialSigs {
8✔
835
                rawSig, err := input.SerializePartialSignature(partialSig)
4✔
836
                if err != nil {
4✔
837
                        return nil, false, fmt.Errorf("error serializing "+
×
838
                                "partial signature: %v", err)
×
839
                }
×
840
                req.OtherPartialSignatures[idx] = rawSig[:]
4✔
841
        }
842

843
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
844
        defer cancel()
4✔
845

4✔
846
        resp, err := r.signerClient.MuSig2CombineSig(ctxt, req)
4✔
847
        if err != nil {
4✔
848
                considerShutdown(err)
×
849
                return nil, false, fmt.Errorf("error combining MuSig2 "+
×
850
                        "signatures in remote signer instance: %v", err)
×
851
        }
×
852

853
        // The final signature is only available when we have all the other
854
        // partial signatures from all participants.
855
        if !resp.HaveAllSignatures {
8✔
856
                return nil, resp.HaveAllSignatures, nil
4✔
857
        }
4✔
858

859
        finalSig, err := schnorr.ParseSignature(resp.FinalSignature)
4✔
860
        if err != nil {
4✔
861
                return nil, false, fmt.Errorf("error parsing final signature: "+
×
862
                        "%v", err)
×
863
        }
×
864

865
        return finalSig, resp.HaveAllSignatures, nil
4✔
866
}
867

868
// MuSig2Cleanup removes a session from memory to free up resources.
869
func (r *RPCKeyRing) MuSig2Cleanup(sessionID input.MuSig2SessionID) error {
4✔
870
        req := &signrpc.MuSig2CleanupRequest{
4✔
871
                SessionId: sessionID[:],
4✔
872
        }
4✔
873

4✔
874
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
875
        defer cancel()
4✔
876

4✔
877
        _, err := r.signerClient.MuSig2Cleanup(ctxt, req)
4✔
878
        if err != nil {
4✔
879
                considerShutdown(err)
×
880
                return fmt.Errorf("error cleaning up MuSig2 session in remote "+
×
881
                        "signer instance: %v", err)
×
882
        }
×
883

884
        return nil
4✔
885
}
886

887
// remoteSign signs the input specified in signDesc of the given transaction tx
888
// using the remote signing instance.
889
func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor,
890
        sigScript []byte) (input.Signature, error) {
4✔
891

4✔
892
        packet, err := packetFromTx(tx)
4✔
893
        if err != nil {
4✔
894
                return nil, fmt.Errorf("error converting TX into PSBT: %w", err)
×
895
        }
×
896

897
        // We need to add witness information for all inputs! Otherwise, we'll
898
        // have a problem when attempting to sign a taproot input!
899
        for idx := range packet.Inputs {
8✔
900
                // Skip the input we're signing for, that will get a special
4✔
901
                // treatment later on.
4✔
902
                if idx == signDesc.InputIndex {
8✔
903
                        continue
4✔
904
                }
905

906
                txIn := tx.TxIn[idx]
4✔
907
                info, err := r.WalletController.FetchInputInfo(
4✔
908
                        &txIn.PreviousOutPoint,
4✔
909
                )
4✔
910
                if err != nil {
4✔
911
                        // Maybe we have an UTXO in the previous output fetcher?
×
912
                        if signDesc.PrevOutputFetcher != nil {
×
913
                                utxo := signDesc.PrevOutputFetcher.FetchPrevOutput(
×
914
                                        txIn.PreviousOutPoint,
×
915
                                )
×
916
                                if utxo != nil && utxo.Value != 0 &&
×
917
                                        len(utxo.PkScript) > 0 {
×
918

×
919
                                        packet.Inputs[idx].WitnessUtxo = utxo
×
920
                                        continue
×
921
                                }
922
                        }
923

924
                        log.Warnf("No UTXO info found for index %d "+
×
925
                                "(prev_outpoint=%v), won't be able to sign "+
×
926
                                "for taproot output!", idx,
×
927
                                txIn.PreviousOutPoint)
×
928
                        continue
×
929
                }
930
                packet.Inputs[idx].WitnessUtxo = &wire.TxOut{
4✔
931
                        Value:    int64(info.Value),
4✔
932
                        PkScript: info.PkScript,
4✔
933
                }
4✔
934
        }
935

936
        // Catch incorrect signing input index, just in case.
937
        if signDesc.InputIndex < 0 || signDesc.InputIndex >= len(packet.Inputs) {
4✔
938
                return nil, fmt.Errorf("invalid input index in sign descriptor")
×
939
        }
×
940
        in := &packet.Inputs[signDesc.InputIndex]
4✔
941
        txIn := tx.TxIn[signDesc.InputIndex]
4✔
942

4✔
943
        // Things are a bit tricky with the sign descriptor. There basically are
4✔
944
        // four ways to describe a key:
4✔
945
        //   1. By public key only. To match this case both family and index
4✔
946
        //      must be set to 0.
4✔
947
        //   2. By family and index only. To match this case the public key
4✔
948
        //      must be nil and either the family or index must be non-zero.
4✔
949
        //   3. All values are set and locator is non-empty. To match this case
4✔
950
        //      the public key must be set and either the family or index must
4✔
951
        //      be non-zero.
4✔
952
        //   4. All values are set and locator is empty. This is a special case
4✔
953
        //      for the very first channel ever created (with the multi-sig key
4✔
954
        //      family which is 0 and the index which is 0 as well). This looks
4✔
955
        //      identical to case 1 and will also be handled like that case.
4✔
956
        // We only really handle case 1 and 2 here, since 3 is no problem and 4
4✔
957
        // is identical to 1.
4✔
958
        switch {
4✔
959
        // Case 1: Public key only. We need to find out the derivation path for
960
        // this public key by asking the wallet. This is only possible for our
961
        // internal, custom 1017 scope since we know all keys derived there are
962
        // internally stored as p2wkh addresses.
963
        case signDesc.KeyDesc.PubKey != nil && signDesc.KeyDesc.IsEmpty():
4✔
964
                pubKeyBytes := signDesc.KeyDesc.PubKey.SerializeCompressed()
4✔
965
                addr, err := btcutil.NewAddressWitnessPubKeyHash(
4✔
966
                        btcutil.Hash160(pubKeyBytes), r.netParams,
4✔
967
                )
4✔
968
                if err != nil {
4✔
969
                        return nil, fmt.Errorf("error deriving address from "+
×
970
                                "public key %x: %v", pubKeyBytes, err)
×
971
                }
×
972

973
                managedAddr, err := r.AddressInfo(addr)
4✔
974
                if err != nil {
4✔
975
                        return nil, fmt.Errorf("error fetching address info "+
×
976
                                "for public key %x: %v", pubKeyBytes, err)
×
977
                }
×
978

979
                pubKeyAddr, ok := managedAddr.(waddrmgr.ManagedPubKeyAddress)
4✔
980
                if !ok {
4✔
981
                        return nil, fmt.Errorf("address derived for public "+
×
982
                                "key %x is not a p2wkh address", pubKeyBytes)
×
983
                }
×
984

985
                scope, path, _ := pubKeyAddr.DerivationInfo()
4✔
986
                if scope.Purpose != keychain.BIP0043Purpose {
4✔
987
                        return nil, fmt.Errorf("address derived for public "+
×
988
                                "key %x is not in custom key scope %d'",
×
989
                                pubKeyBytes, keychain.BIP0043Purpose)
×
990
                }
×
991

992
                // We now have all the information we need to complete our key
993
                // locator information.
994
                signDesc.KeyDesc.KeyLocator = keychain.KeyLocator{
4✔
995
                        Family: keychain.KeyFamily(path.InternalAccount),
4✔
996
                        Index:  path.Index,
4✔
997
                }
4✔
998

999
        // Case 2: Family and index only. This case is easy, we can just go
1000
        // ahead and derive the public key from the family and index and then
1001
        // supply that information in the BIP32 derivation field.
1002
        case signDesc.KeyDesc.PubKey == nil && !signDesc.KeyDesc.IsEmpty():
4✔
1003
                fullDesc, err := r.watchOnlyKeyRing.DeriveKey(
4✔
1004
                        signDesc.KeyDesc.KeyLocator,
4✔
1005
                )
4✔
1006
                if err != nil {
4✔
1007
                        return nil, fmt.Errorf("error deriving key with "+
×
1008
                                "family %d and index %d from the watch-only "+
×
1009
                                "wallet: %v",
×
1010
                                signDesc.KeyDesc.KeyLocator.Family,
×
1011
                                signDesc.KeyDesc.KeyLocator.Index, err)
×
1012
                }
×
1013
                signDesc.KeyDesc.PubKey = fullDesc.PubKey
4✔
1014
        }
1015

1016
        // Make sure we actually know about the input. We either have been
1017
        // watching the UTXO on-chain or we have been given all the required
1018
        // info in the sign descriptor.
1019
        info, err := r.WalletController.FetchInputInfo(&txIn.PreviousOutPoint)
4✔
1020
        switch {
4✔
1021
        // No error, we do have the full UTXO and derivation info available.
1022
        case err == nil:
4✔
1023
                in.WitnessUtxo = &wire.TxOut{
4✔
1024
                        Value:    int64(info.Value),
4✔
1025
                        PkScript: info.PkScript,
4✔
1026
                }
4✔
1027
                in.NonWitnessUtxo = info.PrevTx
4✔
1028
                in.Bip32Derivation = []*psbt.Bip32Derivation{info.Derivation}
4✔
1029

1030
        // The wallet doesn't know about this UTXO, so it's probably a TX that
1031
        // we haven't published yet (e.g. a channel funding TX). So we need to
1032
        // assemble everything from the sign descriptor. We won't be able to
1033
        // supply a non-witness UTXO (=full TX of the input being spent) in this
1034
        // case. That is no problem if the signing instance is another lnd
1035
        // instance since we don't require it for pure witness inputs. But a
1036
        // hardware wallet might require it for security reasons.
1037
        case signDesc.KeyDesc.PubKey != nil && signDesc.Output != nil:
4✔
1038
                in.WitnessUtxo = signDesc.Output
4✔
1039
                in.Bip32Derivation = []*psbt.Bip32Derivation{{
4✔
1040
                        Bip32Path: []uint32{
4✔
1041
                                keychain.BIP0043Purpose +
4✔
1042
                                        hdkeychain.HardenedKeyStart,
4✔
1043
                                r.netParams.HDCoinType +
4✔
1044
                                        hdkeychain.HardenedKeyStart,
4✔
1045
                                uint32(signDesc.KeyDesc.Family) +
4✔
1046
                                        hdkeychain.HardenedKeyStart,
4✔
1047
                                0,
4✔
1048
                                signDesc.KeyDesc.Index,
4✔
1049
                        },
4✔
1050
                        PubKey: signDesc.KeyDesc.PubKey.SerializeCompressed(),
4✔
1051
                }}
4✔
1052

4✔
1053
                // We need to specify a pk script in the witness UTXO, otherwise
4✔
1054
                // the field becomes invalid when serialized as a PSBT. To avoid
4✔
1055
                // running into a generic "Invalid PSBT serialization format"
4✔
1056
                // error later, we return a more descriptive error now.
4✔
1057
                if len(in.WitnessUtxo.PkScript) == 0 {
4✔
1058
                        return nil, fmt.Errorf("error assembling UTXO " +
×
1059
                                "information, output not known to wallet and " +
×
1060
                                "no UTXO pk script provided in sign descriptor")
×
1061
                }
×
1062

1063
        default:
×
1064
                return nil, fmt.Errorf("error assembling UTXO information, "+
×
1065
                        "wallet returned err='%v' and sign descriptor is "+
×
1066
                        "incomplete", err)
×
1067
        }
1068

1069
        // Assemble all other information about the input we have.
1070
        in.RedeemScript = sigScript
4✔
1071
        in.SighashType = signDesc.HashType
4✔
1072
        in.WitnessScript = signDesc.WitnessScript
4✔
1073

4✔
1074
        if len(signDesc.SingleTweak) > 0 {
8✔
1075
                in.Unknowns = append(in.Unknowns, &psbt.Unknown{
4✔
1076
                        Key:   btcwallet.PsbtKeyTypeInputSignatureTweakSingle,
4✔
1077
                        Value: signDesc.SingleTweak,
4✔
1078
                })
4✔
1079
        }
4✔
1080
        if signDesc.DoubleTweak != nil {
4✔
1081
                in.Unknowns = append(in.Unknowns, &psbt.Unknown{
×
1082
                        Key:   btcwallet.PsbtKeyTypeInputSignatureTweakDouble,
×
1083
                        Value: signDesc.DoubleTweak.Serialize(),
×
1084
                })
×
1085
        }
×
1086

1087
        // Add taproot specific fields.
1088
        switch signDesc.SignMethod {
4✔
1089
        case input.TaprootKeySpendBIP0086SignMethod,
1090
                input.TaprootKeySpendSignMethod:
4✔
1091

4✔
1092
                // The key identifying factor for a key spend is that we don't
4✔
1093
                // provide any leaf hashes to signal we want a signature for the
4✔
1094
                // key spend path (with the internal key).
4✔
1095
                d := in.Bip32Derivation[0]
4✔
1096
                in.TaprootBip32Derivation = []*psbt.TaprootBip32Derivation{{
4✔
1097
                        // The x-only public key is just our compressed public
4✔
1098
                        // key without the first byte (type/parity).
4✔
1099
                        XOnlyPubKey:          d.PubKey[1:],
4✔
1100
                        LeafHashes:           nil,
4✔
1101
                        MasterKeyFingerprint: d.MasterKeyFingerprint,
4✔
1102
                        Bip32Path:            d.Bip32Path,
4✔
1103
                }}
4✔
1104

4✔
1105
                // If this is a BIP0086 key spend then the tap tweak is empty,
4✔
1106
                // otherwise it's set to the Taproot root hash.
4✔
1107
                in.TaprootMerkleRoot = signDesc.TapTweak
4✔
1108

1109
        case input.TaprootScriptSpendSignMethod:
4✔
1110
                // The script spend path is a bit more involved when doing it
4✔
1111
                // through the PSBT method. We need to specify the leaf hash
4✔
1112
                // that the signer should sign for.
4✔
1113
                leaf := txscript.TapLeaf{
4✔
1114
                        LeafVersion: txscript.BaseLeafVersion,
4✔
1115
                        Script:      signDesc.WitnessScript,
4✔
1116
                }
4✔
1117
                leafHash := leaf.TapHash()
4✔
1118

4✔
1119
                d := in.Bip32Derivation[0]
4✔
1120
                in.TaprootBip32Derivation = []*psbt.TaprootBip32Derivation{{
4✔
1121
                        XOnlyPubKey:          d.PubKey[1:],
4✔
1122
                        LeafHashes:           [][]byte{leafHash[:]},
4✔
1123
                        MasterKeyFingerprint: d.MasterKeyFingerprint,
4✔
1124
                        Bip32Path:            d.Bip32Path,
4✔
1125
                }}
4✔
1126

4✔
1127
                // We also need to supply a control block. But because we don't
4✔
1128
                // know the internal key nor the merkle proofs (both is not
4✔
1129
                // supplied through the SignOutputRaw RPC) and is technically
4✔
1130
                // not really needed by the signer (since we only want a
4✔
1131
                // signature, the full witness stack is assembled by the caller
4✔
1132
                // of this RPC), we can get by with faking certain information
4✔
1133
                // that we don't have.
4✔
1134
                fakeInternalKey, _ := btcec.ParsePubKey(d.PubKey)
4✔
1135
                fakeKeyIsOdd := d.PubKey[0] == input.PubKeyFormatCompressedOdd
4✔
1136
                controlBlock := txscript.ControlBlock{
4✔
1137
                        InternalKey:     fakeInternalKey,
4✔
1138
                        OutputKeyYIsOdd: fakeKeyIsOdd,
4✔
1139
                        LeafVersion:     leaf.LeafVersion,
4✔
1140
                }
4✔
1141
                blockBytes, err := controlBlock.ToBytes()
4✔
1142
                if err != nil {
4✔
1143
                        return nil, fmt.Errorf("error serializing control "+
×
1144
                                "block: %v", err)
×
1145
                }
×
1146

1147
                in.TaprootLeafScript = []*psbt.TaprootTapLeafScript{{
4✔
1148
                        ControlBlock: blockBytes,
4✔
1149
                        Script:       leaf.Script,
4✔
1150
                        LeafVersion:  leaf.LeafVersion,
4✔
1151
                }}
4✔
1152
        }
1153

1154
        // Okay, let's sign the input by the remote signer now.
1155
        ctxt, cancel := context.WithTimeout(context.Background(), r.rpcTimeout)
4✔
1156
        defer cancel()
4✔
1157

4✔
1158
        var buf bytes.Buffer
4✔
1159
        if err := packet.Serialize(&buf); err != nil {
4✔
1160
                return nil, fmt.Errorf("error serializing PSBT: %w", err)
×
1161
        }
×
1162

1163
        resp, err := r.walletClient.SignPsbt(
4✔
1164
                ctxt, &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()},
4✔
1165
        )
4✔
1166
        if err != nil {
4✔
1167
                considerShutdown(err)
×
1168
                return nil, fmt.Errorf("error signing PSBT in remote signer "+
×
1169
                        "instance: %v", err)
×
1170
        }
×
1171

1172
        signedPacket, err := psbt.NewFromRawBytes(
4✔
1173
                bytes.NewReader(resp.SignedPsbt), false,
4✔
1174
        )
4✔
1175
        if err != nil {
4✔
1176
                return nil, fmt.Errorf("error parsing signed PSBT: %w", err)
×
1177
        }
×
1178

1179
        // We expect a signature in the input now.
1180
        if signDesc.InputIndex >= len(signedPacket.Inputs) {
4✔
1181
                return nil, fmt.Errorf("remote signer returned invalid PSBT")
×
1182
        }
×
1183
        in = &signedPacket.Inputs[signDesc.InputIndex]
4✔
1184

4✔
1185
        return extractSignature(in, signDesc.SignMethod)
4✔
1186
}
1187

1188
// extractSignature attempts to extract the signature from the PSBT input,
1189
// looking at different fields depending on the signing method that was used.
1190
func extractSignature(in *psbt.PInput,
1191
        signMethod input.SignMethod) (input.Signature, error) {
4✔
1192

4✔
1193
        switch signMethod {
4✔
1194
        case input.WitnessV0SignMethod:
4✔
1195
                if len(in.PartialSigs) != 1 {
4✔
1196
                        return nil, fmt.Errorf("remote signer returned "+
×
1197
                                "invalid partial signature, wanted 1, got %d",
×
1198
                                len(in.PartialSigs))
×
1199
                }
×
1200
                sigWithSigHash := in.PartialSigs[0]
4✔
1201
                if sigWithSigHash == nil {
4✔
1202
                        return nil, fmt.Errorf("remote signer returned nil " +
×
1203
                                "signature")
×
1204
                }
×
1205

1206
                // The remote signer always adds the sighash type, so we need to
1207
                // account for that.
1208
                sigLen := len(sigWithSigHash.Signature)
4✔
1209
                if sigLen < ecdsa.MinSigLen+1 {
4✔
1210
                        return nil, fmt.Errorf("remote signer returned "+
×
1211
                                "invalid partial signature: signature too "+
×
1212
                                "short with %d bytes", sigLen)
×
1213
                }
×
1214

1215
                // Parse the signature, but chop off the last byte which is the
1216
                // sighash type.
1217
                sig := sigWithSigHash.Signature[0 : sigLen-1]
4✔
1218
                return ecdsa.ParseDERSignature(sig)
4✔
1219

1220
        // The type of key spend doesn't matter, the signature should be in the
1221
        // same field for both of those signing methods.
1222
        case input.TaprootKeySpendBIP0086SignMethod,
1223
                input.TaprootKeySpendSignMethod:
4✔
1224

4✔
1225
                sigLen := len(in.TaprootKeySpendSig)
4✔
1226
                if sigLen < schnorr.SignatureSize {
4✔
1227
                        return nil, fmt.Errorf("remote signer returned "+
×
1228
                                "invalid key spend signature: signature too "+
×
1229
                                "short with %d bytes", sigLen)
×
1230
                }
×
1231

1232
                return schnorr.ParseSignature(
4✔
1233
                        in.TaprootKeySpendSig[:schnorr.SignatureSize],
4✔
1234
                )
4✔
1235

1236
        case input.TaprootScriptSpendSignMethod:
4✔
1237
                if len(in.TaprootScriptSpendSig) != 1 {
4✔
1238
                        return nil, fmt.Errorf("remote signer returned "+
×
1239
                                "invalid taproot script spend signature, "+
×
1240
                                "wanted 1, got %d",
×
1241
                                len(in.TaprootScriptSpendSig))
×
1242
                }
×
1243
                scriptSpendSig := in.TaprootScriptSpendSig[0]
4✔
1244
                if scriptSpendSig == nil {
4✔
1245
                        return nil, fmt.Errorf("remote signer returned nil " +
×
1246
                                "taproot script spend signature")
×
1247
                }
×
1248

1249
                return schnorr.ParseSignature(scriptSpendSig.Signature)
4✔
1250

1251
        default:
×
1252
                return nil, fmt.Errorf("can't extract signature, unsupported "+
×
1253
                        "signing method: %v", signMethod)
×
1254
        }
1255
}
1256

1257
// connectRPC tries to establish an RPC connection to the given host:port with
1258
// the supplied certificate and macaroon.
1259
func connectRPC(hostPort, tlsCertPath, macaroonPath string,
1260
        timeout time.Duration) (*grpc.ClientConn, error) {
4✔
1261

4✔
1262
        certBytes, err := os.ReadFile(tlsCertPath)
4✔
1263
        if err != nil {
5✔
1264
                return nil, fmt.Errorf("error reading TLS cert file %v: %w",
1✔
1265
                        tlsCertPath, err)
1✔
1266
        }
1✔
1267

1268
        cp := x509.NewCertPool()
4✔
1269
        if !cp.AppendCertsFromPEM(certBytes) {
4✔
1270
                return nil, fmt.Errorf("credentials: failed to append " +
×
1271
                        "certificate")
×
1272
        }
×
1273

1274
        macBytes, err := os.ReadFile(macaroonPath)
4✔
1275
        if err != nil {
4✔
1276
                return nil, fmt.Errorf("error reading macaroon file %v: %w",
×
1277
                        macaroonPath, err)
×
1278
        }
×
1279
        mac := &macaroon.Macaroon{}
4✔
1280
        if err := mac.UnmarshalBinary(macBytes); err != nil {
4✔
1281
                return nil, fmt.Errorf("error decoding macaroon: %w", err)
×
1282
        }
×
1283

1284
        macCred, err := macaroons.NewMacaroonCredential(mac)
4✔
1285
        if err != nil {
4✔
1286
                return nil, fmt.Errorf("error creating creds: %w", err)
×
1287
        }
×
1288

1289
        opts := []grpc.DialOption{
4✔
1290
                grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(
4✔
1291
                        cp, "",
4✔
1292
                )),
4✔
1293
                grpc.WithPerRPCCredentials(macCred),
4✔
1294
                grpc.WithBlock(),
4✔
1295
        }
4✔
1296
        ctxt, cancel := context.WithTimeout(context.Background(), timeout)
4✔
1297
        defer cancel()
4✔
1298
        conn, err := grpc.DialContext(ctxt, hostPort, opts...)
4✔
1299
        if err != nil {
4✔
1300
                return nil, fmt.Errorf("unable to connect to RPC server: %w",
×
1301
                        err)
×
1302
        }
×
1303

1304
        return conn, nil
4✔
1305
}
1306

1307
// packetFromTx creates a PSBT from a tx that potentially already contains
1308
// signed inputs.
1309
func packetFromTx(original *wire.MsgTx) (*psbt.Packet, error) {
4✔
1310
        // The psbt.NewFromUnsignedTx function complains if there are any
4✔
1311
        // scripts or witness content on a TX. So we create a copy of the TX and
4✔
1312
        // nil out all the offending data, but also keep a backup around that we
4✔
1313
        // add to the PSBT afterwards.
4✔
1314
        noSigs := original.Copy()
4✔
1315
        for idx := range noSigs.TxIn {
8✔
1316
                noSigs.TxIn[idx].SignatureScript = nil
4✔
1317
                noSigs.TxIn[idx].Witness = nil
4✔
1318
        }
4✔
1319

1320
        // With all the data that is seen as "signed", we can now create the
1321
        // empty packet.
1322
        packet, err := psbt.NewFromUnsignedTx(noSigs)
4✔
1323
        if err != nil {
4✔
1324
                return nil, err
×
1325
        }
×
1326

1327
        var buf bytes.Buffer
4✔
1328
        for idx, txIn := range original.TxIn {
8✔
1329
                if len(txIn.SignatureScript) > 0 {
4✔
1330
                        packet.Inputs[idx].FinalScriptSig = txIn.SignatureScript
×
1331
                }
×
1332

1333
                if len(txIn.Witness) > 0 {
8✔
1334
                        buf.Reset()
4✔
1335
                        err = psbt.WriteTxWitness(&buf, txIn.Witness)
4✔
1336
                        if err != nil {
4✔
1337
                                return nil, err
×
1338
                        }
×
1339
                        packet.Inputs[idx].FinalScriptWitness = buf.Bytes()
4✔
1340
                }
1341
        }
1342

1343
        return packet, nil
4✔
1344
}
1345

1346
// considerShutdown inspects the error and issues a shutdown (through logging
1347
// a critical error, which will cause the logger to issue a clean shutdown
1348
// request) if the error looks like a connection or general availability error
1349
// and not some application specific problem.
1350
func considerShutdown(err error) {
4✔
1351
        statusErr, isStatusErr := status.FromError(err)
4✔
1352
        switch {
4✔
1353
        // The context attached to the client request has timed out. This can be
1354
        // due to not being able to reach the signing server, or it's taking too
1355
        // long to respond. In either case, request a shutdown.
1356
        case err == context.DeadlineExceeded:
×
1357
                fallthrough
×
1358

1359
        // The signing server's context timed out before the client's due to
1360
        // clock skew, request a shutdown anyway.
1361
        case isStatusErr && statusErr.Code() == codes.DeadlineExceeded:
×
1362
                log.Critical("RPC signing timed out: %v", err)
×
1363

1364
        case isStatusErr && statusErr.Code() == codes.Unavailable:
×
1365
                log.Critical("RPC signing server not available: %v", err)
×
1366
        }
1367
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc