don't use python's random for session IDs
[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
94
95 def hash_160(public_key):
96     try:
97         md = hashlib.new('ripemd160')
98         md.update(hashlib.sha256(public_key).digest())
99         return md.digest()
100     except:
101         import ripemd
102         md = ripemd.new(hashlib.sha256(public_key).digest())
103         return md.digest()
104
105
106 def public_key_to_bc_address(public_key):
107     return hash_160_to_bc_address(hash_160(public_key))
108
109
110 def hash_160_to_bc_address(h160, addrtype = 0):
111     if h160 == 'None':
112         return 'None'
113     vh160 = chr(addrtype) + h160
114     h = Hash(vh160)
115     addr = vh160 + h[0:4]
116     return b58encode(addr)
117
118
119 def bc_address_to_hash_160(addr):
120     if addr == 'None':
121         return 'None'
122     bytes = b58decode(addr, 25)
123     return bytes[1:21]
124
125
126 def b58encode(v):
127     """encode v, which is a string of bytes, to base58."""
128
129     long_value = 0L
130     for (i, c) in enumerate(v[::-1]):
131         long_value += (256**i) * ord(c)
132
133     result = ''
134     while long_value >= __b58base:
135         div, mod = divmod(long_value, __b58base)
136         result = __b58chars[mod] + result
137         long_value = div
138     result = __b58chars[long_value] + result
139
140     # Bitcoin does a little leading-zero-compression:
141     # leading 0-bytes in the input become leading-1s
142     nPad = 0
143     for c in v:
144         if c == '\0':
145             nPad += 1
146         else:
147             break
148
149     return (__b58chars[0]*nPad) + result
150
151
152 def b58decode(v, length):
153     """ decode v into a string of len bytes."""
154     long_value = 0L
155     for (i, c) in enumerate(v[::-1]):
156         long_value += __b58chars.find(c) * (__b58base**i)
157
158     result = ''
159     while long_value >= 256:
160         div, mod = divmod(long_value, 256)
161         result = chr(mod) + result
162         long_value = div
163     result = chr(long_value) + result
164
165     nPad = 0
166     for c in v:
167         if c == __b58chars[0]:
168             nPad += 1
169         else:
170             break
171
172     result = chr(0)*nPad + result
173     if length is not None and len(result) != length:
174         return None
175
176     return result
177
178
179 def EncodeBase58Check(vchIn):
180     hash = Hash(vchIn)
181     return b58encode(vchIn + hash[0:4])
182
183
184 def DecodeBase58Check(psz):
185     vchRet = b58decode(psz, None)
186     key = vchRet[0:-4]
187     csum = vchRet[-4:]
188     hash = Hash(key)
189     cs32 = hash[0:4]
190     if cs32 != csum:
191         return None
192     else:
193         return key
194
195
196
197
198 ########### end pywallet functions #######################
199
200 def random_string(length):
201     with open("/dev/urandom", 'rb') as f:
202         return b58encode( f.read(length) )
203
204 def timestr():
205     return time.strftime("[%d/%m/%Y-%H:%M:%S]")
206
207
208 print_lock = threading.Lock()
209
210
211 def print_log(*args):
212     with print_lock:
213         sys.stderr.write(timestr() + " " + " ".join(imap(str, args)) + "\n")
214         sys.stderr.flush()