tmain.py - electrum-personal-server - Maximally lightweight electrum server for a single user
HTML git clone https://git.parazyd.org/electrum-personal-server
DIR Log
DIR Files
DIR Refs
DIR README
---
tmain.py (14910B)
---
1 #!/usr/bin/python
2 from .py2specials import *
3 from .py3specials import *
4 import binascii
5 import hashlib
6 import re
7 import sys
8 import os
9 import base64
10 import time
11 import random
12 import hmac
13
14 is_python2 = sys.version_info.major == 2
15
16 # Elliptic curve parameters (secp256k1)
17
18 P = 2**256 - 2**32 - 977
19 N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
20 A = 0
21 B = 7
22 Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
23 Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
24 G = (Gx, Gy)
25
26 # Extended Euclidean Algorithm
27 def inv(a, n):
28 lm, hm = 1, 0
29 low, high = a % n, n
30 while low > 1:
31 r = high // low
32 nm, new = hm - lm * r, high - low * r
33 lm, low, hm, high = nm, new, lm, low
34 return lm % n
35
36 # Elliptic curve Jordan form functions
37 # P = (m, n, p, q) where m/n = x, p/q = y
38
39 def isinf(p):
40 return p[0] == 0 and p[1] == 0
41
42
43 def jordan_isinf(p):
44 return p[0][0] == 0 and p[1][0] == 0
45
46
47 def mulcoords(c1, c2):
48 return (c1[0] * c2[0] % P, c1[1] * c2[1] % P)
49
50
51 def mul_by_const(c, v):
52 return (c[0] * v % P, c[1])
53
54
55 def addcoords(c1, c2):
56 return ((c1[0] * c2[1] + c2[0] * c1[1]) % P, c1[1] * c2[1] % P)
57
58
59 def subcoords(c1, c2):
60 return ((c1[0] * c2[1] - c2[0] * c1[1]) % P, c1[1] * c2[1] % P)
61
62
63 def invcoords(c):
64 return (c[1], c[0])
65
66
67 def jordan_add(a, b):
68 if jordan_isinf(a):
69 return b
70 if jordan_isinf(b):
71 return a
72
73 if (a[0][0] * b[0][1] - b[0][0] * a[0][1]) % P == 0:
74 if (a[1][0] * b[1][1] - b[1][0] * a[1][1]) % P == 0:
75 return jordan_double(a)
76 else:
77 return ((0, 1), (0, 1))
78 xdiff = subcoords(b[0], a[0])
79 ydiff = subcoords(b[1], a[1])
80 m = mulcoords(ydiff, invcoords(xdiff))
81 x = subcoords(subcoords(mulcoords(m, m), a[0]), b[0])
82 y = subcoords(mulcoords(m, subcoords(a[0], x)), a[1])
83 return (x, y)
84
85
86 def jordan_double(a):
87 if jordan_isinf(a):
88 return ((0, 1), (0, 1))
89 num = addcoords(mul_by_const(mulcoords(a[0], a[0]), 3), (A, 1))
90 den = mul_by_const(a[1], 2)
91 m = mulcoords(num, invcoords(den))
92 x = subcoords(mulcoords(m, m), mul_by_const(a[0], 2))
93 y = subcoords(mulcoords(m, subcoords(a[0], x)), a[1])
94 return (x, y)
95
96
97 def jordan_multiply(a, n):
98 if jordan_isinf(a) or n == 0:
99 return ((0, 0), (0, 0))
100 if n == 1:
101 return a
102 if n < 0 or n >= N:
103 return jordan_multiply(a, n % N)
104 if (n % 2) == 0:
105 return jordan_double(jordan_multiply(a, n // 2))
106 if (n % 2) == 1:
107 return jordan_add(jordan_double(jordan_multiply(a, n // 2)), a)
108
109
110 def to_jordan(p):
111 return ((p[0], 1), (p[1], 1))
112
113
114 def from_jordan(p):
115 return (p[0][0] * inv(p[0][1], P) % P, p[1][0] * inv(p[1][1], P) % P)
116
117 def fast_multiply(a, n):
118 return from_jordan(jordan_multiply(to_jordan(a), n))
119
120
121 def fast_add(a, b):
122 return from_jordan(jordan_add(to_jordan(a), to_jordan(b)))
123
124 # Functions for handling pubkey and privkey formats
125
126
127 def get_pubkey_format(pub):
128 if is_python2:
129 two = '\x02'
130 three = '\x03'
131 four = '\x04'
132 else:
133 two = 2
134 three = 3
135 four = 4
136
137 if isinstance(pub, (tuple, list)): return 'decimal'
138 elif len(pub) == 65 and pub[0] == four: return 'bin'
139 elif len(pub) == 130 and pub[0:2] == '04': return 'hex'
140 elif len(pub) == 33 and pub[0] in [two, three]: return 'bin_compressed'
141 elif len(pub) == 66 and pub[0:2] in ['02', '03']: return 'hex_compressed'
142 elif len(pub) == 64: return 'bin_electrum'
143 elif len(pub) == 128: return 'hex_electrum'
144 else: raise Exception("Pubkey not in recognized format")
145
146
147 def encode_pubkey(pub, formt):
148 if not isinstance(pub, (tuple, list)):
149 pub = decode_pubkey(pub)
150 if formt == 'decimal': return pub
151 elif formt == 'bin':
152 return b'\x04' + encode(pub[0], 256, 32) + encode(pub[1], 256, 32)
153 elif formt == 'bin_compressed':
154 return from_int_to_byte(2 + (pub[1] % 2)) + encode(pub[0], 256, 32)
155 elif formt == 'hex':
156 return '04' + encode(pub[0], 16, 64) + encode(pub[1], 16, 64)
157 elif formt == 'hex_compressed':
158 return '0' + str(2 + (pub[1] % 2)) + encode(pub[0], 16, 64)
159 elif formt == 'bin_electrum':
160 return encode(pub[0], 256, 32) + encode(pub[1], 256, 32)
161 elif formt == 'hex_electrum':
162 return encode(pub[0], 16, 64) + encode(pub[1], 16, 64)
163 else:
164 raise Exception("Invalid format!")
165
166
167 def decode_pubkey(pub, formt=None):
168 if not formt: formt = get_pubkey_format(pub)
169 if formt == 'decimal': return pub
170 elif formt == 'bin':
171 return (decode(pub[1:33], 256), decode(pub[33:65], 256))
172 elif formt == 'bin_compressed':
173 x = decode(pub[1:33], 256)
174 beta = pow(int(x * x * x + A * x + B), int((P + 1) // 4), int(P))
175 y = (P - beta) if ((beta + from_byte_to_int(pub[0])) % 2) else beta
176 return (x, y)
177 elif formt == 'hex':
178 return (decode(pub[2:66], 16), decode(pub[66:130], 16))
179 elif formt == 'hex_compressed':
180 return decode_pubkey(safe_from_hex(pub), 'bin_compressed')
181 elif formt == 'bin_electrum':
182 return (decode(pub[:32], 256), decode(pub[32:64], 256))
183 elif formt == 'hex_electrum':
184 return (decode(pub[:64], 16), decode(pub[64:128], 16))
185 else:
186 raise Exception("Invalid format!")
187
188
189 def get_privkey_format(priv):
190 if isinstance(priv, int_types): return 'decimal'
191 elif len(priv) == 32: return 'bin'
192 elif len(priv) == 33: return 'bin_compressed'
193 elif len(priv) == 64: return 'hex'
194 elif len(priv) == 66: return 'hex_compressed'
195 else:
196 bin_p = b58check_to_bin(priv)
197 if len(bin_p) == 32: return 'wif'
198 elif len(bin_p) == 33: return 'wif_compressed'
199 else: raise Exception("WIF does not represent privkey")
200
201
202 def encode_privkey(priv, formt, vbyte=0):
203 if not isinstance(priv, int_types):
204 return encode_privkey(decode_privkey(priv), formt, vbyte)
205 if formt == 'decimal': return priv
206 elif formt == 'bin': return encode(priv, 256, 32)
207 elif formt == 'bin_compressed': return encode(priv, 256, 32) + b'\x01'
208 elif formt == 'hex': return encode(priv, 16, 64)
209 elif formt == 'hex_compressed': return encode(priv, 16, 64) + '01'
210 elif formt == 'wif':
211 return bin_to_b58check(encode(priv, 256, 32), 128 + int(vbyte))
212 elif formt == 'wif_compressed':
213 return bin_to_b58check(
214 encode(priv, 256, 32) + b'\x01', 128 + int(vbyte))
215 else:
216 raise Exception("Invalid format!")
217
218
219 def decode_privkey(priv, formt=None):
220 if not formt: formt = get_privkey_format(priv)
221 if formt == 'decimal': return priv
222 elif formt == 'bin': return decode(priv, 256)
223 elif formt == 'bin_compressed': return decode(priv[:32], 256)
224 elif formt == 'hex': return decode(priv, 16)
225 elif formt == 'hex_compressed': return decode(priv[:64], 16)
226 elif formt == 'wif': return decode(b58check_to_bin(priv), 256)
227 elif formt == 'wif_compressed':
228 return decode(b58check_to_bin(priv)[:32], 256)
229 else:
230 raise Exception("WIF does not represent privkey")
231
232
233 def add_pubkeys(p1, p2):
234 f1, f2 = get_pubkey_format(p1), get_pubkey_format(p2)
235 return encode_pubkey(
236 fast_add(
237 decode_pubkey(p1, f1), decode_pubkey(p2, f2)), f1)
238
239
240 def add_privkeys(p1, p2):
241 f1, f2 = get_privkey_format(p1), get_privkey_format(p2)
242 return encode_privkey(
243 (decode_privkey(p1, f1) + decode_privkey(p2, f2)) % N, f1)
244
245
246 def multiply(pubkey, privkey):
247 f1, f2 = get_pubkey_format(pubkey), get_privkey_format(privkey)
248 pubkey, privkey = decode_pubkey(pubkey, f1), decode_privkey(privkey, f2)
249 # http://safecurves.cr.yp.to/twist.html
250 if not isinf(pubkey) and (
251 pubkey[0]**3 + B - pubkey[1] * pubkey[1]) % P != 0:
252 raise Exception("Point not on curve")
253 return encode_pubkey(fast_multiply(pubkey, privkey), f1)
254
255
256 def divide(pubkey, privkey):
257 factor = inv(decode_privkey(privkey), N)
258 return multiply(pubkey, factor)
259
260
261 def compress(pubkey):
262 f = get_pubkey_format(pubkey)
263 if 'compressed' in f: return pubkey
264 elif f == 'bin':
265 return encode_pubkey(decode_pubkey(pubkey, f), 'bin_compressed')
266 elif f == 'hex' or f == 'decimal':
267 return encode_pubkey(decode_pubkey(pubkey, f), 'hex_compressed')
268
269
270 def decompress(pubkey):
271 f = get_pubkey_format(pubkey)
272 if 'compressed' not in f: return pubkey
273 elif f == 'bin_compressed':
274 return encode_pubkey(decode_pubkey(pubkey, f), 'bin')
275 elif f == 'hex_compressed' or f == 'decimal':
276 return encode_pubkey(decode_pubkey(pubkey, f), 'hex')
277
278
279 def privkey_to_pubkey(privkey):
280 f = get_privkey_format(privkey)
281 privkey = decode_privkey(privkey, f)
282 if privkey >= N:
283 raise Exception("Invalid privkey")
284 if f in ['bin', 'bin_compressed', 'hex', 'hex_compressed', 'decimal']:
285 return encode_pubkey(fast_multiply(G, privkey), f)
286 else:
287 return encode_pubkey(fast_multiply(G, privkey), f.replace('wif', 'hex'))
288
289
290 privtopub = privkey_to_pubkey
291
292
293 def privkey_to_address(priv, magicbyte=0):
294 return pubkey_to_address(privkey_to_pubkey(priv), magicbyte)
295
296
297 privtoaddr = privkey_to_address
298
299
300 def neg_pubkey(pubkey):
301 f = get_pubkey_format(pubkey)
302 pubkey = decode_pubkey(pubkey, f)
303 return encode_pubkey((pubkey[0], (P - pubkey[1]) % P), f)
304
305
306 def neg_privkey(privkey):
307 f = get_privkey_format(privkey)
308 privkey = decode_privkey(privkey, f)
309 return encode_privkey((N - privkey) % N, f)
310
311
312 def subtract_pubkeys(p1, p2):
313 f1, f2 = get_pubkey_format(p1), get_pubkey_format(p2)
314 k2 = decode_pubkey(p2, f2)
315 return encode_pubkey(
316 fast_add(
317 decode_pubkey(p1, f1), (k2[0], (P - k2[1]) % P)), f1)
318
319
320 def subtract_privkeys(p1, p2):
321 f1, f2 = get_privkey_format(p1), get_privkey_format(p2)
322 k2 = decode_privkey(p2, f2)
323 return encode_privkey((decode_privkey(p1, f1) - k2) % N, f1)
324
325 # Hashes
326
327
328 def bin_hash160(string):
329 intermed = hashlib.sha256(string).digest()
330 digest = ''
331 digest = hashlib.new('ripemd160', intermed).digest()
332 return digest
333
334
335 def hash160(string):
336 return safe_hexlify(bin_hash160(string))
337
338
339 def bin_sha256(string):
340 binary_data = string if isinstance(string, bytes) else bytes(string,
341 'utf-8')
342 return hashlib.sha256(binary_data).digest()
343
344
345 def sha256(string):
346 return bytes_to_hex_string(bin_sha256(string))
347
348
349 def bin_ripemd160(string):
350 digest = hashlib.new('ripemd160', string).digest()
351 return digest
352
353
354 def ripemd160(string):
355 return safe_hexlify(bin_ripemd160(string))
356
357
358 def bin_dbl_sha256(s):
359 bytes_to_hash = from_string_to_bytes(s)
360 return hashlib.sha256(hashlib.sha256(bytes_to_hash).digest()).digest()
361
362
363 def dbl_sha256(string):
364 return safe_hexlify(bin_dbl_sha256(string))
365
366
367 def bin_slowsha(string):
368 string = from_string_to_bytes(string)
369 orig_input = string
370 for i in range(100000):
371 string = hashlib.sha256(string + orig_input).digest()
372 return string
373
374
375 def slowsha(string):
376 return safe_hexlify(bin_slowsha(string))
377
378
379 def hash_to_int(x):
380 if len(x) in [40, 64]:
381 return decode(x, 16)
382 return decode(x, 256)
383
384
385 def num_to_var_int(x):
386 x = int(x)
387 if x < 253: return from_int_to_byte(x)
388 elif x < 65536: return from_int_to_byte(253) + encode(x, 256, 2)[::-1]
389 elif x < 4294967296: return from_int_to_byte(254) + encode(x, 256, 4)[::-1]
390 else: return from_int_to_byte(255) + encode(x, 256, 8)[::-1]
391
392
393 # WTF, Electrum?
394 def electrum_sig_hash(message):
395 padded = b"\x18Bitcoin Signed Message:\n" + num_to_var_int(len(
396 message)) + from_string_to_bytes(message)
397 return bin_dbl_sha256(padded)
398
399 # Encodings
400
401 def b58check_to_bin(inp):
402 leadingzbytes = len(re.match('^1*', inp).group(0))
403 data = b'\x00' * leadingzbytes + changebase(inp, 58, 256)
404 assert bin_dbl_sha256(data[:-4])[:4] == data[-4:]
405 return data[1:-4]
406
407
408 def get_version_byte(inp):
409 leadingzbytes = len(re.match('^1*', inp).group(0))
410 data = b'\x00' * leadingzbytes + changebase(inp, 58, 256)
411 assert bin_dbl_sha256(data[:-4])[:4] == data[-4:]
412 return ord(data[0])
413
414
415 def hex_to_b58check(inp, magicbyte=0):
416 return bin_to_b58check(binascii.unhexlify(inp), magicbyte)
417
418
419 def b58check_to_hex(inp):
420 return safe_hexlify(b58check_to_bin(inp))
421
422
423 def pubkey_to_address(pubkey, magicbyte=0):
424 if isinstance(pubkey, (list, tuple)):
425 pubkey = encode_pubkey(pubkey, 'bin')
426 if len(pubkey) in [66, 130]:
427 return bin_to_b58check(
428 bin_hash160(binascii.unhexlify(pubkey)), magicbyte)
429 return bin_to_b58check(bin_hash160(pubkey), magicbyte)
430
431
432 pubtoaddr = pubkey_to_address
433
434 # EDCSA
435
436
437 def encode_sig(v, r, s):
438 vb, rb, sb = from_int_to_byte(v), encode(r, 256), encode(s, 256)
439
440 result = base64.b64encode(vb + b'\x00' * (32 - len(rb)) + rb + b'\x00' * (
441 32 - len(sb)) + sb)
442 return result if is_python2 else str(result, 'utf-8')
443
444
445 def decode_sig(sig):
446 bytez = base64.b64decode(sig)
447 return from_byte_to_int(bytez[0]), decode(bytez[1:33], 256), decode(
448 bytez[33:], 256)
449
450 # https://tools.ietf.org/html/rfc6979#section-3.2
451
452
453 def deterministic_generate_k(msghash, priv):
454 v = b'\x01' * 32
455 k = b'\x00' * 32
456 priv = encode_privkey(priv, 'bin')
457 msghash = encode(hash_to_int(msghash), 256, 32)
458 k = hmac.new(k, v + b'\x00' + priv + msghash, hashlib.sha256).digest()
459 v = hmac.new(k, v, hashlib.sha256).digest()
460 k = hmac.new(k, v + b'\x01' + priv + msghash, hashlib.sha256).digest()
461 v = hmac.new(k, v, hashlib.sha256).digest()
462 return decode(hmac.new(k, v, hashlib.sha256).digest(), 256)
463
464
465 def ecdsa_raw_sign(msghash, priv):
466
467 z = hash_to_int(msghash)
468 k = deterministic_generate_k(msghash, priv)
469
470 r, y = fast_multiply(G, k)
471 s = inv(k, N) * (z + r * decode_privkey(priv)) % N
472
473 return 27 + (y % 2), r, s
474
475
476 def ecdsa_sign(msg, priv):
477 return encode_sig(*ecdsa_raw_sign(electrum_sig_hash(msg), priv))
478
479 def ecdsa_raw_verify(msghash, vrs, pub):
480 v, r, s = vrs
481
482 w = inv(s, N)
483 z = hash_to_int(msghash)
484
485 u1, u2 = z * w % N, r * w % N
486 x, y = fast_add(fast_multiply(G, u1), fast_multiply(decode_pubkey(pub), u2))
487
488 return r == x
489
490 def ecdsa_verify(msg, sig, pub):
491 return ecdsa_raw_verify(electrum_sig_hash(msg), decode_sig(sig), pub)
492
493 def estimate_tx_size(ins, outs, txtype='p2pkh'):
494 '''Estimate transaction size.
495 Assuming p2pkh:
496 out: 8+1+3+2+20=34, in: 1+32+4+1+1+~73+1+1+33=147,
497 ver:4,seq:4, +2 (len in,out)
498 total ~= 34*len_out + 147*len_in + 10 (sig sizes vary slightly)
499 '''
500 if txtype=='p2pkh':
501 return 10 + ins*147 +34*outs
502 else:
503 raise NotImplementedError("Non p2pkh transaction size estimation not"+
504 "yet implemented")