Ejemplo n.º 1
0
def disassemble_scripts(input_script, output_script, lock_time, signature_for_hash_type_f):
    "yield pre_annotations, pc, opcode, instruction, post_annotations"

    input_annotations_f, output_annotations_f = annotation_f_for_scripts(
        input_script, output_script, signature_for_hash_type_f)
    pc = 0
    while pc < len(input_script):
        opcode, data, new_pc = get_opcode(input_script, pc)
        pre_annotations, post_annotations = input_annotations_f(pc, opcode, data)
        yield pre_annotations, pc, opcode, instruction_for_opcode(opcode, data), post_annotations
        pc = new_pc

    pc = 0
    while pc < len(output_script):
        opcode, data, new_pc = get_opcode(output_script, pc)
        pre_annotations, post_annotations = output_annotations_f(pc, opcode, data)
        yield pre_annotations, pc, opcode, instruction_for_opcode(opcode, data), post_annotations
        pc = new_pc

    if not is_pay_to_script_hash(output_script):
        return

    stack = []
    eval_script(input_script, signature_for_hash_type_f, lock_time, expected_hash_type=None, stack=stack)
    if stack:
        signatures, new_output_script = stack[:-1], stack[-1]
        new_input_script = bin_script(signatures)
    else:
        signatures, new_output_script, new_input_script = [], b'', b''

    for r in disassemble_scripts(new_input_script, new_output_script, lock_time, signature_for_hash_type_f):
        yield r
Ejemplo n.º 2
0
    def match_script_to_templates(self):
        """Examine the script passed in by tx_out_script and see if it
        matches the form of one of the templates in TEMPLATES. If so,
        return the form it matches; otherwise, return None."""
        
        for script2 in TxScript.TEMPLATES:       
            r = []
            pc1 = pc2 = 0
            while 1:  

                if pc1 == len(self.script) and pc2 == len(script2):
                    return r
               
                opcode1, data1, pc1 = tools.get_opcode(self.script, pc1)            
                opcode2, data2, pc2 = tools.get_opcode(script2, pc2)           

                if opcode2 == opcodes.OP_PUBKEY:
                    l1 = len(data1)
                    if l1 < 33 or l1 > 120:
                        break
                    r.append((opcode2, data1))
                elif opcode2 == opcodes.OP_PUBKEYHASH:
                    if len(data1) != 160/8:
                        break
                    r.append((opcode2, data1))
                elif (opcode1, data1) != (opcode2, data2):
                    break
        raise SolvingError("don't recognize output script")
Ejemplo n.º 3
0
    def solve_finalize_commit(self, **kwargs):
        hash160_lookup = kwargs.get("hash160_lookup")
        sign_value = kwargs.get("sign_value")
        signature_type = kwargs.get("signature_type")
        existing_script = kwargs.get("existing_script")

        # FIXME validate on receiving the commit
        # validate payer sig
        opcode, data, pc = tools.get_opcode(existing_script, 0)  # OP_0
        opcode, payer_sig, pc = tools.get_opcode(existing_script, pc)
        sig_pair, actual_signature_type = parse_signature_blob(payer_sig)
        try:
            public_pair = encoding.sec_to_public_pair(self.payer_sec)
            sig_pair, signature_type = parse_signature_blob(payer_sig)
            valid = ecdsa.verify(ecdsa.generator_secp256k1, public_pair,
                                 sign_value, sig_pair)
            if not valid:
                raise Exception("Invalid payer public_pair!")
        except (encoding.EncodingError, UnexpectedDER):
            raise Exception("Invalid payer public_pair!")

        # sign
        private_key = hash160_lookup.get(encoding.hash160(self.payee_sec))
        secret_exponent, public_pair, compressed = private_key
        payee_sig = self._create_script_signature(
            secret_exponent, sign_value, signature_type
        )

        script_text = "OP_0 {payer_sig} {payee_sig} OP_1".format(
            payer_sig=b2h(payer_sig), payee_sig=b2h(payee_sig)
        )
        return tools.compile(script_text)
Ejemplo n.º 4
0
    def match_script_to_templates(self):
        """Examine the script passed in by tx_out_script and see if it
        matches the form of one of the templates in TEMPLATES. If so,
        return the form it matches; otherwise, return None."""

        for script2 in TxScript.TEMPLATES:
            r = []
            pc1 = pc2 = 0
            while 1:

                if pc1 == len(self.script) and pc2 == len(script2):
                    return r

                opcode1, data1, pc1 = tools.get_opcode(self.script, pc1)
                opcode2, data2, pc2 = tools.get_opcode(script2, pc2)

                if opcode2 == opcodes.OP_PUBKEY:
                    l1 = len(data1)
                    if l1 < 33 or l1 > 120:
                        break
                    r.append((opcode2, data1))
                elif opcode2 == opcodes.OP_PUBKEYHASH:
                    if len(data1) != 160 / 8:
                        break
                    r.append((opcode2, data1))
                elif (opcode1, data1) != (opcode2, data2):
                    break
        raise SolvingError("don't recognize output script")
