// NewKeyFromString returns a new extended key instance from a base58-encoded // extended key. func NewKeyFromString(key string) (*ExtendedKey, error) { // The base58-decoded extended key must consist of a serialized payload // plus an additional 4 bytes for the checksum. decoded := btcutil.Base58Decode(key) if len(decoded) != serializedKeyLen+4 { return nil, ErrInvalidKeyLen } // The serialized format is: // version (4) || depth (1) || parent fingerprint (4)) || // child num (4) || chain code (32) || key data (33) || checksum (4) // Split the payload and checksum up and ensure the checksum matches. payload := decoded[:len(decoded)-4] checkSum := decoded[len(decoded)-4:] expectedCheckSum := btcwire.DoubleSha256(payload)[:4] if !bytes.Equal(checkSum, expectedCheckSum) { return nil, ErrBadChecksum } // Deserialize each of the payload fields. 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] // The key data is a private key if it starts with 0x00. Serialized // compressed pubkeys either start with 0x02 or 0x03. isPrivate := keyData[0] == 0x00 if isPrivate { // Ensure the private key is valid. It must be within the range // of the order of the secp256k1 curve and not be 0. keyData = keyData[1:] keyNum := new(big.Int).SetBytes(keyData) if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 { return nil, ErrUnusableSeed } } else { // Ensure the public key parses correctly and is actually on the // secp256k1 curve. _, err := btcec.ParsePubKey(keyData, btcec.S256()) if err != nil { return nil, err } } return newExtendedKey(version, keyData, chainCode, parentFP, depth, childNum, isPrivate), nil }
// NewAddressPubKey returns a new AddressPubKey which represents a pay-to-pubkey // address. The serializedPubKey parameter must be a valid pubkey and can be // uncompressed, compressed, or hybrid. func NewAddressPubKey(serializedPubKey []byte, net *btcnet.Params) (*AddressPubKey, error) { pubKey, err := btcec.ParsePubKey(serializedPubKey, btcec.S256()) if err != nil { return nil, err } // Set the format of the pubkey. This probably should be returned // from btcec, but do it here to avoid API churn. We already know the // pubkey is valid since it parsed above, so it's safe to simply examine // the leading byte to get the format. pkFormat := PKFUncompressed switch serializedPubKey[0] { case 0x02, 0x03: pkFormat = PKFCompressed case 0x06, 0x07: pkFormat = PKFHybrid } return &AddressPubKey{ pubKeyFormat: pkFormat, pubKey: pubKey, pubKeyHashID: net.PubKeyHashAddrID, }, nil }
// ECPubKey converts the extended key to a btcec public key and returns it. func (k *ExtendedKey) ECPubKey() (*btcec.PublicKey, error) { return btcec.ParsePubKey(k.pubKeyBytes(), btcec.S256()) }
// Child returns a derived child extended key at the given index. When this // extended key is a private extended key (as determined by the IsPrivate // function), a private extended key will be derived. Otherwise, the derived // extended key will be also be a public extended key. // // When the index is greater to or equal than the HardenedKeyStart constant, the // derived extended key will be a hardened extended key. It is only possible to // derive a hardended extended key from a private extended key. Consequently, // this function will return ErrDeriveHardFromPublic if a hardened child // extended key is requested from a public extended key. // // A hardened extended key is useful since, as previously mentioned, it requires // a parent private extended key to derive. In other words, normal child // extended public keys can be derived from a parent public extended key (no // knowledge of the parent private key) whereas hardened extended keys may not // be. // // NOTE: There is an extremely small chance (< 1 in 2^127) the specific child // index does not derive to a usable child. The ErrInvalidChild error will be // returned if this should occur, and the caller is expected to ignore the // invalid child and simply increment to the next index. func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) { // There are four scenarios that could happen here: // 1) Private extended key -> Hardened child private extended key // 2) Private extended key -> Non-hardened child private extended key // 3) Public extended key -> Non-hardened child public extended key // 4) Public extended key -> Hardened child public extended key (INVALID!) // Case #4 is invalid, so error out early. // A hardened child extended key may not be created from a public // extended key. isChildHardened := i >= HardenedKeyStart if !k.isPrivate && isChildHardened { return nil, ErrDeriveHardFromPublic } // The data used to derive the child key depends on whether or not the // child is hardened per [BIP32]. // // For hardened children: // 0x00 || ser256(parentKey) || ser32(i) // // For normal children: // serP(parentPubKey) || ser32(i) keyLen := 33 data := make([]byte, keyLen+4) if isChildHardened { // Case #1. // When the child is a hardened child, the key is known to be a // private key due to the above early return. Pad it with a // leading zero as required by [BIP32] for deriving the child. copy(data[1:], k.key) } else { // Case #2 or #3. // This is either a public or private extended key, but in // either case, the data which is used to derive the child key // starts with the secp256k1 compressed public key bytes. copy(data, k.pubKeyBytes()) } binary.BigEndian.PutUint32(data[keyLen:], i) // Take the HMAC-SHA512 of the current key's chain code and the derived // data: // I = HMAC-SHA512(Key = chainCode, Data = data) hmac512 := hmac.New(sha512.New, k.chainCode) hmac512.Write(data) ilr := hmac512.Sum(nil) // Split "I" into two 32-byte sequences Il and Ir where: // Il = intermediate key used to derive the child // Ir = child chain code il := ilr[:len(ilr)/2] childChainCode := ilr[len(ilr)/2:] // Both derived public or private keys rely on treating the left 32-byte // sequence calculated above (Il) as a 256-bit integer that must be // within the valid range for a secp256k1 private key. There is a small // chance (< 1 in 2^127) this condition will not hold, and in that case, // a child extended key can't be created for this index and the caller // should simply increment to the next index. ilNum := new(big.Int).SetBytes(il) if ilNum.Cmp(btcec.S256().N) >= 0 || ilNum.Sign() == 0 { return nil, ErrInvalidChild } // The algorithm used to derive the child key depends on whether or not // a private or public child is being derived. // // For private children: // childKey = parse256(Il) + parentKey // // For public children: // childKey = serP(point(parse256(Il)) + parentKey) var isPrivate bool var childKey []byte if k.isPrivate { // Case #1 or #2. // Add the parent private key to the intermediate private key to // derive the final child key. // // childKey = parse256(Il) + parenKey keyNum := new(big.Int).SetBytes(k.key) ilNum.Add(ilNum, keyNum) ilNum.Mod(ilNum, btcec.S256().N) childKey = ilNum.Bytes() isPrivate = true } else { // Case #3. // Calculate the corresponding intermediate public key for // intermediate private key. ilx, ily := btcec.S256().ScalarBaseMult(il) if ilx.Sign() == 0 || ily.Sign() == 0 { return nil, ErrInvalidChild } // Convert the serialized compressed parent public key into X // and Y coordinates so it can be added to the intermediate // public key. pubKey, err := btcec.ParsePubKey(k.key, btcec.S256()) if err != nil { return nil, err } // Add the intermediate public key to the parent public key to // derive the final child key. // // childKey = serP(point(parse256(Il)) + parentKey) childX, childY := btcec.S256().Add(ilx, ily, pubKey.X, pubKey.Y) pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY} childKey = pk.SerializeCompressed() } // The fingerprint of the parent for the derived child is the first 4 // bytes of the RIPEMD160(SHA256(parentPubKey)). parentFP := btcutil.Hash160(k.pubKeyBytes())[:4] return newExtendedKey(k.version, childKey, childChainCode, parentFP, k.depth+1, i, isPrivate), nil }