a01d0e1477c64bcce331ea3ec75c7f99307cbf50
[electrum-server.git] / utils / __init__.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 import base64
19 from functools import partial
20 from itertools import imap
21 import random
22 import string
23 import threading
24 import time
25 import hashlib
26 import re
27 import sys
28
29 __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
30 __b58base = len(__b58chars)
31
32
33 def rev_hex(s):
34     return s.decode('hex')[::-1].encode('hex')
35
36
37 def int_to_hex(i, length=1):
38     s = hex(i)[2:].rstrip('L')
39     s = "0"*(2*length - len(s)) + s
40     return rev_hex(s)
41
42
43 def var_int(i):
44     if i < 0xfd:
45         return int_to_hex(i)
46     elif i <= 0xffff:
47         return "fd" + int_to_hex(i, 2)
48     elif i <= 0xffffffff:
49         return "fe" + int_to_hex(i, 4)
50     else:
51         return "ff" + int_to_hex(i, 8)
52
53
54 Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
55
56
57 hash_encode = lambda x: x[::-1].encode('hex')
58
59
60 hash_decode = lambda x: x.decode('hex')[::-1]
61
62
63 def header_to_string(res):
64     pbh = res.get('prev_block_hash')
65     if pbh is None:
66         pbh = '0'*64
67
68     return int_to_hex(res.get('version'), 4) \
69         + rev_hex(pbh) \
70         + rev_hex(res.get('merkle_root')) \
71         + int_to_hex(int(res.get('timestamp')), 4) \
72         + int_to_hex(int(res.get('bits')), 4) \
73         + int_to_hex(int(res.get('nonce')), 4)
74
75
76 def hex_to_int(s):
77     return int('0x' + s[::-1].encode('hex'), 16)
78
79
80 def header_from_string(s):
81     return {
82         'version': hex_to_int(s[0:4]),
83         'prev_block_hash': hash_encode(s[4:36]),
84         'merkle_root': hash_encode(s[36:68]),
85         'timestamp': hex_to_int(s[68:72]),
86         'bits': hex_to_int(s[72:76]),
87         'nonce': hex_to_int(s[76:80]),
88     }
89
90
91 ############ functions from pywallet #####################
92
93 addrtype = 0
94
95
96 def hash_160(public_key):
97     try:
98         md = hashlib.new('ripemd160')
99         md.update(hashlib.sha256(public_key).digest())
100         return md.digest()
101     except:
102         import ripemd
103         md = ripemd.new(hashlib.sha256(public_key).digest())
104         return md.digest()
105
106
107 def public_key_to_bc_address(public_key):
108     return hash_160_to_bc_address(hash_160(public_key))
109
110
111 def hash_160_to_bc_address(h160):
112     if h160 == 'None':
113         return 'None'
114     vh160 = chr(addrtype) + h160
115     h = Hash(vh160)
116     addr = vh160 + h[0:4]
117     return b58encode(addr)
118
119
120 def bc_address_to_hash_160(addr):
121     if addr == 'None':
122         return 'None'
123     bytes = b58decode(addr, 25)
124     return bytes[1:21]
125
126
127 def b58encode(v):
128     """encode v, which is a string of bytes, to base58."""
129
130     long_value = 0L
131     for (i, c) in enumerate(v[::-1]):
132         long_value += (256**i) * ord(c)
133
134     result = ''
135     while long_value >= __b58base:
136         div, mod = divmod(long_value, __b58base)
137         result = __b58chars[mod] + result
138         long_value = div
139     result = __b58chars[long_value] + result
140
141     # Bitcoin does a little leading-zero-compression:
142     # leading 0-bytes in the input become leading-1s
143     nPad = 0
144     for c in v:
145         if c == '\0':
146             nPad += 1
147         else:
148             break
149
150     return (__b58chars[0]*nPad) + result
151
152
153 def b58decode(v, length):
154     """ decode v into a string of len bytes."""
155     long_value = 0L
156     for (i, c) in enumerate(v[::-1]):
157         long_value += __b58chars.find(c) * (__b58base**i)
158
159     result = ''
160     while long_value >= 256:
161         div, mod = divmod(long_value, 256)
162         result = chr(mod) + result
163         long_value = div
164     result = chr(long_value) + result
165
166     nPad = 0
167     for c in v:
168         if c == __b58chars[0]:
169             nPad += 1
170         else:
171             break
172
173     result = chr(0)*nPad + result
174     if length is not None and len(result) != length:
175         return None
176
177     return result
178
179
180 def EncodeBase58Check(vchIn):
181     hash = Hash(vchIn)
182     return b58encode(vchIn + hash[0:4])
183
184
185 def DecodeBase58Check(psz):
186     vchRet = b58decode(psz, None)
187     key = vchRet[0:-4]
188     csum = vchRet[-4:]
189     hash = Hash(key)
190     cs32 = hash[0:4]
191     if cs32 != csum:
192         return None
193     else:
194         return key
195
196
197 def PrivKeyToSecret(privkey):
198     return privkey[9:9+32]
199
200
201 def SecretToASecret(secret):
202     vchIn = chr(addrtype+128) + secret
203     return EncodeBase58Check(vchIn)
204
205
206 def ASecretToSecret(key):
207     vch = DecodeBase58Check(key)
208     if vch and vch[0] == chr(addrtype+128):
209         return vch[1:]
210     else:
211         return False
212
213
214 ########### end pywallet functions #######################
215
216 def random_string(length):
217     return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in xrange(length))
218
219
220 def timestr():
221     return time.strftime("[%d/%m/%Y-%H:%M:%S]")
222
223
224 print_lock = threading.Lock()
225
226
227 def print_log(*args):
228     with print_lock:
229         sys.stderr.write(timestr() + " " + " ".join(imap(str, args)) + "\n")
230         sys.stderr.flush()