def test_message(self): outs = construct_outputs(OUTPUTS + MESSAGES) assert outs[2].amount == hex_to_bytes(OUTPUT_BLOCK_MESSAGES[136:152]) assert outs[2].script_pubkey == hex_to_bytes( OUTPUT_BLOCK_MESSAGES[154:168]) assert outs[3].amount == hex_to_bytes(OUTPUT_BLOCK_MESSAGES[168:184]) assert outs[3].script_pubkey == hex_to_bytes( OUTPUT_BLOCK_MESSAGES[186:])
def create_new_transaction(private_key, unspents, outputs): version = VERSION_1 lock_time = LOCK_TIME timestamp = int(time.time()).to_bytes(4, byteorder='little') outputs = construct_outputs(outputs) # Optimize for speed, not memory, by pre-computing values. inputs = [] for unspent in unspents: script_sig = b'' # empty scriptSig for new unsigned transaction. txid = hex_to_bytes(unspent.txid)[::-1] txindex = unspent.txindex.to_bytes(4, byteorder='little') amount = int(unspent.amount).to_bytes(8, byteorder='little') inputs.append( TxIn(script_sig, txid, txindex, amount=amount, segwit_input=unspent.segwit)) tx_unsigned = TxObj(version=version, timestamp=timestamp, TxIn=inputs, TxOut=outputs, locktime=lock_time) tx = sign_tx(private_key, tx_unsigned, unspents=unspents) return tx
async def create_unsigned_transaction(source_address: str, outputs_dict: Dict[str, Decimal], fee_kb: int) -> Tuple[TxObj, List[Unspent]]: all_utxos = await get_unspent(source_address) confirmed_utxos = [u for u in all_utxos if u.confirmations >= settings.min_confirmations] if not confirmed_utxos: raise InsufficientFunds('No confirmed UTXOs were found') outputs = [(addr, int(amount * SATOSHI_MULTIPLIER)) for addr, amount in outputs_dict.items()] inputs, change_amount = select_unspents(source_address, confirmed_utxos, outputs, fee_kb) if change_amount > DUST_THRESHOLD: outputs.append((source_address, change_amount)) version = VERSION_2 lock_time = LOCK_TIME raw_outputs = construct_outputs(outputs) raw_inputs = [] for unspent in inputs: script_sig = b'' txid = hex_to_bytes(unspent.txid)[::-1] txindex = unspent.txindex.to_bytes(4, byteorder='little') amount = int(unspent.amount).to_bytes(8, byteorder='little') raw_inputs.append(TxIn(script_sig, txid, txindex, amount=amount)) tx_unsigned = TxObj(version, raw_inputs, raw_outputs, lock_time) return tx_unsigned, inputs
def multisig_to_redeemscript(public_keys, m): if m > 16: raise ValueError( 'More than the allowed maximum of 16 public keys cannot be used.') redeemscript = int_to_unknown_bytes(m + 80) for key in public_keys: key_byte = hex_to_bytes(key) length = len(key_byte) if length not in (33, 65): raise ValueError( 'At least one of the provided public keys is of invalid length {}.' .format(length)) redeemscript += script_push(length) + key_byte redeemscript += int_to_unknown_bytes( len(public_keys) + 80 ) + b'\xae' # Only works for n = len(public_keys) < 17. OK due to P2SH script-length limitation. if len(redeemscript) > 520: raise ValueError( 'The redeemScript exceeds the allowed 520-byte limitation with the number of public keys.' ) return redeemscript
def test_get_signatures_1(self): script = hex_to_bytes( '0047304402200b526cf17f86891a62f4bd27745494005682d650c27dda87' '7f35b0161c38bc9002204674a0be6275ce948812c200251802d15eaa1953' '3d864d64b83b992c10b3ecf201' '483045022100a57ba5464a03343bd5ebf21ce0d3d49b84710c62a421b7d5' 'b86de75ca10d8c7602206395d6a552fc0dbb31d3c0b1db34fa4a14cc29d6' '60c8c68172c7e513cb6a0ac901' '475221021816325d19fd34fd87a039e83e35fc9de3c9de64a501a6684b9b' 'f9946364fbb721037d696886864509ed63044d8f1bcd53b8def1247bd2bbe' '056ff81b23e8c09280f52ae') sigs = get_signatures_from_script(script) assert len(sigs) == 2 assert sigs[0][:4] == hex_to_bytes('30440220') assert sigs[0][-4:] == hex_to_bytes('b3ecf201') assert sigs[1][:4] == hex_to_bytes('30450221') assert sigs[1][-4:] == hex_to_bytes('6a0ac901')
def create_p2pkh_transaction(private_key, unspents, outputs): public_key = private_key.public_key public_key_len = len(public_key).to_bytes(1, byteorder='little') version = VERSION_1 lock_time = LOCK_TIME sequence = SEQUENCE hash_type = HASH_TYPE input_count = int_to_unknown_bytes(len(unspents), byteorder='little') output_count = int_to_unknown_bytes(len(outputs), byteorder='little') output_block = construct_output_block(outputs) # Optimize for speed, not memory, by pre-computing values. inputs = [] for unspent in unspents: script = hex_to_bytes(unspent.script) script_len = int_to_unknown_bytes(len(script), byteorder='little') txid = hex_to_bytes(unspent.txid)[::-1] txindex = unspent.txindex.to_bytes(4, byteorder='little') inputs.append(TxIn(script, script_len, txid, txindex)) for i, txin in enumerate(inputs): hashed = sha256(version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + sequence for ti in islice(inputs, i)) + txin.txid + txin.txindex + txin.script_len + txin.script + sequence + b''.join(ti.txid + ti.txindex + OP_0 + sequence for ti in islice(inputs, i + 1, None)) + output_count + output_block + lock_time + hash_type) signature = private_key.sign(hashed) + b'\x01' script_sig = (len(signature).to_bytes(1, byteorder='little') + signature + public_key_len + public_key) txin.script = script_sig txin.script_len = int_to_unknown_bytes(len(script_sig), byteorder='little') return bytes_to_hex(version + input_count + construct_input_block(inputs) + output_count + output_block + lock_time)
def test_valid_address(self): """Test whether valid addresses decode to the correct output.""" for (address, hexscript) in VALID_ADDRESS: witver, witprog = segwit_addr.decode(address) assert witver is not None scriptpubkey = segwit_scriptpubkey(witver, witprog) assert scriptpubkey == hex_to_bytes(hexscript) hrp = address[:2].lower() addr = segwit_addr.encode(hrp, witver, witprog) assert address.lower() == addr
def test_get_signatures_2(self): script = hex_to_bytes( '0047304402200b526cf17f86891a62f4bd27745494005682d650c27dda87' '7f35b0161c38bc9002204674a0be6275ce948812c200251802d15eaa1953' '3d864d64b83b992c10b3ecf201' '00' '695221021816325d19fd34fd87a039e83e35fc9de3c9de64a501a6684b9b' 'f9946364fbb721037d696886864509ed63044d8f1bcd53b8def1247bd2bb' 'e056ff81b23e8c09280f21033dc7fb58b701fc0af63ee3a8b72ebbeed04a' '1c006b50007f32ec6a33a56213f853ae0400483045022100f686296df668' '17198feead5fa24f3f04cb7e6780187e73fc8c531254fd002c13022044ef' 'e2ea00f31de395376d83cb122bd708116d151bdf2de61107d77447b475c6' '0100695221021816325d19fd34fd87a039e83e35fc9de3c9de64a501a668' '4b9bf9946364fbb721037d696886864509ed63044d8f1bcd53b8def1247b' 'd2bbe056ff81b23e8c09280f21033dc7fb58b701fc0af63ee3a8b72ebbee' 'd04a1c006b50007f32ec6a33a56213f853ae') sigs = get_signatures_from_script(script) assert len(sigs) == 1 assert sigs[0][:4] == hex_to_bytes('30440220') assert sigs[0][-4:] == hex_to_bytes('b3ecf201')
def deserialize(txhex): if isinstance(txhex, str) and re.match('^[0-9a-fA-F]*$', txhex): #return deserialize(binascii.unhexlify(txhex)) return deserialize(hex_to_bytes(txhex)) pos = [0] def read_as_int(bytez): pos[0] += bytez return int(bytes_to_hex(txhex[pos[0] - bytez:pos[0]][::-1]), base=16) def read_var_int(): pos[0] += 1 val = int(bytes_to_hex(txhex[pos[0] - 1:pos[0]]), base=16) if val < 253: return val return read_as_int(pow(2, val - 252)) def read_bytes(bytez): pos[0] += bytez return txhex[pos[0] - bytez:pos[0]] def read_var_string(): size = read_var_int() return read_bytes(size) version = read_as_int(4).to_bytes(4, byteorder='little') ins = read_var_int() inputs = [] for _ in range(ins): txid = read_bytes(32) txindex = read_as_int(4).to_bytes(4, byteorder='little') script = read_var_string() sequence = read_as_int(4).to_bytes(4, byteorder='little') inputs.append(TxIn(script, txid, txindex, sequence)) outs = read_var_int() outputs = [] for _ in range(outs): value = read_as_int(8).to_bytes(8, byteorder='little') script = read_var_string() outputs.append(TxOut(value, script)) locktime = read_as_int(4).to_bytes(4, byteorder='little') txobj = TxObj(version, inputs, outputs, locktime) return txobj
def hex_to_wif(private_key, version='main', compressed=False): if version == 'test': prefix = TEST_PRIVATE_KEY else: prefix = MAIN_PRIVATE_KEY if compressed: suffix = PRIVATE_KEY_COMPRESSED_PUBKEY else: suffix = b'' if not isinstance(private_key, bytes): private_key = hex_to_bytes(private_key) private_key = prefix + private_key + suffix return b58encode_check(private_key)
def create_new_transaction(private_key, unspents, outputs): version = VERSION_1 lock_time = LOCK_TIME outputs = construct_outputs(outputs) # Optimize for speed, not memory, by pre-computing values. inputs = [] for unspent in unspents: script = b'' # empty scriptSig for new unsigned transaction. txid = hex_to_bytes(unspent.txid)[::-1] txindex = unspent.txindex.to_bytes(4, byteorder='little') inputs.append(TxIn(script, txid, txindex)) tx_unsigned = TxObj(version, inputs, outputs, lock_time) tx = sign_legacy_tx(private_key, tx_unsigned) return tx
def deserialize(tx): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): return deserialize(hex_to_bytes(tx)) segwit_tx = TxObj.is_segwit(tx) version, tx = read_bytes(tx, 4) timestamp, tx = read_bytes(tx, 4) if segwit_tx: _, tx = read_bytes(tx, 1) # ``marker`` is nulled _, tx = read_bytes(tx, 1) # ``flag`` is nulled ins, tx = read_var_int(tx) inputs = [] for i in range(ins): txid, tx = read_bytes(tx, 32) txindex, tx = read_bytes(tx, 4) script_sig, tx = read_var_string(tx) sequence, tx = read_bytes(tx, 4) inputs.append(TxIn(script_sig, txid, txindex, sequence=sequence)) outs, tx = read_var_int(tx) outputs = [] for _ in range(outs): amount, tx = read_bytes(tx, 8) script_pubkey, tx = read_var_string(tx) outputs.append(TxOut(amount, script_pubkey)) if segwit_tx: for i in range(ins): wnum, tx = read_var_int(tx) witness = int_to_varint(wnum) for _ in range(wnum): w, tx = read_segwit_string(tx) witness += w inputs[i].witness = witness locktime, _ = read_bytes(tx, 4) txobj = TxObj(version, timestamp, inputs, outputs, locktime) return txobj
def is_segwit(cls, tx): if isinstance(tx, cls): tx = bytes(tx) elif not isinstance(tx, bytes): tx = hex_to_bytes(tx) return tx[4:6] == MARKER + FLAG
def test_no_message(self): outs = construct_outputs(OUTPUTS) assert outs[0].amount == hex_to_bytes(OUTPUT_BLOCK[:16]) assert outs[0].script_pubkey == hex_to_bytes(OUTPUT_BLOCK[18:68]) assert outs[1].amount == hex_to_bytes(OUTPUT_BLOCK[68:84]) assert outs[1].script_pubkey == hex_to_bytes(OUTPUT_BLOCK[86:])
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True): """ sanitize_tx_data() fee is in satoshis per byte. """ outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') messages = [] if message: if type(message) == int: messages.append((int_to_unknown_bytes(message), 0)) else: messages.append((hex_to_bytes(message), 0)) # Include return address in output count. num_outputs = len(outputs) + len(messages) + 1 sum_outputs = sum(out[1] for out in outputs) total_in = 0 if combine: # calculated_fee is in total satoshis. calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount calculated_fee = estimate_tx_fee(len(unspents[:index + 1]), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > 0: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extend(messages) return unspents, outputs
def test_segwit_deserialize(self): txobj = deserialize(SEGWIT_TX_1) assert txobj.version == hex_to_bytes(SEGWIT_TX_1[:8]) assert len(txobj.TxIn) == 2 assert txobj.TxIn[0].txid == hex_to_bytes(SEGWIT_TX_1[14:78]) assert txobj.TxIn[0].txindex == hex_to_bytes(SEGWIT_TX_1[78:86]) assert txobj.TxIn[0].script_sig_len == hex_to_bytes(SEGWIT_TX_1[86:88]) assert txobj.TxIn[0].script_sig == hex_to_bytes(SEGWIT_TX_1[88:300]) assert txobj.TxIn[0].sequence == hex_to_bytes(SEGWIT_TX_1[300:308]) assert txobj.TxIn[0].witness == hex_to_bytes(SEGWIT_TX_1[564:566]) assert txobj.TxIn[1].txid == hex_to_bytes(SEGWIT_TX_1[308:372]) assert txobj.TxIn[1].txindex == hex_to_bytes(SEGWIT_TX_1[372:380]) assert txobj.TxIn[1].script_sig_len == hex_to_bytes(SEGWIT_TX_1[380:382]) assert txobj.TxIn[1].script_sig == hex_to_bytes(SEGWIT_TX_1[382:428]) assert txobj.TxIn[1].sequence == hex_to_bytes(SEGWIT_TX_1[428:436]) assert txobj.TxIn[1].witness == hex_to_bytes(SEGWIT_TX_1[566:780]) assert len(txobj.TxOut) == 2 assert txobj.TxOut[0].amount == hex_to_bytes(SEGWIT_TX_1[438:454]) assert txobj.TxOut[0].script_pubkey_len == hex_to_bytes(SEGWIT_TX_1[454:456]) assert txobj.TxOut[0].script_pubkey == hex_to_bytes(SEGWIT_TX_1[456:500]) assert txobj.TxOut[1].amount == hex_to_bytes(SEGWIT_TX_1[500:516]) assert txobj.TxOut[1].script_pubkey_len == hex_to_bytes(SEGWIT_TX_1[516:518]) assert txobj.TxOut[1].script_pubkey == hex_to_bytes(SEGWIT_TX_1[518:564]) assert txobj.locktime == hex_to_bytes(SEGWIT_TX_1[780:])
def create_sweep_transaction(private_keys, destination_address, amount=None, currency='satoshi', fee=None, leftover=None, message=None, compressed=True): private_key_map = {} unspents = [] for key in private_keys: utxos = key.get_unspents() unspents += utxos for utx in utxos: private_key_map[utx.txid] = key version = VERSION_1 lock_time = LOCK_TIME sequence = SEQUENCE hash_type = HASH_TYPE input_count = int_to_unknown_bytes(len(unspents), byteorder='little') # Construct the outputs, taking the fee into account sum_of_unspents = sum([int(x.amount) for x in unspents]) amount = amount or sum_of_unspents outputs = [(destination_address, sum_of_unspents, currency)] unspents, outputs = sanitize_tx_data(unspents, outputs, fee or get_fee_cached(), leftover or private_keys[0].address, combine=True, message=message, compressed=compressed, sweep=True) output_count = int_to_unknown_bytes(len(outputs), byteorder='little') output_block = construct_output_block(outputs) # Optimize for speed, not memory, by pre-computing values. inputs = [] for unspent in unspents: script = hex_to_bytes(unspent.script) script_len = int_to_unknown_bytes(len(script), byteorder='little') txid = hex_to_bytes(unspent.txid)[::-1] txindex = unspent.txindex.to_bytes(4, byteorder='little') inputs.append(TxIn(script, script_len, txid, txindex)) for i, txin in enumerate(inputs): hashed = sha256(version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + sequence for ti in islice(inputs, i)) + txin.txid + txin.txindex + txin.script_len + txin.script + sequence + b''.join(ti.txid + ti.txindex + OP_0 + sequence for ti in islice(inputs, i + 1, None)) + output_count + output_block + lock_time + hash_type) private_key = private_key_map[unspents[i].txid] signature = private_key.sign(hashed) + b'\x01' public_key = private_key.public_key public_key_len = len(public_key).to_bytes(1, byteorder='little') script_sig = (len(signature).to_bytes(1, byteorder='little') + signature + public_key_len + public_key) txin.script = script_sig txin.script_len = int_to_unknown_bytes(len(script_sig), byteorder='little') return bytes_to_hex(version + input_count + construct_input_block(inputs) + output_count + output_block + lock_time)
def serialize_txid(txid: str) -> bytes: """Serializes txid to bytes""" return hex_to_bytes(txid)[::-1]
def test_legacy_deserialize(self): txobj = deserialize(FINAL_TX_1) assert txobj.version == hex_to_bytes(FINAL_TX_1[:8]) assert len(txobj.TxIn) == 1 assert txobj.TxIn[0].txid == hex_to_bytes(FINAL_TX_1[10:74]) assert txobj.TxIn[0].txindex == hex_to_bytes(FINAL_TX_1[74:82]) assert txobj.TxIn[0].script_sig_len == hex_to_bytes(FINAL_TX_1[82:84]) assert txobj.TxIn[0].script_sig == hex_to_bytes(FINAL_TX_1[84:360]) assert txobj.TxIn[0].witness == b'' assert txobj.TxIn[0].sequence == hex_to_bytes(FINAL_TX_1[360:368]) assert len(txobj.TxOut) == 2 assert txobj.TxOut[0].amount == hex_to_bytes(FINAL_TX_1[370:386]) assert txobj.TxOut[0].script_pubkey_len == hex_to_bytes(FINAL_TX_1[386:388]) assert txobj.TxOut[0].script_pubkey == hex_to_bytes(FINAL_TX_1[388:438]) assert txobj.TxOut[1].amount == hex_to_bytes(FINAL_TX_1[438:454]) assert txobj.TxOut[1].script_pubkey_len == hex_to_bytes(FINAL_TX_1[454:456]) assert txobj.TxOut[1].script_pubkey == hex_to_bytes(FINAL_TX_1[456:506]) assert txobj.locktime == hex_to_bytes(FINAL_TX_1[506:])
def test_hex_to_bytes(): assert hex_to_bytes(HEX) == BYTES_BIG assert hex_to_bytes(ODD_HEX) == ODD_HEX_BYTES
def calc_txid(tx_hex): return bytes_to_hex(double_sha256(hex_to_bytes(tx_hex))[::-1])
def sign_tx(private_key, tx, *, unspents): """Signs inputs in provided transaction object for which unspents are provided and can be signed by the private key. :param private_key: Private key :type private_key: ``PrivateKey`` or ``MultiSig`` :param tx: Transaction object :type tx: ``TxObj`` :param unspents: For inputs to be signed their corresponding Unspent objects must be provided. :returns: The signed transaction as hex. :rtype: ``str`` """ # input_dict contains those unspents that can be signed by private_key, # providing additional information for segwit-inputs (the amount to spend) input_dict = {} try: for unspent in unspents: if not private_key.can_sign_unspent(unspent): continue tx_input = hex_to_bytes(unspent.txid)[::-1] + \ unspent.txindex.to_bytes(4, byteorder='little') input_dict[tx_input] = unspent.to_dict() except TypeError: raise ValueError('Please provide as unspents at least all inputs to ' 'be signed with the function call.') # Determine input indices to sign from input_dict (allows for transaction batching) sign_inputs = [j for j, i in enumerate(tx.TxIn) if i.txid+i.txindex in input_dict] segwit_tx = TxObj.is_segwit(tx) version = tx.version lock_time = tx.locktime hash_type = HASH_TYPE input_count = int_to_varint(len(tx.TxIn)) output_count = int_to_varint(len(tx.TxOut)) output_block = b''.join([bytes(o) for o in tx.TxOut]) hashPrevouts = double_sha256(b''.join([i.txid+i.txindex for i in tx.TxIn])) hashSequence = double_sha256(b''.join([i.sequence for i in tx.TxIn])) hashOutputs = double_sha256(output_block) for i in sign_inputs: tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex segwit_input = input_dict[tx_input]['segwit'] tx.TxIn[i].segwit_input = segwit_input public_key = private_key.public_key public_key_push = script_push(len(public_key)) script_code = private_key.scriptcode script_code_len = int_to_varint(len(script_code)) if not segwit_input: hashed = sha256( version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx.TxIn, i)) + tx.TxIn[i].txid + tx.TxIn[i].txindex + script_code_len + script_code + tx.TxIn[i].sequence + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx.TxIn, i + 1, None)) + output_count + output_block + lock_time + hash_type ) input_script_field = tx.TxIn[i].script_sig elif segwit_input: try: tx.TxIn[i].amount = input_dict[tx_input]['amount']\ .to_bytes(8, byteorder='little') except Attributerror: raise ValueError( 'Cannot sign a segwit input when the input\'s amount is ' 'unknown. Maybe no network connection or the input is ' 'already spent? Then please provide all inputs to sign as ' '`Unspent` objects to the function call.') hashed = sha256( # BIP-143: Used for Segwit version + hashPrevouts + hashSequence + tx.TxIn[i].txid + tx.TxIn[i].txindex + script_code_len + script_code + tx.TxIn[i].amount + tx.TxIn[i].sequence + hashOutputs + lock_time + hash_type ) input_script_field = tx.TxIn[i].witness signature = private_key.sign(hashed) + b'\x01' # ------------------------------------------------------------------ if (private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet'): # P2(W)SH input script_blob = b'' sigs = {} # Initial number of witness items (OP_0 + one signature + redeemscript). witness_count = 3 if input_script_field: sig_list = get_signatures_from_script(input_script_field) # Bitcoin Core convention: Every missing signature is denoted # by 0x00. Only used for already partially-signed scriptSigs: script_blob += b'\x00' * (private_key.m - len(sig_list)-1) # Total number of witness items when partially or fully signed: witness_count = private_key.m + 2 # For a partially signed input make a dictionary containing # all the provided signatures with public-keys as keys: for sig in sig_list: for pub in private_key.public_keys: if verify_sig(sig[:-1], hashed, hex_to_bytes(pub)): # If we already found a valid signature for pubkey # we just overwrite it and don't care. sigs[pub] = sig if len(sigs) == private_key.m: raise TypeError('Transaction is already signed with ' 'sufficiently needed signatures.') elif len(sigs) > private_key.m: raise TypeError('Transaction already contains {} ' 'signatures, but only {} needed.').format( len(sigs), private_key.m) sigs[bytes_to_hex(public_key)] = signature witness = b'' # Sort ingthe signatures according to the public-key list: for pub in private_key.public_keys: if pub in sigs: sig = sigs[pub] length = int_to_varint(len(sig)) if segwit_input else \ script_push(len(sig)) witness += length + sig script_sig = b'\x22' + private_key.segwit_scriptcode witness = (int_to_varint(witness_count) if segwit_input else b'') \ + b'\x00' + witness + script_blob witness += (int_to_varint(len(private_key.redeemscript)) if segwit_input else script_push(len(private_key.redeemscript))) \ + private_key.redeemscript script_sig = script_sig if segwit_input else witness witness = witness if segwit_input else b'\x00' if segwit_tx else b'' # ------------------------------------------------------------------ else: # P2(W)PKH input script_sig = b'\x16' + private_key.segwit_scriptcode witness = ( (b'\x02' if segwit_input else b'') + # witness counter len(signature).to_bytes(1, byteorder='little') + signature + public_key_push + public_key ) script_sig = script_sig if segwit_input else witness witness = witness if segwit_input else b'\x00' if segwit_tx else b'' # Providing the signature(s) to the input tx.TxIn[i].script_sig = script_sig tx.TxIn[i].script_sig_len = int_to_varint(len(script_sig)) tx.TxIn[i].witness = witness return tx.to_hex()
def test_message(self): assert construct_output_block(OUTPUTS + MESSAGES) == hex_to_bytes( OUTPUT_BLOCK_MESSAGES)
def sign_tx(private_key, tx, *, unspents): """Signs inputs in provided transaction object for which unspents are provided and can be signed by the private key. :param private_key: Private key :type private_key: ``PrivateKey`` or ``MultiSig`` :param tx: Transaction object :type tx: ``TxObj`` :param unspents: For inputs to be signed their corresponding Unspent objects must be provided. :type unspents: ``list`` of :class:`~bit.network.meta.Unspent` :returns: The signed transaction as hex. :rtype: ``str`` """ # input_dict contains those unspents that can be signed by private_key, # providing additional information for segwit-inputs (the amount to spend) input_dict = {} try: for unspent in unspents: if not private_key.can_sign_unspent(unspent): continue tx_input = hex_to_bytes( unspent.txid)[::-1] + unspent.txindex.to_bytes( 4, byteorder='little') input_dict[tx_input] = unspent.to_dict() except TypeError: raise TypeError( 'Please provide as unspents at least all inputs to be signed with the function call in a list.' ) # Determine input indices to sign from input_dict (allows for transaction batching) sign_inputs = [ j for j, i in enumerate(tx.TxIn) if i.txid + i.txindex in input_dict ] segwit_tx = TxObj.is_segwit(tx) public_key = private_key.public_key public_key_push = script_push(len(public_key)) hash_type = HASH_TYPE # Make input parameters for preimage calculation inputs_parameters = [] # The TxObj in `tx` will below be modified to contain the scriptCodes used # for the transaction structure to be signed # `input_script_field` copies the scriptSigs for partially signed # transactions to later extract signatures from it: input_script_field = [tx.TxIn[i].script_sig for i in range(len(tx.TxIn))] for i in sign_inputs: # Create transaction object for preimage calculation tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex segwit_input = input_dict[tx_input]['segwit'] tx.TxIn[i].segwit_input = segwit_input script_code = private_key.scriptcode script_code_len = int_to_varint(len(script_code)) # Use scriptCode for preimage calculation of transaction object: tx.TxIn[i].script_sig = script_code tx.TxIn[i].script_sig_len = script_code_len if segwit_input: try: tx.TxIn[i].script_sig += input_dict[tx_input][ 'amount'].to_bytes(8, byteorder='little') # For partially signed Segwit transactions the signatures must # be extracted from the witnessScript field: input_script_field[i] = tx.TxIn[i].witness except AttributeError: raise ValueError( 'Cannot sign a segwit input when the input\'s amount is ' 'unknown. Maybe no network connection or the input is ' 'already spent? Then please provide all inputs to sign as ' '`Unspent` objects to the function call.') inputs_parameters.append([i, hash_type, segwit_input]) preimages = calculate_preimages(tx, inputs_parameters) # Calculate signature scripts: for hash, (i, _, segwit_input) in zip(preimages, inputs_parameters): signature = private_key.sign(hash) + b'\x01' # ------------------------------------------------------------------ if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet': # P2(W)SH input script_blob = b'' sigs = {} # Initial number of witness items (OP_0 + one signature + redeemscript). witness_count = 3 if input_script_field[i]: sig_list = get_signatures_from_script(input_script_field[i]) # Bitcoin Core convention: Every missing signature is denoted # by 0x00. Only used for already partially-signed scriptSigs: script_blob += b'\x00' * (private_key.m - len(sig_list) - 1) # Total number of witness items when partially or fully signed: witness_count = private_key.m + 2 # For a partially signed input make a dictionary containing # all the provided signatures with public-keys as keys: for sig in sig_list: for pub in private_key.public_keys: if verify_sig(sig[:-1], hash, pub): # If we already found a valid signature for pubkey # we just overwrite it and don't care. sigs[pub] = sig if len(sigs) >= private_key.m: raise ValueError( 'Transaction is already signed with sufficiently needed signatures.' ) sigs[public_key] = signature witness = b'' # Sort ingthe signatures according to the public-key list: for pub in private_key.public_keys: if pub in sigs: sig = sigs[pub] length = int_to_varint( len(sig)) if segwit_input else script_push(len(sig)) witness += length + sig script_sig = b'\x22' + private_key.segwit_scriptcode witness = (int_to_varint(witness_count) if segwit_input else b'') + b'\x00' + witness + script_blob witness += (int_to_varint(len( private_key.redeemscript)) if segwit_input else script_push( len(private_key.redeemscript))) + private_key.redeemscript script_sig = script_sig if segwit_input else witness witness = witness if segwit_input else b'\x00' if segwit_tx else b'' # ------------------------------------------------------------------ else: # P2(W)PKH input script_sig = b'\x16' + private_key.segwit_scriptcode witness = ((b'\x02' if segwit_input else b'') + len(signature).to_bytes( 1, byteorder='little') # witness counter + signature + public_key_push + public_key) script_sig = script_sig if segwit_input else witness witness = witness if segwit_input else b'\x00' if segwit_tx else b'' # Providing the signature(s) to the input tx.TxIn[i].script_sig = script_sig tx.TxIn[i].script_sig_len = int_to_varint(len(script_sig)) tx.TxIn[i].witness = witness return tx.to_hex()
def sign_tx( private_key, tx, j=-1 ): # Future-TODO: add sw_dict to allow override of segwit input dictionary? # j is the input to be signed and can be a single index, a list of indices, or denote all inputs (-1) if not isinstance(tx, TxObj): # Add sw_dict containing unspent segwit txid:txindex and amount to deserialize tx: sw_dict = {} unspents = private_key.unspents for u in unspents: if u.segwit: tx_input = u.txid + ':' + str(u.txindex) sw_dict[tx_input] = u.amount tx = deserialize(tx, sw_dict, private_key.sw_scriptcode) version = tx.version marker = b'\x00' flag = b'\x01' lock_time = tx.locktime hash_type = HASH_TYPE input_count = int_to_varint(tx.input_count) output_count = int_to_varint(tx.output_count) output_block = b'' for i in range(tx.output_count): output_block += tx.TxOut[i].value output_block += tx.TxOut[i].script_len output_block += tx.TxOut[i].script hashPrevouts = double_sha256(b''.join( [i.txid + i.txindex for i in tx.TxIn])) hashSequence = double_sha256(b''.join([i.sequence for i in tx.TxIn])) hashOutputs = double_sha256(b''.join([bytes(o) for o in tx.TxOut])) if j < 0: # Sign all inputs j = range(len(tx.TxIn)) elif not isinstance(j, list): # Sign a single input j = [j] segwit = False # Global check if at least one input is segwit for i in j: # Check if input is segwit or non-segwit: sw = tx.TxIn[i].segwit segwit = segwit or sw # Global check if at least one input is segwit => Transaction must be of segwit-format public_key = private_key.public_key public_key_len = script_push(len(public_key)) scriptCode = private_key.scriptcode scriptCode_len = int_to_varint(len(scriptCode)) if sw == False: hashed = sha256(version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx.TxIn, i)) + tx.TxIn[i].txid + tx.TxIn[i].txindex + scriptCode_len + scriptCode + tx.TxIn[i].sequence + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx.TxIn, i + 1, None)) + output_count + output_block + lock_time + hash_type) input_script_field = tx.TxIn[i].script else: hashed = sha256( # BIP-143: Used for Segwit version + hashPrevouts + hashSequence + tx.TxIn[i].txid + tx.TxIn[i].txindex + scriptCode_len + scriptCode + tx.TxIn[i].amount + tx.TxIn[i].sequence + hashOutputs + lock_time + hash_type) input_script_field = tx.TxIn[i].witness signature = private_key.sign(hashed) + b'\x01' # ------------------------------------------------------------------ if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet': # P2(W)SH input script_blob = b'' sigs = {} if input_script_field: # If tx is already partially signed: Make a dictionary of the provided signatures with public-keys as key-values sig_list = get_signatures_from_script(input_script_field) if len(sig_list) > private_key.m: raise TypeError( 'Transaction is already signed with {} of {} needed signatures.' ).format(len(sig_list), private_key.m) for sig in sig_list: for pub in private_key.public_keys: if verify_sig(sig[:-1], hashed, hex_to_bytes(pub)): sigs[pub] = sig script_blob += b'\x00' * ( private_key.m - len(sig_list) - 1 ) # Bitcoin Core convention: Every missing signature is denoted by 0x00. Only used for already partially-signed scriptSigs. sigs[bytes_to_hex(public_key)] = signature witness = b'' witness_count = 2 # count number of witness items (OP_0 + each signature + redeemscript). for pub in private_key.public_keys: # Sort the signatures according to the public-key list: if pub in sigs: sig = sigs[pub] length = int_to_varint( len(sig)) if sw == True else script_push(len(sig)) witness += length + sig witness_count += 1 script_sig = b'\x22' + private_key.sw_scriptcode witness = (witness_count.to_bytes(1, byteorder='little') if sw == True else b'') + b'\x00' + witness + script_blob witness += (int_to_varint(len( private_key.redeemscript)) if sw == True else script_push( len(private_key.redeemscript))) + private_key.redeemscript script_sig = witness if sw == False else script_sig witness = b'\x00' if sw == False else witness # ------------------------------------------------------------------ else: # P2(W)PKH input script_sig = b'\x16' + private_key.sw_scriptcode witness = ((b'\x02' if sw == True else b'') + # witness counter len(signature).to_bytes(1, byteorder='little') + signature + public_key_len + public_key) script_sig = witness if sw == False else script_sig witness = b'\x00' if sw == False else witness tx.TxIn[i].script = script_sig tx.TxIn[i].script_len = int_to_varint(len(script_sig)) tx.TxIn[i].witness = witness return bytes_to_hex( version + (marker if segwit == True else b'') + (flag if segwit == True else b'') + input_count + construct_input_block(tx.TxIn) + output_count + output_block + (construct_witness_block(tx.TxIn) if segwit == True else b'') + lock_time)
def deserialize(txhex, sw_dict={}, sw_scriptcode=None): # sw_dict is a dictionary containing segwit-inputs' txid concatenated with txindex using ":" mapping to information of the amount the input contains. # E.g.: sw_dict = {'txid:txindex': amount, ...} if isinstance(txhex, str) and re.match('^[0-9a-fA-F]*$', txhex): return deserialize(hex_to_bytes(txhex), sw_dict, sw_scriptcode) if txhex[ 4: 6] == b'\x00\x01': # ``marker|flag'' == 0001 if segwit-transaction segwit = True else: segwit = False pos = [0] def read_as_int(bytez): pos[0] += bytez return int(bytes_to_hex(txhex[pos[0] - bytez:pos[0]][::-1]), base=16) def read_var_int(): pos[0] += 1 val = int(bytes_to_hex(txhex[pos[0] - 1:pos[0]]), base=16) if val < 253: return val return read_as_int(pow(2, val - 252)) def read_bytes(bytez): pos[0] += bytez return txhex[pos[0] - bytez:pos[0]] def read_var_string(): size = read_var_int() return read_bytes(size) def read_segwit_string(): size = read_var_int() return int_to_varint(size) + read_bytes(size) version = read_as_int(4).to_bytes(4, byteorder='little') if segwit: _ = read_as_int(1).to_bytes(1, byteorder='little') # ``marker`` is read _ = read_as_int(1).to_bytes(1, byteorder='little') # ``flag`` is read ins = read_var_int() inputs = [] for i in range(ins): txid = read_bytes(32) txindex = read_as_int(4).to_bytes(4, byteorder='little') script = read_var_string() sequence = read_as_int(4).to_bytes(4, byteorder='little') # Check if input is segwit: tx_input = bytes_to_hex(txid) + ':' + bytes_to_hex(txindex) sw = True if ( sw_scriptcode == script[1:] or tx_input in sw_dict ) else False # Partially-signed segwit-multisig input or input provided in sw_dict. amount = sw_dict[ tx_input] if tx_input in sw_dict else 0 # Read ``amount`` from sw_dict if it is provided. inputs.append(TxIn(script, txid, txindex, b'', amount, sequence, sw)) outs = read_var_int() outputs = [] for _ in range(outs): value = read_as_int(8).to_bytes(8, byteorder='little') script = read_var_string() outputs.append(TxOut(value, script)) if segwit: for i in range(ins): wnum = read_var_int() witness = int_to_varint(wnum) for _ in range(wnum): witness += read_segwit_string() inputs[i].witness = witness locktime = read_as_int(4).to_bytes(4, byteorder='little') txobj = TxObj(version, inputs, outputs, locktime) return txobj
def test_no_message(self): assert construct_output_block(OUTPUTS) == hex_to_bytes(OUTPUT_BLOCK)
def test_int(intk, debug=False, do_endian=True, do_ops=True): if do_ops: test_with_prime21e_ops(intk) if do_endian: n = int(intk) n2 = int.from_bytes(n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0', byteorder='little') #print(n, '->', n2) test_int(n2, do_endian=False, do_ops=False) # concat PRIME21E n3 = str(intk) + str(PRIME21E) n4 = str(PRIME21E) + str(intk) test_int(n3, do_endian=False, do_ops=False) test_int(n4, do_endian=False, do_ops=False) #test_int(struct.pack('>L', int(intk))) if int(intk) == 0 or int( intk ) > 115792089237316195423570985008687907852837564279074904382605163141518161494337: return 'invalid size' try: sha_hex = to_hex(intk) sha_key = right_pad_zed(sha_hex) #print(len(sha_key), sha_hex, '->', sha_key) sha_key_compressed = Key.from_hex(sha_key) sha_key_uncompressed = uncompressed_key(sha_key_compressed) priv_key_compressed = Key.from_int(int(intk)) priv_key_uncompressed = uncompressed_key(priv_key_compressed) #priv_key_compressed2 = compressed_key(int(intk)) priv_key_compressed2 = compressed_key(priv_key_compressed) #int(intk)) priv_key_compressed3 = Key.from_int(int(intk) & PRIME21E) priv_key_c2 = Key.from_bytes( b58decode( b58encode(utils.hex_to_bytes(utils.int_to_hex(int(intk)))))) priv_key_uc2 = uncompressed_key(priv_key_c2) except Exception as err: print("ERROR: test_int:", err, 'intk:', intk) traceback.print_exc(file=sys.stdout) return False """Debug: print('addrc:{} addru:{} wifc:{} wifu:{}'.format( priv_key_compressed.address, priv_key_uncompressed.address, priv_key_compressed.to_wif(), priv_key_uncompressed.to_wif(), )) """ if debug: print( intk, priv_key_compressed.address, priv_key_uncompressed.address, bytes_to_hex(priv_key_compressed.public_key), bytes_to_hex(priv_key_uncompressed.public_key), ) if test_key(sha_key_compressed): return True if test_key(sha_key_uncompressed): return True if test_key(priv_key_compressed3): return True if test_key(priv_key_compressed): return True if test_key(priv_key_compressed2): return True if test_key(priv_key_uncompressed): return True if test_key(priv_key_uc2): return True if test_key(priv_key_c2): return True return False
def test_construct_input_block(): assert construct_input_block(INPUTS) == hex_to_bytes(INPUT_BLOCK)
def is_segwit(cls, tx): if isinstance(tx, cls): return tx.marker + tx.flag == MARKER + FLAG elif not isinstance(tx, bytes): tx = hex_to_bytes(tx) return tx[4:6] == MARKER + FLAG