1#!/usr/bin/python 2import binascii, re, json, copy, sys 3from .main import * 4from _functools import reduce 5 6### Hex to bin converter and vice versa for objects 7 8 9def json_is_base(obj, base): 10 if not is_python2 and isinstance(obj, bytes): 11 return False 12 13 alpha = get_code_string(base) 14 if isinstance(obj, string_types): 15 for i in range(len(obj)): 16 if alpha.find(obj[i]) == -1: 17 return False 18 return True 19 elif isinstance(obj, int_types) or obj is None: 20 return True 21 elif isinstance(obj, list): 22 for i in range(len(obj)): 23 if not json_is_base(obj[i], base): 24 return False 25 return True 26 else: 27 for x in obj: 28 if not json_is_base(obj[x], base): 29 return False 30 return True 31 32 33def json_changebase(obj, changer): 34 if isinstance(obj, string_or_bytes_types): 35 return changer(obj) 36 elif isinstance(obj, int_types) or obj is None: 37 return obj 38 elif isinstance(obj, list): 39 return [json_changebase(x, changer) for x in obj] 40 return dict((x, json_changebase(obj[x], changer)) for x in obj) 41 42# Transaction serialization and deserialization 43 44 45def deserialize(tx): 46 if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): 47 #tx = bytes(bytearray.fromhex(tx)) 48 return json_changebase(deserialize(binascii.unhexlify(tx)), 49 lambda x: safe_hexlify(x)) 50 # http://stackoverflow.com/questions/4851463/python-closure-write-to-variable-in-parent-scope 51 # Python's scoping rules are demented, requiring me to make pos an object 52 # so that it is call-by-reference 53 pos = [0] 54 55 def read_as_int(bytez): 56 pos[0] += bytez 57 return decode(tx[pos[0]-bytez:pos[0]][::-1], 256) 58 59 def read_var_int(): 60 pos[0] += 1 61 62 val = from_byte_to_int(tx[pos[0]-1]) 63 if val < 253: 64 return val 65 return read_as_int(pow(2, val - 252)) 66 67 def read_bytes(bytez): 68 pos[0] += bytez 69 return tx[pos[0]-bytez:pos[0]] 70 71 def read_var_string(): 72 size = read_var_int() 73 return read_bytes(size) 74 75 obj = {"ins": [], "outs": []} 76 obj["version"] = read_as_int(4) 77 ins = read_var_int() 78 for i in range(ins): 79 obj["ins"].append({ 80 "outpoint": { 81 "hash": read_bytes(32)[::-1], 82 "index": read_as_int(4) 83 }, 84 "script": read_var_string(), 85 "sequence": read_as_int(4) 86 }) 87 outs = read_var_int() 88 for i in range(outs): 89 obj["outs"].append({ 90 "value": read_as_int(8), 91 "script": read_var_string() 92 }) 93 obj["locktime"] = read_as_int(4) 94 return obj 95 96def serialize(txobj): 97 #if isinstance(txobj, bytes): 98 # txobj = bytes_to_hex_string(txobj) 99 o = [] 100 if json_is_base(txobj, 16): 101 json_changedbase = json_changebase(txobj, lambda x: binascii.unhexlify(x)) 102 hexlified = safe_hexlify(serialize(json_changedbase)) 103 return hexlified 104 o.append(encode(txobj["version"], 256, 4)[::-1]) 105 o.append(num_to_var_int(len(txobj["ins"]))) 106 for inp in txobj["ins"]: 107 o.append(inp["outpoint"]["hash"][::-1]) 108 o.append(encode(inp["outpoint"]["index"], 256, 4)[::-1]) 109 o.append(num_to_var_int(len(inp["script"]))+(inp["script"] if inp["script"] or is_python2 else bytes())) 110 o.append(encode(inp["sequence"], 256, 4)[::-1]) 111 o.append(num_to_var_int(len(txobj["outs"]))) 112 for out in txobj["outs"]: 113 o.append(encode(out["value"], 256, 8)[::-1]) 114 o.append(num_to_var_int(len(out["script"]))+out["script"]) 115 o.append(encode(txobj["locktime"], 256, 4)[::-1]) 116 117 return ''.join(o) if is_python2 else reduce(lambda x,y: x+y, o, bytes()) 118 119# Hashing transactions for signing 120 121SIGHASH_ALL = 1 122SIGHASH_NONE = 2 123SIGHASH_SINGLE = 3 124# this works like SIGHASH_ANYONECANPAY | SIGHASH_ALL, might as well make it explicit while 125# we fix the constant 126SIGHASH_ANYONECANPAY = 0x81 127 128 129def signature_form(tx, i, script, hashcode=SIGHASH_ALL): 130 i, hashcode = int(i), int(hashcode) 131 if isinstance(tx, string_or_bytes_types): 132 return serialize(signature_form(deserialize(tx), i, script, hashcode)) 133 newtx = copy.deepcopy(tx) 134 for inp in newtx["ins"]: 135 inp["script"] = "" 136 newtx["ins"][i]["script"] = script 137 if hashcode == SIGHASH_NONE: 138 newtx["outs"] = [] 139 elif hashcode == SIGHASH_SINGLE: 140 newtx["outs"] = newtx["outs"][:len(newtx["ins"])] 141 for out in newtx["outs"][:len(newtx["ins"]) - 1]: 142 out['value'] = 2**64 - 1 143 out['script'] = "" 144 elif hashcode == SIGHASH_ANYONECANPAY: 145 newtx["ins"] = [newtx["ins"][i]] 146 else: 147 pass 148 return newtx 149 150# Making the actual signatures 151 152 153def der_encode_sig(v, r, s): 154 b1, b2 = safe_hexlify(encode(r, 256)), safe_hexlify(encode(s, 256)) 155 if len(b1) and b1[0] in '89abcdef': 156 b1 = '00' + b1 157 if len(b2) and b2[0] in '89abcdef': 158 b2 = '00' + b2 159 left = '02'+encode(len(b1)//2, 16, 2)+b1 160 right = '02'+encode(len(b2)//2, 16, 2)+b2 161 return '30'+encode(len(left+right)//2, 16, 2)+left+right 162 163def der_decode_sig(sig): 164 leftlen = decode(sig[6:8], 16)*2 165 left = sig[8:8+leftlen] 166 rightlen = decode(sig[10+leftlen:12+leftlen], 16)*2 167 right = sig[12+leftlen:12+leftlen+rightlen] 168 return (None, decode(left, 16), decode(right, 16)) 169 170def is_bip66(sig): 171 """Checks hex DER sig for BIP66 consistency""" 172 #https://raw.githubusercontent.com/bitcoin/bips/master/bip-0066.mediawiki 173 #0x30 [total-len] 0x02 [R-len] [R] 0x02 [S-len] [S] [sighash] 174 sig = bytearray.fromhex(sig) if re.match('^[0-9a-fA-F]*$', sig) else bytearray(sig) 175 if (sig[0] == 0x30) and (sig[1] == len(sig)-2): # check if sighash is missing 176 sig.extend(b"\1") # add SIGHASH_ALL for testing 177 #assert (sig[-1] & 124 == 0) and (not not sig[-1]), "Bad SIGHASH value" 178 179 if len(sig) < 9 or len(sig) > 73: return False 180 if (sig[0] != 0x30): return False 181 if (sig[1] != len(sig)-3): return False 182 rlen = sig[3] 183 if (5+rlen >= len(sig)): return False 184 slen = sig[5+rlen] 185 if (rlen + slen + 7 != len(sig)): return False 186 if (sig[2] != 0x02): return False 187 if (rlen == 0): return False 188 if (sig[4] & 0x80): return False 189 if (rlen > 1 and (sig[4] == 0x00) and not (sig[5] & 0x80)): return False 190 if (sig[4+rlen] != 0x02): return False 191 if (slen == 0): return False 192 if (sig[rlen+6] & 0x80): return False 193 if (slen > 1 and (sig[6+rlen] == 0x00) and not (sig[7+rlen] & 0x80)): 194 return False 195 return True 196 197def txhash(tx, hashcode=None): 198 if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): 199 tx = changebase(tx, 16, 256) 200 if hashcode: 201 return dbl_sha256(from_string_to_bytes(tx) + encode(int(hashcode), 256, 4)[::-1]) 202 else: 203 return safe_hexlify(bin_dbl_sha256(tx)[::-1]) 204 205 206def bin_txhash(tx, hashcode=None): 207 return binascii.unhexlify(txhash(tx, hashcode)) 208 209 210def ecdsa_tx_sign(tx, priv, hashcode=SIGHASH_ALL): 211 rawsig = ecdsa_raw_sign(bin_txhash(tx, hashcode), priv) 212 return der_encode_sig(*rawsig)+encode(hashcode, 16, 2) 213 214 215def ecdsa_tx_verify(tx, sig, pub, hashcode=SIGHASH_ALL): 216 return ecdsa_raw_verify(bin_txhash(tx, hashcode), der_decode_sig(sig), pub) 217 218 219def ecdsa_tx_recover(tx, sig, hashcode=SIGHASH_ALL): 220 z = bin_txhash(tx, hashcode) 221 _, r, s = der_decode_sig(sig) 222 left = ecdsa_raw_recover(z, (0, r, s)) 223 right = ecdsa_raw_recover(z, (1, r, s)) 224 return (encode_pubkey(left, 'hex'), encode_pubkey(right, 'hex')) 225 226# Scripts 227 228 229def mk_pubkey_script(addr): 230 # Keep the auxiliary functions around for altcoins' sake 231 return '76a914' + b58check_to_hex(addr) + '88ac' 232 233 234def mk_scripthash_script(addr): 235 return 'a914' + b58check_to_hex(addr) + '87' 236 237# Address representation to output script 238 239 240def address_to_script(addr): 241 if addr[0] == '3' or addr[0] == '2': 242 return mk_scripthash_script(addr) 243 else: 244 return mk_pubkey_script(addr) 245 246# Output script to address representation 247 248 249def script_to_address(script, vbyte=0): 250 if re.match('^[0-9a-fA-F]*$', script): 251 script = binascii.unhexlify(script) 252 if script[:3] == b'\x76\xa9\x14' and script[-2:] == b'\x88\xac' and len(script) == 25: 253 return bin_to_b58check(script[3:-2], vbyte) # pubkey hash addresses 254 else: 255 if vbyte in [111, 196]: 256 # Testnet 257 scripthash_byte = 196 258 elif vbyte == 0: 259 # Mainnet 260 scripthash_byte = 5 261 else: 262 scripthash_byte = vbyte 263 # BIP0016 scripthash addresses 264 return bin_to_b58check(script[2:-1], scripthash_byte) 265 266 267def p2sh_scriptaddr(script, magicbyte=5): 268 if re.match('^[0-9a-fA-F]*$', script): 269 script = binascii.unhexlify(script) 270 return hex_to_b58check(hash160(script), magicbyte) 271scriptaddr = p2sh_scriptaddr 272 273 274def deserialize_script(script): 275 if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): 276 return json_changebase(deserialize_script(binascii.unhexlify(script)), 277 lambda x: safe_hexlify(x)) 278 out, pos = [], 0 279 while pos < len(script): 280 code = from_byte_to_int(script[pos]) 281 if code == 0: 282 out.append(None) 283 pos += 1 284 elif code <= 75: 285 out.append(script[pos+1:pos+1+code]) 286 pos += 1 + code 287 elif code <= 78: 288 szsz = pow(2, code - 76) 289 sz = decode(script[pos+szsz: pos:-1], 256) 290 out.append(script[pos + 1 + szsz:pos + 1 + szsz + sz]) 291 pos += 1 + szsz + sz 292 elif code <= 96: 293 out.append(code - 80) 294 pos += 1 295 else: 296 out.append(code) 297 pos += 1 298 return out 299 300 301def serialize_script_unit(unit): 302 if isinstance(unit, int): 303 if unit < 16: 304 return from_int_to_byte(unit + 80) 305 else: 306 return from_int_to_byte(unit) 307 elif unit is None: 308 return b'\x00' 309 else: 310 if len(unit) <= 75: 311 return from_int_to_byte(len(unit))+unit 312 elif len(unit) < 256: 313 return from_int_to_byte(76)+from_int_to_byte(len(unit))+unit 314 elif len(unit) < 65536: 315 return from_int_to_byte(77)+encode(len(unit), 256, 2)[::-1]+unit 316 else: 317 return from_int_to_byte(78)+encode(len(unit), 256, 4)[::-1]+unit 318 319 320if is_python2: 321 def serialize_script(script): 322 if json_is_base(script, 16): 323 return binascii.hexlify(serialize_script(json_changebase(script, 324 lambda x: binascii.unhexlify(x)))) 325 return ''.join(map(serialize_script_unit, script)) 326else: 327 def serialize_script(script): 328 if json_is_base(script, 16): 329 return safe_hexlify(serialize_script(json_changebase(script, 330 lambda x: binascii.unhexlify(x)))) 331 332 result = bytes() 333 for b in map(serialize_script_unit, script): 334 result += b if isinstance(b, bytes) else bytes(b, 'utf-8') 335 return result 336 337 338def mk_multisig_script(*args): # [pubs],k or pub1,pub2...pub[n],k 339 if isinstance(args[0], list): 340 pubs, k = args[0], int(args[1]) 341 else: 342 pubs = list(filter(lambda x: len(str(x)) >= 32, args)) 343 k = int(args[len(pubs)]) 344 return serialize_script([k]+pubs+[len(pubs)]+[0xae]) 345 346# Signing and verifying 347 348 349def verify_tx_input(tx, i, script, sig, pub): 350 if re.match('^[0-9a-fA-F]*$', tx): 351 tx = binascii.unhexlify(tx) 352 if re.match('^[0-9a-fA-F]*$', script): 353 script = binascii.unhexlify(script) 354 if not re.match('^[0-9a-fA-F]*$', sig): 355 sig = safe_hexlify(sig) 356 hashcode = decode(sig[-2:], 16) 357 modtx = signature_form(tx, int(i), script, hashcode) 358 return ecdsa_tx_verify(modtx, sig, pub, hashcode) 359 360 361def sign(tx, i, priv, hashcode=SIGHASH_ALL): 362 i = int(i) 363 if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): 364 return binascii.unhexlify(sign(safe_hexlify(tx), i, priv)) 365 if len(priv) <= 33: 366 priv = safe_hexlify(priv) 367 pub = privkey_to_pubkey(priv) 368 address = pubkey_to_address(pub) 369 signing_tx = signature_form(tx, i, mk_pubkey_script(address), hashcode) 370 sig = ecdsa_tx_sign(signing_tx, priv, hashcode) 371 txobj = deserialize(tx) 372 txobj["ins"][i]["script"] = serialize_script([sig, pub]) 373 return serialize(txobj) 374 375 376def signall(tx, priv): 377 # if priv is a dictionary, assume format is 378 # { 'txinhash:txinidx' : privkey } 379 if isinstance(priv, dict): 380 for e, i in enumerate(deserialize(tx)["ins"]): 381 k = priv["%s:%d" % (i["outpoint"]["hash"], i["outpoint"]["index"])] 382 tx = sign(tx, e, k) 383 else: 384 for i in range(len(deserialize(tx)["ins"])): 385 tx = sign(tx, i, priv) 386 return tx 387 388 389def multisign(tx, i, script, pk, hashcode=SIGHASH_ALL): 390 if re.match('^[0-9a-fA-F]*$', tx): 391 tx = binascii.unhexlify(tx) 392 if re.match('^[0-9a-fA-F]*$', script): 393 script = binascii.unhexlify(script) 394 modtx = signature_form(tx, i, script, hashcode) 395 return ecdsa_tx_sign(modtx, pk, hashcode) 396 397 398def apply_multisignatures(*args): 399 # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] 400 tx, i, script = args[0], int(args[1]), args[2] 401 sigs = args[3] if isinstance(args[3], list) else list(args[3:]) 402 403 if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): 404 script = binascii.unhexlify(script) 405 sigs = [binascii.unhexlify(x) if x[:2] == '30' else x for x in sigs] 406 if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): 407 return safe_hexlify(apply_multisignatures(binascii.unhexlify(tx), i, script, sigs)) 408 409 # Not pushing empty elements on the top of the stack if passing no 410 # script (in case of bare multisig inputs there is no script) 411 script_blob = [] if script.__len__() == 0 else [script] 412 413 txobj = deserialize(tx) 414 txobj["ins"][i]["script"] = serialize_script([None]+sigs+script_blob) 415 return serialize(txobj) 416 417 418def is_inp(arg): 419 return len(arg) > 64 or "output" in arg or "outpoint" in arg 420 421 422def mktx(*args): 423 # [in0, in1...],[out0, out1...] or in0, in1 ... out0 out1 ... 424 ins, outs = [], [] 425 for arg in args: 426 if isinstance(arg, list): 427 for a in arg: (ins if is_inp(a) else outs).append(a) 428 else: 429 (ins if is_inp(arg) else outs).append(arg) 430 431 txobj = {"locktime": 0, "version": 1, "ins": [], "outs": []} 432 for i in ins: 433 if isinstance(i, dict) and "outpoint" in i: 434 txobj["ins"].append(i) 435 else: 436 if isinstance(i, dict) and "output" in i: 437 i = i["output"] 438 txobj["ins"].append({ 439 "outpoint": {"hash": i[:64], "index": int(i[65:])}, 440 "script": "", 441 "sequence": 4294967295 442 }) 443 for o in outs: 444 if isinstance(o, string_or_bytes_types): 445 addr = o[:o.find(':')] 446 val = int(o[o.find(':')+1:]) 447 o = {} 448 if re.match('^[0-9a-fA-F]*$', addr): 449 o["script"] = addr 450 else: 451 o["address"] = addr 452 o["value"] = val 453 454 outobj = {} 455 if "address" in o: 456 outobj["script"] = address_to_script(o["address"]) 457 elif "script" in o: 458 outobj["script"] = o["script"] 459 else: 460 raise Exception("Could not find 'address' or 'script' in output.") 461 outobj["value"] = o["value"] 462 txobj["outs"].append(outobj) 463 464 return serialize(txobj) 465 466 467def select(unspent, value): 468 value = int(value) 469 high = [u for u in unspent if u["value"] >= value] 470 high.sort(key=lambda u: u["value"]) 471 low = [u for u in unspent if u["value"] < value] 472 low.sort(key=lambda u: -u["value"]) 473 if len(high): 474 return [high[0]] 475 i, tv = 0, 0 476 while tv < value and i < len(low): 477 tv += low[i]["value"] 478 i += 1 479 if tv < value: 480 raise Exception("Not enough funds") 481 return low[:i] 482 483# Only takes inputs of the form { "output": blah, "value": foo } 484 485 486def mksend(*args): 487 argz, change, fee = args[:-2], args[-2], int(args[-1]) 488 ins, outs = [], [] 489 for arg in argz: 490 if isinstance(arg, list): 491 for a in arg: 492 (ins if is_inp(a) else outs).append(a) 493 else: 494 (ins if is_inp(arg) else outs).append(arg) 495 496 isum = sum([i["value"] for i in ins]) 497 osum, outputs2 = 0, [] 498 for o in outs: 499 if isinstance(o, string_types): 500 o2 = { 501 "address": o[:o.find(':')], 502 "value": int(o[o.find(':')+1:]) 503 } 504 else: 505 o2 = o 506 outputs2.append(o2) 507 osum += o2["value"] 508 509 if isum < osum+fee: 510 raise Exception("Not enough money") 511 elif isum > osum+fee+5430: 512 outputs2 += [{"address": change, "value": isum-osum-fee}] 513 514 return mktx(ins, outputs2) 515