github.com/status-im/status-go/extkeys@v1.1.2/utils.go (about)

     1  package extkeys
     2  
     3  import (
     4  	"crypto/hmac"
     5  	"crypto/sha512"
     6  	"errors"
     7  	"math/big"
     8  
     9  	"github.com/btcsuite/btcd/btcec"
    10  )
    11  
    12  // errors
    13  var (
    14  	ErrInvalidSecretKey = errors.New("generated secret key cannot be used")
    15  )
    16  
    17  func splitHMAC(seed, salt []byte) (secretKey, chainCode []byte, err error) {
    18  	data := hmac.New(sha512.New, salt)
    19  	if _, err = data.Write(seed); err != nil {
    20  		return
    21  	}
    22  	I := data.Sum(nil)
    23  
    24  	// Split I into two 32-byte sequences, IL and IR.
    25  	// IL = master secret key
    26  	// IR = master chain code
    27  	secretKey = I[:32]
    28  	chainCode = I[32:]
    29  
    30  	// IL (secretKey) is expected to be a 256-bit integer (it is used as parse256(IL)),
    31  	// and consequently that integer must be within range for SECP256k1 private key.
    32  	//
    33  	// There's tiny possibility (<1 in 2^127) this invariant is violated:
    34  	//   error is returned in that case, and simple resolution is to request another child with i incremented.
    35  	keyBigInt := new(big.Int).SetBytes(secretKey)
    36  	if keyBigInt.Cmp(btcec.S256().N) >= 0 || keyBigInt.Sign() == 0 {
    37  		err = ErrInvalidSecretKey
    38  	}
    39  
    40  	return
    41  }
    42  
    43  // paddedAppend appends the src byte slice to dst, returning the new slice.
    44  // If the length of the source is smaller than the passed size, leading zero
    45  // bytes are appended to the dst slice before appending src.
    46  // nolint: unparam
    47  func paddedAppend(size uint, dst, src []byte) []byte {
    48  	for i := 0; i < int(size)-len(src); i++ {
    49  		dst = append(dst, 0)
    50  	}
    51  	return append(dst, src...)
    52  }