You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
7.4 KiB

  1. package hd
  2. import (
  3. "crypto/ecdsa"
  4. "crypto/hmac"
  5. "crypto/sha256"
  6. "crypto/sha512"
  7. "encoding/base64"
  8. "encoding/binary"
  9. "encoding/hex"
  10. "errors"
  11. "fmt"
  12. "hash"
  13. "math/big"
  14. "strconv"
  15. "strings"
  16. "github.com/btcsuite/btcd/btcec"
  17. "github.com/btcsuite/btcutil/base58"
  18. "github.com/tendermint/go-crypto"
  19. "golang.org/x/crypto/ripemd160"
  20. )
  21. func ComputeAddress(pubKeyHex string, chainHex string, path string, index int32) string {
  22. pubKeyBytes := DerivePublicKeyForPath(
  23. HexDecode(pubKeyHex),
  24. HexDecode(chainHex),
  25. fmt.Sprintf("%v/%v", path, index),
  26. )
  27. return AddrFromPubKeyBytes(pubKeyBytes)
  28. }
  29. func ComputePrivateKey(mprivHex string, chainHex string, path string, index int32) string {
  30. privKeyBytes := DerivePrivateKeyForPath(
  31. HexDecode(mprivHex),
  32. HexDecode(chainHex),
  33. fmt.Sprintf("%v/%v", path, index),
  34. )
  35. return HexEncode(privKeyBytes)
  36. }
  37. func ComputeAddressForPrivKey(privKey string) string {
  38. pubKeyBytes := PubKeyBytesFromPrivKeyBytes(HexDecode(privKey), true)
  39. return AddrFromPubKeyBytes(pubKeyBytes)
  40. }
  41. func SignMessage(privKey string, message string, compress bool) string {
  42. prefixBytes := []byte("Bitcoin Signed Message:\n")
  43. messageBytes := []byte(message)
  44. bytes := []byte{}
  45. bytes = append(bytes, byte(len(prefixBytes)))
  46. bytes = append(bytes, prefixBytes...)
  47. bytes = append(bytes, byte(len(messageBytes)))
  48. bytes = append(bytes, messageBytes...)
  49. privKeyBytes := HexDecode(privKey)
  50. x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
  51. ecdsaPubKey := ecdsa.PublicKey{
  52. Curve: btcec.S256(),
  53. X: x,
  54. Y: y,
  55. }
  56. ecdsaPrivKey := &btcec.PrivateKey{
  57. PublicKey: ecdsaPubKey,
  58. D: new(big.Int).SetBytes(privKeyBytes),
  59. }
  60. sigbytes, err := btcec.SignCompact(btcec.S256(), ecdsaPrivKey, crypto.Sha256(crypto.Sha256(bytes)), compress)
  61. if err != nil {
  62. panic(err)
  63. }
  64. return base64.StdEncoding.EncodeToString(sigbytes)
  65. }
  66. // returns MPK, Chain, and master secret in hex.
  67. func ComputeMastersFromSeed(seed string) (string, string, string, string) {
  68. secret, chain := I64([]byte("Bitcoin seed"), []byte(seed))
  69. pubKeyBytes := PubKeyBytesFromPrivKeyBytes(secret, true)
  70. return HexEncode(pubKeyBytes), HexEncode(secret), HexEncode(chain), HexEncode(secret)
  71. }
  72. func ComputeWIF(privKey string, compress bool) string {
  73. return WIFFromPrivKeyBytes(HexDecode(privKey), compress)
  74. }
  75. func ComputeTxId(rawTxHex string) string {
  76. return HexEncode(ReverseBytes(CalcHash256(HexDecode(rawTxHex))))
  77. }
  78. // Private methods...
  79. func DerivePrivateKeyForPath(privKeyBytes []byte, chain []byte, path string) []byte {
  80. data := privKeyBytes
  81. parts := strings.Split(path, "/")
  82. for _, part := range parts {
  83. prime := part[len(part)-1:] == "'"
  84. // prime == private derivation. Otherwise public.
  85. if prime {
  86. part = part[:len(part)-1]
  87. }
  88. i, err := strconv.Atoi(part)
  89. if err != nil {
  90. panic(err)
  91. }
  92. if i < 0 {
  93. panic(errors.New("index too large."))
  94. }
  95. data, chain = DerivePrivateKey(data, chain, uint32(i), prime)
  96. //printKeyInfo(data, nil, chain)
  97. }
  98. return data
  99. }
  100. func DerivePublicKeyForPath(pubKeyBytes []byte, chain []byte, path string) []byte {
  101. data := pubKeyBytes
  102. parts := strings.Split(path, "/")
  103. for _, part := range parts {
  104. prime := part[len(part)-1:] == "'"
  105. if prime {
  106. panic(errors.New("cannot do a prime derivation from public key"))
  107. }
  108. i, err := strconv.Atoi(part)
  109. if err != nil {
  110. panic(err)
  111. }
  112. if i < 0 {
  113. panic(errors.New("index too large."))
  114. }
  115. data, chain = DerivePublicKey(data, chain, uint32(i))
  116. //printKeyInfo(nil, data, chain)
  117. }
  118. return data
  119. }
  120. func DerivePrivateKey(privKeyBytes []byte, chain []byte, i uint32, prime bool) ([]byte, []byte) {
  121. data := []byte{} // nolint [ megacheck, deadcode ]
  122. if prime {
  123. i = i | 0x80000000
  124. data = append([]byte{byte(0)}, privKeyBytes...)
  125. } else {
  126. public := PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
  127. data = public
  128. }
  129. data = append(data, uint32ToBytes(i)...)
  130. data2, chain2 := I64(chain, data)
  131. x := addScalars(privKeyBytes, data2)
  132. return x, chain2
  133. }
  134. func DerivePublicKey(pubKeyBytes []byte, chain []byte, i uint32) ([]byte, []byte) {
  135. data := []byte{}
  136. data = append(data, pubKeyBytes...)
  137. data = append(data, uint32ToBytes(i)...)
  138. data2, chain2 := I64(chain, data)
  139. data2p := PubKeyBytesFromPrivKeyBytes(data2, true)
  140. return addPoints(pubKeyBytes, data2p), chain2
  141. }
  142. func addPoints(a []byte, b []byte) []byte {
  143. ap, err := btcec.ParsePubKey(a, btcec.S256())
  144. if err != nil {
  145. panic(err)
  146. }
  147. bp, err := btcec.ParsePubKey(b, btcec.S256())
  148. if err != nil {
  149. panic(err)
  150. }
  151. sumX, sumY := btcec.S256().Add(ap.X, ap.Y, bp.X, bp.Y)
  152. sum := (*btcec.PublicKey)(&btcec.PublicKey{ // nolint: unconvert
  153. Curve: btcec.S256(),
  154. X: sumX,
  155. Y: sumY,
  156. })
  157. return sum.SerializeCompressed()
  158. }
  159. func addScalars(a []byte, b []byte) []byte {
  160. aInt := new(big.Int).SetBytes(a)
  161. bInt := new(big.Int).SetBytes(b)
  162. sInt := new(big.Int).Add(aInt, bInt)
  163. x := sInt.Mod(sInt, btcec.S256().N).Bytes()
  164. x2 := [32]byte{}
  165. copy(x2[32-len(x):], x)
  166. return x2[:]
  167. }
  168. func uint32ToBytes(i uint32) []byte {
  169. b := [4]byte{}
  170. binary.BigEndian.PutUint32(b[:], i)
  171. return b[:]
  172. }
  173. func HexEncode(b []byte) string {
  174. return hex.EncodeToString(b)
  175. }
  176. func HexDecode(str string) []byte {
  177. b, _ := hex.DecodeString(str)
  178. return b
  179. }
  180. func I64(key []byte, data []byte) ([]byte, []byte) {
  181. mac := hmac.New(sha512.New, key)
  182. mac.Write(data)
  183. I := mac.Sum(nil)
  184. return I[:32], I[32:]
  185. }
  186. // This returns a Bitcoin-like address.
  187. func AddrFromPubKeyBytes(pubKeyBytes []byte) string {
  188. prefix := byte(0x00) // TODO Make const or configurable
  189. h160 := CalcHash160(pubKeyBytes)
  190. h160 = append([]byte{prefix}, h160...)
  191. checksum := CalcHash256(h160)
  192. b := append(h160, checksum[:4]...)
  193. return base58.Encode(b)
  194. }
  195. func AddrBytesFromPubKeyBytes(pubKeyBytes []byte) (addrBytes []byte, checksum []byte) {
  196. prefix := byte(0x00) // TODO Make const or configurable
  197. h160 := CalcHash160(pubKeyBytes)
  198. _h160 := append([]byte{prefix}, h160...)
  199. checksum = CalcHash256(_h160)[:4]
  200. return h160, checksum
  201. }
  202. func WIFFromPrivKeyBytes(privKeyBytes []byte, compress bool) string {
  203. prefix := byte(0x80) // TODO Make const or configurable
  204. bytes := append([]byte{prefix}, privKeyBytes...)
  205. if compress {
  206. bytes = append(bytes, byte(1))
  207. }
  208. checksum := CalcHash256(bytes)
  209. bytes = append(bytes, checksum[:4]...)
  210. return base58.Encode(bytes)
  211. }
  212. func PubKeyBytesFromPrivKeyBytes(privKeyBytes []byte, compress bool) (pubKeyBytes []byte) {
  213. x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
  214. pub := (*btcec.PublicKey)(&btcec.PublicKey{ // nolint: unconvert
  215. Curve: btcec.S256(),
  216. X: x,
  217. Y: y,
  218. })
  219. if compress {
  220. return pub.SerializeCompressed()
  221. }
  222. return pub.SerializeUncompressed()
  223. }
  224. // Calculate the hash of hasher over buf.
  225. func CalcHash(buf []byte, hasher hash.Hash) []byte {
  226. hasher.Write(buf)
  227. return hasher.Sum(nil)
  228. }
  229. // calculate hash160 which is ripemd160(sha256(data))
  230. func CalcHash160(buf []byte) []byte {
  231. return CalcHash(CalcHash(buf, sha256.New()), ripemd160.New())
  232. }
  233. // calculate hash256 which is sha256(sha256(data))
  234. func CalcHash256(buf []byte) []byte {
  235. return CalcHash(CalcHash(buf, sha256.New()), sha256.New())
  236. }
  237. // calculate sha512(data)
  238. func CalcSha512(buf []byte) []byte {
  239. return CalcHash(buf, sha512.New())
  240. }
  241. func ReverseBytes(buf []byte) []byte {
  242. var res []byte
  243. if len(buf) == 0 {
  244. return res
  245. }
  246. // Walk till mid-way, swapping bytes from each end:
  247. // b[i] and b[len-i-1]
  248. blen := len(buf)
  249. res = make([]byte, blen)
  250. mid := blen / 2
  251. for left := 0; left <= mid; left++ {
  252. right := blen - left - 1
  253. res[left] = buf[right]
  254. res[right] = buf[left]
  255. }
  256. return res
  257. }