def calculate_preimages(tx_obj, inputs_parameters): """Calculates preimages for provided transaction structure and input values. :param tx_obj: The transaction object used to calculate preimage from using a transaction digest algorithm, such as BIP-143 for Segwit inputs. This transaction object must hence have scriptCodes filled into the corresponding scriptSigs in the inputs. :type tx_obj: :object:`~bit.transaction.TxObj` :param inputs_parameters: A list of tuples with input index as integer, hash type as integer and a boolean flag to denote if the input is spending from a Segwit output. For example: [(0, 1, True), (2, 1, False), (...)] :type inputs_parameters: A `list` of `tuple` """ # Tx object data: input_count = int_to_varint(len(tx_obj.TxIn)) output_count = int_to_varint(len(tx_obj.TxOut)) output_block = b''.join([bytes(o) for o in tx_obj.TxOut]) hashPrevouts = double_sha256(b''.join( [i.txid + i.txindex for i in tx_obj.TxIn])) hashSequence = double_sha256(b''.join([i.sequence for i in tx_obj.TxIn])) hashOutputs = double_sha256(output_block) preimages = [] for input_index, hash_type, segwit_input in inputs_parameters: # We can only handle hashType == 1: if hash_type != HASH_TYPE: raise ValueError('Bit only support hashType of value 1.') # Calculate prehashes: if segwit_input: # BIP-143 preimage: hashed = sha256( tx_obj.version + hashPrevouts + hashSequence + tx_obj.TxIn[input_index].txid + tx_obj.TxIn[input_index].txindex + tx_obj.TxIn[input_index].script_sig_len + tx_obj.TxIn[input_index].script_sig # scriptCode length + tx_obj.TxIn[input_index]. sequence # scriptCode (includes amount) + hashOutputs + tx_obj.locktime + hash_type) else: hashed = sha256( tx_obj.version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx_obj.TxIn, input_index)) + tx_obj.TxIn[input_index].txid + tx_obj.TxIn[input_index].txindex + tx_obj.TxIn[input_index].script_sig_len + tx_obj.TxIn[input_index].script_sig # scriptCode length + tx_obj.TxIn[input_index].sequence # scriptCode + b''.join( ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx_obj.TxIn, input_index + 1, None)) + output_count + output_block + tx_obj.locktime + hash_type) preimages.append(hashed) return preimages
def maybe(i, length): try: test_key( Key.from_bytes( double_sha256(i.to_bytes(length=length, byteorder='big')))) test_key( Key.from_bytes( double_sha256(i.to_bytes(length=length, byteorder='little')))) test_key( Key.from_bytes(sha256(i.to_bytes(length=length, byteorder='big')))) test_key( Key.from_bytes( sha256(i.to_bytes(length=length, byteorder='little')))) except Exception as err: print('ERROR: i={} length={}'.format(i, length)) pass
def multisig_to_segwit_address(public_keys, m, version='main'): if version == 'test': version = TEST_SCRIPT_HASH else: version = MAIN_SCRIPT_HASH return b58encode_check(version + ripemd160_sha256(b'\x00\x20' + sha256(multisig_to_redeemscript(public_keys, m))))
def test_scriptcode(self): key1 = PrivateKeyTestnet() key2 = PrivateKeyTestnet() multisig = MultiSigTestnet(key1, [key1.public_key, key2.public_key], 2) assert multisig.scriptcode == multisig.redeemscript assert multisig.segwit_scriptcode == (b'\x00' + b'\x20' + sha256(multisig.redeemscript))
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 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 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 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 sign_legacy_tx(private_key, tx, j=-1): # 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): tx = deserialize(tx) version = tx.version 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 inputs = tx.TxIn if j < 0: j = range(len(inputs)) elif not isinstance(j, list): j = [j] for i in j: 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)) hashed = sha256(version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(inputs, i)) + inputs[i].txid + inputs[i].txindex + scriptCode_len + scriptCode + inputs[i].sequence + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(inputs, i + 1, None)) + output_count + output_block + lock_time + hash_type) signature = private_key.sign(hashed) + b'\x01' # ------------------------------------------------------------------ if private_key.instance == 'MultiSig' or private_key.instance == 'MultiSigTestnet': script_blob = b'' sigs = {} if tx.TxIn[ i].script: # 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(tx.TxIn[i].script) 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 script_sig = b'' # P2SH - Multisig for pub in private_key.public_keys: # Sort the signatures according to the public-key list: if pub in sigs: sig = sigs[pub] length = script_push(len(sig)) script_sig += length + sig script_sig = b'\x00' + script_sig + script_blob script_sig += script_push(len( private_key.redeemscript)) + private_key.redeemscript # ------------------------------------------------------------------ else: script_sig = ( # P2PKH len(signature).to_bytes(1, byteorder='little') + signature + public_key_len + public_key) inputs[i].script = script_sig inputs[i].script_len = int_to_varint(len(script_sig)) return bytes_to_hex(version + input_count + construct_input_block(inputs) + output_count + output_block + lock_time)