53 lines
1.4 KiB
Go
53 lines
1.4 KiB
Go
package extkeys
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha512"
|
|
"errors"
|
|
"math/big"
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
)
|
|
|
|
// errors
|
|
var (
|
|
ErrInvalidSecretKey = errors.New("generated secret key cannot be used")
|
|
)
|
|
|
|
func splitHMAC(seed, salt []byte) (secretKey, chainCode []byte, err error) {
|
|
data := hmac.New(sha512.New, salt)
|
|
if _, err = data.Write(seed); err != nil {
|
|
return
|
|
}
|
|
I := data.Sum(nil)
|
|
|
|
// Split I into two 32-byte sequences, IL and IR.
|
|
// IL = master secret key
|
|
// IR = master chain code
|
|
secretKey = I[:32]
|
|
chainCode = I[32:]
|
|
|
|
// IL (secretKey) is expected to be a 256-bit integer (it is used as parse256(IL)),
|
|
// and consequently that integer must be within range for SECP256k1 private key.
|
|
//
|
|
// There's tiny possibility (<1 in 2^127) this invariant is violated:
|
|
// error is returned in that case, and simple resolution is to request another child with i incremented.
|
|
keyBigInt := new(big.Int).SetBytes(secretKey)
|
|
if keyBigInt.Cmp(btcec.S256().N) >= 0 || keyBigInt.Sign() == 0 {
|
|
err = ErrInvalidSecretKey
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// paddedAppend appends the src byte slice to dst, returning the new slice.
|
|
// If the length of the source is smaller than the passed size, leading zero
|
|
// bytes are appended to the dst slice before appending src.
|
|
// nolint: unparam
|
|
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...)
|
|
}
|