github.com/status-im/status-go/extkeys@v1.1.2/hdkey.go (about)

     1  package extkeys
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"errors"
     9  	"fmt"
    10  	"math/big"
    11  
    12  	"github.com/btcsuite/btcd/btcec"
    13  	"github.com/btcsuite/btcd/chaincfg"
    14  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    15  	"github.com/btcsuite/btcutil"
    16  	"github.com/btcsuite/btcutil/base58"
    17  )
    18  
    19  // Implementation of the following BIPs:
    20  //   - BIP32 (https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
    21  //   - BIP39 (https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
    22  //   - BIP44 (https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
    23  //
    24  // Referencing
    25  // https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
    26  // https://bitcoin.org/en/developer-guide#hardened-keys
    27  
    28  // Reference Implementations
    29  // https://github.com/btcsuite/btcutil/tree/master/hdkeychain
    30  // https://github.com/WeMeetAgain/go-hdwallet
    31  
    32  // https://github.com/ConsenSys/eth-lightwallet/blob/master/lib/keystore.js
    33  // https://github.com/bitpay/bitcore-lib/tree/master/lib
    34  
    35  // MUST CREATE HARDENED CHILDREN OF THE MASTER PRIVATE KEY (M) TO PREVENT
    36  // A COMPROMISED CHILD KEY FROM COMPROMISING THE MASTER KEY.
    37  // AS THERE ARE NO NORMAL CHILDREN FOR THE MASTER KEYS,
    38  // THE MASTER PUBLIC KEY IS NOT USED IN HD WALLETS.
    39  // ALL OTHER KEYS CAN HAVE NORMAL CHILDREN,
    40  // SO THE CORRESPONDING EXTENDED PUBLIC KEYS MAY BE USED INSTEAD.
    41  
    42  // TODO make sure we're doing this ^^^^ !!!!!!
    43  
    44  type KeyPurpose int
    45  
    46  const (
    47  	KeyPurposeWallet KeyPurpose = iota + 1
    48  	KeyPurposeChat
    49  )
    50  
    51  const (
    52  	// HardenedKeyStart defines a starting point for hardened key.
    53  	// Each extended key has 2^31 normal child keys and 2^31 hardened child keys.
    54  	// Thus the range for normal child keys is [0, 2^31 - 1] and the range for hardened child keys is [2^31, 2^32 - 1].
    55  	HardenedKeyStart = 0x80000000 // 2^31
    56  
    57  	// MinSeedBytes is the minimum number of bytes allowed for a seed to a master node.
    58  	MinSeedBytes = 16 // 128 bits
    59  
    60  	// MaxSeedBytes is the maximum number of bytes allowed for a seed to a master node.
    61  	MaxSeedBytes = 64 // 512 bits
    62  
    63  	// serializedKeyLen is the length of a serialized public or private
    64  	// extended key.  It consists of 4 bytes version, 1 byte depth, 4 bytes
    65  	// fingerprint, 4 bytes child number, 32 bytes chain code, and 33 bytes
    66  	// public/private key data.
    67  	serializedKeyLen = 4 + 1 + 4 + 4 + 32 + 33 // 78 bytes
    68  
    69  	// CoinTypeBTC is BTC coin type
    70  	CoinTypeBTC = 0 // 0x80000000
    71  
    72  	// CoinTypeTestNet is test net coin type
    73  	CoinTypeTestNet = 1 // 0x80000001
    74  
    75  	// CoinTypeETH is ETH coin type
    76  	CoinTypeETH = 60 // 0x8000003c
    77  
    78  	// EmptyExtendedKeyString marker string for zero extended key
    79  	EmptyExtendedKeyString = "Zeroed extended key"
    80  
    81  	// MaxDepth is the maximum depth of an extended key.
    82  	// Extended keys with depth MaxDepth cannot derive child keys.
    83  	MaxDepth = 255
    84  )
    85  
    86  // errors
    87  var (
    88  	ErrInvalidKey                 = errors.New("key is invalid")
    89  	ErrInvalidKeyPurpose          = errors.New("key purpose is invalid")
    90  	ErrInvalidSeed                = errors.New("seed is invalid")
    91  	ErrInvalidSeedLen             = fmt.Errorf("the recommended size of seed is %d-%d bits", MinSeedBytes, MaxSeedBytes)
    92  	ErrDerivingHardenedFromPublic = errors.New("cannot derive a hardened key from public key")
    93  	ErrBadChecksum                = errors.New("bad extended key checksum")
    94  	ErrInvalidKeyLen              = errors.New("serialized extended key length is invalid")
    95  	ErrDerivingChild              = errors.New("error deriving child key")
    96  	ErrInvalidMasterKey           = errors.New("invalid master key supplied")
    97  	ErrMaxDepthExceeded           = errors.New("max depth exceeded")
    98  )
    99  
   100  var (
   101  	// PrivateKeyVersion is version for private key
   102  	PrivateKeyVersion, _ = hex.DecodeString("0488ADE4")
   103  
   104  	// PublicKeyVersion is version for public key
   105  	PublicKeyVersion, _ = hex.DecodeString("0488B21E")
   106  
   107  	// EthBIP44ParentPath is BIP44 keys parent's derivation path
   108  	EthBIP44ParentPath = []uint32{
   109  		HardenedKeyStart + 44,          // purpose
   110  		HardenedKeyStart + CoinTypeETH, // cointype set to ETH
   111  		HardenedKeyStart + 0,           // account
   112  		0,                              // 0 - public, 1 - private
   113  	}
   114  
   115  	// EIP1581KeyTypeChat is used as chat key_type in the derivation of EIP1581 keys
   116  	EIP1581KeyTypeChat uint32 = 0x00
   117  
   118  	// EthEIP1581ChatParentPath is EIP-1581 chat keys parent's derivation path
   119  	EthEIP1581ChatParentPath = []uint32{
   120  		HardenedKeyStart + 43,                 // purpose
   121  		HardenedKeyStart + CoinTypeETH,        // cointype set to ETH
   122  		HardenedKeyStart + 1581,               // EIP-1581 subpurpose
   123  		HardenedKeyStart + EIP1581KeyTypeChat, // key_type (chat)
   124  	}
   125  )
   126  
   127  // ExtendedKey represents BIP44-compliant HD key
   128  type ExtendedKey struct {
   129  	Version          []byte // 4 bytes, mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private
   130  	Depth            uint8  // 1 byte,  depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ....
   131  	FingerPrint      []byte // 4 bytes, fingerprint of the parent's key (0x00000000 if master key)
   132  	ChildNumber      uint32 // 4 bytes, This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
   133  	KeyData          []byte // 33 bytes, the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
   134  	ChainCode        []byte // 32 bytes, the chain code
   135  	IsPrivate        bool   // (non-serialized) if false, this chain will only contain a public key and can only create a public key chain.
   136  	CachedPubKeyData []byte // (non-serialized) used for memoization of public key (calculated from a private key)
   137  }
   138  
   139  // nolint: gas
   140  const masterSecret = "Bitcoin seed"
   141  
   142  // NewMaster creates new master node, root of HD chain/tree.
   143  // Both master and child nodes are of ExtendedKey type, and all the children derive from the root node.
   144  func NewMaster(seed []byte) (*ExtendedKey, error) {
   145  	// Ensure seed is within expected limits
   146  	lseed := len(seed)
   147  	if lseed < MinSeedBytes || lseed > MaxSeedBytes {
   148  		return nil, ErrInvalidSeedLen
   149  	}
   150  
   151  	secretKey, chainCode, err := splitHMAC(seed, []byte(masterSecret))
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	master := &ExtendedKey{
   157  		Version:     PrivateKeyVersion,
   158  		Depth:       0,
   159  		FingerPrint: []byte{0x00, 0x00, 0x00, 0x00},
   160  		ChildNumber: 0,
   161  		KeyData:     secretKey,
   162  		ChainCode:   chainCode,
   163  		IsPrivate:   true,
   164  	}
   165  
   166  	return master, nil
   167  }
   168  
   169  // Child derives extended key at a given index i.
   170  // If parent is private, then derived key is also private. If parent is public, then derived is public.
   171  //
   172  // If i >= HardenedKeyStart, then hardened key is generated.
   173  // You can only generate hardened keys from private parent keys.
   174  // If you try generating hardened key form public parent key, ErrDerivingHardenedFromPublic is returned.
   175  //
   176  // There are four CKD (child key derivation) scenarios:
   177  // 1) Private extended key -> Hardened child private extended key
   178  // 2) Private extended key -> Non-hardened child private extended key
   179  // 3) Public extended key -> Non-hardened child public extended key
   180  // 4) Public extended key -> Hardened child public extended key (INVALID!)
   181  func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
   182  	if k.Depth == MaxDepth {
   183  		return nil, ErrMaxDepthExceeded
   184  	}
   185  
   186  	// A hardened child may not be created from a public extended key (Case #4).
   187  	isChildHardened := i >= HardenedKeyStart
   188  	if !k.IsPrivate && isChildHardened {
   189  		return nil, ErrDerivingHardenedFromPublic
   190  	}
   191  
   192  	keyLen := 33
   193  	seed := make([]byte, keyLen+4)
   194  	if isChildHardened {
   195  		// Case #1: 0x00 || ser256(parentKey) || ser32(i)
   196  		copy(seed[1:], k.KeyData) // 0x00 || ser256(parentKey)
   197  	} else {
   198  		// Case #2 and #3: serP(parentPubKey) || ser32(i)
   199  		copy(seed, k.pubKeyBytes())
   200  	}
   201  	binary.BigEndian.PutUint32(seed[keyLen:], i)
   202  
   203  	secretKey, chainCode, err := splitHMAC(seed, k.ChainCode)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	child := &ExtendedKey{
   209  		ChainCode:   chainCode,
   210  		Depth:       k.Depth + 1,
   211  		ChildNumber: i,
   212  		IsPrivate:   k.IsPrivate,
   213  		// The fingerprint for the derived child is the first 4 bytes of parent's
   214  		FingerPrint: btcutil.Hash160(k.pubKeyBytes())[:4],
   215  	}
   216  
   217  	if k.IsPrivate {
   218  		// Case #1 or #2: childKey = parse256(IL) + parentKey
   219  		parentKeyBigInt := new(big.Int).SetBytes(k.KeyData)
   220  		keyBigInt := new(big.Int).SetBytes(secretKey)
   221  		keyBigInt.Add(keyBigInt, parentKeyBigInt)
   222  		keyBigInt.Mod(keyBigInt, btcec.S256().N)
   223  
   224  		// Make sure that child.KeyData is 32 bytes of data even if the value is represented with less bytes.
   225  		// When we derive a child of this key, we call splitHMAC that does a sha512 of a seed that is:
   226  		// - 1 byte with 0x00
   227  		// - 32 bytes for the key data
   228  		// - 4 bytes for the child key index
   229  		// If we don't padd the KeyData, it will be shifted to left in that 32 bytes space
   230  		// generating a different seed and different child key.
   231  		// This part fixes a bug we had previously and described at:
   232  		// https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846#.86inuifuq
   233  		keyData := keyBigInt.Bytes()
   234  		if len(keyData) < 32 {
   235  			extra := make([]byte, 32-len(keyData))
   236  			keyData = append(extra, keyData...)
   237  		}
   238  
   239  		child.KeyData = keyData
   240  		child.Version = PrivateKeyVersion
   241  	} else {
   242  		// Case #3: childKey = serP(point(parse256(IL)) + parentKey)
   243  
   244  		// Calculate the corresponding intermediate public key for intermediate private key.
   245  		keyx, keyy := btcec.S256().ScalarBaseMult(secretKey)
   246  		if keyx.Sign() == 0 || keyy.Sign() == 0 {
   247  			return nil, ErrInvalidKey
   248  		}
   249  
   250  		// Convert the serialized compressed parent public key into X and Y coordinates
   251  		// so it can be added to the intermediate public key.
   252  		pubKey, err := btcec.ParsePubKey(k.KeyData, btcec.S256())
   253  		if err != nil {
   254  			return nil, err
   255  		}
   256  
   257  		// childKey = serP(point(parse256(IL)) + parentKey)
   258  		childX, childY := btcec.S256().Add(keyx, keyy, pubKey.X, pubKey.Y)
   259  		pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY}
   260  		child.KeyData = pk.SerializeCompressed()
   261  		child.Version = PublicKeyVersion
   262  	}
   263  	return child, nil
   264  }
   265  
   266  // ChildForPurpose derives the child key at index i using a derivation path based on the purpose.
   267  func (k *ExtendedKey) ChildForPurpose(p KeyPurpose, i uint32) (*ExtendedKey, error) {
   268  	switch p {
   269  	case KeyPurposeWallet:
   270  		return k.EthBIP44Child(i)
   271  	case KeyPurposeChat:
   272  		return k.EthEIP1581ChatChild(i)
   273  	default:
   274  		return nil, ErrInvalidKeyPurpose
   275  	}
   276  }
   277  
   278  // BIP44Child returns Status CKD#i (where i is child index).
   279  // BIP44 format is used: m / purpose' / coin_type' / account' / change / address_index
   280  // BIP44Child is depracated in favour of EthBIP44Child
   281  // Param coinType is deprecated; we override it to always use CoinTypeETH.
   282  func (k *ExtendedKey) BIP44Child(coinType, i uint32) (*ExtendedKey, error) {
   283  	return k.EthBIP44Child(i)
   284  }
   285  
   286  // BIP44Child returns Status CKD#i (where i is child index).
   287  // BIP44 format is used: m / purpose' / coin_type' / account' / change / address_index
   288  func (k *ExtendedKey) EthBIP44Child(i uint32) (*ExtendedKey, error) {
   289  	if !k.IsPrivate {
   290  		return nil, ErrInvalidMasterKey
   291  	}
   292  
   293  	if k.Depth != 0 {
   294  		return nil, ErrInvalidMasterKey
   295  	}
   296  
   297  	// m/44'/60'/0'/0/index
   298  	extKey, err := k.Derive(append(EthBIP44ParentPath, i))
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  	return extKey, nil
   304  }
   305  
   306  // EthEIP1581ChatChild returns the whisper key #i (where i is child index).
   307  // EthEIP1581ChatChild format is used is the one defined in the EIP-1581:
   308  // m / 43' / coin_type' / 1581' / key_type / index
   309  func (k *ExtendedKey) EthEIP1581ChatChild(i uint32) (*ExtendedKey, error) {
   310  	if !k.IsPrivate {
   311  		return nil, ErrInvalidMasterKey
   312  	}
   313  
   314  	if k.Depth != 0 {
   315  		return nil, ErrInvalidMasterKey
   316  	}
   317  
   318  	// m/43'/60'/1581'/0/index
   319  	extKey, err := k.Derive(append(EthEIP1581ChatParentPath, i))
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  
   324  	return extKey, nil
   325  }
   326  
   327  // Derive returns a derived child key at a given path
   328  func (k *ExtendedKey) Derive(path []uint32) (*ExtendedKey, error) {
   329  	var err error
   330  	extKey := k
   331  	for _, i := range path {
   332  		extKey, err = extKey.Child(i)
   333  		if err != nil {
   334  			return nil, ErrDerivingChild
   335  		}
   336  	}
   337  
   338  	return extKey, nil
   339  }
   340  
   341  // Neuter returns a new extended public key from a give extended private key.
   342  // If the input extended key is already public, it will be returned unaltered.
   343  func (k *ExtendedKey) Neuter() (*ExtendedKey, error) {
   344  	// Already an extended public key.
   345  	if !k.IsPrivate {
   346  		return k, nil
   347  	}
   348  
   349  	// Get the associated public extended key version bytes.
   350  	version, err := chaincfg.HDPrivateKeyToPublicKeyID(k.Version)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	// Convert it to an extended public key.  The key for the new extended
   356  	// key will simply be the pubkey of the current extended private key.
   357  	return &ExtendedKey{
   358  		Version:     version,
   359  		KeyData:     k.pubKeyBytes(),
   360  		ChainCode:   k.ChainCode,
   361  		FingerPrint: k.FingerPrint,
   362  		Depth:       k.Depth,
   363  		ChildNumber: k.ChildNumber,
   364  		IsPrivate:   false,
   365  	}, nil
   366  }
   367  
   368  // IsZeroed returns true if key is nil or empty
   369  func (k *ExtendedKey) IsZeroed() bool {
   370  	return k == nil || len(k.KeyData) == 0
   371  }
   372  
   373  // String returns the extended key as a human-readable base58-encoded string.
   374  func (k *ExtendedKey) String() string {
   375  	if k.IsZeroed() {
   376  		return EmptyExtendedKeyString
   377  	}
   378  
   379  	var childNumBytes [4]byte
   380  	binary.BigEndian.PutUint32(childNumBytes[:], k.ChildNumber)
   381  
   382  	// The serialized format is:
   383  	//   version (4) || depth (1) || parent fingerprint (4)) ||
   384  	//   child num (4) || chain code (32) || key data (33) || checksum (4)
   385  	serializedBytes := make([]byte, 0, serializedKeyLen+4)
   386  	serializedBytes = append(serializedBytes, k.Version...)
   387  	serializedBytes = append(serializedBytes, k.Depth)
   388  	serializedBytes = append(serializedBytes, k.FingerPrint...)
   389  	serializedBytes = append(serializedBytes, childNumBytes[:]...)
   390  	serializedBytes = append(serializedBytes, k.ChainCode...)
   391  	if k.IsPrivate {
   392  		serializedBytes = append(serializedBytes, 0x00)
   393  		serializedBytes = paddedAppend(32, serializedBytes, k.KeyData)
   394  	} else {
   395  		serializedBytes = append(serializedBytes, k.pubKeyBytes()...)
   396  	}
   397  
   398  	checkSum := chainhash.DoubleHashB(serializedBytes)[:4]
   399  	serializedBytes = append(serializedBytes, checkSum...)
   400  	return base58.Encode(serializedBytes)
   401  }
   402  
   403  // pubKeyBytes returns bytes for the serialized compressed public key associated
   404  // with this extended key in an efficient manner including memoization as
   405  // necessary.
   406  //
   407  // When the extended key is already a public key, the key is simply returned as
   408  // is since it's already in the correct form.  However, when the extended key is
   409  // a private key, the public key will be calculated and memoized so future
   410  // accesses can simply return the cached result.
   411  func (k *ExtendedKey) pubKeyBytes() []byte {
   412  	// Just return the key if it's already an extended public key.
   413  	if !k.IsPrivate {
   414  		return k.KeyData
   415  	}
   416  
   417  	pkx, pky := btcec.S256().ScalarBaseMult(k.KeyData)
   418  	pubKey := btcec.PublicKey{Curve: btcec.S256(), X: pkx, Y: pky}
   419  	return pubKey.SerializeCompressed()
   420  }
   421  
   422  // ToECDSA returns the key data as ecdsa.PrivateKey
   423  func (k *ExtendedKey) ToECDSA() *ecdsa.PrivateKey {
   424  	privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), k.KeyData)
   425  	return privKey.ToECDSA()
   426  }
   427  
   428  // NewKeyFromString returns a new extended key instance from a base58-encoded
   429  // extended key.
   430  func NewKeyFromString(key string) (*ExtendedKey, error) {
   431  	if key == EmptyExtendedKeyString || len(key) == 0 {
   432  		return &ExtendedKey{}, nil
   433  	}
   434  
   435  	// The base58-decoded extended key must consist of a serialized payload
   436  	// plus an additional 4 bytes for the checksum.
   437  	decoded := base58.Decode(key)
   438  	if len(decoded) != serializedKeyLen+4 {
   439  		return nil, ErrInvalidKeyLen
   440  	}
   441  
   442  	// The serialized format is:
   443  	//   version (4) || depth (1) || parent fingerprint (4)) ||
   444  	//   child num (4) || chain code (32) || key data (33) || checksum (4)
   445  
   446  	// Split the payload and checksum up and ensure the checksum matches.
   447  	payload := decoded[:len(decoded)-4]
   448  	checkSum := decoded[len(decoded)-4:]
   449  	expectedCheckSum := chainhash.DoubleHashB(payload)[:4]
   450  	if !bytes.Equal(checkSum, expectedCheckSum) {
   451  		return nil, ErrBadChecksum
   452  	}
   453  
   454  	// Deserialize each of the payload fields.
   455  	version := payload[:4]
   456  	depth := payload[4:5][0]
   457  	fingerPrint := payload[5:9]
   458  	childNumber := binary.BigEndian.Uint32(payload[9:13])
   459  	chainCode := payload[13:45]
   460  	keyData := payload[45:78]
   461  
   462  	// The key data is a private key if it starts with 0x00.  Serialized
   463  	// compressed pubkeys either start with 0x02 or 0x03.
   464  	isPrivate := keyData[0] == 0x00
   465  	if isPrivate {
   466  		// Ensure the private key is valid.  It must be within the range
   467  		// of the order of the secp256k1 curve and not be 0.
   468  		keyData = keyData[1:]
   469  		keyNum := new(big.Int).SetBytes(keyData)
   470  		if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 {
   471  			return nil, ErrInvalidSeed
   472  		}
   473  	} else {
   474  		// Ensure the public key parses correctly and is actually on the
   475  		// secp256k1 curve.
   476  		_, err := btcec.ParsePubKey(keyData, btcec.S256())
   477  		if err != nil {
   478  			return nil, err
   479  		}
   480  	}
   481  
   482  	return &ExtendedKey{
   483  		Version:     version,
   484  		KeyData:     keyData,
   485  		ChainCode:   chainCode,
   486  		FingerPrint: fingerPrint,
   487  		Depth:       depth,
   488  		ChildNumber: childNumber,
   489  		IsPrivate:   isPrivate,
   490  	}, nil
   491  }