Exemple #1
0
def make_ms_address(M, keys, idx=0, is_change=0, addr_fmt=AF_P2SH, testnet=1, **make_redeem_args):
    # Construct addr and script need to represent a p2sh address
    import bech32
    from pycoin.encoding import b2a_hashed_base58, hash160

    if 'path_mapper' not in make_redeem_args:
        make_redeem_args['path_mapper'] = lambda cosigner: [HARD(45), cosigner, is_change, idx]

    script, pubkeys, xfp_paths = make_redeem(M, keys, **make_redeem_args)

    if addr_fmt == AF_P2WSH:
        hrp = ['bc', 'tb'][testnet]
        data = sha256(script).digest()
        addr = bech32.encode(hrp, 0, data)
        scriptPubKey = bytes([0x0, 0x20]) + data
    else:
        if addr_fmt == AF_P2SH:
            digest = hash160(script)
        elif addr_fmt == AF_P2WSH_P2SH:
            digest = hash160(b'\x00\x20' + sha256(script).digest())
        else:
            raise ValueError(addr_fmt)

        prefix = bytes([196]) if testnet else bytes([5])
        addr = b2a_hashed_base58(prefix + digest)

        scriptPubKey = bytes([0xa9, 0x14]) + digest + bytes([0x87])

    return addr, scriptPubKey, script, zip(pubkeys, xfp_paths)
