コード例 #1
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
コード例 #2
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
コード例 #3
0
ファイル: keys.py プロジェクト: warrenween/blockstack-core
def is_singlesig_hex(privkey_info):
    """
    Does the given private key info represent
    a single signature bundle? (i.e. one private key)?
    """
    return virtualchain.is_singlesig(privkey_info) and re.match(
        r"^[0-9a-fA-F]+$", privkey_info)
コード例 #4
0
ファイル: keys.py プロジェクト: warrenween/blockstack-core
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
コード例 #5
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
コード例 #6
0
ファイル: scripts.py プロジェクト: Redd-ID/blockstack-core
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
コード例 #7
0
def get_data_privkey(user_zonefile, wallet_keys=None, config_path=CONFIG_PATH):
    """
    Get the data private key that matches this zonefile.
    * If the zonefile has a public key that this wallet does not have, then there is no data key.
    * If the zonefile does not have a public key, then:
      * if the data private key in the wallet matches the owner private key, then the wallet data key is the data key to use.
      (this is for legacy compatibility with onename.com, which does not create data keys for users)
      * otherwise, there is no data key

    Return the private key on success
    Return {'error': ...} if we could not find the key
    """
    from .wallet import get_wallet
    from .user import user_zonefile_data_pubkey

    zonefile_data_pubkey = None

    try:
        # NOTE: uncompressed...
        zonefile_data_pubkey = user_zonefile_data_pubkey(user_zonefile)
    except ValueError:
        log.error('Multiple pubkeys defined in zone file')
        return {'error': 'Multiple data public keys in zonefile'}

    wallet_keys = {} if wallet_keys is None else wallet_keys
    if wallet_keys.get('data_privkey', None) is None:
        log.error('No data private key set')
        return {'error': 'No data private key in wallet keys'}

    wallet = get_wallet(config_path=CONFIG_PATH) if wallet_keys is None else wallet_keys
    assert wallet, 'Failed to get wallet'

    if not wallet.has_key('data_privkey'):
        log.error("No data private key in wallet")
        return {'error': 'No data private key in wallet'}

    data_privkey = wallet['data_privkey']

    # NOTE: uncompresssed
    wallet_data_pubkey = keylib.key_formatting.decompress(get_pubkey_hex(str(data_privkey)))

    if zonefile_data_pubkey is None and wallet_data_pubkey is not None:
        # zone file does not have a data key set.
        # the wallet data key *must* match the owner key
        owner_privkey_info = wallet['owner_privkey']
        owner_privkey = None
        if virtualchain.is_singlesig(owner_privkey_info):
            owner_privkey = owner_privkey_info
        elif virtualchain.is_multisig(owner_privkey_info):
            owner_privkey = owner_privkey_info['private_keys'][0]

        owner_pubkey = keylib.key_formatting.decompress(get_pubkey_hex(str(owner_privkey)))
        if owner_pubkey != wallet_data_pubkey:
            # doesn't match. no data key 
            return {'error': 'No zone file key, and data key does not match owner key ({} != {})'.format(owner_pubkey, wallet_data_pubkey)}
        
    return str(data_privkey)
コード例 #8
0
ファイル: keys.py プロジェクト: warrenween/blockstack-core
def privkey_to_string(privkey_info):
    """
    Convert private key to string
    Return None on invalid
    """
    if virtualchain.is_singlesig(privkey_info):
        return singlesig_privkey_to_string(privkey_info)

    if virtualchain.is_multisig(privkey_info):
        return multisig_privkey_to_string(privkey_info)

    return None
コード例 #9
0
def privkey_to_string(privkey_info):
    """
    Convert private key to string
    Return None on invalid
    """
    if virtualchain.is_singlesig(privkey_info):
        return singlesig_privkey_to_string(privkey_info)

    if virtualchain.is_multisig(privkey_info):
        return multisig_privkey_to_string(privkey_info)

    return None
コード例 #10
0
def privkey_to_string(privkey_info):
    """
    Convert private key to string
    Return None on invalid
    """
    if virtualchain.is_singlesig(privkey_info):
        return singlesig_privkey_to_string(privkey_info)

    elif isinstance(privkey_info,
                    dict) and privkey_info.has_key('private_keys'):
        return multisig_privkey_to_string(privkey_info)

    return None
