address.go raw

   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