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")