def der_encode_sig(v, r, s): b1, b2 = safe_hexlify(encode(r, 256)), safe_hexlify(encode(s, 256)) if r >= 2**255: b1 = '00' + b1 if s >= 2**255: b2 = '00' + b2 left = '02' + encode(len(b1) // 2, 16, 2) + b1 right = '02' + encode(len(b2) // 2, 16, 2) + b2 return '30' + encode(len(left + right) // 2, 16, 2) + left + right
def der_encode_sig(v, r, s): b1, b2 = safe_hexlify(encode(r, 256)), safe_hexlify(encode(s, 256)) if r >= 2**255: b1 = '00' + b1 if s >= 2**255: b2 = '00' + b2 left = '02'+encode(len(b1)//2, 16, 2)+b1 right = '02'+encode(len(b2)//2, 16, 2)+b2 return '30'+encode(len(left+right)//2, 16, 2)+left+right
def sign(tx, i, priv, hashcode=SIGHASH_ALL): i = int(i) if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): return binascii.unhexlify(sign(safe_hexlify(tx), i, priv)) if len(priv) <= 33: priv = safe_hexlify(priv) pub = privkey_to_pubkey(priv) address = pubkey_to_address(pub) signing_tx = signature_form(tx, i, mk_pubkey_script(address), hashcode) sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = deserialize(tx) txobj["ins"][i]["script"] = serialize_script([sig, pub]) return serialize(txobj)
def txhash(tx, hashcode=None): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): tx = changebase(tx, 16, 256) if hashcode: return dbl_sha256(from_string_to_bytes(tx) + encode(int(hashcode), 256, 4)[::-1]) else: return safe_hexlify(bin_dbl_sha256(tx)[::-1])
def serialize(txobj): #if isinstance(txobj, bytes): # txobj = bytes_to_hex_string(txobj) o = [] if json_is_base(txobj, 16): json_changedbase = json_changebase(txobj, lambda x: binascii.unhexlify(x)) hexlified = safe_hexlify(serialize(json_changedbase)) return hexlified o.append(encode(txobj["version"], 256, 4)[::-1]) o.append(num_to_var_int(len(txobj["ins"]))) for inp in txobj["ins"]: o.append(inp["outpoint"]["hash"][::-1]) o.append(encode(inp["outpoint"]["index"], 256, 4)[::-1]) o.append( num_to_var_int(len(inp["script"])) + (inp["script"] if inp["script"] or is_python2 else bytes())) o.append(encode(inp["sequence"], 256, 4)[::-1]) o.append(num_to_var_int(len(txobj["outs"]))) for out in txobj["outs"]: o.append(encode(out["value"], 256, 8)[::-1]) o.append(num_to_var_int(len(out["script"])) + out["script"]) o.append(encode(txobj["locktime"], 256, 4)[::-1]) return ''.join(o) if is_python2 else reduce(lambda x, y: x + y, o, bytes())
def mk_opreturn(msg, rawtx=None, json=0): def op_push(data): import struct if len(data) < 0x4c: return from_int_to_byte(len(data)) + from_string_to_bytes(data) elif len(data) < 0xff: return from_int_to_byte(76) + struct.pack( '<B', len(data)) + from_string_to_bytes(data) elif len(data) < 0xffff: return from_int_to_byte(77) + struct.pack( '<H', len(data)) + from_string_to_bytes(data) elif len(data) < 0xffffffff: return from_int_to_byte(78) + struct.pack( '<I', len(data)) + from_string_to_bytes(data) else: raise Exception("Input data error. Rawtx must be hex chars" \ + "0xffffffff > len(data) > 0") orhex = safe_hexlify(b'\x6a' + op_push(msg)) orjson = {'script': orhex, 'value': 0} if rawtx is not None: try: txo = deserialize(rawtx) if not 'outs' in txo.keys(): raise Exception("OP_Return cannot be the sole output!") txo['outs'].append(orjson) newrawtx = serialize(txo) return newrawtx except: raise Exception("Raw Tx Error!") return orhex if not json else orjson
def mk_opreturn(msg, rawtx=None, json=0): def op_push(data): import struct if len(data) < 0x4c: return from_int_to_byte(len(data)) + from_string_to_bytes(data) elif len(data) < 0xff: return from_int_to_byte(76) + struct.pack('<B', len(data)) + from_string_to_bytes(data) elif len(data) < 0xffff: return from_int_to_byte(77) + struct.pack('<H', len(data)) + from_string_to_bytes(data) elif len(data) < 0xffffffff: return from_int_to_byte(78) + struct.pack('<I', len(data)) + from_string_to_bytes(data) else: raise Exception("Input data error. Rawtx must be hex chars" \ + "0xffffffff > len(data) > 0") orhex = safe_hexlify(b'\x6a' + op_push(msg)) orjson = {'script' : orhex, 'value' : 0} if rawtx is not None: try: txo = deserialize(rawtx) if not 'outs' in txo.keys(): raise Exception("OP_Return cannot be the sole output!") txo['outs'].append(orjson) newrawtx = serialize(txo) return newrawtx except: raise Exception("Raw Tx Error!") return orhex if not json else orjson
def deserialize_script(script): if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): return json_changebase(deserialize_script(binascii.unhexlify(script)), lambda x: safe_hexlify(x)) out, pos = [], 0 while pos < len(script): code = from_byte_to_int(script[pos]) if code == 0: out.append(None) pos += 1 elif code <= 75: out.append(script[pos + 1:pos + 1 + code]) pos += 1 + code elif code <= 78: szsz = pow(2, code - 76) sz = decode(script[pos + szsz:pos:-1], 256) out.append(script[pos + 1 + szsz:pos + 1 + szsz + sz]) pos += 1 + szsz + sz elif code <= 96: out.append(code - 80) pos += 1 else: out.append(code) pos += 1 return out
def deserialize_script(script): if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): return json_changebase(deserialize_script(binascii.unhexlify(script)), lambda x: safe_hexlify(x)) out, pos = [], 0 while pos < len(script): code = from_byte_to_int(script[pos]) if code == 0: out.append(None) pos += 1 elif code <= 75: out.append(script[pos+1:pos+1+code]) pos += 1 + code elif code <= 78: szsz = pow(2, code - 76) sz = decode(script[pos+szsz: pos:-1], 256) out.append(script[pos + 1 + szsz:pos + 1 + szsz + sz]) pos += 1 + szsz + sz elif code <= 96: out.append(code - 80) pos += 1 else: out.append(code) pos += 1 return out
def txhash(tx, hashcode=None): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): tx = changebase(tx, 16, 256) if hashcode: return dbl_sha256( from_string_to_bytes(tx) + encode(int(hashcode), 256, 4)[::-1]) else: return safe_hexlify(bin_dbl_sha256(tx)[::-1])
def serialize_script(script): if json_is_base(script, 16): return safe_hexlify(serialize_script(json_changebase(script, lambda x: binascii.unhexlify(x)))) result = bytes() for b in map(serialize_script_unit, script): result += b if isinstance(b, bytes) else bytes(b, 'utf-8') return result
def verify_tx_input(tx, i, script, sig, pub): if re.match('^[0-9a-fA-F]*$', tx): tx = binascii.unhexlify(tx) if re.match('^[0-9a-fA-F]*$', script): script = binascii.unhexlify(script) if not re.match('^[0-9a-fA-F]*$', sig): sig = safe_hexlify(sig) hashcode = decode(sig[-2:], 16) modtx = signature_form(tx, int(i), script, hashcode) return ecdsa_tx_verify(modtx, sig, pub, hashcode)
def serialize_script(script): if json_is_base(script, 16): return safe_hexlify( serialize_script( json_changebase(script, lambda x: binascii.unhexlify(x)))) result = bytes() for b in map(serialize_script_unit, script): result += b if isinstance(b, bytes) else bytes(b, 'utf-8') return result
def eligius_pushtx(tx): if not re.match('^[0-9a-fA-F]*$', tx): tx = safe_hexlify(tx) s = make_request( 'http://eligius.st/~wizkid057/newstats/pushtxn.php', 'transaction='+tx+'&send=Push') strings = re.findall('string[^"]*"[^"]*"', s) for string in strings: quote = re.findall('"[^"]*"', string)[0] if len(quote) >= 5: return quote[1:-1]
def blockr_pushtx(tx, network='btc'): if network == 'testnet': blockr_url = 'https://tbtc.blockr.io/api/v1/tx/push' elif network == 'btc': blockr_url = 'https://btc.blockr.io/api/v1/tx/push' else: raise Exception( 'Unsupported network {0} for blockr_pushtx'.format(network)) if not re.match('^[0-9a-fA-F]*$', tx): tx = safe_hexlify(tx) return make_request(blockr_url, '{"hex":"%s"}' % tx)
def deserialize(tx): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): #tx = bytes(bytearray.fromhex(tx)) return json_changebase(deserialize(binascii.unhexlify(tx)), lambda x: safe_hexlify(x)) # http://stackoverflow.com/questions/4851463/python-closure-write-to-variable-in-parent-scope # Python's scoping rules are demented, requiring me to make pos an object # so that it is call-by-reference pos = [0] def read_as_int(bytez): pos[0] += bytez return decode(tx[pos[0]-bytez:pos[0]][::-1], 256) def read_var_int(): pos[0] += 1 val = from_byte_to_int(tx[pos[0]-1]) if val < 253: return val return read_as_int(pow(2, val - 252)) def read_bytes(bytez): pos[0] += bytez return tx[pos[0]-bytez:pos[0]] def read_var_string(): size = read_var_int() return read_bytes(size) obj = {"ins": [], "outs": []} obj["version"] = read_as_int(4) ins = read_var_int() for i in range(ins): obj["ins"].append({ "outpoint": { "hash": read_bytes(32)[::-1], "index": read_as_int(4) }, "script": read_var_string(), "sequence": read_as_int(4) }) outs = read_var_int() for i in range(outs): obj["outs"].append({ "value": read_as_int(8), "script": read_var_string() }) obj["locktime"] = read_as_int(4) return obj
def apply_multisignatures(*args): # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] tx, i, script = args[0], int(args[1]), args[2] sigs = args[3] if isinstance(args[3], list) else list(args[3:]) if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): script = binascii.unhexlify(script) sigs = [binascii.unhexlify(x) if x[:2] == '30' else x for x in sigs] if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): return safe_hexlify(apply_multisignatures(binascii.unhexlify(tx), i, script, sigs)) txobj = deserialize(tx) txobj["ins"][i]["script"] = serialize_script([None]+sigs+[script]) return serialize(txobj)
def deserialize(tx): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): #tx = bytes(bytearray.fromhex(tx)) return json_changebase(deserialize(binascii.unhexlify(tx)), lambda x: safe_hexlify(x)) # http://stackoverflow.com/questions/4851463/python-closure-write-to-variable-in-parent-scope # Python's scoping rules are demented, requiring me to make pos an object # so that it is call-by-reference pos = [0] def read_as_int(bytez): pos[0] += bytez return decode(tx[pos[0] - bytez:pos[0]][::-1], 256) def read_var_int(): pos[0] += 1 val = from_byte_to_int(tx[pos[0] - 1]) if val < 253: return val return read_as_int(pow(2, val - 252)) def read_bytes(bytez): pos[0] += bytez return tx[pos[0] - bytez:pos[0]] def read_var_string(): size = read_var_int() return read_bytes(size) obj = {"ins": [], "outs": []} obj["version"] = read_as_int(4) ins = read_var_int() for i in range(ins): obj["ins"].append({ "outpoint": { "hash": read_bytes(32)[::-1], "index": read_as_int(4) }, "script": read_var_string(), "sequence": read_as_int(4) }) outs = read_var_int() for i in range(outs): obj["outs"].append({ "value": read_as_int(8), "script": read_var_string() }) obj["locktime"] = read_as_int(4) return obj
def apply_multisignatures(*args): # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] tx, i, script = args[0], int(args[1]), args[2] sigs = args[3] if isinstance(args[3], list) else list(args[3:]) if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): script = binascii.unhexlify(script) sigs = [binascii.unhexlify(x) if x[:2] == '30' else x for x in sigs] if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): return safe_hexlify( apply_multisignatures(binascii.unhexlify(tx), i, script, sigs)) txobj = deserialize(tx) txobj["ins"][i]["script"] = serialize_script([None] + sigs + [script]) return serialize(txobj)
def serialize(txobj): #if isinstance(txobj, bytes): # txobj = bytes_to_hex_string(txobj) o = [] if json_is_base(txobj, 16): json_changedbase = json_changebase(txobj, lambda x: binascii.unhexlify(x)) hexlified = safe_hexlify(serialize(json_changedbase)) return hexlified o.append(encode(txobj["version"], 256, 4)[::-1]) o.append(num_to_var_int(len(txobj["ins"]))) for inp in txobj["ins"]: o.append(inp["outpoint"]["hash"][::-1]) o.append(encode(inp["outpoint"]["index"], 256, 4)[::-1]) o.append(num_to_var_int(len(inp["script"]))+(inp["script"] if inp["script"] or is_python2 else bytes())) o.append(encode(inp["sequence"], 256, 4)[::-1]) o.append(num_to_var_int(len(txobj["outs"]))) for out in txobj["outs"]: o.append(encode(out["value"], 256, 8)[::-1]) o.append(num_to_var_int(len(out["script"]))+out["script"]) o.append(encode(txobj["locktime"], 256, 4)[::-1]) return ''.join(o) if is_python2 else reduce(lambda x,y: x+y, o, bytes())
def bci_pushtx(tx): if not re.match('^[0-9a-fA-F]*$', tx): tx = safe_hexlify(tx) return make_request('https://blockchain.info/pushtx', 'tx='+tx)
def helloblock_pushtx(tx): if not re.match('^[0-9a-fA-F]*$', tx): tx = safe_hexlify(tx) return make_request('https://mainnet.helloblock.io/v1/transactions', 'rawTxHex='+tx)