Ejemplo n.º 5
0
def get_nulldata(tx):
    index, out = _get_nulldata_output(tx)
    if not out:
        raise exceptions.NoNulldataOutput(tx)
    opcode, data, pc = tools.get_opcode(out.script, 0)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    return index, data
Ejemplo n.º 6
0
def get_nulldata(tx):
    index, out = _get_nulldata_output(tx)
    if not out:
        raise exceptions.NoNulldataOutput(tx)
    opcode, data, pc = tools.get_opcode(out.script, 0)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    return index, data
Ejemplo n.º 7
0
def _validate(reference_script_hex, untrusted_script_hex):
    ref_script_bin = h2b(reference_script_hex)
    untrusted_script_bin = h2b(untrusted_script_hex)
    r_pc = 0
    u_pc = 0
    while r_pc < len(ref_script_bin) and u_pc < len(untrusted_script_bin):
        r_opcode, r_data, r_pc = tools.get_opcode(ref_script_bin, r_pc)
        u_opcode, u_data, u_pc = tools.get_opcode(untrusted_script_bin, u_pc)
        if r_data is not None and b2h(r_data) == "deadbeef":
            continue  # placeholder for expected variable
        if r_opcode != u_opcode or r_data != u_data:
            raise InvalidScript(b2h(untrusted_script_bin))
    if r_pc != len(ref_script_bin) or u_pc != len(untrusted_script_bin):
        raise InvalidScript(b2h(untrusted_script_bin))
Ejemplo n.º 8
0
def get_word(script_bin, index):
    pc = 0
    i = 0
    while pc < len(script_bin) and i <= index:
        opcode, data, pc = tools.get_opcode(script_bin, pc)
        i += 1
    if i != index + 1:
        raise ValueError(index)
    return opcode, data, tools.disassemble_for_opcode_data(opcode, data)
Ejemplo n.º 9
0
def get_word(script, index):
    pc = 0
    i = 0
    while pc < len(script) and i <= index:
        opcode, data, pc = tools.get_opcode(script, pc)
        i += 1
    if i != index + 1:
        raise ValueError(index)
    return opcode, data, tools.disassemble_for_opcode_data(opcode, data)
Ejemplo n.º 10
0
    def solve_finalize_commit(self, **kwargs):
        hash160_lookup = kwargs.get("hash160_lookup")
        signature_type = kwargs.get("signature_type")
        existing_script = kwargs.get("existing_script")

        # validate existing script
        reference_script_hex = _compile_commit_scriptsig(
            "deadbeef", "deadbeef", b2h(self.script))
        _validate(reference_script_hex, b2h(existing_script))

        # check provided payer signature
        try:
            opcode, data, pc = tools.get_opcode(existing_script, 0)  # OP_0
            opcode, payer_sig, pc = tools.get_opcode(existing_script, pc)

            # verify signature type
            sig_r_s, actual_signature_type = parse_signature_blob(payer_sig)
            assert (signature_type == actual_signature_type)

            # verify payer signature
            public_pair = encoding.sec_to_public_pair(self.payer_sec)
            sign_value = kwargs.get("sign_value")

            public_pair = encoding.sec_to_public_pair(self.payer_sec)
            sign_value = kwargs["signature_for_hash_type_f"](
                signature_type, kwargs["script_to_hash"])

            if not ecdsa.verify(ecdsa.generator_secp256k1, public_pair,
                                sign_value, sig_r_s):
                raise InvalidPayerSignature("invalid r s values")
        except UnexpectedDER:
            raise InvalidPayerSignature("not in DER format")

        # sign
        private_key = hash160_lookup.get(encoding.hash160(self.payee_sec))
        secret_exponent, public_pair, compressed = private_key
        payee_sig = self._create_sig(secret_exponent, **kwargs)

        script_asm = COMMIT_SCRIPTSIG.format(payer_sig=b2h(payer_sig),
                                             payee_sig=b2h(payee_sig))
        return tools.compile(script_asm)
