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

lightningnetwork / lnd / 11170835610

03 Oct 2024 10:41PM UTC coverage: 49.188% (-9.6%) from 58.738%
11170835610

push

github

web-flow
Merge pull request #9154 from ziggie1984/master

multi: bump btcd version.

3 of 6 new or added lines in 6 files covered. (50.0%)

26110 existing lines in 428 files now uncovered.

97359 of 197934 relevant lines covered (49.19%)

1.04 hits per line

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

82.5
/keychain/btcwallet.go
1
package keychain
2

3
import (
4
        "crypto/sha256"
5
        "fmt"
6

7
        "github.com/btcsuite/btcd/btcec/v2"
8
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
9
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
10
        "github.com/btcsuite/btcd/chaincfg/chainhash"
11
        "github.com/btcsuite/btcd/txscript"
12
        "github.com/btcsuite/btcwallet/waddrmgr"
13
        "github.com/btcsuite/btcwallet/wallet"
14
        "github.com/btcsuite/btcwallet/walletdb"
15
)
16

17
const (
18
        // CoinTypeBitcoin specifies the BIP44 coin type for Bitcoin key
19
        // derivation.
20
        CoinTypeBitcoin uint32 = 0
21

22
        // CoinTypeTestnet specifies the BIP44 coin type for all testnet key
23
        // derivation.
24
        CoinTypeTestnet = 1
25
)
26

27
var (
28
        // lightningAddrSchema is the scope addr schema for all keys that we
29
        // derive. We'll treat them all as p2wkh addresses, as atm we must
30
        // specify a particular type.
31
        lightningAddrSchema = waddrmgr.ScopeAddrSchema{
32
                ExternalAddrType: waddrmgr.WitnessPubKey,
33
                InternalAddrType: waddrmgr.WitnessPubKey,
34
        }
35

36
        // waddrmgrNamespaceKey is the namespace key that the waddrmgr state is
37
        // stored within the top-level waleltdb buckets of btcwallet.
38
        waddrmgrNamespaceKey = []byte("waddrmgr")
39
)
40

41
// BtcWalletKeyRing is an implementation of both the KeyRing and SecretKeyRing
42
// interfaces backed by btcwallet's internal root waddrmgr. Internally, we'll
43
// be using a ScopedKeyManager to do all of our derivations, using the key
44
// scope and scope addr scehma defined above. Re-using the existing key scope
45
// construction means that all key derivation will be protected under the root
46
// seed of the wallet, making each derived key fully deterministic.
47
type BtcWalletKeyRing struct {
48
        // wallet is a pointer to the active instance of the btcwallet core.
49
        // This is required as we'll need to manually open database
50
        // transactions in order to derive addresses and lookup relevant keys
51
        wallet *wallet.Wallet
52

53
        // chainKeyScope defines the purpose and coin type to be used when generating
54
        // keys for this keyring.
55
        chainKeyScope waddrmgr.KeyScope
56

57
        // lightningScope is a pointer to the scope that we'll be using as a
58
        // sub key manager to derive all the keys that we require.
59
        lightningScope *waddrmgr.ScopedKeyManager
60
}
61

62
// NewBtcWalletKeyRing creates a new implementation of the
63
// keychain.SecretKeyRing interface backed by btcwallet.
64
//
65
// NOTE: The passed waddrmgr.Manager MUST be unlocked in order for the keychain
66
// to function.
67
func NewBtcWalletKeyRing(w *wallet.Wallet, coinType uint32) SecretKeyRing {
2✔
68
        // Construct the key scope that will be used within the waddrmgr to
2✔
69
        // create an HD chain for deriving all of our required keys. A different
2✔
70
        // scope is used for each specific coin type.
2✔
71
        chainKeyScope := waddrmgr.KeyScope{
2✔
72
                Purpose: BIP0043Purpose,
2✔
73
                Coin:    coinType,
2✔
74
        }
2✔
75

2✔
76
        return &BtcWalletKeyRing{
2✔
77
                wallet:        w,
2✔
78
                chainKeyScope: chainKeyScope,
2✔
79
        }
2✔
80
}
2✔
81

