1 package waddrmgr
2 3 import (
4 "encoding/hex"
5 "fmt"
6 "github.com/p9c/p9/pkg/btcaddr"
7 "sync"
8 9 ec "github.com/p9c/p9/pkg/ecc"
10 "github.com/p9c/p9/pkg/util"
11 "github.com/p9c/p9/pkg/util/hdkeychain"
12 "github.com/p9c/p9/pkg/util/zero"
13 "github.com/p9c/p9/pkg/walletdb"
14 )
15 16 // AddressType represents the various address types waddrmgr is currently able
17 // to generate, and maintain.
18 //
19 // NOTE: These MUST be stable as they're used for scope address schema
20 // recognition within the database.
21 type AddressType uint8
22 23 const (
24 // PubKeyHash is a regular p2pkh address.
25 PubKeyHash AddressType = iota
26 // Script reprints a raw script address.
27 Script
28 // RawPubKey is just raw public key to be used within scripts, This type
29 // indicates that a scoped manager with this address type shouldn't be consulted
30 // during historical rescans.
31 RawPubKey
32 // // NestedWitnessPubKey represents a p2wkh output nested within a p2sh output.
33 // // Using this address type, the wallet can receive funds from other wallet's
34 // // which don't yet recognize the new segwit standard output types. Receiving
35 // // funds to this address maintains the scalability, and malleability fixes due
36 // // to segwit in a backwards compatible manner.
37 // NestedWitnessPubKey
38 // // WitnessPubKey represents a p2wkh (pay-to-witness-key-hash) address type.
39 // WitnessPubKey
40 )
41 42 // ManagedAddress is an interface that provides access to information regarding
43 // an address managed by an address manager. Concrete implementations of this
44 // type may provide further fields to provide information specific to that type
45 // of address.
46 type ManagedAddress interface {
47 // Account returns the account the address is associated with.
48 Account() uint32
49 // Address returns a util.Address for the backing address.
50 Address() btcaddr.Address
51 // AddrHash returns the key or script hash related to the address
52 AddrHash() []byte
53 // Imported returns true if the backing address was imported instead of being
54 // part of an address chain.
55 Imported() bool
56 // Internal returns true if the backing address was created for internal use
57 // such as a change output of a transaction.
58 Internal() bool
59 // Compressed returns true if the backing address is compressed.
60 Compressed() bool
61 // Used returns true if the backing address has been used in a transaction.
62 Used(ns walletdb.ReadBucket) bool
63 // AddrType returns the address type of the managed address. This can be used to
64 // quickly discern the address type without further processing
65 AddrType() AddressType
66 }
67 68 // ManagedPubKeyAddress extends ManagedAddress and additionally provides the
69 // public and private keys for pubkey-based addresses.
70 type ManagedPubKeyAddress interface {
71 ManagedAddress
72 // PubKey returns the public key associated with the address.
73 PubKey() *ec.PublicKey
74 // ExportPubKey returns the public key associated with the address serialized as
75 // a hex encoded string.
76 ExportPubKey() string
77 // PrivKey returns the private key for the address. It can fail if the address
78 // manager is watching-only or locked, or the address does not have any keys.
79 PrivKey() (*ec.PrivateKey, error)
80 // ExportPrivKey returns the private key associated with the address serialized
81 // as Wallet Import Format (WIF).
82 ExportPrivKey() (*util.WIF, error)
83 // DerivationInfo contains the information required to derive the key that backs
84 // the address via traditional methods from the HD root. For imported keys, the
85 // first value will be set to false to indicate that we don't know exactly how
86 // the key was derived.
87 DerivationInfo() (KeyScope, DerivationPath, bool)
88 }
89 90 // ManagedScriptAddress extends ManagedAddress and represents a
91 // pay-to-script-hash style of bitcoin addresses. It additionally provides
92 // information about the script.
93 type ManagedScriptAddress interface {
94 ManagedAddress
95 // Script returns the script associated with the address.
96 Script() ([]byte, error)
97 }
98 99 // managedAddress represents a public key address. It also may or may not have
100 // the private key associated with the public key.
101 type managedAddress struct {
102 manager *ScopedKeyManager
103 address btcaddr.Address
104 pubKey *ec.PublicKey
105 privKeyEncrypted []byte
106 privKeyCT []byte // non-nil if unlocked
107 privKeyMutex sync.Mutex
108 derivationPath DerivationPath
109 addrType AddressType
110 imported bool
111 internal bool
112 compressed bool
113 // used bool
114 }
115 116 // Enforce managedAddress satisfies the ManagedPubKeyAddress interface.
117 var _ ManagedPubKeyAddress = (*managedAddress)(nil)
118 119 // unlock decrypts and stores a pointer to the associated private key. It will
120 // fail if the key is invalid or the encrypted private key is not available. The
121 // returned clear text private key will always be a copy that may be safely used
122 // by the caller without worrying about it being zeroed during an address lock.
123 func (a *managedAddress) unlock(key EncryptorDecryptor) ([]byte, error) {
124 // Protect concurrent access to clear text private key.
125 a.privKeyMutex.Lock()
126 defer a.privKeyMutex.Unlock()
127 if len(a.privKeyCT) == 0 {
128 var e error
129 var privKey []byte
130 if privKey, e = key.Decrypt(a.privKeyEncrypted); E.Chk(e) {
131 str := fmt.Sprintf("failed to decrypt private key for %s", a.address)
132 return nil, managerError(ErrCrypto, str, e)
133 }
134 a.privKeyCT = privKey
135 }
136 privKeyCopy := make([]byte, len(a.privKeyCT))
137 copy(privKeyCopy, a.privKeyCT)
138 return privKeyCopy, nil
139 }
140 141 // lock zeroes the associated clear text private key.
142 func (a *managedAddress) lock() {
143 // Zero and nil the clear text private key associated with this address.
144 a.privKeyMutex.Lock()
145 zero.Bytes(a.privKeyCT)
146 a.privKeyCT = nil
147 a.privKeyMutex.Unlock()
148 }
149 150 // Account returns the account number the address is associated with.
151 //
152 // This is part of the ManagedAddress interface implementation.
153 func (a *managedAddress) Account() uint32 {
154 return a.derivationPath.Account
155 }
156 157 // AddrType returns the address type of the managed address. This can be used to
158 // quickly discern the address type without further processing
159 //
160 // This is part of the ManagedAddress interface implementation.
161 func (a *managedAddress) AddrType() AddressType {
162 return a.addrType
163 }
164 165 // Address returns the util.Address which represents the managed address. This
166 // will be a pay-to-pubkey-hash address.
167 //
168 // This is part of the ManagedAddress interface implementation.
169 func (a *managedAddress) Address() btcaddr.Address {
170 return a.address
171 }
172 173 // AddrHash returns the public key hash for the address.
174 //
175 // This is part of the ManagedAddress interface implementation.
176 func (a *managedAddress) AddrHash() []byte {
177 var hash []byte
178 switch n := a.address.(type) {
179 case *btcaddr.PubKeyHash:
180 hash = n.Hash160()[:]
181 case *btcaddr.ScriptHash:
182 hash = n.Hash160()[:]
183 // case *util.AddressWitnessPubKeyHash:
184 // hash = n.Hash160()[:]
185 }
186 return hash
187 }
188 189 // Imported returns true if the address was imported instead of being part of an
190 // address chain.
191 //
192 // This is part of the ManagedAddress interface implementation.
193 func (a *managedAddress) Imported() bool {
194 return a.imported
195 }
196 197 // Internal returns true if the address was created for internal use such as a
198 // change output of a transaction.
199 //
200 // This is part of the ManagedAddress interface implementation.
201 func (a *managedAddress) Internal() bool {
202 return a.internal
203 }
204 205 // Compressed returns true if the address is compressed.
206 //
207 // This is part of the ManagedAddress interface implementation.
208 func (a *managedAddress) Compressed() bool {
209 return a.compressed
210 }
211 212 // Used returns true if the address has been used in a transaction.
213 //
214 // This is part of the ManagedAddress interface implementation.
215 func (a *managedAddress) Used(ns walletdb.ReadBucket) bool {
216 return a.manager.fetchUsed(ns, a.AddrHash())
217 }
218 219 // PubKey returns the public key associated with the address.
220 //
221 // This is part of the ManagedPubKeyAddress interface implementation.
222 func (a *managedAddress) PubKey() *ec.PublicKey {
223 return a.pubKey
224 }
225 226 // pubKeyBytes returns the serialized public key bytes for the managed address
227 // based on whether or not the managed address is marked as compressed.
228 func (a *managedAddress) pubKeyBytes() []byte {
229 if a.compressed {
230 return a.pubKey.SerializeCompressed()
231 }
232 return a.pubKey.SerializeUncompressed()
233 }
234 235 // ExportPubKey returns the public key associated with the address serialized as
236 // a hex encoded string.
237 //
238 // This is part of the ManagedPubKeyAddress interface implementation.
239 func (a *managedAddress) ExportPubKey() string {
240 return hex.EncodeToString(a.pubKeyBytes())
241 }
242 243 // PrivKey returns the private key for the address. It can fail if the address
244 // manager is watching-only or locked, or the address does not have any keys.
245 //
246 // This is part of the ManagedPubKeyAddress interface implementation.
247 func (a *managedAddress) PrivKey() (*ec.PrivateKey, error) {
248 // No private keys are available for a watching-only address manager.
249 if a.manager.rootManager.WatchOnly() {
250 return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
251 }
252 a.manager.mtx.Lock()
253 defer a.manager.mtx.Unlock()
254 // Account manager must be unlocked to decrypt the private key.
255 if a.manager.rootManager.IsLocked() {
256 return nil, managerError(ErrLocked, errLocked, nil)
257 }
258 // Decrypt the key as needed. Also, make sure it's a copy since the private key
259 // stored in memory can be cleared at any time. Otherwise the returned private
260 // key could be invalidated from under the caller.
261 var privKeyCopy []byte
262 var e error
263 if privKeyCopy, e = a.unlock(a.manager.rootManager.cryptoKeyPriv); E.Chk(e) {
264 return nil, e
265 }
266 privKey, _ := ec.PrivKeyFromBytes(ec.S256(), privKeyCopy)
267 zero.Bytes(privKeyCopy)
268 return privKey, nil
269 }
270 271 // ExportPrivKey returns the private key associated with the address in Wallet
272 // Import Format (WIF).
273 //
274 // This is part of the ManagedPubKeyAddress interface implementation.
275 func (a *managedAddress) ExportPrivKey() (*util.WIF, error) {
276 var pk *ec.PrivateKey
277 var e error
278 if pk, e = a.PrivKey(); E.Chk(e) {
279 return nil, e
280 }
281 return util.NewWIF(pk, a.manager.rootManager.chainParams, a.compressed)
282 }
283 284 // DerivationInfo contains the information required to derive the key that backs
285 // the address via traditional methods from the HD root. For imported keys, the
286 // first value will be set to false to indicate that we don't know exactly how
287 // the key was derived.
288 //
289 // This is part of the ManagedPubKeyAddress interface implementation.
290 func (a *managedAddress) DerivationInfo() (KeyScope, DerivationPath, bool) {
291 var (
292 scope KeyScope
293 path DerivationPath
294 )
295 // If this key is imported, then we can't return any information as we don't
296 // know precisely how the key was derived.
297 if a.imported {
298 return scope, path, false
299 }
300 return a.manager.Scope(), a.derivationPath, true
301 }
302 303 // newManagedAddressWithoutPrivKey returns a new managed address based on the
304 // passed account, public key, and whether or not the public key should be
305 // compressed.
306 func newManagedAddressWithoutPrivKey(
307 m *ScopedKeyManager,
308 derivationPath DerivationPath, pubKey *ec.PublicKey, compressed bool,
309 addrType AddressType,
310 ) (*managedAddress, error) {
311 // Create a pay-to-pubkey-hash address from the public key.
312 var pubKeyHash []byte
313 if compressed {
314 pubKeyHash = btcaddr.Hash160(pubKey.SerializeCompressed())
315 } else {
316 pubKeyHash = btcaddr.Hash160(pubKey.SerializeUncompressed())
317 }
318 var address btcaddr.Address
319 var e error
320 switch addrType {
321 // case NestedWitnessPubKey:
322 // // For this address type we'l generate an address which is backwards compatible
323 // // to Bitcoin nodes running 0.6.0 onwards, but allows us to take advantage of
324 // // segwit's scripting improvements, and malleability fixes.
325 // //
326 // // First, we'll generate a normal p2wkh address from the pubkey hash.
327 // var witAddr *util.AddressWitnessPubKeyHash
328 // if witAddr, e = util.NewAddressWitnessPubKeyHash(
329 // pubKeyHash, m.rootManager.chainParams,
330 // ); E.Chk(e) {
331 // return nil, e
332 // }
333 // // Next we'll generate the witness program which can be used as a pkScript to
334 // // pay to this generated address.
335 // var witnessProgram []byte
336 // if witnessProgram, e = txscript.PayToAddrScript(witAddr); E.Chk(e) {
337 // return nil, e
338 // }
339 // // Finally, we'll use the witness program itself as the pre-image to a p2sh
340 // // address. In order to spend, we first use the witnessProgram as the sigScript,
341 // // then present the proper <sig, pubkey> pair as the witness.
342 // if address, e = util.NewScriptHash(
343 // witnessProgram, m.rootManager.chainParams,
344 // ); E.Chk(e) {
345 // return nil, e
346 // }
347 case PubKeyHash:
348 if address, e = btcaddr.NewPubKeyHash(
349 pubKeyHash, m.rootManager.chainParams,
350 ); E.Chk(e) {
351 return nil, e
352 }
353 // case WitnessPubKey:
354 // if address, e = util.NewAddressWitnessPubKeyHash(
355 // pubKeyHash, m.rootManager.chainParams,
356 // ); E.Chk(e) {
357 // return nil, e
358 // }
359 }
360 return &managedAddress{
361 manager: m,
362 address: address,
363 derivationPath: derivationPath,
364 imported: false,
365 internal: false,
366 addrType: addrType,
367 compressed: compressed,
368 pubKey: pubKey,
369 privKeyEncrypted: nil,
370 privKeyCT: nil,
371 }, nil
372 }
373 374 // newManagedAddress returns a new managed address based on the passed account,
375 // private key, and whether or not the public key is compressed. The managed
376 // address will have access to the private and public keys.
377 func newManagedAddress(
378 s *ScopedKeyManager, derivationPath DerivationPath,
379 privKey *ec.PrivateKey, compressed bool,
380 addrType AddressType,
381 ) (*managedAddress, error) {
382 // Encrypt the private key.
383 //
384 // NOTE: The privKeyBytes here are set into the managed address which are
385 // cleared when locked, so they aren't cleared here.
386 privKeyBytes := privKey.Serialize()
387 var privKeyEncrypted []byte
388 var e error
389 if privKeyEncrypted, e = s.rootManager.cryptoKeyPriv.Encrypt(privKeyBytes); E.Chk(e) {
390 str := "failed to encrypt private key"
391 return nil, managerError(ErrCrypto, str, e)
392 }
393 // Leverage the code to create a managed address without a private key and then
394 // add the private key to it.
395 ecPubKey := (*ec.PublicKey)(&privKey.PublicKey)
396 var managedAddr *managedAddress
397 if managedAddr, e = newManagedAddressWithoutPrivKey(
398 s,
399 derivationPath,
400 ecPubKey,
401 compressed,
402 addrType,
403 ); E.Chk(e) {
404 return nil, e
405 }
406 managedAddr.privKeyEncrypted = privKeyEncrypted
407 managedAddr.privKeyCT = privKeyBytes
408 return managedAddr, nil
409 }
410 411 // newManagedAddressFromExtKey returns a new managed address based on the passed
412 // account and extended key. The managed address will have access to the private
413 // and public keys if the provided extended key is private, otherwise it will
414 // only have access to the public key.
415 func newManagedAddressFromExtKey(
416 s *ScopedKeyManager, derivationPath DerivationPath, key *hdkeychain.ExtendedKey,
417 addrType AddressType,
418 ) (managedAddr *managedAddress, e error) {
419 // Create a new managed address based on the public or private key depending on
420 // whether the generated key is private.
421 if key.IsPrivate() {
422 var privKey *ec.PrivateKey
423 if privKey, e = key.ECPrivKey(); E.Chk(e) {
424 return nil, e
425 }
426 // Ensure the temp private key big integer is cleared after use.
427 if managedAddr, e = newManagedAddress(
428 s, derivationPath, privKey, true, addrType,
429 ); E.Chk(e) {
430 return nil, e
431 }
432 } else {
433 var pubKey *ec.PublicKey
434 if pubKey, e = key.ECPubKey(); E.Chk(e) {
435 return nil, e
436 }
437 if managedAddr, e = newManagedAddressWithoutPrivKey(
438 s, derivationPath, pubKey, true,
439 addrType,
440 ); E.Chk(e) {
441 return nil, e
442 }
443 }
444 return managedAddr, nil
445 }
446 447 // scriptAddress represents a pay-to-script-hash address.
448 type scriptAddress struct {
449 manager *ScopedKeyManager
450 account uint32
451 address *btcaddr.ScriptHash
452 scriptEncrypted []byte
453 scriptCT []byte
454 scriptMutex sync.Mutex
455 // used bool
456 }
457 458 // Enforce scriptAddress satisfies the ManagedScriptAddress interface.
459 var _ ManagedScriptAddress = (*scriptAddress)(nil)
460 461 // unlock decrypts and stores the associated script. It will fail if the key is
462 // invalid or the encrypted script is not available. The returned clear text
463 // script will always be a copy that may be safely used by the caller without
464 // worrying about it being zeroed during an address lock.
465 func (a *scriptAddress) unlock(key EncryptorDecryptor) (scriptCopy []byte, e error) {
466 // Protect concurrent access to clear text script.
467 a.scriptMutex.Lock()
468 defer a.scriptMutex.Unlock()
469 if len(a.scriptCT) == 0 {
470 var script []byte
471 if script, e = key.Decrypt(a.scriptEncrypted); E.Chk(e) {
472 str := fmt.Sprintf("failed to decrypt script for %s", a.address)
473 return nil, managerError(ErrCrypto, str, e)
474 }
475 a.scriptCT = script
476 }
477 scriptCopy = make([]byte, len(a.scriptCT))
478 copy(scriptCopy, a.scriptCT)
479 return scriptCopy, nil
480 }
481 482 // lock zeroes the associated clear text private key.
483 func (a *scriptAddress) lock() {
484 // Zero and nil the clear text script associated with this address.
485 a.scriptMutex.Lock()
486 zero.Bytes(a.scriptCT)
487 a.scriptCT = nil
488 a.scriptMutex.Unlock()
489 }
490 491 // Account returns the account the address is associated with. This will always
492 // be the ImportedAddrAccount constant for script addresses.
493 //
494 // This is part of the ManagedAddress interface implementation.
495 func (a *scriptAddress) Account() uint32 {
496 return a.account
497 }
498 499 // AddrType returns the address type of the managed address. This can be used to
500 // quickly discern the address type without further processing
501 //
502 // This is part of the ManagedAddress interface implementation.
503 func (a *scriptAddress) AddrType() AddressType {
504 return Script
505 }
506 507 // Address returns the util.Address which represents the managed address. This
508 // will be a pay-to-script-hash address.
509 //
510 // This is part of the ManagedAddress interface implementation.
511 func (a *scriptAddress) Address() btcaddr.Address {
512 return a.address
513 }
514 515 // AddrHash returns the script hash for the address.
516 //
517 // This is part of the ManagedAddress interface implementation.
518 func (a *scriptAddress) AddrHash() []byte {
519 return a.address.Hash160()[:]
520 }
521 522 // Imported always returns true since script addresses are always imported
523 // addresses and not part of any chain.
524 //
525 // This is part of the ManagedAddress interface implementation.
526 func (a *scriptAddress) Imported() bool {
527 return true
528 }
529 530 // Internal always returns false since script addresses are always imported
531 // addresses and not part of any chain in order to be for internal use.
532 //
533 // This is part of the ManagedAddress interface implementation.
534 func (a *scriptAddress) Internal() bool {
535 return false
536 }
537 538 // Compressed returns false since script addresses are never compressed.
539 //
540 // This is part of the ManagedAddress interface implementation.
541 func (a *scriptAddress) Compressed() bool {
542 return false
543 }
544 545 // Used returns true if the address has been used in a transaction.
546 //
547 // This is part of the ManagedAddress interface implementation.
548 func (a *scriptAddress) Used(ns walletdb.ReadBucket) bool {
549 return a.manager.fetchUsed(ns, a.AddrHash())
550 }
551 552 // Script returns the script associated with the address.
553 //
554 // This implements the ScriptAddress interface.
555 func (a *scriptAddress) Script() ([]byte, error) {
556 // No script is available for a watching-only address manager.
557 if a.manager.rootManager.WatchOnly() {
558 return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
559 }
560 a.manager.mtx.Lock()
561 defer a.manager.mtx.Unlock()
562 // Account manager must be unlocked to decrypt the script.
563 if a.manager.rootManager.IsLocked() {
564 return nil, managerError(ErrLocked, errLocked, nil)
565 }
566 // Decrypt the script as needed. Also, make sure it's a copy since the script
567 // stored in memory can be cleared at any time. Otherwise, the returned script
568 // could be invalidated from under the caller.
569 return a.unlock(a.manager.rootManager.cryptoKeyScript)
570 }
571 572 // newScriptAddress initializes and returns a new pay-to-script-hash address.
573 func newScriptAddress(
574 m *ScopedKeyManager, account uint32, scriptHash,
575 scriptEncrypted []byte,
576 ) (*scriptAddress, error) {
577 var e error
578 var address *btcaddr.ScriptHash
579 if address, e = btcaddr.NewScriptHashFromHash(
580 scriptHash, m.rootManager.chainParams,
581 ); E.Chk(e) {
582 return nil, e
583 }
584 return &scriptAddress{
585 manager: m,
586 account: account,
587 address: address,
588 scriptEncrypted: scriptEncrypted,
589 }, nil
590 }
591