Ejemplo n.º 11
0
def who_signed_tx(tx, tx_in_idx, netcode='BTC'):
    """
    Given a transaction (tx) an input index (tx_in_idx), attempt to figure
    out which addresses where used in signing (so far). This method
    depends on tx.unspents being properly configured. This should work on
    partially-signed MULTISIG transactions (it will return as many
    addresses as there are good signatures).
    Returns a list of ( address, sig_type ) pairs.
    Raises NoAddressesForScriptTypeError if addresses cannot be determined
    for the input's script.
    TODO: This does not yet support P2SH.
    """
    tx_in = tx.txs_in[tx_in_idx]
    parent_tx_out_idx = tx_in.previous_index
    parent_tx_out_script = tx.unspents[tx_in_idx].script
    script_obj = script_obj_from_script(parent_tx_out_script)
    signed_by = []

    if type(script_obj) not in (ScriptPayToAddress, ScriptPayToPublicKey,
                                ScriptMultisig):
        raise NoAddressesForScriptTypeError(
            'unable to determine signing addresses for script type of parent tx {}[{}]'
            .format(b2h_rev(tx_in.previous_hash), parent_tx_out_idx))

    script = tx_in.script
    pc = 0
    while pc < len(script):
        opcode, data, pc = get_opcode(script, pc)
        if data is None:
            continue
        try:
            sig_pair, sig_type = parse_signature_blob(data)
        except (ValueError, TypeError, binascii.Error, UnexpectedDER):
            continue

        sig_hash = tx.signature_hash(parent_tx_out_script, parent_tx_out_idx,
                                     sig_type)

        for sec_key in script_obj.sec_keys:
            public_pair = sec_to_public_pair(sec_key)

            if ecdsa_verify(generator_secp256k1, public_pair, sig_hash,
                            sig_pair):
                addr_pfx = address_prefix_for_netcode(netcode)
                addr = public_pair_to_bitcoin_address(public_pair,
                                                      address_prefix=addr_pfx)
                signed_by.append((addr, sig_type))
    return signed_by
Ejemplo n.º 12
0
def who_signed_tx(tx, tx_in_idx, netcode='BTC'):
    """
    Given a transaction (tx) an input index (tx_in_idx), attempt to figure
    out which addresses where used in signing (so far). This method
    depends on tx.unspents being properly configured. This should work on
    partially-signed MULTISIG transactions (it will return as many
    addresses as there are good signatures).
    Returns a list of ( address, sig_type ) pairs.
    Raises NoAddressesForScriptTypeError if addresses cannot be determined
    for the input's script.
    TODO: This does not yet support P2SH.
    """
    tx_in = tx.txs_in[tx_in_idx]
    parent_tx_out_idx = tx_in.previous_index
    parent_tx_out_script = tx.unspents[tx_in_idx].script
    script_obj = script_obj_from_script(parent_tx_out_script)
    signed_by = []

    if type(script_obj) not in (ScriptPayToAddress, ScriptPayToPublicKey, ScriptMultisig):
        raise NoAddressesForScriptTypeError(
            'unable to determine signing addresses for script type of parent tx {}[{}]'
            .format(b2h_rev(tx_in.previous_hash), parent_tx_out_idx))

    script = tx_in.script
    pc = 0
    while pc < len(script):
        opcode, data, pc = get_opcode(script, pc)
        if data is None:
            continue
        try:
            sig_pair, sig_type = parse_signature_blob(data)
        except (ValueError, TypeError, binascii.Error, UnexpectedDER):
            continue

        sig_hash = tx.signature_hash(parent_tx_out_script, parent_tx_out_idx, sig_type)

        for sec_key in script_obj.sec_keys:
            public_pair = sec_to_public_pair(sec_key)

            if ecdsa_verify(generator_secp256k1, public_pair, sig_hash, sig_pair):
                addr_pfx = address_prefix_for_netcode(netcode)
                addr = public_pair_to_bitcoin_address(public_pair, address_prefix=addr_pfx)
                signed_by.append((addr, sig_type))
    return signed_by
Ejemplo n.º 13
0
def extract_msg(script):
    msg_hex = unhexlify(script['hex'])
    opcode, msg, _ = tools.get_opcode(msg_hex, 1)
    if 0x51 <= opcode and opcode <= 0x60:
        msg = bytes(chr(opcode - 0x50), 'utf-8')
    return msg