82
// keyScope attempts to return the key scope that we'll use to derive all of
83
// our keys. If the scope has already been fetched from the database, then a
84
// cached version will be returned. Otherwise, we'll fetch it from the database
85
// and cache it for subsequent accesses.
86
func (b *BtcWalletKeyRing) keyScope() (*waddrmgr.ScopedKeyManager, error) {
2✔
87
        // If the scope has already been populated, then we'll return it
2✔
88
        // directly.
2✔
89
        if b.lightningScope != nil {
4✔
90
                return b.lightningScope, nil
2✔
91
        }
2✔
92

93
        // Otherwise, we'll first do a check to ensure that the root manager
94
        // isn't locked, as otherwise we won't be able to *use* the scope.
95
        if !b.wallet.Manager.WatchOnly() && b.wallet.Manager.IsLocked() {
2✔
96
                return nil, fmt.Errorf("cannot create BtcWalletKeyRing with " +
×
97
                        "locked waddrmgr.Manager")
×
98
        }
×
99

100
        // If the manager is indeed unlocked, then we'll fetch the scope, cache
101
        // it, and return to the caller.
102
        lnScope, err := b.wallet.Manager.FetchScopedKeyManager(b.chainKeyScope)
2✔
103
        if err != nil {
2✔
104
                return nil, err
×
105
        }
×
106

107
        b.lightningScope = lnScope
2✔
108

2✔
109
        return lnScope, nil
2✔
110
}
111

112
// createAccountIfNotExists will create the corresponding account for a key
113
// family if it doesn't already exist in the database.
114
func (b *BtcWalletKeyRing) createAccountIfNotExists(
115
        addrmgrNs walletdb.ReadWriteBucket, keyFam KeyFamily,
116
        scope *waddrmgr.ScopedKeyManager) error {
2✔
117

2✔
118
        // If this is the multi-sig key family, then we can return early as
2✔
119
        // this is the default account that's created.
2✔
120
        if keyFam == KeyFamilyMultiSig {
4✔
121
                return nil
2✔
122
        }
2✔
123

124
        // Otherwise, we'll check if the account already exists, if so, we can
125
        // once again bail early.
126
        _, err := scope.AccountName(addrmgrNs, uint32(keyFam))
2✔
127
        if err == nil {
4✔
128
                return nil
2✔
129
        }
2✔
130

131
        // If we reach this point, then the account hasn't yet been created, so
132
        // we'll need to create it before we can proceed.
133
        return scope.NewRawAccount(addrmgrNs, uint32(keyFam))
2✔
134
}
135

136
// DeriveNextKey attempts to derive the *next* key within the key family
137
// (account in BIP43) specified. This method should return the next external
138
// child within this branch.
139
//
140
// NOTE: This is part of the keychain.KeyRing interface.
141
func (b *BtcWalletKeyRing) DeriveNextKey(keyFam KeyFamily) (KeyDescriptor, error) {
2✔
142
        var (
2✔
143
                pubKey *btcec.PublicKey
2✔
144
                keyLoc KeyLocator
2✔
145
        )
2✔
146

2✔
147
        db := b.wallet.Database()
2✔
148
        err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
4✔
149
                addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2✔
150

2✔
151
                scope, err := b.keyScope()
2✔
152
                if err != nil {
2✔
153
                        return err
×
154
                }
×
155

156
                // If the account doesn't exist, then we may need to create it
157
                // for the first time in order to derive the keys that we
158
                // require.
159
                err = b.createAccountIfNotExists(addrmgrNs, keyFam, scope)
2✔
160
                if err != nil {
2✔
161
                        return err
×
162
                }
×
163

164
                addrs, err := scope.NextExternalAddresses(
2✔
165
                        addrmgrNs, uint32(keyFam), 1,
2✔
166
                )
2✔
167
                if err != nil {
2✔
168
                        return err
×
169
                }
×
170

171
                // Extract the first address, ensuring that it is of the proper
172
                // interface type, otherwise we can't manipulate it below.
173
                addr, ok := addrs[0].(waddrmgr.ManagedPubKeyAddress)
2✔
174
                if !ok {
2✔
175
                        return fmt.Errorf("address is not a managed pubkey " +
×
176
                                "addr")
×
177
                }
×
178

179
                pubKey = addr.PubKey()
2✔
180

2✔
181
                _, pathInfo, _ := addr.DerivationInfo()
2✔
182
                keyLoc = KeyLocator{
2✔
183
                        Family: keyFam,
2✔
184
                        Index:  pathInfo.Index,
2✔
185
                }
2✔
186

2✔
187
                return nil
2✔
188
        })