コード例 #11
0
ファイル: wallet.py プロジェクト: warrenween/blockstack-core
def get_data_key_from_owner_key_LEGACY(owner_privkey):
    """
    Given the owner private key, select a data private key to use.

    THIS IS ONLY FOR LEGACY CLIENTS THAT DO NOT HAVE DATA PRIVATE KEYS
    DEFINED IN THEIR WALLETS.
    """
    data_privkey = None
    if virtualchain.is_singlesig(owner_privkey):
        data_privkey = owner_privkey
    else:
        # data private key gets instantiated from the first owner private key,
        # if we have a multisig key bundle.
        data_privkey = owner_privkey['private_keys'][0]

    return data_privkey
コード例 #12
0
def get_data_key_from_owner_key_LEGACY(owner_privkey):
    """
    Given the owner private key, select a data private key to use.

    THIS IS ONLY FOR LEGACY CLIENTS THAT DO NOT HAVE DATA PRIVATE KEYS
    DEFINED IN THEIR WALLETS.
    """
    data_privkey = None
    if virtualchain.is_singlesig(owner_privkey):
        data_privkey = owner_privkey
    else:
        # data private key gets instantiated from the first owner private key,
        # if we have a multisig key bundle.
        data_privkey = owner_privkey['private_keys'][0]

    return data_privkey
コード例 #13
0
ファイル: wallet.py プロジェクト: lacabra/blockstack-core
def make_legacy_wallet_013_keys(data, password):
    """
    Given a legacy 0.13 wallet with "owner private key" and "payment private key"
    defined, generate the owner, payment, and data values.

    In these wallets, the data key is the same as the owner key.

    Return {'payment': priv, 'owner': priv, 'data': priv} on success
    Return {'error': ...} on error
    """
    payment_privkey = decrypt_private_key_info(
        data['encrypted_payment_privkey'], password)
    owner_privkey = decrypt_private_key_info(data['encrypted_owner_privkey'],
                                             password)

    err = None
    if 'error' in payment_privkey:
        err = payment_privkey['error']
    else:
        payment_privkey = payment_privkey.pop('private_key_info')

    if 'error' in owner_privkey:
        err = owner_privkey['error']
    else:
        owner_privkey = owner_privkey.pop('private_key_info')

    if err:
        ret = {'error': "Failed to decrypt owner and payment keys"}
        log.debug("Failed to decrypt owner or payment keys: {}".format(err))
        return ret

    data_privkey = None
    if virtualchain.is_singlesig(owner_privkey):
        data_privkey = virtualchain.get_singlesig_privkey(owner_privkey)
    else:
        # data private key gets instantiated from the first owner private key,
        # if we have a multisig key bundle.
        data_privkey = owner_privkey['private_keys'][0]

    key_defaults = {
        'payment': payment_privkey,
        'owner': owner_privkey,
        'data': data_privkey
    }

    return key_defaults
コード例 #14
0
def make_legacy_wallet_013_keys(data, password):
    """
    Given a legacy 0.13 wallet with "owner private key" and "payment private key"
    defined, generate the owner, payment, and data values.

    In these wallets, the data key is the same as the owner key.

    Return {'payment': priv, 'owner': priv, 'data': priv} on success
    Return {'error': ...} on error
    """
    payment_privkey = decrypt_private_key_info(data['encrypted_payment_privkey'], password)
    owner_privkey = decrypt_private_key_info(data['encrypted_owner_privkey'], password)

    err = None
    if 'error' in payment_privkey:
        err = payment_privkey['error']
    else:
        payment_privkey = payment_privkey.pop('private_key_info')

    if 'error' in owner_privkey:
        err = owner_privkey['error']
    else:
        owner_privkey = owner_privkey.pop('private_key_info')

    if err:
        ret = {'error': "Failed to decrypt owner and payment keys"}
        log.debug("Failed to decrypt owner or payment keys: {}".format(err))
        return ret
 
    data_privkey = None
    if virtualchain.is_singlesig(owner_privkey):
        data_privkey = owner_privkey
    else:
        # data private key gets instantiated from the first owner private key,
        # if we have a multisig key bundle.
        data_privkey = owner_privkey['private_keys'][0]

    key_defaults = {
        'payment': payment_privkey,
        'owner': owner_privkey,
        'data': data_privkey
    }

    return key_defaults
