OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / go-crypto / hd / address.go
1 package hd
2
3 import (
4         "crypto/ecdsa"
5         "crypto/hmac"
6         "crypto/sha256"
7         "crypto/sha512"
8         "encoding/base64"
9         "encoding/binary"
10         "encoding/hex"
11         "errors"
12         "fmt"
13         "hash"
14         "math/big"
15         "strconv"
16         "strings"
17
18         "github.com/btcsuite/btcd/btcec"
19         "github.com/btcsuite/btcutil/base58"
20         "github.com/tendermint/go-crypto"
21         "golang.org/x/crypto/ripemd160"
22 )
23
24 func ComputeAddress(pubKeyHex string, chainHex string, path string, index int32) string {
25         pubKeyBytes := DerivePublicKeyForPath(
26                 HexDecode(pubKeyHex),
27                 HexDecode(chainHex),
28                 fmt.Sprintf("%v/%v", path, index),
29         )
30         return AddrFromPubKeyBytes(pubKeyBytes)
31 }
32
33 func ComputePrivateKey(mprivHex string, chainHex string, path string, index int32) string {
34         privKeyBytes := DerivePrivateKeyForPath(
35                 HexDecode(mprivHex),
36                 HexDecode(chainHex),
37                 fmt.Sprintf("%v/%v", path, index),
38         )
39         return HexEncode(privKeyBytes)
40 }
41
42 func ComputeAddressForPrivKey(privKey string) string {
43         pubKeyBytes := PubKeyBytesFromPrivKeyBytes(HexDecode(privKey), true)
44         return AddrFromPubKeyBytes(pubKeyBytes)
45 }
46
47 func SignMessage(privKey string, message string, compress bool) string {
48         prefixBytes := []byte("Bitcoin Signed Message:\n")
49         messageBytes := []byte(message)
50         bytes := []byte{}
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{
58                 Curve: btcec.S256(),
59                 X:     x,
60                 Y:     y,
61         }
62         ecdsaPrivKey := &btcec.PrivateKey{
63                 PublicKey: ecdsaPubKey,
64                 D:         new(big.Int).SetBytes(privKeyBytes),
65         }
66         sigbytes, err := btcec.SignCompact(btcec.S256(), ecdsaPrivKey, crypto.Sha256(crypto.Sha256(bytes)), compress)
67         if err != nil {
68                 panic(err)
69         }
70         return base64.StdEncoding.EncodeToString(sigbytes)
71 }
72
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)
78 }
79
80 func ComputeWIF(privKey string, compress bool) string {
81         return WIFFromPrivKeyBytes(HexDecode(privKey), compress)
82 }
83
84 func ComputeTxId(rawTxHex string) string {
85         return HexEncode(ReverseBytes(CalcHash256(HexDecode(rawTxHex))))
86 }
87
88 /*
89 func printKeyInfo(privKeyBytes []byte, pubKeyBytes []byte, chain []byte) {
90         if pubKeyBytes == nil {
91                 pubKeyBytes = PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
92         }
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),
97                 addr,
98                 HexEncode(chain))
99 }
100 */
101
102 func DerivePrivateKeyForPath(privKeyBytes []byte, chain []byte, path string) []byte {
103         data := privKeyBytes
104         parts := strings.Split(path, "/")
105         for _, part := range parts {
106                 prime := part[len(part)-1:] == "'"
107                 // prime == private derivation. Otherwise public.
108                 if prime {
109                         part = part[:len(part)-1]
110                 }
111                 i, err := strconv.Atoi(part)
112                 if err != nil {
113                         panic(err)
114                 }
115                 if i < 0 {
116                         panic(errors.New("index too large."))
117                 }
118                 data, chain = DerivePrivateKey(data, chain, uint32(i), prime)
119                 //printKeyInfo(data, nil, chain)
120         }
121         return data
122 }
123
124 func DerivePublicKeyForPath(pubKeyBytes []byte, chain []byte, path string) []byte {
125         data := pubKeyBytes
126         parts := strings.Split(path, "/")
127         for _, part := range parts {
128                 prime := part[len(part)-1:] == "'"
129                 if prime {
130                         panic(errors.New("cannot do a prime derivation from public key"))
131                 }
132                 i, err := strconv.Atoi(part)
133                 if err != nil {
134                         panic(err)
135                 }
136                 if i < 0 {
137                         panic(errors.New("index too large."))
138                 }
139                 data, chain = DerivePublicKey(data, chain, uint32(i))
140                 //printKeyInfo(nil, data, chain)
141         }
142         return data
143 }
144
145 func DerivePrivateKey(privKeyBytes []byte, chain []byte, i uint32, prime bool) ([]byte, []byte) {
146         var data []byte
147         if prime {
148                 i = i | 0x80000000
149                 data = append([]byte{byte(0)}, privKeyBytes...)
150         } else {
151                 public := PubKeyBytesFromPrivKeyBytes(privKeyBytes, true)
152                 data = public
153         }
154         data = append(data, uint32ToBytes(i)...)
155         data2, chain2 := I64(chain, data)
156         x := addScalars(privKeyBytes, data2)
157         return x, chain2
158 }
159
160 func DerivePublicKey(pubKeyBytes []byte, chain []byte, i uint32) ([]byte, []byte) {
161         data := []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
167 }
168
169 func addPoints(a []byte, b []byte) []byte {
170         ap, err := btcec.ParsePubKey(a, btcec.S256())
171         if err != nil {
172                 panic(err)
173         }
174         bp, err := btcec.ParsePubKey(b, btcec.S256())
175         if err != nil {
176                 panic(err)
177         }
178         sumX, sumY := btcec.S256().Add(ap.X, ap.Y, bp.X, bp.Y)
179         sum := &btcec.PublicKey{
180                 Curve: btcec.S256(),
181                 X:     sumX,
182                 Y:     sumY,
183         }
184         return sum.SerializeCompressed()
185 }
186
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()
192         x2 := [32]byte{}
193         copy(x2[32-len(x):], x)
194         return x2[:]
195 }
196
197 func uint32ToBytes(i uint32) []byte {
198         b := [4]byte{}
199         binary.BigEndian.PutUint32(b[:], i)
200         return b[:]
201 }
202
203 func HexEncode(b []byte) string {
204         return hex.EncodeToString(b)
205 }
206
207 func HexDecode(str string) []byte {
208         b, _ := hex.DecodeString(str)
209         return b
210 }
211
212 func I64(key []byte, data []byte) ([]byte, []byte) {
213         mac := hmac.New(sha512.New, key)
214         mac.Write(data)
215         I := mac.Sum(nil)
216         return I[:32], I[32:]
217 }
218
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)
227 }
228
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
235 }
236
237 func WIFFromPrivKeyBytes(privKeyBytes []byte, compress bool) string {
238         prefix := byte(0x80) // TODO Make const or configurable
239         bytes := append([]byte{prefix}, privKeyBytes...)
240         if compress {
241                 bytes = append(bytes, byte(1))
242         }
243         checksum := CalcHash256(bytes)
244         bytes = append(bytes, checksum[:4]...)
245         return base58.Encode(bytes)
246 }
247
248 func PubKeyBytesFromPrivKeyBytes(privKeyBytes []byte, compress bool) (pubKeyBytes []byte) {
249         x, y := btcec.S256().ScalarBaseMult(privKeyBytes)
250         pub := &btcec.PublicKey{
251                 Curve: btcec.S256(),
252                 X:     x,
253                 Y:     y,
254         }
255
256         if compress {
257                 return pub.SerializeCompressed()
258         }
259         return pub.SerializeUncompressed()
260 }
261
262 // Calculate the hash of hasher over buf.
263 func CalcHash(buf []byte, hasher hash.Hash) []byte {
264         hasher.Write(buf)
265         return hasher.Sum(nil)
266 }
267
268 // calculate hash160 which is ripemd160(sha256(data))
269 func CalcHash160(buf []byte) []byte {
270         return CalcHash(CalcHash(buf, sha256.New()), ripemd160.New())
271 }
272
273 // calculate hash256 which is sha256(sha256(data))
274 func CalcHash256(buf []byte) []byte {
275         return CalcHash(CalcHash(buf, sha256.New()), sha256.New())
276 }
277
278 // calculate sha512(data)
279 func CalcSha512(buf []byte) []byte {
280         return CalcHash(buf, sha512.New())
281 }
282
283 func ReverseBytes(buf []byte) []byte {
284         var res []byte
285         if len(buf) == 0 {
286                 return res
287         }
288
289         // Walk till mid-way, swapping bytes from each end:
290         // b[i] and b[len-i-1]
291         blen := len(buf)
292         res = make([]byte, blen)
293         mid := blen / 2
294         for left := 0; left <= mid; left++ {
295                 right := blen - left - 1
296                 res[left] = buf[right]
297                 res[right] = buf[left]
298         }
299         return res
300 }