189
        if err != nil {
2✔
190
                return KeyDescriptor{}, err
×
191
        }
×
192

193
        return KeyDescriptor{
2✔
194
                PubKey:     pubKey,
2✔
195
                KeyLocator: keyLoc,
2✔
196
        }, nil
2✔
197
}
198

199
// DeriveKey attempts to derive an arbitrary key specified by the passed
200
// KeyLocator. This may be used in several recovery scenarios, or when manually
201
// rotating something like our current default node key.
202
//
203
// NOTE: This is part of the keychain.KeyRing interface.
204
func (b *BtcWalletKeyRing) DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error) {
2✔
205
        var keyDesc KeyDescriptor
2✔
206

2✔
207
        db := b.wallet.Database()
2✔
208
        err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
4✔
209
                addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2✔
210

2✔
211
                scope, err := b.keyScope()
2✔
212
                if err != nil {
2✔
213
                        return err
×
214
                }
×
215

216
                // If the account doesn't exist, then we may need to create it
217
                // for the first time in order to derive the keys that we
218
                // require. We skip this if we're using a remote signer in which
219
                // case we _need_ to create all accounts when creating the
220
                // wallet, so it must exist now.
221
                if !b.wallet.Manager.WatchOnly() {
4✔
222
                        err = b.createAccountIfNotExists(
2✔
223
                                addrmgrNs, keyLoc.Family, scope,
2✔
224
                        )
2✔
225
                        if err != nil {
2✔
226
                                return err
×
227
                        }
×
228
                }
229

230
                path := waddrmgr.DerivationPath{
2✔
231
                        InternalAccount: uint32(keyLoc.Family),
2✔
232
                        Branch:          0,
2✔
233
                        Index:           keyLoc.Index,
2✔
234
                }
2✔
235
                addr, err := scope.DeriveFromKeyPath(addrmgrNs, path)
2✔
236
                if err != nil {
2✔
237
                        return err
×
238
                }
×
239

240
                keyDesc.KeyLocator = keyLoc
2✔
241
                keyDesc.PubKey = addr.(waddrmgr.ManagedPubKeyAddress).PubKey()
2✔
242

2✔
243
                return nil
2✔
244
        })
245
        if err != nil {
2✔
246
                return keyDesc, err
×
247
        }
×
248

249
        return keyDesc, nil
2✔
250
}
251