Exemple #2
0
    def doit(given_addr, path=None, addr_fmt=None, script=None):
        if not script:
            try:
                # prefer using xpub if we can
                mk = BIP32Node.from_wallet_key(master_xpub)
                sk = mk.subkey_for_path(path[2:])
            except PublicPrivateMismatchError:
                mk = BIP32Node.from_wallet_key(simulator_fixed_xprv)
                sk = mk.subkey_for_path(path[2:])


        if addr_fmt == AF_CLASSIC:
            # easy
            assert sk.address() == given_addr

        elif addr_fmt & AFC_PUBKEY:

            pkh = sk.hash160(use_uncompressed=False)

            if addr_fmt == AF_P2WPKH:
                hrp, data = bech32_decode(given_addr)
                decoded = convertbits(data[1:], 5, 8, False)
                assert hrp in {'tb', 'bc' }
                assert bytes(decoded[-20:]) == pkh
            else:
                assert addr_fmt == AF_P2WPKH_P2SH
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert len(expect) == 20
                assert hash160(b'\x00\x14' + pkh) == expect

        elif addr_fmt & AFC_SCRIPT:
            assert script, 'need a redeem/witness script'
            if addr_fmt == AF_P2SH:
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert hash160(script) == expect

            elif addr_fmt == AF_P2WSH:
                hrp, data = bech32_decode(given_addr)
                assert hrp in {'tb', 'bc' }
                decoded = convertbits(data[1:], 5, 8, False)
                assert bytes(decoded[-32:]) == sha256(script).digest()

            elif addr_fmt == AF_P2WSH_P2SH:
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert hash160(b'\x00\x20' + sha256(script).digest()) == expect

            else:
                raise pytest.fail(f'not ready for {addr_fmt:x} yet')
        else:
            raise ValueError(addr_fmt)

        return sk if not script else None
 def solve_change(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     spend_secret = kwargs["spend_secret"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_sig(secret_exponent, **kwargs)
     spend_secret_hash = get_deposit_spend_secret_hash(b2h(self.script))
     provided_spend_secret_hash = b2h(encoding.hash160(h2b(spend_secret)))
     assert (spend_secret_hash == provided_spend_secret_hash)
     script_asm = CHANGE_SCRIPTSIG.format(sig=b2h(sig), secret=spend_secret)
     return tools.compile(script_asm)
Exemple #4
0
def p2sh_address(key):
    """
    Function to convert the given private key to the P2SH key
    used to signify a SegWit address starting with '3'.

    This SegWit address is a <redeemScript>
    (https://bitcoincore.org/en/segwit_wallet_dev/#creation-of-p2sh-p2wpkh-address).

    It starts with a OP_0, followed by a canonical push of the keyhash 
    (i.e. 0x0014{20-byte keyhash}).
    """
    return b2a_hashed_base58(b'\5' +
                             hash160(b'\x00\x14' +
                                     hash160(key.sec(use_uncompressed=False))))
Exemple #5
0
 def solve_change(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     spend_secret = kwargs["spend_secret"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_script_signature(
         secret_exponent, kwargs["sign_value"], kwargs["signature_type"]
     )
     spend_secret_hash = get_deposit_spend_secret_hash(self.script)
     provided_spend_secret_hash = b2h(hash160(h2b(spend_secret)))
     assert(spend_secret_hash == provided_spend_secret_hash)
     script_text = "{sig} {secret} OP_1 OP_0".format(
         sig=b2h(sig), secret=spend_secret
     )
     return tools.compile(script_text)
Exemple #6
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)
Exemple #7
0
    def doit(given_addr, path, addr_fmt):
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])

        if addr_fmt == AF_CLASSIC:
            # easy
            assert sk.address() == given_addr

        elif addr_fmt & AFC_PUBKEY:

            pkh = sk.hash160(use_uncompressed=False)

            if addr_fmt == AF_P2WPKH:
                hrp, data = bech32_decode(given_addr)
                decoded = convertbits(data[1:], 5, 8, False)
                assert hrp in {'tb', 'bc'}
                assert bytes(decoded[-20:]) == pkh
            else:
                assert addr_fmt == AF_P2WPKH_P2SH
                assert given_addr[0] in '23'
                expect = a2b_hashed_base58(given_addr)[1:]
                assert len(expect) == 20
                assert hash160(b'\x00\x14' + pkh) == expect

        elif addr_fmt & AFC_SCRIPT:
            raise pytest.fail('multisig/p2sh addr not handled')
        else:
            raise ValueError(addr_fmt)
Exemple #8
0
def make_change_addr(wallet, style):
    # provide script, pubkey and xpath for a legit-looking change output
    import struct, random
    from pycoin.encoding import hash160

    redeem_scr, actual_scr = None, None
    deriv = [12, 34, random.randint(0, 1000)]

    xfp, = struct.unpack('I', wallet.fingerprint())

    dest = wallet.subkey_for_path('/'.join(str(i) for i in deriv))

    target = dest.hash160()
    assert len(target) == 20

    is_segwit = False
    if style == 'p2pkh':
        redeem_scr = bytes([0x76, 0xa9, 0x14]) + target + bytes([0x88, 0xac])
    elif style == 'p2wpkh':
        redeem_scr = bytes([0, 20]) + target
        is_segwit = True
    elif style == 'p2wpkh-p2sh':
        redeem_scr = bytes([0, 20]) + target
        actual_scr = bytes([0xa9, 0x14]) + hash160(redeem_scr) + bytes([0x87])
    else:
        raise ValueError('cant make fake change output of type: ' + style)

    return redeem_scr, actual_scr, is_segwit, dest.sec(), struct.pack(
        '4I', xfp, *deriv)
def address_for_pay_to_script(script, netcode=None):
    if netcode is None:
        netcode = get_current_netcode()
    address_prefix = pay_to_script_prefix_for_netcode(netcode)
    if address_prefix:
        return encoding.hash160_sec_to_bitcoin_address(
            encoding.hash160(script), address_prefix=address_prefix)
    return None
 def solve_revoke(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     revoke_secret = kwargs["revoke_secret"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_sig(secret_exponent, **kwargs)
     return tools.compile(
         REVOKE_SCRIPTSIG.format(sig=b2h(sig), revoke_secret=revoke_secret))
Exemple #11
0
 def solve_timeout(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_script_signature(
         secret_exponent, kwargs["sign_value"], kwargs["signature_type"]
     )
     return tools.compile("{sig} OP_0 OP_0".format(sig=b2h(sig)))
Exemple #12
0
 def sign_data(self, data, privKey):
     with self.lock:
         symbols_set = string.ascii_letters + string.digits
         salt = ''.join([random.choice(symbols_set) for _ in xrange(20)])
         data = int((hash160(str(data) + salt)).encode('hex'), 16)
         return {
             'salt': salt,
             'sign': ecdsa.sign(ecdsa.generator_secp256k1, privKey, data),
         }
Exemple #13
0
def build_p2sh_lookup(args):
    scripts, warnings = parse_scripts(args)
    for w in warnings:
        print(w)

    p2sh_lookup = {}
    for script in scripts:
        p2sh_lookup[hash160(script)] = script
    return p2sh_lookup
Exemple #14
0
def build_p2sh_lookup(args):
    scripts, warnings = parse_scripts(args)
    for w in warnings:
        print(w)

    p2sh_lookup = {}
    for script in scripts:
        p2sh_lookup[hash160(script)] = script
    return p2sh_lookup
Exemple #15
0
 def sign_data(self, data, privKey):
     with self.lock:
         symbols_set = string.ascii_letters + string.digits
         salt = ''.join([random.choice(symbols_set) for _ in xrange(20)])
         data = int((hash160(str(data) + salt)).encode('hex'), 16)
         return {
             'salt': salt,
             'sign': ecdsa.sign(ecdsa.generator_secp256k1, privKey, data),
         }
    def solve_payout(self, **kwargs):
        hash160_lookup = kwargs["hash160_lookup"]
        spend_secret = kwargs["spend_secret"]
        private_key = hash160_lookup.get(encoding.hash160(self.payee_sec))
        secret_exponent, public_pair, compressed = private_key

        sig = self._create_sig(secret_exponent, **kwargs)
        return tools.compile(
            PAYOUT_SCRIPTSIG.format(sig=b2h(sig), spend_secret=spend_secret))
 def solve_create_commit(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_sig(secret_exponent, **kwargs)
     signature_placeholder = kwargs.get("signature_placeholder",
                                        DEFAULT_PLACEHOLDER_SIGNATURE)
     script_asm = COMMIT_SCRIPTSIG.format(
         payer_sig=b2h(sig), payee_sig=b2h(signature_placeholder))
     return tools.compile(script_asm)
Exemple #18
0
    def hash160(self, use_uncompressed=None):
        """
        Return the hash160 representation of this key, if available.
        If use_uncompressed is not set, the preferred representation is returned.
        """
        use_uncompressed = self._use_uncompressed(use_uncompressed)
        if self.public_pair() is None:
            if use_uncompressed:
                return self._hash160_uncompressed
            return self._hash160_compressed

        if use_uncompressed:
            if self._hash160_uncompressed is None:
                self._hash160_uncompressed = hash160(self.sec(use_uncompressed=use_uncompressed))
            return self._hash160_uncompressed

        if self._hash160_compressed is None:
            self._hash160_compressed = hash160(self.sec(use_uncompressed=use_uncompressed))
        return self._hash160_compressed
Exemple #19
0
    def get_hash(self):
        if hasattr(self, "hash"):
            return self.hash
        full_data = ""
        full_data += str(self.name + self.last_name + str(self.sex) +
                         str(self.date) + self.ID)

        self.hash = encoding.hash160(full_data.encode())
        print(self.hash)
        return self.hash
Exemple #20
0
    def hash160(self, use_uncompressed=None):
        """
        Return the hash160 representation of this key, if available.
        If use_uncompressed is not set, the preferred representation is returned.
        """
        use_uncompressed = self._use_uncompressed(use_uncompressed)
        if self.public_pair() is None:
            if use_uncompressed:
                return self._hash160_uncompressed
            return self._hash160_compressed

        if use_uncompressed:
            if self._hash160_uncompressed is None:
                self._hash160_uncompressed = hash160(self.sec(use_uncompressed=use_uncompressed))
            return self._hash160_uncompressed

        if self._hash160_compressed is None:
            self._hash160_compressed = hash160(self.sec(use_uncompressed=use_uncompressed))
        return self._hash160_compressed
 def address(self, address_prefix=b'\0'):
     if self.is_coinbase():
         return "(coinbase)"
     # attempt to return the source address
     sec = self.public_key_sec()
     if sec:
         bitcoin_address = encoding.hash160_sec_to_bitcoin_address(
             encoding.hash160(sec), address_prefix=address_prefix)
         return bitcoin_address
     return "(unknown)"
Exemple #22
0
def test_public(sim_execfile):
    "verify contents of public 'dump' file"
    from pycoin.key.BIP32Node import BIP32Node
    from pycoin.contrib.segwit_addr import encode as sw_encode
    from pycoin.contrib.segwit_addr import decode as sw_decode
    from pycoin.encoding import a2b_hashed_base58, hash160

    pub = sim_execfile('devtest/dump_public.py')
    assert 'Error' not in pub

    #print(pub)

    pub, dev = pub.split('#DEBUG#', 1)
    assert 'pub' in pub
    assert 'prv' not in pub
    assert 'prv' in dev

    lines = [i.strip() for i in pub.split('\n')]

    for ln in lines:
        if ln[1:4] == 'pub':
            node_pub = BIP32Node.from_wallet_key(ln)
            break

    node_prv = BIP32Node.from_wallet_key(dev.strip())

    # pub and private are linked
    assert node_prv.hwif(as_private=False) == node_pub.hwif()

    # check every path we derived
    count = 0
    for ln in lines:
        if ln[0:1] == 'm' and '=>' in ln:
            subpath, result = ln.split(' => ', 1)

            sk = node_prv.subkey_for_path(subpath[2:])

            if result[0:2] in {'tp', 'xp'}:
                expect = BIP32Node.from_wallet_key(result)
                assert sk.hwif(as_private=False) == result
            elif result[0] in '1mn':
                assert result == sk.address(False)
            elif result[0:3] in {'bc1', 'tb1'}:
                h20 = sk.hash160()
                assert result == sw_encode(result[0:2], 0, h20)
            elif result[0] in '23':
                h20 = hash160(b'\x00\x14' + sk.hash160())
                assert h20 == a2b_hashed_base58(result)[1:]
            else:
                raise ValueError(result)

            count += 1
            print("OK: %s" % ln)

    assert count > 12
Exemple #23
0
    def payto_for_path(self, path):
        """Get the payto script for the path.  See also :meth:`.script`

        :param: path: the derivation path
        :type: path: str
        :return: the script
        :rtype: LeafPayTo
        """
        script = self.script_for_path(path)
        payto = LeafPayTo(hash160=encoding.hash160(script.script()), path=path)
        return payto
Exemple #24
0
    def payto_for_path(self, path):
        """Get the payto script for the path.  See also :meth:`.script`

        :param: path: the derivation path
        :type: path: str
        :return: the script
        :rtype: LeafPayTo
        """
        script = self.script_for_path(path)
        payto = LeafPayTo(hash160=encoding.hash160(script.script()), path=path)
        return payto
 def doit(addr, sk):
     if addr[0] in '1mn':
         assert addr == sk.address(False)
     elif addr[0:3] in {'bc1', 'tb1'}:
         h20 = sk.hash160()
         assert addr == sw_encode(addr[0:2], 0, h20)
     elif addr[0] in '23':
         h20 = hash160(b'\x00\x14' + sk.hash160())
         assert h20 == a2b_hashed_base58(addr)[1:]
     else:
         raise ValueError(addr)
Exemple #26
0
    def _calculate_all(self):
        for attr in "_secret_exponent _public_pair _wif_uncompressed _wif_compressed _sec_compressed" \
                " _sec_uncompressed _hash160_compressed _hash160_uncompressed _address_compressed" \
                " _address_uncompressed _netcode".split():
            setattr(self, attr, getattr(self, attr, None))

        if self._hierarchical_wallet:
            if self._hierarchical_wallet.is_private:
                self._secret_exponent = self._hierarchical_wallet.secret_exponent
            else:
                self._public_pair = self._hierarchical_wallet.public_pair
            self._netcode = self._hierarchical_wallet.netcode

        wif_prefix = wif_prefix_for_netcode(self._netcode)

        if self._secret_exponent:
            self._wif_uncompressed = secret_exponent_to_wif(
                self._secret_exponent, compressed=False, wif_prefix=wif_prefix)
            self._wif_compressed = secret_exponent_to_wif(
                self._secret_exponent, compressed=True, wif_prefix=wif_prefix)
            self._public_pair = ecdsa.public_pair_for_secret_exponent(
                ecdsa.generator_secp256k1, self._secret_exponent)

        if self._public_pair:
            self._sec_compressed = public_pair_to_sec(self._public_pair,
                                                      compressed=True)
            self._sec_uncompressed = public_pair_to_sec(self._public_pair,
                                                        compressed=False)
            self._hash160_compressed = hash160(self._sec_compressed)
            self._hash160_uncompressed = hash160(self._sec_uncompressed)

        address_prefix = address_prefix_for_netcode(self._netcode)

        if self._hash160_compressed:
            self._address_compressed = hash160_sec_to_bitcoin_address(
                self._hash160_compressed, address_prefix=address_prefix)

        if self._hash160_uncompressed:
            self._address_uncompressed = hash160_sec_to_bitcoin_address(
                self._hash160_uncompressed, address_prefix=address_prefix)
Exemple #27
0
 def solve_create_commit(self, **kwargs):
     hash160_lookup = kwargs["hash160_lookup"]
     private_key = hash160_lookup.get(encoding.hash160(self.payer_sec))
     secret_exponent, public_pair, compressed = private_key
     sig = self._create_script_signature(
         secret_exponent, kwargs["sign_value"], kwargs["signature_type"]
     )
     signature_placeholder = kwargs.get("signature_placeholder",
                                        DEFAULT_PLACEHOLDER_SIGNATURE)
     script_text = "OP_0 {payer_sig} {payee_sig} OP_1".format(
         payer_sig=b2h(sig), payee_sig=b2h(signature_placeholder)
     )
     return tools.compile(script_text)
Exemple #28
0
    def _calculate_all(self):
        for attr in "_secret_exponent _public_pair _wif_uncompressed _wif_compressed _sec_compressed" \
                " _sec_uncompressed _hash160_compressed _hash160_uncompressed _address_compressed" \
                " _address_uncompressed _netcode".split():
                setattr(self, attr, getattr(self, attr, None))

        if self._hierarchical_wallet:
            if self._hierarchical_wallet.is_private:
                self._secret_exponent = self._hierarchical_wallet.secret_exponent
            else:
                self._public_pair = self._hierarchical_wallet.public_pair
            self._netcode = self._hierarchical_wallet.netcode

        wif_prefix = wif_prefix_for_netcode(self._netcode)

        if self._secret_exponent:
            self._wif_uncompressed = secret_exponent_to_wif(
                self._secret_exponent, compressed=False, wif_prefix=wif_prefix)
            self._wif_compressed = secret_exponent_to_wif(
                self._secret_exponent, compressed=True, wif_prefix=wif_prefix)
            self._public_pair = ecdsa.public_pair_for_secret_exponent(
                ecdsa.generator_secp256k1, self._secret_exponent)

        if self._public_pair:
            self._sec_compressed = public_pair_to_sec(self._public_pair, compressed=True)
            self._sec_uncompressed = public_pair_to_sec(self._public_pair, compressed=False)
            self._hash160_compressed = hash160(self._sec_compressed)
            self._hash160_uncompressed = hash160(self._sec_uncompressed)

        address_prefix = address_prefix_for_netcode(self._netcode)

        if self._hash160_compressed:
            self._address_compressed = hash160_sec_to_bitcoin_address(
                self._hash160_compressed, address_prefix=address_prefix)

        if self._hash160_uncompressed:
            self._address_uncompressed = hash160_sec_to_bitcoin_address(
                self._hash160_uncompressed, address_prefix=address_prefix)
def scriptsig2adddr(scriptsig):
    if type(scriptsig) is not bytes:
        scriptsig = binascii.unhexlify(scriptsig)
    pos = 0
    ln = scriptsig[pos]
    pos += 1
    sig = sigscript[pos:pos + ln]
    pos += ln
    ln = scriptsig[pos]
    pos += 1
    pubkey = scriptsig[pos:pos + ln:]
    pubkeyhash = encoding.hash160(pubkey)
    r = encoding.b2a_hashed_base58(settings.PUB_PREFIX + pubkeyhash)
    return r
Exemple #30
0
    def fromPrivkey(cls, ecdsaPrivkey):
        """Returns a new Address object from the private key.
        The private key can be used to get the public key,
        hence the need only for the private key.
        """
        rawPrivkey = cls.PRIVATE_KEY_PREFIX + ecdsaPrivkey.to_string()
        privkey = b2a_hashed_base58(rawPrivkey)

        ecdsaPubkey = ecdsaPrivkey.get_verifying_key()
        rawPubkey = cls.PUBLIC_KEY_PREFIX + hash160(
            "\x04" + ecdsaPubkey.to_string())
        pubkey = b2a_hashed_base58(rawPubkey)

        return cls(pubkey, privkey)
def sign_change_recover(get_txs_func, payer_wif, rawtx, deposit_script_hex,
                        spend_secret):
    """ Sign change recover transaction.

    Args:
        get_txs_func (function): txid list -> matching raw transactions.
        payer_wif (str): Payer wif used for signing.
        rawtx (str): Change raw transaction to be signed.
        deposit_script_hex (str): Matching deposit script for transaction.
        spend_secret (str): Deposit spend secret to recover change.

    Return:
        Signed change raw transaction.
    """
    validate_deposit_script(deposit_script_hex)
    spend_secret_hash = get_deposit_spend_secret_hash(deposit_script_hex)
    provided_spend_secret_hash = b2h(encoding.hash160(h2b(spend_secret)))
    assert provided_spend_secret_hash == spend_secret_hash
    return _sign_deposit_recover(get_txs_func, payer_wif, rawtx,
                                 deposit_script_hex, "change", spend_secret)
    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)
Exemple #33
0
 def address(self, use_uncompressed=None):
     """
     Return the public address representation of this key, if available.
     If use_uncompressed is not set, the preferred representation is returned.
     """
     hash_160 = self.hash160(use_uncompressed=use_uncompressed)
     if hash_160:
         is_p2pwk = address_wit_for_netcode(self._netcode)
         if is_p2pwk:
             witness = ScriptPayToAddressWit(b'\0', hash_160)
             return witness.info(self._netcode)['address_f']()
         is_p2pwk_in_p2sh = pay_to_script_wit_for_netcode(self._netcode)
         if is_p2pwk_in_p2sh:
             address_prefix = pay_to_script_prefix_for_netcode(
                 self._netcode)
             wit_script = ScriptPayToAddressWit(b'\0', hash_160).script()
             hash_160 = hash160(wit_script)
         else:
             address_prefix = address_prefix_for_netcode(self._netcode)
         return hash160_sec_to_bitcoin_address(
             hash_160, address_prefix=address_prefix)
     return None
Exemple #34
0
    def getJSONData(self):
        """Returns a dict that can later be plugged into
        the fromObj method for later retrieval of an Address.
        This is particularly useful for storing/retrieving
        from a data store."""
        return {"pubkey": self.pubkey, "privkey": self.privkey}


class TestnetAddress(Address):
    """TestnetAddress represents a Bitcoin Testnet address.
    Be sure that bitcoind is running with the "-testnet" flag.
    """
    PUBLIC_KEY_PREFIX = "\x6F"
    PRIVATE_KEY_PREFIX = "\xEF"


if __name__ == "__main__":
    # test the key generation
    test_key = 'a' * 32
    address = Address.new(test_key)
    print address.pubkey
    rawPubkey = Address.PUBLIC_KEY_PREFIX + hash160(
        "\x04" + address.rawPubkey())
    print b2a_hashed_base58(rawPubkey)
    assert address.privkey \
        == "5JZB2s2RCtRUunKiqMbb6rAj3Z7TkJwa8zknL1cfTFpWoQArd6n", \
        "address generation isn't what was expected"

    assert address.rawPrivkey() == test_key, "wrong priv key"
Exemple #35
0
def main():
    parser = argparse.ArgumentParser(
        description="Manipulate bitcoin (or alt coin) transactions.",
        epilog=EPILOG)

    parser.add_argument(
        '-t',
        "--transaction-version",
        type=int,
        help='Transaction version, either 1 (default) or 3 (not yet supported).'
    )

    parser.add_argument(
        '-l',
        "--lock-time",
        type=parse_locktime,
        help='Lock time; either a block'
        'index, or a date/time (example: "2014-01-01T15:00:00"')

    parser.add_argument(
        '-n',
        "--network",
        default="BTC",
        help='Define network code (M=Bitcoin mainnet, T=Bitcoin testnet).')

    parser.add_argument(
        '-a',
        "--augment",
        action='store_true',
        help='augment tx by adding any missing spendable metadata by fetching'
        ' inputs from cache and/or web services')

    parser.add_argument(
        "-i",
        "--fetch-spendables",
        metavar="address",
        action="append",
        help=
        'Add all unspent spendables for the given bitcoin address. This information'
        ' is fetched from web services.')

    parser.add_argument(
        '-f',
        "--private-key-file",
        metavar="path-to-private-keys",
        action="append",
        help=
        'file containing WIF or BIP0032 private keys. If file name ends with .gpg, '
        '"gpg -d" will be invoked automatically. File is read one line at a time, and if '
        'the file contains only one WIF per line, it will also be scanned for a bitcoin '
        'address, and any addresses found will be assumed to be public keys for the given'
        ' private key.',
        type=argparse.FileType('r'))

    parser.add_argument('-g',
                        "--gpg-argument",
                        help='argument to pass to gpg (besides -d).',
                        default='')

    parser.add_argument("--remove-tx-in",
                        metavar="tx_in_index_to_delete",
                        action="append",
                        type=int,
                        help='remove a tx_in')

    parser.add_argument("--remove-tx-out",
                        metavar="tx_out_index_to_delete",
                        action="append",
                        type=int,
                        help='remove a tx_out')

    parser.add_argument(
        '-F',
        "--fee",
        help='fee, in satoshis, to pay on transaction, or '
        '"standard" to auto-calculate. This is only useful if the "split pool" '
        'is used; otherwise, the fee is automatically set to the unclaimed funds.',
        default="standard",
        metavar="transaction-fee",
        type=parse_fee)

    parser.add_argument(
        '-C',
        "--cache",
        help='force the resultant transaction into the transaction cache.'
        ' Mostly for testing.',
        action='store_true'),

    parser.add_argument(
        '-u',
        "--show-unspents",
        action='store_true',
        help='show TxOut items for this transaction in Spendable form.')

    parser.add_argument(
        '-b',
        "--bitcoind-url",
        help=
        'URL to bitcoind instance to validate against (http://user:pass@host:port).'
    )

    parser.add_argument(
        '-o',
        "--output-file",
        metavar="path-to-output-file",
        type=argparse.FileType('wb'),
        help='file to write transaction to. This supresses most other output.')

    parser.add_argument(
        '-p',
        "--pay-to-script",
        metavar="pay-to-script",
        action="append",
        help=
        'a hex version of a script required for a pay-to-script input (a bitcoin address that starts with 3)'
    )

    parser.add_argument(
        '-P',
        "--pay-to-script-file",
        metavar="pay-to-script-file",
        nargs=1,
        type=argparse.FileType('r'),
        help=
        'a file containing hex scripts (one per line) corresponding to pay-to-script inputs'
    )

    parser.add_argument(
        "argument",
        nargs="+",
        help='generic argument: can be a hex transaction id '
        '(exactly 64 characters) to be fetched from cache or a web service;'
        ' a transaction as a hex string; a path name to a transaction to be loaded;'
        ' a spendable 4-tuple of the form tx_id/tx_out_idx/script_hex/satoshi_count '
        'to be added to TxIn list; an address/satoshi_count to be added to the TxOut '
        'list; an address to be added to the TxOut list and placed in the "split'
        ' pool".')

    args = parser.parse_args()

    # defaults

    txs = []
    spendables = []
    payables = []

    key_iters = []

    TX_ID_RE = re.compile(r"^[0-9a-fA-F]{64}$")

    # there are a few warnings we might optionally print out, but only if
    # they are relevant. We don't want to print them out multiple times, so we
    # collect them here and print them at the end if they ever kick in.

    warning_tx_cache = None
    warning_get_tx = None
    warning_spendables = None

    if args.private_key_file:
        wif_re = re.compile(r"[1-9a-km-zA-LMNP-Z]{51,111}")
        # address_re = re.compile(r"[1-9a-kmnp-zA-KMNP-Z]{27-31}")
        for f in args.private_key_file:
            if f.name.endswith(".gpg"):
                gpg_args = ["gpg", "-d"]
                if args.gpg_argument:
                    gpg_args.extend(args.gpg_argument.split())
                gpg_args.append(f.name)
                popen = subprocess.Popen(gpg_args, stdout=subprocess.PIPE)
                f = popen.stdout
            for line in f.readlines():
                # decode
                if isinstance(line, bytes):
                    line = line.decode("utf8")
                # look for WIFs
                possible_keys = wif_re.findall(line)

                def make_key(x):
                    try:
                        return Key.from_text(x)
                    except Exception:
                        return None

                keys = [make_key(x) for x in possible_keys]
                for key in keys:
                    if key:
                        key_iters.append((k.wif() for k in key.subkeys("")))

                # if len(keys) == 1 and key.hierarchical_wallet() is None:
                #    # we have exactly 1 WIF. Let's look for an address
                #   potential_addresses = address_re.findall(line)

    # update p2sh_lookup
    p2sh_lookup = {}
    if args.pay_to_script:
        for p2s in args.pay_to_script:
            try:
                script = h2b(p2s)
                p2sh_lookup[hash160(script)] = script
            except Exception:
                print("warning: error parsing pay-to-script value %s" % p2s)

    if args.pay_to_script_file:
        hex_re = re.compile(r"[0-9a-fA-F]+")
        for f in args.pay_to_script_file:
            count = 0
            for l in f:
                try:
                    m = hex_re.search(l)
                    if m:
                        p2s = m.group(0)
                        script = h2b(p2s)
                        p2sh_lookup[hash160(script)] = script
                        count += 1
                except Exception:
                    print("warning: error parsing pay-to-script file %s" %
                          f.name)
            if count == 0:
                print("warning: no scripts found in %s" % f.name)

    # we create the tx_db lazily
    tx_db = None

    for arg in args.argument:

        # hex transaction id
        if TX_ID_RE.match(arg):
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx = tx_db.get(h2b_rev(arg))
            if not tx:
                for m in [
                        warning_tx_cache, warning_get_tx, warning_spendables
                ]:
                    if m:
                        print("warning: %s" % m, file=sys.stderr)
                parser.error("can't find Tx with id %s" % arg)
            txs.append(tx)
            continue

        # hex transaction data
        try:
            tx = Tx.tx_from_hex(arg)
            txs.append(tx)
            continue
        except Exception:
            pass

        is_valid = is_address_valid(arg, allowable_netcodes=[args.network])
        if is_valid:
            payables.append((arg, 0))
            continue

        try:
            key = Key.from_text(arg)
            # TODO: check network
            if key.wif() is None:
                payables.append((key.address(), 0))
                continue
            # TODO: support paths to subkeys
            key_iters.append((k.wif() for k in key.subkeys("")))
            continue
        except Exception:
            pass

        if os.path.exists(arg):
            try:
                with open(arg, "rb") as f:
                    if f.name.endswith("hex"):
                        f = io.BytesIO(codecs.getreader("hex_codec")(f).read())
                    tx = Tx.parse(f)
                    txs.append(tx)
                    try:
                        tx.parse_unspents(f)
                    except Exception as ex:
                        pass
                    continue
            except Exception:
                pass

        parts = arg.split("/")
        if len(parts) == 4:
            # spendable
            try:
                spendables.append(Spendable.from_text(arg))
                continue
            except Exception:
                pass

        if len(parts) == 2 and is_address_valid(
                parts[0], allowable_netcodes=[args.network]):
            try:
                payables.append(parts)
                continue
            except ValueError:
                pass

        parser.error("can't parse %s" % arg)

    if args.fetch_spendables:
        warning_spendables = message_about_spendables_for_address_env()
        for address in args.fetch_spendables:
            spendables.extend(spendables_for_address(address))

    for tx in txs:
        if tx.missing_unspents() and args.augment:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx.unspents_from_db(tx_db, ignore_missing=True)

    txs_in = []
    txs_out = []
    unspents = []
    # we use a clever trick here to keep each tx_in corresponding with its tx_out
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[:smaller])
        txs_out.extend(tx.txs_out[:smaller])
        unspents.extend(tx.unspents[:smaller])
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[smaller:])
        txs_out.extend(tx.txs_out[smaller:])
        unspents.extend(tx.unspents[smaller:])
    for spendable in spendables:
        txs_in.append(spendable.tx_in())
        unspents.append(spendable)
    for address, coin_value in payables:
        script = standard_tx_out_script(address)
        txs_out.append(TxOut(coin_value, script))

    lock_time = args.lock_time
    version = args.transaction_version

    # if no lock_time is explicitly set, inherit from the first tx or use default
    if lock_time is None:
        if txs:
            lock_time = txs[0].lock_time
        else:
            lock_time = DEFAULT_LOCK_TIME

    # if no version is explicitly set, inherit from the first tx or use default
    if version is None:
        if txs:
            version = txs[0].version
        else:
            version = DEFAULT_VERSION

    if args.remove_tx_in:
        s = set(args.remove_tx_in)
        txs_in = [tx_in for idx, tx_in in enumerate(txs_in) if idx not in s]

    if args.remove_tx_out:
        s = set(args.remove_tx_out)
        txs_out = [
            tx_out for idx, tx_out in enumerate(txs_out) if idx not in s
        ]

    tx = Tx(txs_in=txs_in,
            txs_out=txs_out,
            lock_time=lock_time,
            version=version,
            unspents=unspents)

    fee = args.fee
    try:
        distribute_from_split_pool(tx, fee)
    except ValueError as ex:
        print("warning: %s" % ex.args[0], file=sys.stderr)

    unsigned_before = tx.bad_signature_count()
    if unsigned_before > 0 and key_iters:

        def wif_iter(iters):
            while len(iters) > 0:
                for idx, iter in enumerate(iters):
                    try:
                        wif = next(iter)
                        yield wif
                    except StopIteration:
                        iters = iters[:idx] + iters[idx + 1:]
                        break

        print("signing...", file=sys.stderr)
        sign_tx(tx, wif_iter(key_iters), p2sh_lookup=p2sh_lookup)

    unsigned_after = tx.bad_signature_count()
    if unsigned_after > 0 and key_iters:
        print("warning: %d TxIn items still unsigned" % unsigned_after,
              file=sys.stderr)

    if len(tx.txs_in) == 0:
        print("warning: transaction has no inputs", file=sys.stderr)

    if len(tx.txs_out) == 0:
        print("warning: transaction has no outputs", file=sys.stderr)

    include_unspents = (unsigned_after > 0)
    tx_as_hex = tx.as_hex(include_unspents=include_unspents)

    if args.output_file:
        f = args.output_file
        if f.name.endswith(".hex"):
            f.write(tx_as_hex.encode("utf8"))
        else:
            tx.stream(f)
            if include_unspents:
                tx.stream_unspents(f)
        f.close()
    elif args.show_unspents:
        for spendable in tx.tx_outs_as_spendable():
            print(spendable.as_text())
    else:
        if not tx.missing_unspents():
            check_fees(tx)
        dump_tx(tx, args.network)
        if include_unspents:
            print(
                "including unspents in hex dump since transaction not fully signed"
            )
        print(tx_as_hex)

    if args.cache:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_get_tx = message_about_get_tx_env()
            tx_db = get_tx_db()
        tx_db.put(tx)

    if args.bitcoind_url:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_get_tx = message_about_get_tx_env()
            tx_db = get_tx_db()
        validate_bitcoind(tx, tx_db, args.bitcoind_url)

    if tx.missing_unspents():
        print("\n** can't validate transaction as source transactions missing",
              file=sys.stderr)
    else:
        try:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx.validate_unspents(tx_db)
            print('all incoming transaction values validated')
        except BadSpendableError as ex:
            print("\n**** ERROR: FEES INCORRECTLY STATED: %s" % ex.args[0],
                  file=sys.stderr)
        except Exception as ex:
            print(
                "\n*** can't validate source transactions as untampered: %s" %
                ex.args[0],
                file=sys.stderr)

    # print warnings
    for m in [warning_tx_cache, warning_get_tx, warning_spendables]:
        if m:
            print("warning: %s" % m, file=sys.stderr)
Exemple #36
0
def address_for_pay_to_script(script, netcode=None):
    if netcode is None:
        netcode = get_current_netcode()
    address_prefix = pay_to_script_prefix_for_netcode(netcode)
    return encoding.hash160_sec_to_bitcoin_address(encoding.hash160(script), address_prefix=address_prefix)
Exemple #37
0
def hash160hex(hexdata):
    return b2h(hash160(h2b(hexdata)))
Exemple #38
0
def main():
    parser = argparse.ArgumentParser(
        description="Manipulate bitcoin (or alt coin) transactions.",
        epilog=EPILOG)

    parser.add_argument('-t', "--transaction-version", type=int,
                        help='Transaction version, either 1 (default) or 3 (not yet supported).')

    parser.add_argument('-l', "--lock-time", type=parse_locktime, help='Lock time; either a block'
                        'index, or a date/time (example: "2014-01-01T15:00:00"')

    parser.add_argument('-n', "--network", default="BTC",
                        help='Define network code (M=Bitcoin mainnet, T=Bitcoin testnet).')

    parser.add_argument('-a', "--augment", action='store_true',
                        help='augment tx by adding any missing spendable metadata by fetching'
                             ' inputs from cache and/or web services')

    parser.add_argument('-s', "--verbose-signature", action='store_true',
                        help='Display technical signature details.')

    parser.add_argument("-i", "--fetch-spendables", metavar="address", action="append",
                        help='Add all unspent spendables for the given bitcoin address. This information'
                        ' is fetched from web services.')

    parser.add_argument('-f', "--private-key-file", metavar="path-to-private-keys", action="append",
                        help='file containing WIF or BIP0032 private keys. If file name ends with .gpg, '
                        '"gpg -d" will be invoked automatically. File is read one line at a time, and if '
                        'the file contains only one WIF per line, it will also be scanned for a bitcoin '
                        'address, and any addresses found will be assumed to be public keys for the given'
                        ' private key.',
                        type=argparse.FileType('r'))

    parser.add_argument('-g', "--gpg-argument", help='argument to pass to gpg (besides -d).', default='')

    parser.add_argument("--remove-tx-in", metavar="tx_in_index_to_delete", action="append", type=int,
                        help='remove a tx_in')

    parser.add_argument("--remove-tx-out", metavar="tx_out_index_to_delete", action="append", type=int,
                        help='remove a tx_out')

    parser.add_argument('-F', "--fee", help='fee, in satoshis, to pay on transaction, or '
                        '"standard" to auto-calculate. This is only useful if the "split pool" '
                        'is used; otherwise, the fee is automatically set to the unclaimed funds.',
                        default="standard", metavar="transaction-fee", type=parse_fee)

    parser.add_argument('-C', "--cache", help='force the resultant transaction into the transaction cache.'
                        ' Mostly for testing.', action='store_true'),

    parser.add_argument('-u', "--show-unspents", action='store_true',
                        help='show TxOut items for this transaction in Spendable form.')

    parser.add_argument('-b', "--bitcoind-url",
                        help='URL to bitcoind instance to validate against (http://user:pass@host:port).')

    parser.add_argument('-o', "--output-file", metavar="path-to-output-file", type=argparse.FileType('wb'),
                        help='file to write transaction to. This supresses most other output.')

    parser.add_argument('-d', "--disassemble", action='store_true',
                        help='Disassemble scripts.')

    parser.add_argument("--trace", action='store_true', help='Trace scripts.')

    parser.add_argument('-p', "--pay-to-script", metavar="pay-to-script", action="append",
                        help='a hex version of a script required for a pay-to-script input (a bitcoin address that starts with 3)')

    parser.add_argument('-P', "--pay-to-script-file", metavar="pay-to-script-file", nargs=1, type=argparse.FileType('r'),
                        help='a file containing hex scripts (one per line) corresponding to pay-to-script inputs')

    parser.add_argument("argument", nargs="+", help='generic argument: can be a hex transaction id '
                        '(exactly 64 characters) to be fetched from cache or a web service;'
                        ' a transaction as a hex string; a path name to a transaction to be loaded;'
                        ' a spendable 4-tuple of the form tx_id/tx_out_idx/script_hex/satoshi_count '
                        'to be added to TxIn list; an address/satoshi_count to be added to the TxOut '
                        'list; an address to be added to the TxOut list and placed in the "split'
                        ' pool".')

    args = parser.parse_args()

    # defaults

    txs = []
    spendables = []
    payables = []

    key_iters = []

    TX_ID_RE = re.compile(r"^[0-9a-fA-F]{64}$")

    # there are a few warnings we might optionally print out, but only if
    # they are relevant. We don't want to print them out multiple times, so we
    # collect them here and print them at the end if they ever kick in.

    warning_tx_cache = None
    warning_tx_for_tx_hash = None
    warning_spendables = None

    if args.private_key_file:
        wif_re = re.compile(r"[1-9a-km-zA-LMNP-Z]{51,111}")
        # address_re = re.compile(r"[1-9a-kmnp-zA-KMNP-Z]{27-31}")
        for f in args.private_key_file:
            if f.name.endswith(".gpg"):
                gpg_args = ["gpg", "-d"]
                if args.gpg_argument:
                    gpg_args.extend(args.gpg_argument.split())
                gpg_args.append(f.name)
                popen = subprocess.Popen(gpg_args, stdout=subprocess.PIPE)
                f = popen.stdout
            for line in f.readlines():
                # decode
                if isinstance(line, bytes):
                    line = line.decode("utf8")
                # look for WIFs
                possible_keys = wif_re.findall(line)

                def make_key(x):
                    try:
                        return Key.from_text(x)
                    except Exception:
                        return None

                keys = [make_key(x) for x in possible_keys]
                for key in keys:
                    if key:
                        key_iters.append((k.wif() for k in key.subkeys("")))

                # if len(keys) == 1 and key.hierarchical_wallet() is None:
                #    # we have exactly 1 WIF. Let's look for an address
                #   potential_addresses = address_re.findall(line)

    # update p2sh_lookup
    p2sh_lookup = {}
    if args.pay_to_script:
        for p2s in args.pay_to_script:
            try:
                script = h2b(p2s)
                p2sh_lookup[hash160(script)] = script
            except Exception:
                print("warning: error parsing pay-to-script value %s" % p2s)

    if args.pay_to_script_file:
        hex_re = re.compile(r"[0-9a-fA-F]+")
        for f in args.pay_to_script_file:
            count = 0
            for l in f:
                try:
                    m = hex_re.search(l)
                    if m:
                        p2s = m.group(0)
                        script = h2b(p2s)
                        p2sh_lookup[hash160(script)] = script
                        count += 1
                except Exception:
                    print("warning: error parsing pay-to-script file %s" % f.name)
            if count == 0:
                print("warning: no scripts found in %s" % f.name)

    # we create the tx_db lazily
    tx_db = None

    for arg in args.argument:

        # hex transaction id
        if TX_ID_RE.match(arg):
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
                tx_db = get_tx_db(args.network)
            tx = tx_db.get(h2b_rev(arg))
            if not tx:
                for m in [warning_tx_cache, warning_tx_for_tx_hash, warning_spendables]:
                    if m:
                        print("warning: %s" % m, file=sys.stderr)
                parser.error("can't find Tx with id %s" % arg)
            txs.append(tx)
            continue

        # hex transaction data
        try:
            tx = Tx.from_hex(arg)
            txs.append(tx)
            continue
        except Exception:
            pass

        is_valid = is_address_valid(arg, allowable_netcodes=[args.network])
        if is_valid:
            payables.append((arg, 0))
            continue

        try:
            key = Key.from_text(arg)
            # TODO: check network
            if key.wif() is None:
                payables.append((key.address(), 0))
                continue
            # TODO: support paths to subkeys
            key_iters.append((k.wif() for k in key.subkeys("")))
            continue
        except Exception:
            pass

        if os.path.exists(arg):
            try:
                with open(arg, "rb") as f:
                    if f.name.endswith("hex"):
                        f = io.BytesIO(codecs.getreader("hex_codec")(f).read())
                    tx = Tx.parse(f)
                    txs.append(tx)
                    try:
                        tx.parse_unspents(f)
                    except Exception as ex:
                        pass
                    continue
            except Exception:
                pass

        parts = arg.split("/")
        if len(parts) == 4:
            # spendable
            try:
                spendables.append(Spendable.from_text(arg))
                continue
            except Exception:
                pass

        if len(parts) == 2 and is_address_valid(parts[0], allowable_netcodes=[args.network]):
            try:
                payables.append(parts)
                continue
            except ValueError:
                pass

        parser.error("can't parse %s" % arg)

    if args.fetch_spendables:
        warning_spendables = message_about_spendables_for_address_env(args.network)
        for address in args.fetch_spendables:
            spendables.extend(spendables_for_address(address))

    for tx in txs:
        if tx.missing_unspents() and args.augment:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
                tx_db = get_tx_db(args.network)
            tx.unspents_from_db(tx_db, ignore_missing=True)

    txs_in = []
    txs_out = []
    unspents = []
    # we use a clever trick here to keep each tx_in corresponding with its tx_out
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[:smaller])
        txs_out.extend(tx.txs_out[:smaller])
        unspents.extend(tx.unspents[:smaller])
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[smaller:])
        txs_out.extend(tx.txs_out[smaller:])
        unspents.extend(tx.unspents[smaller:])
    for spendable in spendables:
        txs_in.append(spendable.tx_in())
        unspents.append(spendable)
    for address, coin_value in payables:
        script = standard_tx_out_script(address)
        txs_out.append(TxOut(coin_value, script))

    lock_time = args.lock_time
    version = args.transaction_version

    # if no lock_time is explicitly set, inherit from the first tx or use default
    if lock_time is None:
        if txs:
            lock_time = txs[0].lock_time
        else:
            lock_time = DEFAULT_LOCK_TIME

    # if no version is explicitly set, inherit from the first tx or use default
    if version is None:
        if txs:
            version = txs[0].version
        else:
            version = DEFAULT_VERSION

    if args.remove_tx_in:
        s = set(args.remove_tx_in)
        txs_in = [tx_in for idx, tx_in in enumerate(txs_in) if idx not in s]

    if args.remove_tx_out:
        s = set(args.remove_tx_out)
        txs_out = [tx_out for idx, tx_out in enumerate(txs_out) if idx not in s]

    tx = Tx(txs_in=txs_in, txs_out=txs_out, lock_time=lock_time, version=version, unspents=unspents)

    fee = args.fee
    try:
        distribute_from_split_pool(tx, fee)
    except ValueError as ex:
        print("warning: %s" % ex.args[0], file=sys.stderr)

    unsigned_before = tx.bad_signature_count()
    unsigned_after = unsigned_before
    if unsigned_before > 0 and key_iters:
        def wif_iter(iters):
            while len(iters) > 0:
                for idx, iter in enumerate(iters):
                    try:
                        wif = next(iter)
                        yield wif
                    except StopIteration:
                        iters = iters[:idx] + iters[idx+1:]
                        break

        print("signing...", file=sys.stderr)
        sign_tx(tx, wif_iter(key_iters), p2sh_lookup=p2sh_lookup)

        unsigned_after = tx.bad_signature_count()
        if unsigned_after > 0:
            print("warning: %d TxIn items still unsigned" % unsigned_after, file=sys.stderr)

    if len(tx.txs_in) == 0:
        print("warning: transaction has no inputs", file=sys.stderr)

    if len(tx.txs_out) == 0:
        print("warning: transaction has no outputs", file=sys.stderr)

    include_unspents = (unsigned_after > 0)
    tx_as_hex = tx.as_hex(include_unspents=include_unspents)

    if args.output_file:
        f = args.output_file
        if f.name.endswith(".hex"):
            f.write(tx_as_hex.encode("utf8"))
        else:
            tx.stream(f)
            if include_unspents:
                tx.stream_unspents(f)
        f.close()
    elif args.show_unspents:
        for spendable in tx.tx_outs_as_spendable():
            print(spendable.as_text())
    else:
        if not tx.missing_unspents():
            check_fees(tx)
        dump_tx(tx, args.network, args.verbose_signature, args.disassemble, args.trace)
        if include_unspents:
            print("including unspents in hex dump since transaction not fully signed")
        print(tx_as_hex)

    if args.cache:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
            tx_db = get_tx_db(args.network)
        tx_db.put(tx)

    if args.bitcoind_url:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
            tx_db = get_tx_db(args.network)
        validate_bitcoind(tx, tx_db, args.bitcoind_url)

    if tx.missing_unspents():
        print("\n** can't validate transaction as source transactions missing", file=sys.stderr)
    else:
        try:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
                tx_db = get_tx_db(args.network)
            tx.validate_unspents(tx_db)
            print('all incoming transaction values validated')
        except BadSpendableError as ex:
            print("\n**** ERROR: FEES INCORRECTLY STATED: %s" % ex.args[0], file=sys.stderr)
        except Exception as ex:
            print("\n*** can't validate source transactions as untampered: %s" %
                  ex.args[0], file=sys.stderr)

    # print warnings
    for m in [warning_tx_cache, warning_tx_for_tx_hash, warning_spendables]:
        if m:
            print("warning: %s" % m, file=sys.stderr)
