extkeys: extended key can derive a child only if its depth is less than 255 (#1032)

This commit is contained in:
Andrea Franz 2018-06-22 14:21:49 +02:00 committed by Ivan Daniluk
parent 51ab9053ab
commit 1974f39e0c
2 changed files with 32 additions and 4 deletions

View File

@ -70,6 +70,10 @@ const (
// EmptyExtendedKeyString marker string for zero extended key
EmptyExtendedKeyString = "Zeroed extended key"
// MaxDepth is the maximum depth of an extended key.
// Extended keys with depth MaxDepth cannot derive child keys.
MaxDepth = 255
)
// errors
@ -82,6 +86,7 @@ var (
ErrInvalidKeyLen = errors.New("serialized extended key length is invalid")
ErrDerivingChild = errors.New("error deriving child key")
ErrInvalidMasterKey = errors.New("invalid master key supplied")
ErrMaxDepthExceeded = errors.New("max depth exceeded")
)
var (
@ -95,7 +100,7 @@ var (
// ExtendedKey represents BIP44-compliant HD key
type ExtendedKey struct {
Version []byte // 4 bytes, mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private
Depth uint16 // 1 byte, depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ....
Depth uint8 // 1 byte, depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ....
FingerPrint []byte // 4 bytes, fingerprint of the parent's key (0x00000000 if master key)
ChildNumber uint32 // 4 bytes, This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
KeyData []byte // 33 bytes, the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
@ -147,6 +152,10 @@ func NewMaster(seed []byte) (*ExtendedKey, error) {
// 3) Public extended key -> Non-hardened child public extended key
// 4) Public extended key -> Hardened child public extended key (INVALID!)
func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
if k.Depth == MaxDepth {
return nil, ErrMaxDepthExceeded
}
// A hardened child may not be created from a public extended key (Case #4).
isChildHardened := i >= HardenedKeyStart
if !k.IsPrivate && isChildHardened {
@ -286,7 +295,6 @@ func (k *ExtendedKey) String() string {
}
var childNumBytes [4]byte
depthByte := byte(k.Depth % 256)
binary.BigEndian.PutUint32(childNumBytes[:], k.ChildNumber)
// The serialized format is:
@ -294,7 +302,7 @@ func (k *ExtendedKey) String() string {
// child num (4) || chain code (32) || key data (33) || checksum (4)
serializedBytes := make([]byte, 0, serializedKeyLen+4)
serializedBytes = append(serializedBytes, k.Version...)
serializedBytes = append(serializedBytes, depthByte)
serializedBytes = append(serializedBytes, k.Depth)
serializedBytes = append(serializedBytes, k.FingerPrint...)
serializedBytes = append(serializedBytes, childNumBytes[:]...)
serializedBytes = append(serializedBytes, k.ChainCode...)
@ -363,7 +371,7 @@ func NewKeyFromString(key string) (*ExtendedKey, error) {
// Deserialize each of the payload fields.
version := payload[:4]
depth := uint16(payload[4:5][0])
depth := payload[4:5][0]
fingerPrint := payload[5:9]
childNumber := binary.BigEndian.Uint32(payload[9:13])
chainCode := payload[13:45]

View File

@ -511,6 +511,26 @@ func TestErrors(t *testing.T) {
}
}
func TestMaxDepth(t *testing.T) {
mnemonic := NewMnemonic()
phrase, err := mnemonic.MnemonicPhrase(128, EnglishLanguage)
if err != nil {
t.Errorf("Test failed: could not create mnemonic phrase: %v", err)
}
lastParentKey, err := NewMaster(mnemonic.MnemonicSeed(phrase, "test-password"))
if err != nil {
t.Errorf("couldn't create master extended key: %v", err)
}
lastParentKey.Depth = 255
_, err = lastParentKey.Child(0)
if err != ErrMaxDepthExceeded {
t.Errorf("Expected ErrMaxDepthExceeded, got %+v", err)
}
}
func TestBIP44ChildDerivation(t *testing.T) {
keyString := masterPrivKey1
derivedKey1String := "xprvA38t8tFW4vbuB7WJXEqMFmZqRrcZUKWqqMcGjjKjr2hbfvPhRtLLJGL4ayWG8shF1VkuUikVGodGshLiKRS7WrdsrGSVDQCY33qoPBxG2Kp"