def make_wallet_keys(data_privkey=None, owner_privkey=None, payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None,
    }

    if data_privkey is not None:
        if not virtualchain.is_singlesig(data_privkey):
            raise ValueError('Invalid data key info')

        pk_data = ecdsa_private_key(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if virtualchain.is_multisig(owner_privkey):
            pks = owner_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(owner_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['owner_privkey'] = multisig_info
            ret['owner_addresses'] = [virtualchain.get_privkey_address(multisig_info)]

        elif virtualchain.is_singlesig(owner_privkey):
            pk_owner = ecdsa_private_key(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner
            ret['owner_addresses'] = [virtualchain.get_privkey_address(pk_owner)]

        else:
            raise ValueError('Invalid owner key info')

    if payment_privkey is None:
        return ret

    if virtualchain.is_multisig(payment_privkey):
        pks = payment_privkey['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(payment_privkey['redeem_script'])
        assert m <= len(pks)

        multisig_info = virtualchain.make_multisig_info(m, pks)
        ret['payment_privkey'] = multisig_info
        ret['payment_addresses'] = [virtualchain.get_privkey_address(multisig_info)]

    elif virtualchain.is_singlesig(payment_privkey):
        pk_payment = ecdsa_private_key(payment_privkey).to_hex()
        ret['payment_privkey'] = pk_payment
        ret['payment_addresses'] = [virtualchain.get_privkey_address(pk_payment)]

    else:
        raise ValueError('Invalid payment key info')

    ret['data_pubkey'] = ecdsa_private_key(ret['data_privkey']).public_key().to_hex()
    ret['data_pubkeys'] = [ret['data_pubkey']]

    return ret
예제 #2
0
def make_wallet_keys(data_privkey=None,
                     owner_privkey=None,
                     payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None
    }

    if data_privkey is not None:
        if not is_singlesig(data_privkey):
            raise ValueError("Invalid data key info")

        pk_data = virtualchain.BitcoinPrivateKey(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if is_multisig(owner_privkey):
            pks = [
                virtualchain.BitcoinPrivateKey(pk).to_hex()
                for pk in owner_privkey['private_keys']
            ]
            m, pubs = virtualchain.parse_multisig_redeemscript(
                owner_privkey['redeem_script'])
            ret['owner_privkey'] = virtualchain.make_multisig_info(m, pks)

        elif is_singlesig(owner_privkey):
            pk_owner = virtualchain.BitcoinPrivateKey(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner

        else:
            raise ValueError("Invalid owner key info")

    if payment_privkey is not None:
        if is_multisig(payment_privkey):
            pks = [
                virtualchain.BitcoinPrivateKey(pk).to_hex()
                for pk in payment_privkey['private_keys']
            ]
            m, pubs = virtualchain.parse_multisig_redeemscript(
                payment_privkey['redeem_script'])
            ret['payment_privkey'] = virtualchain.make_multisig_info(m, pks)

        elif is_singlesig(payment_privkey):
            pk_payment = virtualchain.BitcoinPrivateKey(
                payment_privkey).to_hex()
            ret['payment_privkey'] = pk_payment

        else:
            raise ValueError("Invalid payment key info")

    return ret
예제 #3
0
def sign_multisig(hash_hex, redeem_script, secret_keys):
    assert len(redeem_script) > 0
    m, pk_hexes = virtualchain.parse_multisig_redeemscript(redeem_script)

    privs = {}
    for sk in secret_keys:
        pk = virtualchain.ecdsalib.ecdsa_private_key(sk).public_key().to_hex()

        compressed_pubkey = keylib.key_formatting.compress(pk)
        uncompressed_pubkey = keylib.key_formatting.decompress(pk)

        privs[compressed_pubkey] = sk
        privs[uncompressed_pubkey] = sk

    used_keys, sigs = [], []
    for pk in pk_hexes:
        if pk not in privs:
            continue
        if len(used_keys) == m:
            break
        assert pk not in used_keys, 'Tried to reuse key {}'.format(pk)

        sk_hex = privs[pk]
        used_keys.append(pk)

        b64sig = virtualchain.ecdsalib.sign_digest(hash_hex, sk_hex)
        sighex = binascii.hexlify(base64.b64decode(b64sig))
        sigs.append(sighex)

    assert len(
        used_keys) == m, 'Missing private keys (used {}, required {})'.format(
            len(used_keys), m)
    return base64.b64encode(
        virtualchain.btc_script_serialize([None] + sigs + [redeem_script]))
예제 #4
0
def get_privkey_info_params(privkey_info, config_path=CONFIG_PATH):
    """
    Get the parameters that characterize a private key
    info bundle:  the number of private keys, and the
    number of signatures required to make a valid
    transaction.
    * for single private keys, this is (1, 1)
    * for multisig info dicts, this is (m, n)

    Return (m, n) on success
    Return (None, None) on failure
    """

    if privkey_info is None:
        from .backend.blockchain import get_block_height

        key_config = (2, 3)
        log.warning('No private key info given, assuming {} key config'.format(
            key_config))
        return key_config

    if virtualchain.is_singlesig(privkey_info):
        return (1, 1)

    elif virtualchain.is_multisig(privkey_info):
        m, pubs = virtualchain.parse_multisig_redeemscript(
            privkey_info['redeem_script'])
        if m is None or pubs is None:
            return None, None
        return m, len(pubs)

    return None, None
def get_privkey_info_params(privkey_info, config_path=CONFIG_PATH):
    """
    Get the parameters that characterize a private key
    info bundle:  the number of private keys, and the
    number of signatures required to make a valid
    transaction.
    * for single private keys, this is (1, 1)
    * for multisig info dicts, this is (m, n)

    Return (m, n) on success
    Return (None, None) on failure
    """

    if privkey_info is None:
        from .backend.blockchain import get_block_height

        key_config = (2, 3)
        log.warning('No private key info given, assuming {} key config'.format(key_config))
        return key_config

    if virtualchain.is_singlesig( privkey_info ):
        return (1, 1)
    
    elif virtualchain.is_multisig( privkey_info ):
        m, pubs = virtualchain.parse_multisig_redeemscript(privkey_info['redeem_script'])
        if m is None or pubs is None:
            return None, None
        return m, len(pubs)

    return None, None
예제 #6
0
def verify_multisig(address, hash_hex, scriptSig):
    script_parts = virtualchain.btc_script_deserialize(scriptSig)
    if len(script_parts) < 2:
        log.warn("Verfiying multisig failed, couldn't grab script parts")
        return False
    redeem_script = script_parts[-1]
    script_sigs = script_parts[1:-1]

    if virtualchain.btc_make_p2sh_address(redeem_script) != address:
        log.warn(("Address {} does not match the public key in the" +
                  " provided scriptSig: provided redeemscript = {}").format(
                      address, redeem_script))
        return False

    m, pk_hexes = virtualchain.parse_multisig_redeemscript(redeem_script)
    if len(script_sigs) != m:
        log.warn("Failed to validate multi-sig, not correct number of signatures: have {}, require {}".format(
            len(script_sigs), m))
        return False

    cur_pk = 0
    for cur_sig in script_sigs:
        sig64 = base64.b64encode(binascii.unhexlify(cur_sig))
        sig_passed = False
        while not sig_passed:
            if cur_pk >= len(pk_hexes):
                log.warn("Failed to validate multi-signature, ran out of pks to check")
                return False
            sig_passed = virtualchain.ecdsalib.verify_digest(hash_hex, pk_hexes[cur_pk], sig64)
            cur_pk += 1

    return True
def sign_multisig(hash_hex, redeem_script, secret_keys):
    assert len(redeem_script) > 0
    m, pk_hexes = virtualchain.parse_multisig_redeemscript(redeem_script)

    privs = {}
    for sk in secret_keys:
        pk = virtualchain.ecdsalib.ecdsa_private_key(sk).public_key().to_hex()

        compressed_pubkey = keylib.key_formatting.compress(pk)
        uncompressed_pubkey = keylib.key_formatting.decompress(pk)

        privs[compressed_pubkey] = sk
        privs[uncompressed_pubkey] = sk

    used_keys, sigs = [],[]
    for pk in pk_hexes:
        if pk not in privs:
            continue
        if len(used_keys) == m:
            break
        assert pk not in used_keys, 'Tried to reuse key {}'.format(pk)

        sk_hex = privs[pk]
        used_keys.append(pk)

        b64sig = virtualchain.ecdsalib.sign_digest(hash_hex, sk_hex)
        sighex = binascii.hexlify(base64.b64decode(b64sig))
        sigs.append(sighex)

    assert len(used_keys) == m, 'Missing private keys (used {}, required {})'.format(len(used_keys), m)
    return base64.b64encode(virtualchain.btc_script_serialize([None] + sigs + [redeem_script]))
def tx_estimate_signature_len_bytes(privkey_info):
    if virtualchain.is_singlesig(privkey_info):
        return 73
    else:
        m, _ = virtualchain.parse_multisig_redeemscript( privkey_info['redeem_script'] )
        siglengths = 74 * m
        scriptlen = len(privkey_info['redeem_script']) / 2
        return 6 + scriptlen + siglengths
예제 #9
0
def tx_estimate_signature_len_bytes(privkey_info):
    if virtualchain.is_singlesig(privkey_info):
        return 73
    else:
        m, _ = virtualchain.parse_multisig_redeemscript(
            privkey_info['redeem_script'])
        siglengths = 74 * m
        scriptlen = len(privkey_info['redeem_script']) / 2
        return 6 + scriptlen + siglengths
예제 #10
0
    def _convert_key(given_privkey, key_type):
        if virtualchain.is_multisig(given_privkey):
            pks = given_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                given_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['{}_privkey'.format(key_type)] = multisig_info
            ret['{}_addresses'.format(key_type)] = [
                virtualchain.get_privkey_address(multisig_info)
            ]

        elif virtualchain.is_singlesig(given_privkey):
            pk = ecdsa_private_key(given_privkey).to_hex()
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [
                virtualchain.get_privkey_address(pk)
            ]

        elif virtualchain.btc_is_singlesig_segwit(given_privkey):
            pk = virtualchain.make_segwit_info(
                virtualchain.get_singlesig_privkey(given_privkey))
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [pk['address']]

        elif virtualchain.btc_is_multisig_segwit(given_privkey):
            pks = given_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                given_privkey['redeem_script'])
            assert m <= len(pks)

            pk = virtualchain.make_multisig_segwit_info(m, pks)
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [pk['address']]

        else:
            raise ValueError('Invalid owner key info')
예제 #11
0
def tx_sign_multisig(tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction

    TODO: move to virtualchain
    """
    # sign in the right order.  map all possible public keys to their private key
    privs = {}
    for pk in private_keys:
        pubk = keylib.ECPrivateKey(pk).public_key().to_hex()

        compressed_pubkey = keylib.key_formatting.compress(pubk)
        uncompressed_pubkey = keylib.key_formatting.decompress(pubk)

        privs[compressed_pubkey] = pk
        privs[uncompressed_pubkey] = pk

    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys, sigs = [], []
    for public_key in public_keys:
        if public_key not in privs:
            continue

        if len(used_keys) == m:
            break

        assert public_key not in used_keys, 'Tried to reuse key {}'.format(
            public_key)

        pk_str = privs[public_key]
        used_keys.append(public_key)

        sig = tx_make_input_signature(tx, idx, redeem_script, pk_str, hashcode)
        sigs.append(sig)

    assert len(
        used_keys) == m, 'Missing private keys (used {}, required {})'.format(
            len(used_keys), m)
    return bitcoin.apply_multisignatures(tx, idx, str(redeem_script), sigs)
예제 #12
0
def tx_sign_multisig(blockstack_tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction
    """

    # sign in the right order
    privs = dict([
        (virtualchain.BitcoinPrivateKey(str(pk_str)).public_key().to_hex(),
         str(pk_str)) for pk_str in private_keys
    ])
    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys = []
    sigs = []

    for ki in xrange(0, len(public_keys)):
        if not privs.has_key(public_keys[ki]):
            continue

        if len(used_keys) == m:
            break

        assert public_keys[
            ki] not in used_keys, "Tried to reuse key %s" % public_keys[ki]

        pk_str = privs[public_keys[ki]]
        used_keys.append(public_keys[ki])

        pk_hex = virtualchain.BitcoinPrivateKey(str(pk_str)).to_hex()
        sig = bitcoin.multisign(blockstack_tx,
                                idx,
                                str(redeem_script),
                                pk_hex,
                                hashcode=hashcode)
        sigs.append(sig)

    assert len(used_keys) == m, "Missing private keys"

    return bitcoin.apply_multisignatures(blockstack_tx, idx,
                                         str(redeem_script), sigs)
예제 #13
0
def tx_sign_multisig(tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction

    TODO: move to virtualchain
    """
    # sign in the right order
    privs = {
        virtualchain.BitcoinPrivateKey(str(pk)).public_key().to_hex(): str(pk)
        for pk in private_keys
    }
    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys, sigs = [], []
    for public_key in public_keys:
        if public_key not in privs:
            continue

        if len(used_keys) == m:
            break

        assert public_key not in used_keys, 'Tried to reuse key {}'.format(
            public_key)

        pk_str = privs[public_key]
        used_keys.append(public_key)

        pk_hex = virtualchain.BitcoinPrivateKey(str(pk_str)).to_hex()

        sig = tx_make_input_signature(tx, idx, redeem_script, pk_str, hashcode)
        # sig = bitcoin.multisign(tx, idx, str(redeem_script), pk_hex, hashcode=hashcode)
        sigs.append(sig)

    assert len(used_keys) == m, 'Missing private keys'
    return bitcoin.apply_multisignatures(tx, idx, str(redeem_script), sigs)
예제 #14
0
def make_wallet_keys(data_privkey=None,
                     owner_privkey=None,
                     payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None,
    }

    if data_privkey is not None:
        if not virtualchain.is_singlesig(data_privkey):
            raise ValueError('Invalid data key info')

        pk_data = ecdsa_private_key(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if virtualchain.is_multisig(owner_privkey):
            pks = owner_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                owner_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['owner_privkey'] = multisig_info
            ret['owner_addresses'] = [
                virtualchain.get_privkey_address(multisig_info)
            ]

        elif virtualchain.is_singlesig(owner_privkey):
            pk_owner = ecdsa_private_key(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner
            ret['owner_addresses'] = [
                virtualchain.get_privkey_address(pk_owner)
            ]

        else:
            raise ValueError('Invalid owner key info')

    if payment_privkey is None:
        return ret

    if virtualchain.is_multisig(payment_privkey):
        pks = payment_privkey['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(
            payment_privkey['redeem_script'])
        assert m <= len(pks)

        multisig_info = virtualchain.make_multisig_info(m, pks)
        ret['payment_privkey'] = multisig_info
        ret['payment_addresses'] = [
            virtualchain.get_privkey_address(multisig_info)
        ]

    elif virtualchain.is_singlesig(payment_privkey):
        pk_payment = ecdsa_private_key(payment_privkey).to_hex()
        ret['payment_privkey'] = pk_payment
        ret['payment_addresses'] = [
            virtualchain.get_privkey_address(pk_payment)
        ]

    else:
        raise ValueError('Invalid payment key info')

    ret['data_pubkey'] = ecdsa_private_key(
        ret['data_privkey']).public_key().to_hex()
    ret['data_pubkeys'] = [ret['data_pubkey']]

    return ret
예제 #15
0
def make_wallet_keys(data_privkey=None,
                     owner_privkey=None,
                     payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None,
    }

    if data_privkey is not None:
        if not is_singlesig(data_privkey):
            raise ValueError('Invalid data key info')

        pk_data = virtualchain.BitcoinPrivateKey(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if is_multisig(owner_privkey):
            pks = [
                virtualchain.BitcoinPrivateKey(pk).to_hex()
                for pk in owner_privkey['private_keys']
            ]
            m, pubs = virtualchain.parse_multisig_redeemscript(
                owner_privkey['redeem_script'])
            ret['owner_privkey'] = virtualchain.make_multisig_info(m, pks)
            ret['owner_addresses'] = [ret['owner_privkey']['address']]

        elif is_singlesig(owner_privkey):
            pk_owner = virtualchain.BitcoinPrivateKey(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner
            ret['owner_addresses'] = [
                virtualchain.BitcoinPrivateKey(
                    pk_owner).public_key().address()
            ]

        else:
            raise ValueError('Invalid owner key info')

    if payment_privkey is None:
        return ret

    if is_multisig(payment_privkey):
        pks = [
            virtualchain.BitcoinPrivateKey(pk).to_hex()
            for pk in payment_privkey['private_keys']
        ]
        m, pubs = virtualchain.parse_multisig_redeemscript(
            payment_privkey['redeem_script'])
        ret['payment_privkey'] = virtualchain.make_multisig_info(m, pks)
        ret['payment_addresses'] = [ret['payment_privkey']['address']]

    elif is_singlesig(payment_privkey):
        pk_payment = virtualchain.BitcoinPrivateKey(payment_privkey).to_hex()
        ret['payment_privkey'] = pk_payment
        ret['payment_addresses'] = [
            virtualchain.BitcoinPrivateKey(pk_payment).public_key().address()
        ]

    else:
        raise ValueError('Invalid payment key info')

    ret['data_pubkey'] = ECPrivateKey(
        ret['data_privkey']).public_key().to_hex()
    ret['data_pubkeys'] = [ret['data_pubkey']]

    return ret
예제 #16
0
def get_compressed_and_decompressed_private_key_info(privkey_info):
    """
    Get the compressed and decompressed versions of private keys and addresses
    Return {'compressed_addr': ..., 'compressed_private_key_info': ..., 'decompressed_addr': ..., 'decompressed_private_key_info': ...} on success
    """
    if virtualchain.is_multisig(
            privkey_info) or virtualchain.btc_is_multisig_segwit(privkey_info):

        # get both compressed and decompressed addresses
        privkeys = privkey_info['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(
            privkey_info['redeem_script'])
        privkeys_hex = [ecdsa_private_key(pk).to_hex() for pk in privkeys]

        decompressed_privkeys = map(
            lambda pk: pk if len(pk) == 64 else pk[:-2], privkeys_hex)
        compressed_privkeys = map(
            lambda pk: pk
            if len(pk) == 66 and pk[:-2] == '01' else pk, privkeys_hex)

        decompressed_multisig = virtualchain.make_multisig_info(
            m, decompressed_privkeys, compressed=True)
        compressed_multisig = virtualchain.make_multisig_info(
            m, compressed_privkeys, compressed=False)

        decompressed_addr = virtualchain.address_reencode(
            decompressed_multisig['address'])
        compressed_addr = virtualchain.address_reencode(
            compressed_multisig['address'])

        return {
            'decompressed_private_key_info': decompressed_multisig,
            'compressed_private_key_info': compressed_multisig,
            'compressed_addr': compressed_addr,
            'decompressed_addr': decompressed_addr
        }

    elif virtualchain.is_singlesig(
            privkey_info) or virtualchain.btc_is_singlesig_segwit(
                privkey_info):

        pk = virtualchain.get_singlesig_privkey(privkey_info)

        # get both compressed and decompressed addresses
        compressed_pk = None
        decompressed_pk = None
        if len(pk) == 66 and pk.endswith('01'):
            compressed_pk = pk
            decompressed_pk = pk[:-2]
        else:
            compressed_pk = pk
            decompressed_pk = pk + '01'

        compressed_pubk = ecdsa_private_key(
            compressed_pk).public_key().to_hex()
        decompressed_pubk = ecdsa_private_key(
            decompressed_pk).public_key().to_hex()

        compressed_addr = virtualchain.address_reencode(
            keylib.public_key_to_address(compressed_pubk))
        decompressed_addr = virtualchain.address_reencode(
            keylib.public_key_to_address(decompressed_pubk))

        return {
            'decompressed_private_key_info': decompressed_pk,
            'compressed_private_key_info': compressed_pk,
            'compressed_addr': compressed_addr,
            'decompressed_addr': decompressed_addr
        }

    else:
        raise ValueError("Invalid key bundle")