store hashes in the database, to optimize space. use util.py
[electrum-server.git] / backends / bitcoind / util.py
1 #!/usr/bin/env python
2 #
3 # Electrum - lightweight Bitcoin client
4 # Copyright (C) 2011 thomasv@gitorious
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19
20 import hashlib, base64, re
21
22
23 def rev_hex(s):
24     return s.decode('hex')[::-1].encode('hex')
25
26 def int_to_hex(i, length=1):
27     s = hex(i)[2:].rstrip('L')
28     s = "0"*(2*length - len(s)) + s
29     return rev_hex(s)
30
31 def var_int(i):
32     if i<0xfd:
33         return int_to_hex(i)
34     elif i<=0xffff:
35         return "fd"+int_to_hex(i,2)
36     elif i<=0xffffffff:
37         return "fe"+int_to_hex(i,4)
38     else:
39         return "ff"+int_to_hex(i,8)
40
41
42 Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
43 hash_encode = lambda x: x[::-1].encode('hex')
44 hash_decode = lambda x: x.decode('hex')[::-1]
45
46
47 def header_to_string(res):
48     pbh = res.get('prev_block_hash')
49     if pbh is None: pbh = '0'*64
50     s = int_to_hex(res.get('version'),4) \
51         + rev_hex(pbh) \
52         + rev_hex(res.get('merkle_root')) \
53         + int_to_hex(int(res.get('timestamp')),4) \
54         + int_to_hex(int(res.get('bits')),4) \
55         + int_to_hex(int(res.get('nonce')),4)
56     return s
57
58 def header_from_string( s):
59     hex_to_int = lambda s: eval('0x' + s[::-1].encode('hex'))
60     h = {}
61     h['version'] = hex_to_int(s[0:4])
62     h['prev_block_hash'] = hash_encode(s[4:36])
63     h['merkle_root'] = hash_encode(s[36:68])
64     h['timestamp'] = hex_to_int(s[68:72])
65     h['bits'] = hex_to_int(s[72:76])
66     h['nonce'] = hex_to_int(s[76:80])
67     return h
68
69
70 ############ functions from pywallet ##################### 
71
72 addrtype = 0
73
74 def hash_160(public_key):
75     try:
76         md = hashlib.new('ripemd160')
77         md.update(hashlib.sha256(public_key).digest())
78         return md.digest()
79     except:
80         import ripemd
81         md = ripemd.new(hashlib.sha256(public_key).digest())
82         return md.digest()
83
84
85 def public_key_to_bc_address(public_key):
86     h160 = hash_160(public_key)
87     return hash_160_to_bc_address(h160)
88
89 def hash_160_to_bc_address(h160):
90     vh160 = chr(addrtype) + h160
91     h = Hash(vh160)
92     addr = vh160 + h[0:4]
93     return b58encode(addr)
94
95 def bc_address_to_hash_160(addr):
96     bytes = b58decode(addr, 25)
97     return bytes[1:21]
98
99
100 __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
101 __b58base = len(__b58chars)
102
103 def b58encode(v):
104     """ encode v, which is a string of bytes, to base58."""
105
106     long_value = 0L
107     for (i, c) in enumerate(v[::-1]):
108         long_value += (256**i) * ord(c)
109
110     result = ''
111     while long_value >= __b58base:
112         div, mod = divmod(long_value, __b58base)
113         result = __b58chars[mod] + result
114         long_value = div
115     result = __b58chars[long_value] + result
116
117     # Bitcoin does a little leading-zero-compression:
118     # leading 0-bytes in the input become leading-1s
119     nPad = 0
120     for c in v:
121         if c == '\0': nPad += 1
122         else: break
123
124     return (__b58chars[0]*nPad) + result
125
126 def b58decode(v, length):
127     """ decode v into a string of len bytes."""
128     long_value = 0L
129     for (i, c) in enumerate(v[::-1]):
130         long_value += __b58chars.find(c) * (__b58base**i)
131
132     result = ''
133     while long_value >= 256:
134         div, mod = divmod(long_value, 256)
135         result = chr(mod) + result
136         long_value = div
137     result = chr(long_value) + result
138
139     nPad = 0
140     for c in v:
141         if c == __b58chars[0]: nPad += 1
142         else: break
143
144     result = chr(0)*nPad + result
145     if length is not None and len(result) != length:
146         return None
147
148     return result
149
150
151 def EncodeBase58Check(vchIn):
152     hash = Hash(vchIn)
153     return b58encode(vchIn + hash[0:4])
154
155 def DecodeBase58Check(psz):
156     vchRet = b58decode(psz, None)
157     key = vchRet[0:-4]
158     csum = vchRet[-4:]
159     hash = Hash(key)
160     cs32 = hash[0:4]
161     if cs32 != csum:
162         return None
163     else:
164         return key
165
166 def PrivKeyToSecret(privkey):
167     return privkey[9:9+32]
168
169 def SecretToASecret(secret):
170     vchIn = chr(addrtype+128) + secret
171     return EncodeBase58Check(vchIn)
172
173 def ASecretToSecret(key):
174     vch = DecodeBase58Check(key)
175     if vch and vch[0] == chr(addrtype+128):
176         return vch[1:]
177     else:
178         return False
179
180 ########### end pywallet functions #######################
181