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.

352 lines
10 KiB

  1. package hd
  2. // XXX This package doesn't work with our address scheme,
  3. // XXX and it probably doesn't work for our other pubkey types.
  4. // XXX Fix it up to be more general but compatible.
  5. import (
  6. "crypto/ecdsa"
  7. "crypto/hmac"
  8. "crypto/sha256"
  9. "crypto/sha512"
  10. "encoding/base64"
  11. "encoding/binary"
  12. "encoding/hex"
  13. "errors"
  14. "fmt"
  15. "hash"
  16. "math/big"
  17. "strconv"
  18. "strings"
  19. "github.com/btcsuite/btcd/btcec"
  20. "github.com/btcsuite/btcutil/base58"
  21. "golang.org/x/crypto/ripemd160"
  22. )
  23. /*
  24. This file implements BIP32 HD wallets.
  25. Note it only works for SECP256k1 keys.
  26. It also includes some Bitcoin specific utility functions.
  27. */
  28. // ComputeBTCAddress returns the BTC address using the pubKeyHex and chainCodeHex
  29. // for the given path and index.
  30. func ComputeBTCAddress(pubKeyHex string, chainCodeHex string, path string, index int32) string {
  31. pubKeyBytes := DerivePublicKeyForPath(
  32. HexDecode(pubKeyHex),
  33. HexDecode(chainCodeHex),
  34. fmt.Sprintf("%v/%v", path, index),
  35. )
  36. return BTCAddrFromPubKeyBytes(pubKeyBytes)
  37. }
  38. // ComputePrivateKey returns the private key using the master mprivHex and chainCodeHex
  39. // for the given path and index.
  40. func ComputePrivateKey(mprivHex string, chainHex string, path string, index int32) string {
  41. privKeyBytes := DerivePrivateKeyForPath(
  42. HexDecode(mprivHex),
  43. HexDecode(chainHex),
  44. fmt.Sprintf("%v/%v", path, index),
  45. )
  46. return HexEncode(privKeyBytes)
  47. }
  48. // ComputeBTCAddressForPrivKey returns the Bitcoin address for the given privKey.
  49. func ComputeBTCAddressForPrivKey(privKey string) string {
  50. pubKeyBytes := PubKeyBytesFromPrivKeyBytes(HexDecode(privKey), true)
  51. return BTCAddrFromPubKeyBytes(pubKeyBytes)
  52. }
  53. // SignBTCMessage signs a "Bitcoin Signed Message".
  54. func SignBTCMessage(privKey string, message string, compress bool) string {
  55. prefixBytes := []byte("Bitcoin Signed Message:\n")
  56. messageBytes := []byte(message)
  57. bytes := []byte{}
  58. bytes = append(bytes, byte(len(prefixBytes)))
  59. bytes = append(bytes, prefixBytes...)
  60. bytes = append(bytes, byte(len(messageBytes)))
  61. bytes = append(bytes, messageBytes...)
  62. privKeyBytes := HexDecode(privKey)
  63. x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
  64. ecdsaPubKey := ecdsa.PublicKey{
  65. Curve: btcec.S256(),
  66. X: x,
  67. Y: y,
  68. }
  69. ecdsaPrivKey := &btcec.PrivateKey{
  70. PublicKey: ecdsaPubKey,
  71. D: new(big.Int).SetBytes(privKeyBytes),
  72. }
  73. sigbytes, err := btcec.SignCompact(btcec.S256(), ecdsaPrivKey, CalcHash256(bytes), compress)
  74. if err != nil {
  75. panic(err)
  76. }
  77. return base64.StdEncoding.EncodeToString(sigbytes)
  78. }
  79. // ComputeMastersFromSeed returns the master public key, master secret, and chain code in hex.
  80. func ComputeMastersFromSeed(seed string) (string, string, string) {
  81. key, data := []byte("Bitcoin seed"), []byte(seed)
  82. secret, chain := I64(key, data)
  83. pubKeyBytes := PubKeyBytesFromPrivKeyBytes(secret, true)
  84. return HexEncode(pubKeyBytes), HexEncode(secret), HexEncode(chain)
  85. }
  86. // ComputeWIF returns the privKey in Wallet Import Format.
  87. func ComputeWIF(privKey string, compress bool) string {
  88. return WIFFromPrivKeyBytes(HexDecode(privKey), compress)
  89. }
  90. // ComputeBTCTxId returns the bitcoin transaction ID.
  91. func ComputeBTCTxId(rawTxHex string) string {
  92. return HexEncode(ReverseBytes(CalcHash256(HexDecode(rawTxHex))))
  93. }
  94. /*
  95. func printKeyInfo(privKeyBytes []byte, pubKeyBytes []byte, chain []byte) {
  96. if pubKeyBytes == nil {
  97. pubKeyBytes = PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
  98. }
  99. addr := AddrFromPubKeyBytes(pubKeyBytes)
  100. log.Println("\nprikey:\t%v\npubKeyBytes:\t%v\naddr:\t%v\nchain:\t%v",
  101. HexEncode(privKeyBytes),
  102. HexEncode(pubKeyBytes),
  103. addr,
  104. HexEncode(chain))
  105. }
  106. */
  107. //-------------------------------------------------------------------
  108. // DerivePrivateKeyForPath derives the private key by following the path from privKeyBytes,
  109. // using the given chainCode.
  110. func DerivePrivateKeyForPath(privKeyBytes []byte, chainCode []byte, path string) []byte {
  111. data := privKeyBytes
  112. parts := strings.Split(path, "/")
  113. for _, part := range parts {
  114. prime := part[len(part)-1:] == "'"
  115. // prime == private derivation. Otherwise public.
  116. if prime {
  117. part = part[:len(part)-1]
  118. }
  119. i, err := strconv.Atoi(part)
  120. if err != nil {
  121. panic(err)
  122. }
  123. if i < 0 {
  124. panic(errors.New("index too large."))
  125. }
  126. data, chainCode = DerivePrivateKey(data, chainCode, uint32(i), prime)
  127. //printKeyInfo(data, nil, chain)
  128. }
  129. return data
  130. }
  131. // DerivePublicKeyForPath derives the public key by following the path from pubKeyBytes
  132. // using the given chainCode.
  133. func DerivePublicKeyForPath(pubKeyBytes []byte, chainCode []byte, path string) []byte {
  134. data := pubKeyBytes
  135. parts := strings.Split(path, "/")
  136. for _, part := range parts {
  137. prime := part[len(part)-1:] == "'"
  138. if prime {
  139. panic(errors.New("cannot do a prime derivation from public key"))
  140. }
  141. i, err := strconv.Atoi(part)
  142. if err != nil {
  143. panic(err)
  144. }
  145. if i < 0 {
  146. panic(errors.New("index too large."))
  147. }
  148. data, chainCode = DerivePublicKey(data, chainCode, uint32(i))
  149. //printKeyInfo(nil, data, chainCode)
  150. }
  151. return data
  152. }
  153. // DerivePrivateKey derives the private key with index and chainCode.
  154. // If prime is true, the derivation is 'hardened'.
  155. // It returns the new private key and new chain code.
  156. func DerivePrivateKey(privKeyBytes []byte, chainCode []byte, index uint32, prime bool) ([]byte, []byte) {
  157. var data []byte
  158. if prime {
  159. index = index | 0x80000000
  160. data = append([]byte{byte(0)}, privKeyBytes...)
  161. } else {
  162. public := PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
  163. data = public
  164. }
  165. data = append(data, uint32ToBytes(index)...)
  166. data2, chainCode2 := I64(chainCode, data)
  167. x := addScalars(privKeyBytes, data2)
  168. return x, chainCode2
  169. }
  170. // DerivePublicKey derives the public key with index and chainCode.
  171. // It returns the new public key and new chain code.
  172. func DerivePublicKey(pubKeyBytes []byte, chainCode []byte, index uint32) ([]byte, []byte) {
  173. data := []byte{}
  174. data = append(data, pubKeyBytes...)
  175. data = append(data, uint32ToBytes(index)...)
  176. data2, chainCode2 := I64(chainCode, data)
  177. data2p := PubKeyBytesFromPrivKeyBytes(data2, true)
  178. return addPoints(pubKeyBytes, data2p), chainCode2
  179. }
  180. // eliptic curve pubkey addition
  181. func addPoints(a []byte, b []byte) []byte {
  182. ap, err := btcec.ParsePubKey(a, btcec.S256())
  183. if err != nil {
  184. panic(err)
  185. }
  186. bp, err := btcec.ParsePubKey(b, btcec.S256())
  187. if err != nil {
  188. panic(err)
  189. }
  190. sumX, sumY := btcec.S256().Add(ap.X, ap.Y, bp.X, bp.Y)
  191. sum := &btcec.PublicKey{
  192. Curve: btcec.S256(),
  193. X: sumX,
  194. Y: sumY,
  195. }
  196. return sum.SerializeCompressed()
  197. }
  198. // modular big endian addition
  199. func addScalars(a []byte, b []byte) []byte {
  200. aInt := new(big.Int).SetBytes(a)
  201. bInt := new(big.Int).SetBytes(b)
  202. sInt := new(big.Int).Add(aInt, bInt)
  203. x := sInt.Mod(sInt, btcec.S256().N).Bytes()
  204. x2 := [32]byte{}
  205. copy(x2[32-len(x):], x)
  206. return x2[:]
  207. }
  208. func uint32ToBytes(i uint32) []byte {
  209. b := [4]byte{}
  210. binary.BigEndian.PutUint32(b[:], i)
  211. return b[:]
  212. }
  213. //-------------------------------------------------------------------
  214. // HexEncode encodes b in hex.
  215. func HexEncode(b []byte) string {
  216. return hex.EncodeToString(b)
  217. }
  218. // HexDecode hex decodes the str. If str is not valid hex
  219. // it will return an empty byte slice.
  220. func HexDecode(str string) []byte {
  221. b, _ := hex.DecodeString(str)
  222. return b
  223. }
  224. // I64 returns the two halfs of the SHA512 HMAC of key and data.
  225. func I64(key []byte, data []byte) ([]byte, []byte) {
  226. mac := hmac.New(sha512.New, key)
  227. mac.Write(data)
  228. I := mac.Sum(nil)
  229. return I[:32], I[32:]
  230. }
  231. //-------------------------------------------------------------------
  232. const (
  233. btcPrefixPubKeyHash = byte(0x00)
  234. btcPrefixPrivKey = byte(0x80)
  235. )
  236. // BTCAddrFromPubKeyBytes returns a B58 encoded Bitcoin mainnet address.
  237. func BTCAddrFromPubKeyBytes(pubKeyBytes []byte) string {
  238. versionPrefix := btcPrefixPubKeyHash // TODO Make const or configurable
  239. h160 := CalcHash160(pubKeyBytes)
  240. h160 = append([]byte{versionPrefix}, h160...)
  241. checksum := CalcHash256(h160)
  242. b := append(h160, checksum[:4]...)
  243. return base58.Encode(b)
  244. }
  245. // BTCAddrBytesFromPubKeyBytes returns a hex Bitcoin mainnet address and its checksum.
  246. func BTCAddrBytesFromPubKeyBytes(pubKeyBytes []byte) (addrBytes []byte, checksum []byte) {
  247. versionPrefix := btcPrefixPubKeyHash // TODO Make const or configurable
  248. h160 := CalcHash160(pubKeyBytes)
  249. _h160 := append([]byte{versionPrefix}, h160...)
  250. checksum = CalcHash256(_h160)[:4]
  251. return h160, checksum
  252. }
  253. // WIFFromPrivKeyBytes returns the privKeyBytes in Wallet Import Format.
  254. func WIFFromPrivKeyBytes(privKeyBytes []byte, compress bool) string {
  255. versionPrefix := btcPrefixPrivKey // TODO Make const or configurable
  256. bytes := append([]byte{versionPrefix}, privKeyBytes...)
  257. if compress {
  258. bytes = append(bytes, byte(1))
  259. }
  260. checksum := CalcHash256(bytes)
  261. bytes = append(bytes, checksum[:4]...)
  262. return base58.Encode(bytes)
  263. }
  264. // PubKeyBytesFromPrivKeyBytes returns the optionally compressed public key bytes.
  265. func PubKeyBytesFromPrivKeyBytes(privKeyBytes []byte, compress bool) (pubKeyBytes []byte) {
  266. x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
  267. pub := &btcec.PublicKey{
  268. Curve: btcec.S256(),
  269. X: x,
  270. Y: y,
  271. }
  272. if compress {
  273. return pub.SerializeCompressed()
  274. }
  275. return pub.SerializeUncompressed()
  276. }
  277. //--------------------------------------------------------------
  278. // CalcHash returns the hash of data using hasher.
  279. func CalcHash(data []byte, hasher hash.Hash) []byte {
  280. hasher.Write(data)
  281. return hasher.Sum(nil)
  282. }
  283. // CalcHash160 returns the ripemd160(sha256(data)).
  284. func CalcHash160(data []byte) []byte {
  285. return CalcHash(CalcHash(data, sha256.New()), ripemd160.New())
  286. }
  287. // CalcHash256 returns the sha256(sha256(data)).
  288. func CalcHash256(data []byte) []byte {
  289. return CalcHash(CalcHash(data, sha256.New()), sha256.New())
  290. }
  291. // CalcSha512 returns the sha512(data).
  292. func CalcSha512(data []byte) []byte {
  293. return CalcHash(data, sha512.New())
  294. }
  295. // ReverseBytes returns the buf in the opposite order
  296. func ReverseBytes(buf []byte) []byte {
  297. var res []byte
  298. if len(buf) == 0 {
  299. return res
  300. }
  301. // Walk till mid-way, swapping bytes from each end:
  302. // b[i] and b[len-i-1]
  303. blen := len(buf)
  304. res = make([]byte, blen)
  305. mid := blen / 2
  306. for left := 0; left <= mid; left++ {
  307. right := blen - left - 1
  308. res[left] = buf[right]
  309. res[right] = buf[left]
  310. }
  311. return res
  312. }