Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chaincfg: Add RegisterHDKeyID func to populate HD key ID pairs #1617

Merged
merged 1 commit into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion chaincfg/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,10 @@ var (
// is intended to identify the network for a hierarchical deterministic
// private extended key is not registered.
ErrUnknownHDKeyID = errors.New("unknown hd private extended key bytes")

// ErrInvalidHDKeyID describes an error where the provided hierarchical
// deterministic version bytes, or hd key id, is malformed.
ErrInvalidHDKeyID = errors.New("invalid hd extended key version bytes")
)

var (
Expand Down Expand Up @@ -619,7 +623,11 @@ func Register(params *Params) error {
registeredNets[params.Net] = struct{}{}
pubKeyHashAddrIDs[params.PubKeyHashAddrID] = struct{}{}
scriptHashAddrIDs[params.ScriptHashAddrID] = struct{}{}
hdPrivToPubKeyIDs[params.HDPrivateKeyID] = params.HDPublicKeyID[:]

err := RegisterHDKeyID(params.HDPublicKeyID[:], params.HDPrivateKeyID[:])
if err != nil {
return err
}

// A valid Bech32 encoded segwit address always has as prefix the
// human-readable part for the given net followed by '1'.
Expand Down Expand Up @@ -666,6 +674,29 @@ func IsBech32SegwitPrefix(prefix string) bool {
return ok
}

// RegisterHDKeyID registers a public and private hierarchical deterministic
// extended key ID pair.
//
// Non-standard HD version bytes, such as the ones documented in SLIP-0132,
// should be registered using this method for library packages to lookup key
// IDs (aka HD version bytes). When the provided key IDs are invalid, the
// ErrInvalidHDKeyID error will be returned.
//
// Reference:
// SLIP-0132 : Registered HD version bytes for BIP-0032
// https://github.com/satoshilabs/slips/blob/master/slip-0132.md
func RegisterHDKeyID(hdPublicKeyID []byte, hdPrivateKeyID []byte) error {
if len(hdPublicKeyID) != 4 || len(hdPrivateKeyID) != 4 {
return ErrInvalidHDKeyID
}

var keyID [4]byte
copy(keyID[:], hdPrivateKeyID)
hdPrivToPubKeyIDs[keyID] = hdPublicKeyID

return nil
}

// HDPrivateKeyToPublicKeyID accepts a private hierarchical deterministic
// extended key id and returns the associated public key id. When the provided
// id is not registered, the ErrUnknownHDKeyID error will be returned.
Expand Down
53 changes: 52 additions & 1 deletion chaincfg/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

package chaincfg

import "testing"
import (
"bytes"
"testing"
)

// TestInvalidHashStr ensures the newShaHashFromStr function panics when used to
// with an invalid hash string.
Expand Down Expand Up @@ -33,3 +36,51 @@ func TestMustRegisterPanic(t *testing.T) {
// Intentionally try to register duplicate params to force a panic.
mustRegister(&MainNetParams)
}

func TestRegisterHDKeyID(t *testing.T) {
t.Parallel()

// Ref: https://github.com/satoshilabs/slips/blob/master/slip-0132.md
hdKeyIDZprv := []byte{0x02, 0xaa, 0x7a, 0x99}
hdKeyIDZpub := []byte{0x02, 0xaa, 0x7e, 0xd3}

if err := RegisterHDKeyID(hdKeyIDZpub, hdKeyIDZprv); err != nil {
t.Fatalf("RegisterHDKeyID: expected no error, got %v", err)
}

got, err := HDPrivateKeyToPublicKeyID(hdKeyIDZprv)
if err != nil {
t.Fatalf("HDPrivateKeyToPublicKeyID: expected no error, got %v", err)
}

if !bytes.Equal(got, hdKeyIDZpub) {
t.Fatalf("HDPrivateKeyToPublicKeyID: expected result %v, got %v",
hdKeyIDZpub, got)
}
}

func TestInvalidHDKeyID(t *testing.T) {
t.Parallel()

prvValid := []byte{0x02, 0xaa, 0x7a, 0x99}
pubValid := []byte{0x02, 0xaa, 0x7e, 0xd3}
prvInvalid := []byte{0x00}
pubInvalid := []byte{0x00}

if err := RegisterHDKeyID(pubInvalid, prvValid); err != ErrInvalidHDKeyID {
t.Fatalf("RegisterHDKeyID: want err ErrInvalidHDKeyID, got %v", err)
}

if err := RegisterHDKeyID(pubValid, prvInvalid); err != ErrInvalidHDKeyID {
t.Fatalf("RegisterHDKeyID: want err ErrInvalidHDKeyID, got %v", err)
}

if err := RegisterHDKeyID(pubInvalid, prvInvalid); err != ErrInvalidHDKeyID {
t.Fatalf("RegisterHDKeyID: want err ErrInvalidHDKeyID, got %v", err)
}

// FIXME: The error type should be changed to ErrInvalidHDKeyID.
if _, err := HDPrivateKeyToPublicKeyID(prvInvalid); err != ErrUnknownHDKeyID {
t.Fatalf("HDPrivateKeyToPublicKeyID: want err ErrUnknownHDKeyID, got %v", err)
}
onyb marked this conversation as resolved.
Show resolved Hide resolved
}