예제 #1
0
def make_fully_valid(pubkey_start):
    """Take a too short data pubkey and make it look like a real pubkey.

    Take an obfuscated chunk of data that is two bytes too short to be a pubkey and
    add a sign byte to its beginning and a nonce byte to its end. Choose these
    bytes so that the resulting sequence of bytes is a fully valid pubkey (i.e. on
    the ECDSA curve). Find the correct bytes by guessing randomly until the check
    passes. (In parsing, these two bytes are ignored.)
    """
    assert type(pubkey_start) == bytes
    assert len(pubkey_start) == 31    # One sign byte and one nonce byte required (for 33 bytes).

    random_bytes = hashlib.sha256(pubkey_start).digest()      # Deterministically generated, for unit tests.
    sign = (random_bytes[0] & 0b1) + 2                  # 0x02 or 0x03
    nonce = initial_nonce = random_bytes[1]

    pubkey = b''
    while not script.is_fully_valid(pubkey):
        # Increment nonce.
        nonce += 1
        assert nonce != initial_nonce

        # Construct a possibly fully valid public key.
        pubkey = bytes([sign]) + pubkey_start + bytes([nonce % 256])

    assert len(pubkey) == 33
    return pubkey
예제 #2
0
def compose_transaction(db, name, params,
                        encoding='auto',
                        fee_per_kb=config.DEFAULT_FEE_PER_KB,
                        regular_dust_size=config.DEFAULT_REGULAR_DUST_SIZE,
                        multisig_dust_size=config.DEFAULT_MULTISIG_DUST_SIZE,
                        op_return_value=config.DEFAULT_OP_RETURN_VALUE,
                        pubkey=None,
                        allow_unconfirmed_inputs=False,
                        fee=None,
                        fee_provided=0):
    """Create and return a transaction."""

    # Get provided pubkeys.
    if type(pubkey) == str:
        provided_pubkeys = [pubkey]
    elif type(pubkey) == list:
        provided_pubkeys = pubkey
    elif pubkey == None:
        provided_pubkeys = []
    else:
        assert False

    # Get additional pubkeys from `source` and `destination` params.
    # Convert `source` and `destination` to pubkeyhash form.
    for address_name in ['source', 'destination']:
        if address_name in params:
            address = params[address_name]
            provided_pubkeys += script.extract_pubkeys(address)
            params[address_name] = script.make_pubkeyhash(address)

    # Check validity of collected pubkeys.
    for pubkey in provided_pubkeys:
        if not script.is_fully_valid(binascii.unhexlify(pubkey)):
            raise script.AddressError('invalid public key: {}'.format(pubkey))

    compose_method = sys.modules['shellpartylib.lib.messages.{}'.format(name)].compose
    compose_params = inspect.getargspec(compose_method)[0]
    missing_params = [p for p in compose_params if p not in params and p != 'db']
    for param in missing_params:
        params[param] = None

    # try:  # NOTE: For debugging, e.g. with `Invalid Params` error.
    tx_info = compose_method(db, **params)
    return transaction.construct(db, tx_info, encoding=encoding,
                                        fee_per_kb=fee_per_kb,
                                        regular_dust_size=regular_dust_size,
                                        multisig_dust_size=multisig_dust_size,
                                        op_return_value=op_return_value,
                                        provided_pubkeys=provided_pubkeys,
                                        allow_unconfirmed_inputs=allow_unconfirmed_inputs,
                                        exact_fee=fee,
                                        fee_provided=fee_provided)
예제 #3
0
def get_pubkey_monosig(pubkeyhash, pubkey_resolver=input_pubkey):
    if wallet.is_valid(pubkeyhash):

        # If in wallet, get from wallet.
        logging.debug('Looking for public key for `{}` in wallet.'.format(pubkeyhash))
        if wallet.is_mine(pubkeyhash):
            pubkey = wallet.get_pubkey(pubkeyhash)
            if pubkey:
                return pubkey
        logging.debug('Public key for `{}` not found in wallet.'.format(pubkeyhash))

        # If in blockchain (and not in wallet), get from blockchain.
        logging.debug('Looking for public key for `{}` in blockchain.'.format(pubkeyhash))
        try:
            pubkey = util.api('search_pubkey', {'pubkeyhash': pubkeyhash, 'provided_pubkeys': None})
        except util.RPCError as e:
            pubkey = None
        if pubkey:
            return pubkey
        logging.debug('Public key for `{}` not found in blockchain.'.format(pubkeyhash))

        # If not in wallet and not in blockchain, get from user.
        answer = pubkey_resolver(pubkeyhash)
        if not answer:
            return None

        # Public Key or Private Key?
        is_fully_valid_pubkey = True
        try:
            is_fully_valid_pubkey = script.is_fully_valid(binascii.unhexlify(answer))
        except binascii.Error:
            is_fully_valid_pubkey = False
        if is_fully_valid_pubkey:
            logging.debug('Answer was a fully valid public key.')
            pubkey = answer
        else:
            logging.debug('Answer was not a fully valid public key. Assuming answer was a private key.')
            private_key = answer
            try:
                pubkey = script.private_key_to_public_key(private_key)
            except script.AltcoinSupportError:
                raise InputError('invalid private key')
        if pubkeyhash != script.pubkey_to_pubkeyhash(binascii.unhexlify(bytes(pubkey, 'utf-8'))):
            raise InputError('provided public or private key does not match the source address')

        return pubkey

    return None