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 }