Ejemplo n.º 14
0
def solve(self, **kwargs):
    """
    The kwargs required depend upon the script type.
    hash160_lookup:
        dict-like structure that returns a secret exponent for a hash160
    existing_script:
        existing solution to improve upon (optional)
    sign_value:
        the integer value to sign (derived from the transaction hash)
    signature_type:
        usually SIGHASH_ALL (1)
    """
    # we need a hash160 => secret_exponent lookup
    db = kwargs.get("hash160_lookup")
    if db is None:
        raise SolvingError("missing hash160_lookup parameter")

    sign_value = kwargs.get("sign_value")
    signature_type = kwargs.get("signature_type")

    secs_solved = set()
    existing_signatures = []
    existing_script = kwargs.get("existing_script")
    if existing_script:
        pc = 0
        opcode, data, pc = tools.get_opcode(existing_script, pc)
        # ignore the first opcode
        while pc < len(existing_script):
            opcode, data, pc = tools.get_opcode(existing_script, pc)
            sig_pair, actual_signature_type = parse_signature_blob(data)
            for sec_key in self.sec_keys:
                try:
                    public_pair = encoding.sec_to_public_pair(sec_key)
                    sig_pair, signature_type = parse_signature_blob(data)
                    v = ecdsa.verify(ecdsa.generator_secp256k1, public_pair, sign_value, sig_pair)
                    if v:
                        existing_signatures.append(data)
                        secs_solved.add(sec_key)
                        break
                except encoding.EncodingError:
                    # if public_pair is invalid, we just ignore it
                    pass

    for sec_key in self.sec_keys:
        if sec_key in secs_solved:
            continue
        if len(existing_signatures) >= self.n:
            break
        hash160 = encoding.hash160(sec_key)
        result = db.get(hash160)
        if result is None:
            continue
        secret_exponent, public_pair, compressed = result
        binary_signature = self._create_script_signature(secret_exponent, sign_value, signature_type)
        existing_signatures.append(b2h(binary_signature))
    DUMMY_SIGNATURE = "OP_0"
    while len(existing_signatures) < self.n:
        existing_signatures.append(DUMMY_SIGNATURE)

    script = "OP_0 %s" % " ".join(s for s in existing_signatures)
    solution = tools.compile(script)
    return solution
Ejemplo n.º 15
0
def get_hash160_data(tx, output_index):
    out = tx.txs_out[output_index]
    opcode, data, pc = tools.get_opcode(out.script, 0)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    return data
Ejemplo n.º 16
0
def solve(self, **kwargs):
    """
    The kwargs required depend upon the script type.
    hash160_lookup:
        dict-like structure that returns a secret exponent for a hash160
    existing_script:
        existing solution to improve upon (optional)
    sign_value:
        the integer value to sign (derived from the transaction hash)
    signature_type:
        usually SIGHASH_ALL (1)
    """
    # we need a hash160 => secret_exponent lookup
    db = kwargs.get("hash160_lookup")
    if db is None:
        raise SolvingError("missing hash160_lookup parameter")

    sign_value = kwargs.get("sign_value")
    signature_type = kwargs.get("signature_type")

    secs_solved = set()
    existing_signatures = []
    existing_script = kwargs.get("existing_script")
    if existing_script:
        pc = 0
        opcode, data, pc = tools.get_opcode(existing_script, pc)
        # ignore the first opcode
        while pc < len(existing_script):
            opcode, data, pc = tools.get_opcode(existing_script, pc)
            sig_pair, actual_signature_type = parse_signature_blob(data)
            for sec_key in self.sec_keys:
                try:
                    public_pair = encoding.sec_to_public_pair(sec_key)
                    sig_pair, signature_type = parse_signature_blob(data)
                    v = ecdsa.verify(ecdsa.generator_secp256k1, public_pair,
                                     sign_value, sig_pair)
                    if v:
                        existing_signatures.append(data)
                        secs_solved.add(sec_key)
                        break
                except encoding.EncodingError:
                    # if public_pair is invalid, we just ignore it
                    pass

    for sec_key in self.sec_keys:
        if sec_key in secs_solved:
            continue
        if len(existing_signatures) >= self.n:
            break
        hash160 = encoding.hash160(sec_key)
        result = db.get(hash160)
        if result is None:
            continue
        secret_exponent, public_pair, compressed = result
        binary_signature = self._create_script_signature(
            secret_exponent, sign_value, signature_type)
        existing_signatures.append(b2h(binary_signature))
    DUMMY_SIGNATURE = "OP_0"
    while len(existing_signatures) < self.n:
        existing_signatures.append(DUMMY_SIGNATURE)

    script = "OP_0 %s" % " ".join(s for s in existing_signatures)
    solution = tools.compile(script)
    return solution
Ejemplo n.º 17
0
def get_hash160_data(tx, output_index):
    out = tx.txs_out[output_index]
    opcode, data, pc = tools.get_opcode(out.script, 0)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    opcode, data, pc = tools.get_opcode(out.script, pc)
    return data
Ejemplo n.º 18
0
def extract_msg(script):
  msg_hex   = unhexlify(script['hex'])
  opcode, msg, _ = tools.get_opcode(msg_hex, 1)
  if 0x51 <= opcode and opcode <= 0x60:
    msg = bytes(chr(opcode - 0x50), 'utf-8')
  return msg