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