func NewKeyFromString(key string) (*ExtendedKey, error) {
	decoded := base58.Decode(key)
	if len(decoded) != serializedKeyLen+4 {
		return nil, ErrInvalidKeyLen
	}
	payload := decoded[:len(decoded)-4]
	checkSum := decoded[len(decoded)-4:]
	expectedCheckSum := chainhash.DoubleHashB(payload)[:4]
	if !bytes.Equal(checkSum, expectedCheckSum) {
		return nil, ErrBadChecksum
	}
	version := payload[:4]
	depth := uint16(payload[4:5][0])
	parentFP := payload[5:9]
	childNum := binary.BigEndian.Uint32(payload[9:13])
	chainCode := payload[13:45]
	keyData := payload[45:78]
	isPrivate := keyData[0] == 0x00
	if isPrivate {
		keyData = keyData[1:]
		keyNum := new(big.Int).SetBytes(keyData)
		if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 {
			return nil, ErrUnusableSeed
		}
	} else {
		_, err := btcec.ParsePubKey(keyData, btcec.S256())
		if err != nil {
			return nil, err
		}
	}
	return newExtendedKey(version, keyData, chainCode, parentFP, depth,
		childNum, isPrivate), nil
}
NewKeyFromString returns a new extended key instance from a base58-encoded
extended key.
package hdkeychain
import (
	"bytes"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/binary"
	"errors"
	"fmt"
	"math/big"
	"github.com/bitgo/prova/btcec"
	"github.com/bitgo/prova/chaincfg"
	"github.com/bitgo/prova/chaincfg/chainhash"
	"github.com/bitgo/prova/provautil"
	"github.com/bitgo/prova/provautil/base58"
)
const (
	RecommendedSeedLen = 32  
	HardenedKeyStart = 0x80000000  
	MinSeedBytes = 16  
	MaxSeedBytes = 64  
	serializedKeyLen = 4 + 1 + 4 + 4 + 32 + 33  
)
var (
	ErrDeriveHardFromPublic = errors.New("cannot derive a hardened key " +
		"from a public key")
	ErrNotPrivExtKey = errors.New("unable to create private keys from a " +
		"public extended key")
	ErrInvalidChild = errors.New("the extended key at this index is invalid")
	ErrUnusableSeed = errors.New("unusable seed")
	ErrInvalidSeedLen = fmt.Errorf("seed length must be between %d and %d "+
		"bits", MinSeedBytes*8, MaxSeedBytes*8)
	ErrBadChecksum = errors.New("bad extended key checksum")
	ErrInvalidKeyLen = errors.New("the provided serialized extended key " +
		"length is invalid")
)
var masterKey = []byte("Bitcoin seed")
type ExtendedKey struct {
	key       []byte  
	pubKey    []byte  
	chainCode []byte
	depth     uint16
	parentFP  []byte
	childNum  uint32
	version   []byte
	isPrivate bool
}
func newExtendedKey(version, key, chainCode, parentFP []byte, depth uint16,
	childNum uint32, isPrivate bool) *ExtendedKey {
	return &ExtendedKey{
		key:       key,
		chainCode: chainCode,
		depth:     depth,
		parentFP:  parentFP,
		childNum:  childNum,
		version:   version,
		isPrivate: isPrivate,
	}
}
func (k *ExtendedKey) pubKeyBytes() []byte {
	if !k.isPrivate {
		return k.key
	}
	if len(k.pubKey) == 0 {
		pkx, pky := btcec.S256().ScalarBaseMult(k.key)
		pubKey := btcec.PublicKey{Curve: btcec.S256(), X: pkx, Y: pky}
		k.pubKey = pubKey.SerializeCompressed()
	}
	return k.pubKey
}
func (k *ExtendedKey) IsPrivate() bool {
	return k.isPrivate
}
func (k *ExtendedKey) ParentFingerprint() uint32 {
	return binary.BigEndian.Uint32(k.parentFP)
}
func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
	isChildHardened := i >= HardenedKeyStart
	if !k.isPrivate && isChildHardened {
		return nil, ErrDeriveHardFromPublic
	}
	keyLen := 33
	data := make([]byte, keyLen+4)
	if isChildHardened {
		copy(data[1:], k.key)
	} else {
		copy(data, k.pubKeyBytes())
	}
	binary.BigEndian.PutUint32(data[keyLen:], i)
	hmac512 := hmac.New(sha512.New, k.chainCode)
	hmac512.Write(data)
	ilr := hmac512.Sum(nil)
	il := ilr[:len(ilr)/2]
	childChainCode := ilr[len(ilr)/2:]
	ilNum := new(big.Int).SetBytes(il)
	if ilNum.Cmp(btcec.S256().N) >= 0 || ilNum.Sign() == 0 {
		return nil, ErrInvalidChild
	}
	var isPrivate bool
	var childKey []byte
	if k.isPrivate {
		keyNum := new(big.Int).SetBytes(k.key)
		ilNum.Add(ilNum, keyNum)
		ilNum.Mod(ilNum, btcec.S256().N)
		childKey = ilNum.Bytes()
		isPrivate = true
	} else {
		ilx, ily := btcec.S256().ScalarBaseMult(il)
		if ilx.Sign() == 0 || ily.Sign() == 0 {
			return nil, ErrInvalidChild
		}
		pubKey, err := btcec.ParsePubKey(k.key, btcec.S256())
		if err != nil {
			return nil, err
		}
		childX, childY := btcec.S256().Add(ilx, ily, pubKey.X, pubKey.Y)
		pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY}
		childKey = pk.SerializeCompressed()
	}
	parentFP := provautil.Hash160(k.pubKeyBytes())[:4]
	return newExtendedKey(k.version, childKey, childChainCode, parentFP,
		k.depth+1, i, isPrivate), nil
}
func (k *ExtendedKey) Neuter() (*ExtendedKey, error) {
	if !k.isPrivate {
		return k, nil
	}
	version, err := chaincfg.HDPrivateKeyToPublicKeyID(k.version)
	if err != nil {
		return nil, err
	}
	return newExtendedKey(version, k.pubKeyBytes(), k.chainCode, k.parentFP,
		k.depth, k.childNum, false), nil
}
func (k *ExtendedKey) ECPubKey() (*btcec.PublicKey, error) {
	return btcec.ParsePubKey(k.pubKeyBytes(), btcec.S256())
}
func (k *ExtendedKey) ECPrivKey() (*btcec.PrivateKey, error) {
	if !k.isPrivate {
		return nil, ErrNotPrivExtKey
	}
	privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), k.key)
	return privKey, nil
}
func (k *ExtendedKey) Address(net *chaincfg.Params) (*provautil.AddressPubKeyHash, error) {
	pkHash := provautil.Hash160(k.pubKeyBytes())
	return provautil.NewAddressPubKeyHash(pkHash, net)
}
func paddedAppend(size uint, dst, src []byte) []byte {
	for i := 0; i < int(size)-len(src); i++ {
		dst = append(dst, 0)
	}
	return append(dst, src...)
}
func (k *ExtendedKey) String() string {
	if len(k.key) == 0 {
		return "zeroed extended key"
	}
	var childNumBytes [4]byte
	depthByte := byte(k.depth % 256)
	binary.BigEndian.PutUint32(childNumBytes[:], k.childNum)
	serializedBytes := make([]byte, 0, serializedKeyLen+4)
	serializedBytes = append(serializedBytes, k.version...)
	serializedBytes = append(serializedBytes, depthByte)
	serializedBytes = append(serializedBytes, k.parentFP...)
	serializedBytes = append(serializedBytes, childNumBytes[:]...)
	serializedBytes = append(serializedBytes, k.chainCode...)
	if k.isPrivate {
		serializedBytes = append(serializedBytes, 0x00)
		serializedBytes = paddedAppend(32, serializedBytes, k.key)
	} else {
		serializedBytes = append(serializedBytes, k.pubKeyBytes()...)
	}
	checkSum := chainhash.DoubleHashB(serializedBytes)[:4]
	serializedBytes = append(serializedBytes, checkSum...)
	return base58.Encode(serializedBytes)
}
func (k *ExtendedKey) IsForNet(net *chaincfg.Params) bool {
	return bytes.Equal(k.version, net.HDPrivateKeyID[:]) ||
		bytes.Equal(k.version, net.HDPublicKeyID[:])
}
func (k *ExtendedKey) SetNet(net *chaincfg.Params) {
	if k.isPrivate {
		k.version = net.HDPrivateKeyID[:]
	} else {
		k.version = net.HDPublicKeyID[:]
	}
}
func zero(b []byte) {
	lenb := len(b)
	for i := 0; i < lenb; i++ {
		b[i] = 0
	}
}
func (k *ExtendedKey) Zero() {
	zero(k.key)
	zero(k.pubKey)
	zero(k.chainCode)
	zero(k.parentFP)
	k.version = nil
	k.key = nil
	k.depth = 0
	k.childNum = 0
	k.isPrivate = false
}
func NewMaster(seed []byte, net *chaincfg.Params) (*ExtendedKey, error) {
	if len(seed) < MinSeedBytes || len(seed) > MaxSeedBytes {
		return nil, ErrInvalidSeedLen
	}
	hmac512 := hmac.New(sha512.New, masterKey)
	hmac512.Write(seed)
	lr := hmac512.Sum(nil)
	secretKey := lr[:len(lr)/2]
	chainCode := lr[len(lr)/2:]
	secretKeyNum := new(big.Int).SetBytes(secretKey)
	if secretKeyNum.Cmp(btcec.S256().N) >= 0 || secretKeyNum.Sign() == 0 {
		return nil, ErrUnusableSeed
	}
	parentFP := []byte{0x00, 0x00, 0x00, 0x00}
	return newExtendedKey(net.HDPrivateKeyID[:], secretKey, chainCode,
		parentFP, 0, 0, true), nil
}