252
// DerivePrivKey attempts to derive the private key that corresponds to the
253
// passed key descriptor.
254
//
255
// NOTE: This is part of the keychain.SecretKeyRing interface.
256
func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (
257
        *btcec.PrivateKey, error) {
2✔
258

2✔
259
        var key *btcec.PrivateKey
2✔
260

2✔
261
        scope, err := b.keyScope()
2✔
262
        if err != nil {
2✔
263
                return nil, err
×
264
        }
×
265

266
        // First, attempt to see if we can read the key directly from
267
        // btcwallet's internal cache, if we can then we can skip all the
268
        // operations below (fast path).
269
        if keyDesc.PubKey == nil {
4✔
270
                keyPath := waddrmgr.DerivationPath{
2✔
271
                        InternalAccount: uint32(keyDesc.Family),
2✔
272
                        Account:         uint32(keyDesc.Family),
2✔
273
                        Branch:          0,
2✔
274
                        Index:           keyDesc.Index,
2✔
275
                }
2✔
276
                privKey, err := scope.DeriveFromKeyPathCache(keyPath)
2✔
277
                if err == nil {
4✔
278
                        return privKey, nil
2✔
279
                }
2✔
280
        }
281

282
        db := b.wallet.Database()
2✔
283
        err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
4✔
284
                addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2✔
285

2✔
286
                // If the account doesn't exist, then we may need to create it
2✔
287
                // for the first time in order to derive the keys that we
2✔
288
                // require. We skip this if we're using a remote signer in which
2✔
289
                // case we _need_ to create all accounts when creating the
2✔
290
                // wallet, so it must exist now.
2✔
291
                if !b.wallet.Manager.WatchOnly() {
4✔
292
                        err = b.createAccountIfNotExists(
2✔
293
                                addrmgrNs, keyDesc.Family, scope,
2✔
294
                        )
2✔
295
                        if err != nil {
2✔
296
                                return err
×
297
                        }
×
298
                }
299

300
                // If the public key isn't set or they have a non-zero index,
301
                // then we know that the caller instead knows the derivation
302
                // path for a key.
303
                if keyDesc.PubKey == nil || keyDesc.Index > 0 {
4✔
304
                        // Now that we know the account exists, we can safely
2✔
305
                        // derive the full private key from the given path.
2✔
306
                        path := waddrmgr.DerivationPath{
2✔
307
                                InternalAccount: uint32(keyDesc.Family),
2✔
308
                                Branch:          0,
2✔
309
                                Index:           keyDesc.Index,
2✔
310
                        }
2✔
311
                        addr, err := scope.DeriveFromKeyPath(addrmgrNs, path)
2✔
312
                        if err != nil {
2✔
313
                                return err
×
314
                        }
×
315

316
                        key, err = addr.(waddrmgr.ManagedPubKeyAddress).PrivKey()
2✔
317
                        if err != nil {
2✔
318
                                return err
×
319
                        }
×
320

321
                        return nil
2✔
322
                }
323

324
                // If the public key isn't nil, then this indicates that we
325
                // need to scan for the private key, assuming that we know the
326
                // valid key family.
327
                nextPath := waddrmgr.DerivationPath{
2✔
328
                        InternalAccount: uint32(keyDesc.Family),
2✔
329
                        Branch:          0,
2✔
330
                        Index:           0,
2✔
331
                }
2✔
332

2✔
333
                // We'll now iterate through our key range in an attempt to
2✔
334
                // find the target public key.
2✔
335
                //
2✔
336
                // TODO(roasbeef): possibly move scanning into wallet to allow
2✔
337
                // to be parallelized
2✔
338
                for i := 0; i < MaxKeyRangeScan; i++ {
4✔
339
                        // Derive the next key in the range and fetch its
2✔
340
                        // managed address.
2✔
341
                        addr, err := scope.DeriveFromKeyPath(
2✔
342
                                addrmgrNs, nextPath,
2✔
343
                        )
2✔
344
                        if err != nil {
2✔
345
                                return err
×
346
                        }
×
347
                        managedAddr := addr.(waddrmgr.ManagedPubKeyAddress)
2✔
348

2✔
349
                        // If this is the target public key, then we'll return
2✔
350
                        // it directly back to the caller.
2✔
351
                        if managedAddr.PubKey().IsEqual(keyDesc.PubKey) {
4✔
352
                                key, err = managedAddr.PrivKey()
2✔
353
                                if err != nil {
2✔
354
                                        return err
×
355
                                }
×
356

357
                                return nil
2✔
358
                        }
359

360
                        // This wasn't the target key, so roll forward and try
361
                        // the next one.
362
                        nextPath.Index++
2✔
363
                }
364

365
                // If we reach this point, then we we're unable to derive the
366
                // private key, so return an error back to the user.
UNCOV
367
                return ErrCannotDerivePrivKey
×
368
        })
369
        if err != nil {
2✔
UNCOV
370
                return nil, err
×
UNCOV
371
        }
×
372

373
        return key, nil
2✔
374
}
375

376
// ECDH performs a scalar multiplication (ECDH-like operation) between the
377
// target key descriptor and remote public key. The output returned will be
378
// the sha256 of the resulting shared point serialized in compressed format. If
379
// k is our private key, and P is the public key, we perform the following
380
// operation:
381
//
382
//        sx := k*P s := sha256(sx.SerializeCompressed())
383
//
384
// NOTE: This is part of the keychain.ECDHRing interface.
385
func (b *BtcWalletKeyRing) ECDH(keyDesc KeyDescriptor,
386
        pub *btcec.PublicKey) ([32]byte, error) {
2✔
387

2✔
388
        privKey, err := b.DerivePrivKey(keyDesc)
2✔
389
        if err != nil {
2✔
390
                return [32]byte{}, err
×
391
        }
×
392

393
        var (
2✔
394
                pubJacobian btcec.JacobianPoint
2✔
395
                s           btcec.JacobianPoint
2✔
396
        )
2✔
397
        pub.AsJacobian(&pubJacobian)
2✔
398

2✔
399
        btcec.ScalarMultNonConst(&privKey.Key, &pubJacobian, &s)
2✔
400
        s.ToAffine()
2✔
401
        sPubKey := btcec.NewPublicKey(&s.X, &s.Y)
2✔
402
        h := sha256.Sum256(sPubKey.SerializeCompressed())
2✔
403

2✔
404
        return h, nil
2✔
405
}
406