コード例 #15
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')
コード例 #16
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,
    }

    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')

    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:
        _convert_key(owner_privkey, 'owner')

    if payment_privkey is None:
        return ret

    _convert_key(payment_privkey, 'payment')

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

    return ret
コード例 #17
0
ファイル: keys.py プロジェクト: warrenween/blockstack-core
def get_data_privkey(user_zonefile, wallet_keys=None, config_path=CONFIG_PATH):
    """
    Get the data private key that matches this zonefile.
    * If the zonefile has a public key that this wallet does not have, then there is no data key.
    * If the zonefile does not have a public key, then:
      * if the data private key in the wallet matches the owner private key, then the wallet data key is the data key to use.
      (this is for legacy compatibility with onename.com, which does not create data keys for users)
      * otherwise, there is no data key

    Return the private key on success
    Return {'error': ...} if we could not find the key
    """
    from .wallet import get_wallet
    from .user import user_zonefile_data_pubkey

    zonefile_data_pubkey = None

    try:
        # NOTE: uncompressed...
        zonefile_data_pubkey = user_zonefile_data_pubkey(user_zonefile)
    except ValueError:
        log.error('Multiple pubkeys defined in zone file')
        return {'error': 'Multiple data public keys in zonefile'}

    wallet_keys = {} if wallet_keys is None else wallet_keys
    if wallet_keys.get('data_privkey', None) is None:
        log.error('No data private key set')
        return {'error': 'No data private key in wallet keys'}

    wallet = get_wallet(
        config_path=CONFIG_PATH) if wallet_keys is None else wallet_keys
    assert wallet, 'Failed to get wallet'

    if not wallet.has_key('data_privkey'):
        log.error("No data private key in wallet")
        return {'error': 'No data private key in wallet'}

    data_privkey = wallet['data_privkey']

    # NOTE: uncompresssed
    wallet_data_pubkey = keylib.key_formatting.decompress(
        get_pubkey_hex(str(data_privkey)))

    if zonefile_data_pubkey is None and wallet_data_pubkey is not None:
        # zone file does not have a data key set.
        # the wallet data key *must* match the owner key
        owner_privkey_info = wallet['owner_privkey']
        owner_privkey = None
        if virtualchain.is_singlesig(owner_privkey_info):
            owner_privkey = owner_privkey_info
        elif virtualchain.is_multisig(owner_privkey_info):
            owner_privkey = owner_privkey_info['private_keys'][0]

        owner_pubkey = keylib.key_formatting.decompress(
            get_pubkey_hex(str(owner_privkey)))
        if owner_pubkey != wallet_data_pubkey:
            # doesn't match. no data key
            return {
                'error':
                'No zone file key, and data key does not match owner key ({} != {})'
                .format(owner_pubkey, wallet_data_pubkey)
            }

    return str(data_privkey)
