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.

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