18 "github.com/btcsuite/btcd/btcec"
19 "github.com/btcsuite/btcutil/base58"
20 "github.com/tendermint/go-crypto"
21 "golang.org/x/crypto/ripemd160"
24 func ComputeAddress(pubKeyHex string, chainHex string, path string, index int32) string {
25 pubKeyBytes := DerivePublicKeyForPath(
28 fmt.Sprintf("%v/%v", path, index),
30 return AddrFromPubKeyBytes(pubKeyBytes)
33 func ComputePrivateKey(mprivHex string, chainHex string, path string, index int32) string {
34 privKeyBytes := DerivePrivateKeyForPath(
37 fmt.Sprintf("%v/%v", path, index),
39 return HexEncode(privKeyBytes)
42 func ComputeAddressForPrivKey(privKey string) string {
43 pubKeyBytes := PubKeyBytesFromPrivKeyBytes(HexDecode(privKey), true)
44 return AddrFromPubKeyBytes(pubKeyBytes)
47 func SignMessage(privKey string, message string, compress bool) string {
48 prefixBytes := []byte("Bitcoin Signed Message:\n")
49 messageBytes := []byte(message)
51 bytes = append(bytes, byte(len(prefixBytes)))
52 bytes = append(bytes, prefixBytes...)
53 bytes = append(bytes, byte(len(messageBytes)))
54 bytes = append(bytes, messageBytes...)
55 privKeyBytes := HexDecode(privKey)
56 x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
57 ecdsaPubKey := ecdsa.PublicKey{
62 ecdsaPrivKey := &btcec.PrivateKey{
63 PublicKey: ecdsaPubKey,
64 D: new(big.Int).SetBytes(privKeyBytes),
66 sigbytes, err := btcec.SignCompact(btcec.S256(), ecdsaPrivKey, crypto.Sha256(crypto.Sha256(bytes)), compress)
70 return base64.StdEncoding.EncodeToString(sigbytes)
73 // returns MPK, Chain, and master secret in hex.
74 func ComputeMastersFromSeed(seed string) (string, string, string, string) {
75 secret, chain := I64([]byte("Bitcoin seed"), []byte(seed))
76 pubKeyBytes := PubKeyBytesFromPrivKeyBytes(secret, true)
77 return HexEncode(pubKeyBytes), HexEncode(secret), HexEncode(chain), HexEncode(secret)
80 func ComputeWIF(privKey string, compress bool) string {
81 return WIFFromPrivKeyBytes(HexDecode(privKey), compress)
84 func ComputeTxId(rawTxHex string) string {
85 return HexEncode(ReverseBytes(CalcHash256(HexDecode(rawTxHex))))
89 func printKeyInfo(privKeyBytes []byte, pubKeyBytes []byte, chain []byte) {
90 if pubKeyBytes == nil {
91 pubKeyBytes = PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
93 addr := AddrFromPubKeyBytes(pubKeyBytes)
94 log.Println("\nprikey:\t%v\npubKeyBytes:\t%v\naddr:\t%v\nchain:\t%v",
95 HexEncode(privKeyBytes),
96 HexEncode(pubKeyBytes),
102 func DerivePrivateKeyForPath(privKeyBytes []byte, chain []byte, path string) []byte {
104 parts := strings.Split(path, "/")
105 for _, part := range parts {
106 prime := part[len(part)-1:] == "'"
107 // prime == private derivation. Otherwise public.
109 part = part[:len(part)-1]
111 i, err := strconv.Atoi(part)
116 panic(errors.New("index too large."))
118 data, chain = DerivePrivateKey(data, chain, uint32(i), prime)
119 //printKeyInfo(data, nil, chain)
124 func DerivePublicKeyForPath(pubKeyBytes []byte, chain []byte, path string) []byte {
126 parts := strings.Split(path, "/")
127 for _, part := range parts {
128 prime := part[len(part)-1:] == "'"
130 panic(errors.New("cannot do a prime derivation from public key"))
132 i, err := strconv.Atoi(part)
137 panic(errors.New("index too large."))
139 data, chain = DerivePublicKey(data, chain, uint32(i))
140 //printKeyInfo(nil, data, chain)
145 func DerivePrivateKey(privKeyBytes []byte, chain []byte, i uint32, prime bool) ([]byte, []byte) {
149 data = append([]byte{byte(0)}, privKeyBytes...)
151 public := PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
154 data = append(data, uint32ToBytes(i)...)
155 data2, chain2 := I64(chain, data)
156 x := addScalars(privKeyBytes, data2)
160 func DerivePublicKey(pubKeyBytes []byte, chain []byte, i uint32) ([]byte, []byte) {
162 data = append(data, pubKeyBytes...)
163 data = append(data, uint32ToBytes(i)...)
164 data2, chain2 := I64(chain, data)
165 data2p := PubKeyBytesFromPrivKeyBytes(data2, true)
166 return addPoints(pubKeyBytes, data2p), chain2
169 func addPoints(a []byte, b []byte) []byte {
170 ap, err := btcec.ParsePubKey(a, btcec.S256())
174 bp, err := btcec.ParsePubKey(b, btcec.S256())
178 sumX, sumY := btcec.S256().Add(ap.X, ap.Y, bp.X, bp.Y)
179 sum := &btcec.PublicKey{
184 return sum.SerializeCompressed()
187 func addScalars(a []byte, b []byte) []byte {
188 aInt := new(big.Int).SetBytes(a)
189 bInt := new(big.Int).SetBytes(b)
190 sInt := new(big.Int).Add(aInt, bInt)
191 x := sInt.Mod(sInt, btcec.S256().N).Bytes()
193 copy(x2[32-len(x):], x)
197 func uint32ToBytes(i uint32) []byte {
199 binary.BigEndian.PutUint32(b[:], i)
203 func HexEncode(b []byte) string {
204 return hex.EncodeToString(b)
207 func HexDecode(str string) []byte {
208 b, _ := hex.DecodeString(str)
212 func I64(key []byte, data []byte) ([]byte, []byte) {
213 mac := hmac.New(sha512.New, key)
216 return I[:32], I[32:]
219 // This returns a Bitcoin-like address.
220 func AddrFromPubKeyBytes(pubKeyBytes []byte) string {
221 prefix := byte(0x00) // TODO Make const or configurable
222 h160 := CalcHash160(pubKeyBytes)
223 h160 = append([]byte{prefix}, h160...)
224 checksum := CalcHash256(h160)
225 b := append(h160, checksum[:4]...)
226 return base58.Encode(b)
229 func AddrBytesFromPubKeyBytes(pubKeyBytes []byte) (addrBytes []byte, checksum []byte) {
230 prefix := byte(0x00) // TODO Make const or configurable
231 h160 := CalcHash160(pubKeyBytes)
232 _h160 := append([]byte{prefix}, h160...)
233 checksum = CalcHash256(_h160)[:4]
234 return h160, checksum
237 func WIFFromPrivKeyBytes(privKeyBytes []byte, compress bool) string {
238 prefix := byte(0x80) // TODO Make const or configurable
239 bytes := append([]byte{prefix}, privKeyBytes...)
241 bytes = append(bytes, byte(1))
243 checksum := CalcHash256(bytes)
244 bytes = append(bytes, checksum[:4]...)
245 return base58.Encode(bytes)
248 func PubKeyBytesFromPrivKeyBytes(privKeyBytes []byte, compress bool) (pubKeyBytes []byte) {
249 x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
250 pub := &btcec.PublicKey{
257 return pub.SerializeCompressed()
259 return pub.SerializeUncompressed()
262 // Calculate the hash of hasher over buf.
263 func CalcHash(buf []byte, hasher hash.Hash) []byte {
265 return hasher.Sum(nil)
268 // calculate hash160 which is ripemd160(sha256(data))
269 func CalcHash160(buf []byte) []byte {
270 return CalcHash(CalcHash(buf, sha256.New()), ripemd160.New())
273 // calculate hash256 which is sha256(sha256(data))
274 func CalcHash256(buf []byte) []byte {
275 return CalcHash(CalcHash(buf, sha256.New()), sha256.New())
278 // calculate sha512(data)
279 func CalcSha512(buf []byte) []byte {
280 return CalcHash(buf, sha512.New())
283 func ReverseBytes(buf []byte) []byte {
289 // Walk till mid-way, swapping bytes from each end:
290 // b[i] and b[len-i-1]
292 res = make([]byte, blen)
294 for left := 0; left <= mid; left++ {
295 right := blen - left - 1
296 res[left] = buf[right]
297 res[right] = buf[left]