407
// SignMessage signs the given message, single or double SHA256 hashing it
408
// first, with the private key described in the key locator.
409
//
410
// NOTE: This is part of the keychain.MessageSignerRing interface.
411
func (b *BtcWalletKeyRing) SignMessage(keyLoc KeyLocator,
412
        msg []byte, doubleHash bool) (*ecdsa.Signature, error) {
2✔
413

2✔
414
        privKey, err := b.DerivePrivKey(KeyDescriptor{
2✔
415
                KeyLocator: keyLoc,
2✔
416
        })
2✔
417
        if err != nil {
2✔
418
                return nil, err
×
419
        }
×
420

421
        var digest []byte
2✔
422
        if doubleHash {
4✔
423
                digest = chainhash.DoubleHashB(msg)
2✔
424
        } else {
4✔
425
                digest = chainhash.HashB(msg)
2✔
426
        }
2✔
427
        return ecdsa.Sign(privKey, digest), nil
2✔
428
}
429

430
// SignMessageCompact signs the given message, single or double SHA256 hashing
431
// it first, with the private key described in the key locator and returns
432
// the signature in the compact, public key recoverable format.
433
//
434
// NOTE: This is part of the keychain.MessageSignerRing interface.
435
func (b *BtcWalletKeyRing) SignMessageCompact(keyLoc KeyLocator,
436
        msg []byte, doubleHash bool) ([]byte, error) {
2✔
437

2✔
438
        privKey, err := b.DerivePrivKey(KeyDescriptor{
2✔
439
                KeyLocator: keyLoc,
2✔
440
        })
2✔
441
        if err != nil {
2✔
442
                return nil, err
×
443
        }
×
444

445
        var digest []byte
2✔
446
        if doubleHash {
4✔
447
                digest = chainhash.DoubleHashB(msg)
2✔
448
        } else {
4✔
449
                digest = chainhash.HashB(msg)
2✔
450
        }
2✔
451

452
        return ecdsa.SignCompact(privKey, digest, true), nil
2✔
453
}
454

455
// SignMessageSchnorr uses the Schnorr signature algorithm to sign the given
456
// message, single or double SHA256 hashing it first, with the private key
457
// described in the key locator and the optional tweak applied to the private
458
// key.
459
//
460
// NOTE: This is part of the keychain.MessageSignerRing interface.
461
func (b *BtcWalletKeyRing) SignMessageSchnorr(keyLoc KeyLocator,
462
        msg []byte, doubleHash bool, taprootTweak []byte,
463
        tag []byte) (*schnorr.Signature, error) {
2✔
464

2✔
465
        privKey, err := b.DerivePrivKey(KeyDescriptor{
2✔
466
                KeyLocator: keyLoc,
2✔
467
        })
2✔
468
        if err != nil {
2✔
469
                return nil, err
×
470
        }
×
471

472
        if len(taprootTweak) > 0 {
4✔
473
                privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak)
2✔
474
        }
2✔
475

476
        // If a tag was provided, we need to take the tagged hash of the input.
477
        var digest []byte
2✔
478
        switch {
2✔
479
        case len(tag) > 0:
2✔
480
                taggedHash := chainhash.TaggedHash(tag, msg)
2✔
481
                digest = taggedHash[:]
2✔
482
        case doubleHash:
×
483
                digest = chainhash.DoubleHashB(msg)
×
484
        default:
2✔
485
                digest = chainhash.HashB(msg)
2✔
486
        }
487
        return schnorr.Sign(privKey, digest)
2✔
488
}
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