コード例 #18
0
ファイル: keys.py プロジェクト: warrenween/blockstack-core
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
コード例 #19
0
ファイル: wallet.py プロジェクト: warrenween/blockstack-core
def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
    """
    Encrypt the wallet.
    Return the encrypted dict on success
    Return {'error': ...} on error
    """
    
    if test_legacy:
        assert BLOCKSTACK_TEST, 'test_legacy only works in test mode'

    # must be conformant to the current schema
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    owner_address = virtualchain.get_privkey_address(decrypted_wallet['owner_privkey'])
    payment_address = virtualchain.get_privkey_address(decrypted_wallet['payment_privkey'])
    data_pubkey = None
    data_privkey_info = None

    if decrypted_wallet.has_key('data_privkey'):

        # make sure data key is hex encoded
        data_privkey_info = decrypted_wallet.get('data_privkey', None)
        if not test_legacy:
            assert data_privkey_info

        if data_privkey_info:
            if not is_singlesig_hex(data_privkey_info):
                data_privkey_info = ecdsa_private_key(data_privkey_info).to_hex()

            if not virtualchain.is_singlesig(data_privkey_info):
                log.error('Invalid data private key')
                return {'error': 'Invalid data private key'}
        
        data_pubkey = ecdsa_private_key(data_privkey_info).public_key().to_hex()

            
    wallet = {
        'owner_addresses': [owner_address],
        'payment_addresses': decrypted_wallet['payment_addresses'],
        'version': decrypted_wallet['version'],
        'enc': None,        # to be filled in
    }

    if data_pubkey:
        wallet['data_pubkey'] = data_pubkey
        wallet['data_pubkeys'] = [data_pubkey]
    
    wallet_enc = {
        'owner_privkey': decrypted_wallet['owner_privkey'],
        'payment_privkey': decrypted_wallet['payment_privkey'],
    }

    if data_privkey_info:
        wallet_enc['data_privkey'] = data_privkey_info

    # extra sanity check: make sure that when re-combined with the wallet,
    # we're still valid 
    recombined_wallet = copy.deepcopy(wallet)
    recombined_wallet.update(wallet_enc)
    try:
        jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            # no data key is allowed if we're testing the absence of a data key 
            jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    # good to go!
    # encrypt secrets 
    wallet_secret_str = json.dumps(wallet_enc, sort_keys=True)
    password_hex = hexlify(password)
    encrypted_secret_str = aes_encrypt(wallet_secret_str, password_hex)

    # fulfill wallet
    wallet['enc'] = encrypted_secret_str
    
    # sanity check
    try:
        jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    return wallet
コード例 #20
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")
コード例 #21
0
def is_singlesig_hex(privkey_info):
    """
    Does the given private key info represent
    a single signature bundle? (i.e. one private key)?
    """
    return virtualchain.is_singlesig(privkey_info) and re.match(r"^[0-9a-fA-F]+$", privkey_info)
コード例 #22
0
def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
    """
    Encrypt the wallet.
    Return the encrypted dict on success
    Return {'error': ...} on error
    """
    
    if test_legacy:
        assert BLOCKSTACK_TEST, 'test_legacy only works in test mode'

    # must be conformant to the current schema
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    owner_address = virtualchain.get_privkey_address(decrypted_wallet['owner_privkey'])
    payment_address = virtualchain.get_privkey_address(decrypted_wallet['payment_privkey'])
    data_pubkey = None
    data_privkey_info = None

    if decrypted_wallet.has_key('data_privkey'):

        # make sure data key is hex encoded
        data_privkey_info = decrypted_wallet.get('data_privkey', None)
        if not test_legacy:
            assert data_privkey_info

        if data_privkey_info:
            if not is_singlesig_hex(data_privkey_info):
                data_privkey_info = ecdsa_private_key(data_privkey_info).to_hex()

            if not virtualchain.is_singlesig(data_privkey_info):
                log.error('Invalid data private key')
                return {'error': 'Invalid data private key'}
        
        data_pubkey = ecdsa_private_key(data_privkey_info).public_key().to_hex()

            
    wallet = {
        'owner_addresses': [owner_address],
        'payment_addresses': decrypted_wallet['payment_addresses'],
        'version': decrypted_wallet['version'],
        'enc': None,        # to be filled in
    }

    if data_pubkey:
        wallet['data_pubkey'] = data_pubkey
        wallet['data_pubkeys'] = [data_pubkey]
    
    wallet_enc = {
        'owner_privkey': decrypted_wallet['owner_privkey'],
        'payment_privkey': decrypted_wallet['payment_privkey'],
    }

    if data_privkey_info:
        wallet_enc['data_privkey'] = data_privkey_info

    # extra sanity check: make sure that when re-combined with the wallet,
    # we're still valid 
    recombined_wallet = copy.deepcopy(wallet)
    recombined_wallet.update(wallet_enc)
    try:
        jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            # no data key is allowed if we're testing the absence of a data key 
            jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    # good to go!
    # encrypt secrets 
    wallet_secret_str = json.dumps(wallet_enc, sort_keys=True)
    password_hex = hexlify(password)
    encrypted_secret_str = aes_encrypt(wallet_secret_str, password_hex)

    # fulfill wallet
    wallet['enc'] = encrypted_secret_str
    
    # sanity check
    try:
        jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    return wallet