Exemple #39
0
def parse_context(args, parser):
    # defaults

    txs = []
    spendables = []
    payables = []

    key_iters = []

    TX_ID_RE = re.compile(r"^[0-9a-fA-F]{64}$")

    # there are a few warnings we might optionally print out, but only if
    # they are relevant. We don't want to print them out multiple times, so we
    # collect them here and print them at the end if they ever kick in.

    warning_tx_cache = None
    warning_tx_for_tx_hash = None
    warning_spendables = None

    if args.private_key_file:
        wif_re = re.compile(r"[1-9a-km-zA-LMNP-Z]{51,111}")
        # address_re = re.compile(r"[1-9a-kmnp-zA-KMNP-Z]{27-31}")
        for f in args.private_key_file:
            if f.name.endswith(".gpg"):
                gpg_args = ["gpg", "-d"]
                if args.gpg_argument:
                    gpg_args.extend(args.gpg_argument.split())
                gpg_args.append(f.name)
                popen = subprocess.Popen(gpg_args, stdout=subprocess.PIPE)
                f = popen.stdout
            for line in f.readlines():
                # decode
                if isinstance(line, bytes):
                    line = line.decode("utf8")
                # look for WIFs
                possible_keys = wif_re.findall(line)

                def make_key(x):
                    try:
                        return Key.from_text(x)
                    except Exception:
                        return None

                keys = [make_key(x) for x in possible_keys]
                for key in keys:
                    if key:
                        key_iters.append((k.wif() for k in key.subkeys("")))

                # if len(keys) == 1 and key.hierarchical_wallet() is None:
                #    # we have exactly 1 WIF. Let's look for an address
                #   potential_addresses = address_re.findall(line)

    # update p2sh_lookup
    p2sh_lookup = {}
    if args.pay_to_script:
        for p2s in args.pay_to_script:
            try:
                script = h2b(p2s)
                p2sh_lookup[hash160(script)] = script
            except Exception:
                print("warning: error parsing pay-to-script value %s" % p2s)

    if args.pay_to_script_file:
        hex_re = re.compile(r"[0-9a-fA-F]+")
        for f in args.pay_to_script_file:
            count = 0
            for l in f:
                try:
                    m = hex_re.search(l)
                    if m:
                        p2s = m.group(0)
                        script = h2b(p2s)
                        p2sh_lookup[hash160(script)] = script
                        count += 1
                except Exception:
                    print("warning: error parsing pay-to-script file %s" % f.name)
            if count == 0:
                print("warning: no scripts found in %s" % f.name)

    # we create the tx_db lazily
    tx_db = None

    for arg in args.argument:

        # hex transaction id
        if TX_ID_RE.match(arg):
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
                tx_db = get_tx_db(args.network)
            tx = tx_db.get(h2b_rev(arg))
            if not tx:
                for m in [warning_tx_cache, warning_tx_for_tx_hash, warning_spendables]:
                    if m:
                        print("warning: %s" % m, file=sys.stderr)
                parser.error("can't find Tx with id %s" % arg)
            txs.append(tx)
            continue

        # hex transaction data
        try:
            tx = Tx.from_hex(arg)
            txs.append(tx)
            continue
        except Exception:
            pass

        is_valid = is_address_valid(arg, allowable_netcodes=[args.network])
        if is_valid:
            payables.append((arg, 0))
            continue

        try:
            key = Key.from_text(arg)
            # TODO: check network
            if key.wif() is None:
                payables.append((key.address(), 0))
                continue
            # TODO: support paths to subkeys
            key_iters.append((k.wif() for k in key.subkeys("")))
            continue
        except Exception:
            pass

        if os.path.exists(arg):
            try:
                with open(arg, "rb") as f:
                    if f.name.endswith("hex"):
                        f = io.BytesIO(codecs.getreader("hex_codec")(f).read())
                    tx = Tx.parse(f)
                    txs.append(tx)
                    try:
                        tx.parse_unspents(f)
                    except Exception as ex:
                        pass
                    continue
            except Exception:
                pass

        parts = arg.split("/")
        if len(parts) == 4:
            # spendable
            try:
                spendables.append(Spendable.from_text(arg))
                continue
            except Exception:
                pass

        if len(parts) == 2 and is_address_valid(parts[0], allowable_netcodes=[args.network]):
            try:
                payables.append(parts)
                continue
            except ValueError:
                pass

        parser.error("can't parse %s" % arg)

    if args.fetch_spendables:
        warning_spendables = message_about_spendables_for_address_env(args.network)
        for address in args.fetch_spendables:
            spendables.extend(spendables_for_address(address))

    for tx in txs:
        if tx.missing_unspents() and args.augment:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_tx_for_tx_hash = message_about_tx_for_tx_hash_env(args.network)
                tx_db = get_tx_db(args.network)
            tx.unspents_from_db(tx_db, ignore_missing=True)

    return (txs, spendables, payables, key_iters, p2sh_lookup, tx_db, warning_tx_cache,
            warning_tx_for_tx_hash, warning_spendables)
Exemple #40
0
def hash_bin(data):
    """ripemd160(hashlib.sha256(data)"""
    return hash160(data)
Exemple #41
0
def hash_hex(hexdata):
    """ripemd160(hashlib.sha256(hexdata)"""
    return binascii.hexlify(hash160(binascii.unhexlify(hexdata)))
Exemple #42
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
 def do_test(blob, expected_hash):
     self.assertEqual(encoding.hash160(blob), expected_hash)
Exemple #44
0
 def do_test(blob, expected_hash):
     self.assertEqual(encoding.hash160(blob), expected_hash)