def _is_public_key_valid(self, hex: str) -> bool: try: PublicKey.from_hex(hex) return True except (ValueError, TypeError): # ValueError <- PublicKey.from_hex() # TypeError <- PublicKey() return False
def test_to_address_compressed(self): pubkey_hex = '036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) address = output.to_address() assert isinstance(address, P2PKH_Address) assert address.to_string() == '16ZbRYV2f1NNuNQ9FDYyUMC2d1cjGS2G3L'
def test_to_script_bytes(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) raw = output.to_script_bytes() assert isinstance(raw, bytes) assert raw == push_item(bytes.fromhex(pubkey_hex)) + pack_byte(OP_CHECKSIG)
def _convert_version_14(self) -> None: # convert imported wallets for 3.0 if not self._is_upgrade_method_needed(13, 13): return if self.get('wallet_type') == 'imported': addresses = self.get('addresses') if type(addresses) is list: addresses = dict([(x, None) for x in addresses]) self.put('addresses', addresses) elif self.get('wallet_type') == 'standard': if self.get('keystore').get('type') == 'imported': addresses = set(self.get('addresses').get('receiving')) pubkeys = self.get('keystore').get('keypairs').keys() assert len(addresses) == len(pubkeys) d = {} for pubkey in pubkeys: addr = PublicKey.from_hex(pubkey).to_address( coin=Net.COIN).to_string() assert addr in addresses d[addr] = { 'pubkey': pubkey, 'redeem_script': None, 'type': 'p2pkh' } self.put('addresses', d) self.put('pubkeys', None) self.put('wallet_type', 'imported') self.put('seed_version', 14)
def get_tx_derivations(self, tx): keypairs = {} for txin_index, txin in enumerate(tx.inputs()): sigs = txin['signatures'] x_pubkeys = txin['x_pubkeys'] # Remove pubkeys that have already signed used = set() sig_idx = len(sigs) - 1 pub_idx = len(x_pubkeys) - 1 pre_hash = tx.preimage_hash(txin_index) while sig_idx >= 0: sig = sigs[sig_idx] sig_idx -= 1 if sig is not None: sig = bytes.fromhex(sig)[:-1] while pub_idx >= 0: x_pubkey = x_pubkeys[pub_idx] public_key = PublicKey.from_hex( xpubkey_to_pubkey(x_pubkey)) used.add(x_pubkey) if public_key.verify_der_signature( sig, pre_hash, None): break pub_idx -= 1 pub_idx -= 1 for x_pubkey in x_pubkeys: if x_pubkey in used: continue derivation = self.get_pubkey_derivation(x_pubkey) if not derivation: continue keypairs[x_pubkey] = derivation return keypairs
def _write(self): if threading.currentThread().isDaemon(): logger.error('daemon thread cannot write wallet') return if not self.modified: return s = json.dumps(self.data, indent=4, sort_keys=True) if self.pubkey: c = zlib.compress(s.encode()) s = PublicKey.from_hex(self.pubkey).encrypt_message_to_base64(c) temp_path = "%s.tmp.%s" % (self.path, os.getpid()) with open(temp_path, "w", encoding='utf-8') as f: f.write(s) f.flush() os.fsync(f.fileno()) mode = os.stat(self.path).st_mode if self.file_exists( ) else stat.S_IREAD | stat.S_IWRITE # perform atomic write on POSIX systems try: os.rename(temp_path, self.path) except: os.remove(self.path) os.rename(temp_path, self.path) os.chmod(self.path, mode) self._file_exists = True self.raw = s logger.debug("saved '%s'", self.path) self.modified = False
def createmultisig(self, threshold, pubkeys): """Create multisig address""" assert isinstance(pubkeys, list), (type(threshold), type(pubkeys)) public_keys = [PublicKey.from_hex(pubkey) for pubkey in sorted(pubkeys)] output = P2MultiSig_Output(public_keys, threshold) redeem_script = output.to_script_bytes() address = P2SH_Address(hash160(redeem_script)).to_string() return {'address':address, 'redeemScript':redeem_script.hex()}
def test_to_script(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) S = output.to_script() assert isinstance(S, Script) assert S == output.to_script_bytes() assert isinstance(classify_output_script(S, Bitcoin), P2PK_Output)
def __init__(self, d): Software_KeyStore.__init__(self) keypairs = d.get('keypairs', {}) self.keypairs = { PublicKey.from_hex(pubkey): enc_privkey for pubkey, enc_privkey in keypairs.items() } self._sorted = None
def from_pubkey(cls, pubkey): '''Returns a P2PKH address from a public key. The public key can be bytes or a hex string.''' if isinstance(pubkey, str): pubkey = PublicKey.from_hex(pubkey) else: pubkey = PublicKey.from_bytes(pubkey) return cls(hash_160(pubkey.to_bytes()), cls.ADDR_P2PKH)
def get_pubkey_derivation(self, x_pubkey): if x_pubkey[0:2] in ['02', '03', '04']: pubkey = PublicKey.from_hex(x_pubkey) if pubkey in self.keypairs: return pubkey elif x_pubkey[0:2] == 'fd': addr = _script_to_address(x_pubkey[2:]) return self.address_to_pubkey(addr)
def load_state(self, keyinstance_rows: List[KeyInstanceRow]) -> None: self._keypairs.clear() self._public_keys.clear() for row in keyinstance_rows: data = json.loads(row.derivation_data) public_key = PublicKey.from_hex(data['pub']) self._public_keys[row.keyinstance_id] = public_key self._keypairs[public_key] = cast(str, data['prv'])
def test_raw_public_keys(self, raw_hex, coin): public_key = PublicKey.from_hex(raw_hex) x_pubkey = XPublicKey.from_hex(raw_hex) # assert x_pubkey.to_bytes() == bytes.fromhex(raw_hex) # assert x_pubkey.to_hex() == raw_hex assert not x_pubkey.is_bip32_key() assert x_pubkey.to_public_key() == public_key assert x_pubkey.to_address() == public_key.to_address(coin=coin) assert x_pubkey.to_address().coin() is coin
def test_update_password(self): keystore = Imported_KeyStore() keystore._keypairs = { PublicKey.from_hex(a): b for a, b in keypairs_dict.items() } keystore.update_password('new password', 'password') pubkey = list(keystore._keypairs.keys())[0] assert keystore.export_private_key(pubkey, 'new password') == ( 'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617') with pytest.raises(AssertionError): keystore.update_password('', 'new password')
def test_to_address_uncompressed(self): pubkey_hex = ( '046d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e' '2487e6222a6664e079c8edf7518defd562dbeda1e7593dfd7f0be285880a24dab' ) pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) address = output.to_address() assert isinstance(address, P2PKH_Address) assert address.to_string() == '1G9f5Kdd5A8MeBN8jduUNfcAXUVvtFxVhP'
def test_old_keystore(self, raw_hex, public_key_hex, coin): public_key = PublicKey.from_hex(public_key_hex) assert public_key.is_compressed() is False x_pubkey = XPublicKey.from_hex(raw_hex) # assert x_pubkey.to_bytes() == bytes.fromhex(raw_hex) # assert x_pubkey.to_hex() == raw_hex assert not x_pubkey.is_bip32_key() assert x_pubkey.to_public_key() == public_key assert x_pubkey.to_public_key().is_compressed() is False assert x_pubkey.to_address() == public_key.to_address(coin=coin) assert x_pubkey.to_address().coin() is coin
def _write(self) -> bytes: # We pack as JSON before encrypting, so can't just put in the generic key value store, # as that is unencrypted and would just be JSON values in the DB. s = json.dumps(self._data, indent=4, sort_keys=True) if self._pubkey: c = zlib.compress(s.encode()) raw = PublicKey.from_hex(self._pubkey).encrypt_message(c) else: raw = s.encode() self._db_values.set("jsondata", raw) self._primed = True return raw
def get_preimage_script(self, txin): _type = txin['type'] if _type == 'p2pkh': return txin['address'].to_script_bytes().hex() elif _type == 'p2sh': pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) return multisig_script(pubkeys, txin['num_sig']) elif _type == 'p2pk': output = P2PK_Output(PublicKey.from_hex(txin['pubkeys'][0])) return output.to_script_bytes().hex() elif _type == 'unknown': # this approach enables most P2SH smart contracts # (but take care if using OP_CODESEPARATOR) return txin['scriptCode'] else: raise RuntimeError('Unknown txin type', _type)
def xpubkey_to_address(x_pubkey): if x_pubkey[0:2] == 'fd': address = _script_to_address(x_pubkey[2:]) return x_pubkey, address if x_pubkey[0:2] in ['02', '03', '04']: pubkey = x_pubkey elif x_pubkey[0:2] == 'ff': xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey) pubkey = BIP32_KeyStore.get_pubkey_from_xpub(xpub, s) elif x_pubkey[0:2] == 'fe': mpk, s = Old_KeyStore.parse_xpubkey(x_pubkey) pubkey = Old_KeyStore.get_pubkey_from_mpk(mpk, s[0], s[1]) else: raise Exception("Cannot parse pubkey") if pubkey: address = PublicKey.from_hex(pubkey).to_address(coin=Net.COIN) return pubkey, address
def _convert_version_13_b(self) -> None: # version 13 is ambiguous, and has an earlier and a later structure if not self._is_upgrade_method_needed(0, 13): return if self.get('wallet_type') == 'standard': if self.get('keystore').get('type') == 'imported': pubkeys = self.get('keystore').get('keypairs').keys() d: Dict[str, List[str]] = {'change': []} receiving_addresses = [] for pubkey in pubkeys: addr = PublicKey.from_hex(pubkey).to_address( coin=Net.COIN).to_string() receiving_addresses.append(addr) d['receiving'] = receiving_addresses self.put('addresses', d) self.put('pubkeys', None) self.put('seed_version', 13)
def _write(self) -> bytes: seed_version = self._get_seed_version() raw = json.dumps(self._data, indent=4, sort_keys=True) if self._pubkey: c = zlib.compress(raw.encode()) raw = PublicKey.from_hex(self._pubkey).encrypt_message_to_base64(c) temp_path = "%s.tmp.%s" % (self._path, os.getpid()) with open(temp_path, "w", encoding='utf-8') as f: f.write(raw) f.flush() os.fsync(f.fileno()) mode = os.stat(self._path).st_mode if self.file_exists( ) else stat.S_IREAD | stat.S_IWRITE os.replace(temp_path, self._path) os.chmod(self._path, mode) return raw.encode()
def _write(self) -> bytes: records: List[Tuple[str, bytes]] = [] # We pack as JSON before encrypting, so can't just put in the generic key value store, # as that is unencrypted and would just be JSON values in the DB. s = json.dumps(self._data, indent=4, sort_keys=True) if self._pubkey: c = zlib.compress(s.encode()) raw = PublicKey.from_hex(self._pubkey).encrypt_message(c) else: raw = s.encode() records.append(("jsondata", raw)) if self._primed: self._db_values.update_many(records) else: self._db_values.add_many(records) self._primed = True return raw
'bcf7ae875b585e00a61055372c1e99046b20f5fbfcd8659959afb6f428326bfa', out_index=1, height=500000, address=address_from_string('1LoVGDgRs9hTfTNJNuXKSpywcbdvwRXpmK'), is_coinbase=False), UTXO( value=1804376, script_pubkey=Script.from_hex( '4104d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0aac' ), tx_hash= '3f5a1badfe1beb42b650f325b20935f09f3ab43a3c473c5be18f58308fc7eff1', out_index=3, height=50000, address=PublicKey.from_hex( '04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a' ), is_coinbase=False) ], { XPublicKey('04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a'): (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", False), XPublicKey('02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c'): (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", True), XPublicKey('fd76a914d9351dcbad5b8f3b8bfa2f2cdc85c28118ca932688ac'): (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", True), XPublicKey('fd76a914a65d1a239d4ec666643d350c7bb8fc44d288112888ac'): (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", False),
def _mpk_to_PublicKey(cls, mpk: str) -> PublicKey: return PublicKey.from_hex('04' + mpk)
def sign_transaction(self, tx: Transaction, password: str) -> None: if tx.is_complete(): return try: p2pkhTransaction = True inputhasharray = [] hasharray = [] pubkeyarray = [] # Build hasharray from inputs for txin in tx.inputs: if txin.type() != ScriptType.P2PKH: p2pkhTransaction = False for x_pubkey in txin.x_pubkeys: if self.is_signature_candidate(x_pubkey): key_derivation = x_pubkey.bip32_path() assert len(key_derivation) == 2 inputPath = "%s/%d/%d" % (self.get_derivation(), *key_derivation) inputHash = tx.preimage_hash(txin) hasharray_i = { 'hash': inputHash.hex(), 'keypath': inputPath } hasharray.append(hasharray_i) inputhasharray.append(inputHash) break else: self.give_error("No matching x_key for sign_transaction" ) # should never happen # Build pubkeyarray from annotated change outputs. # The user is on their own if they have unannotated non-change self-outputs. for txout in tx.outputs: if txout.x_pubkeys: for xpubkey in [ xpk for xpk in txout.x_pubkeys if self.is_signature_candidate(xpk) ]: key_path_text = compose_chain_string( xpubkey.derivation_path())[1:] changePath = self.get_derivation( ) + key_path_text # "/1/0", no "m" pubkeyarray.append({ 'pubkey': xpubkey.to_public_key().to_hex(), 'keypath': changePath, }) # Special serialization of the unsigned transaction for # the mobile verification app. # At the moment, verification only works for p2pkh transactions. if p2pkhTransaction: class CustomTXSerialization(Transaction): @classmethod def input_script(self, txin, estimate_size=False): type_ = txin.type() if type_ == ScriptType.P2PKH: return Transaction.get_preimage_script(txin) if type_ == ScriptType.MULTISIG_P2SH: # Multisig verification has partial support, but is # disabled. This is the expected serialization though, so we # leave it here until we activate it. return '00' + push_script( Transaction.get_preimage_script(txin)) raise RuntimeError(f'unsupported type {type_}') tx_dbb_serialized = CustomTXSerialization.from_hex( tx.serialize()).serialize() else: # We only need this for the signing echo / verification. tx_dbb_serialized = None # Build sign command dbb_signatures: List[Dict[str, Any]] = [] steps = math.ceil(1.0 * len(hasharray) / self.maxInputs) for step in range(int(steps)): hashes = hasharray[step * self.maxInputs:(step + 1) * self.maxInputs] msg_data: Dict[str, Any] = { "sign": { "data": hashes, "checkpub": pubkeyarray, }, } if tx_dbb_serialized is not None: msg_data["sign"]["meta"] = sha256d(tx_dbb_serialized).hex() msg = json.dumps(msg_data).encode('ascii') assert self.plugin is not None dbb_client: DigitalBitbox_Client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception("Could not sign transaction.") reply = dbb_client.hid_send_encrypt(msg) if 'error' in reply: raise Exception(reply['error']['message']) if 'echo' not in reply: raise Exception("Could not sign transaction.") if self.plugin.is_mobile_paired( ) and tx_dbb_serialized is not None: reply['tx'] = tx_dbb_serialized self.plugin.comserver_post_notification(reply) if steps > 1: self.handler.show_message( _("Signing large transaction. Please be patient ...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for " "3 seconds.") + " " + _("(Touch {} of {})").format((step + 1), steps) + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." ) + "\n\n") else: self.handler.show_message( _("Signing transaction...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for " "3 seconds.") + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." )) # Send twice, first returns an echo for smart verification reply = dbb_client.hid_send_encrypt(msg) self.handler.finished() if 'error' in reply: if reply["error"].get('code') in (600, 601): # aborted via LED short touch or timeout raise UserCancelled() raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception("Could not sign transaction.") dbb_signatures.extend(reply['sign']) # Fill signatures if len(dbb_signatures) != len(tx.inputs): raise RuntimeError("Incorrect number of transactions signed") for txin, siginfo, pre_hash in zip(tx.inputs, dbb_signatures, inputhasharray): if txin.is_complete(): continue for pubkey_index, x_pubkey in enumerate(txin.x_pubkeys): compact_sig = bytes.fromhex(siginfo['sig']) if 'recid' in siginfo: # firmware > v2.1.1 recid = int(siginfo['recid'], 16) recoverable_sig = compact_sig + bytes([recid]) pk = PublicKey.from_recoverable_signature( recoverable_sig, pre_hash, None) elif 'pubkey' in siginfo: # firmware <= v2.1.1 pk = PublicKey.from_hex(siginfo['pubkey']) if pk != x_pubkey.to_public_key(): continue full_sig = (compact_signature_to_der(compact_sig) + bytes([Transaction.nHashType() & 255])) txin.signatures[pubkey_index] = full_sig except UserCancelled: raise except Exception as e: self.give_error(e, True) else: logger.debug("Transaction is_complete %s", tx.is_complete())
def encrypt(self, pubkey, message): """Encrypt a message with a public key. Use quotes if the message contains whitespaces.""" public_key = PublicKey.from_hex(pubkey) encrypted = public_key.encrypt_message_to_base64(message) return encrypted
'f75ac48afcbb68bdd6a00f58a648bda9e5eb5e73bd51ef130a6e72dc698d001000301' )) with pytest.raises(ValueError): keystore.is_signature_candidate(XPublicKey.from_hex( 'fe18863ac1de668decc6406880c4c8d9a74e9986a5e8d9f2be262ac4af8a68863b37d' 'f75ac48afcbb68bdd6a00f58a648bda9e5eb5e73bd51ef130a6e72dc698d001000301' )) # Password b'password'; one minikey, one WIF keypairs_dict = { '02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c': 'tfxSNL1G2aHpNCELs8aGnmB0SvlRHgZ3tXlLmO/XoVPElTo4/Pr+Gx+icCa4Dpjd+HtfhA+5pChRumaQ5QFbzFItC0uQ+ZVtRhr/sRxakrE=', '04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae863d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095': 'NithPh1OqOiALYK0TP4wBdZZOOWVF+wJwBakvlrH7mpho65PVR3DMuC3WAdmyMJ2' } imported_keystore = Imported_KeyStore() imported_keystore._keypairs = { PublicKey.from_hex(a): b for a, b in keypairs_dict.items() } class TestImported_KeyStore: @pytest.mark.parametrize("WIF,pk_string", ( ("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ", "04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd" "85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a"), ("KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617", "02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c"), ("SZEfg4eYxCJoqzumUqP34g", "04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae86" "3d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095" ), ("S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy", "04fb4fd5872ff2f8a46c2d496383fccc503c0260ef126ffbac61407f6bd384e5d"
], # 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ (uncompressed) "2df53273de1b740e6f566eba00d90366e53afd2c6af896a9488515f8ef5abbd8": [ ], # 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ (P2PK) "7149d82068249701104cd662bfe8ebc0af131ce6e781b124cc6297f45f7f6de5": [ { "height": 50000, "value": 1804376, "tx_hash": "3f5a1badfe1beb42b650f325b20935f09f3ab43a3c473c5be18f58308fc7eff1", "tx_pos": 3, }, ], } result_S = ([{'height': 437146, 'value': 45318048, 'tx_hash': '9f2c45a12db0144909b5db269415f7319179105982ac70ed80d76ea79d923ebf', 'tx_pos': 0, 'address': Address.from_string("1KXf5PUHNaV42jE9NbJFPKhGGN1fSSGJNK"), 'type': 'p2pkh', 'prevout_hash': '9f2c45a12db0144909b5db269415f7319179105982ac70ed80d76ea79d923ebf', 'prevout_n': 0, 'pubkeys': ['04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae863d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095'], 'x_pubkeys': ['04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae863d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095'], 'signatures': [None], 'num_sig': 1}], {'04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae863d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095': (b'\x98\xe3\x15\xc3%j\x97\x17\xd4\xdd\xea0\xeb*\n-V\xa1d\x93yN\xb0SSf\xea"\xd8i\xa3 ', False), '03e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c012889': (b'\x98\xe3\x15\xc3%j\x97\x17\xd4\xdd\xea0\xeb*\n-V\xa1d\x93yN\xb0SSf\xea"\xd8i\xa3 ', True)}) result_K = ([{'height': 500000, 'value': 18043706, 'tx_hash': 'bcf7ae875b585e00a61055372c1e99046b20f5fbfcd8659959afb6f428326bfa', 'tx_pos': 1, 'address': Address.from_string("1LoVGDgRs9hTfTNJNuXKSpywcbdvwRXpmK"), 'type': 'p2pkh', 'prevout_hash': 'bcf7ae875b585e00a61055372c1e99046b20f5fbfcd8659959afb6f428326bfa', 'prevout_n': 1, 'pubkeys': ['02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c'], 'x_pubkeys': ['02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c'], 'signatures': [None], 'num_sig': 1}], {'02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c': (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", True)}) result_5 = ([{'height': 50000, 'value': 1804376, 'tx_hash': '3f5a1badfe1beb42b650f325b20935f09f3ab43a3c473c5be18f58308fc7eff1', 'tx_pos': 3, 'address': PublicKey.from_hex("04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a"), 'type': 'p2pk', 'prevout_hash': '3f5a1badfe1beb42b650f325b20935f09f3ab43a3c473c5be18f58308fc7eff1', 'prevout_n': 3, 'pubkeys': ['04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a'], 'x_pubkeys': ['04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a'], 'signatures': [None], 'num_sig': 1}], {'04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e55842ae2bd115d1ed7cc0e82d934e929c97648cb0a': (b"\x0c(\xfc\xa3\x86\xc7\xa2'`\x0b/\xe5\x0b|\xae\x11\xec\x86\xd3\xbf\x1f\xbeG\x1b\xe8\x98'\xe1\x9dr\xaa\x1d", False)}) @pytest.mark.parametrize("privkey,answer", ( ("SZEfg4eYxCJoqzumUqP34g", result_S), ("KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617", result_K), ("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ", result_5), )) def test_sweep_preparations(privkey,answer): def get_utxos(script_hash): return sweep_utxos[script_hash] result = sweep_preparations([privkey], get_utxos) assert result == answer
def test_bad_type(self): public_key = PublicKey.from_hex( '034339a901d8526c4d733c8ea7c861f1a6324f37f6b86f838725820e0c5fc19570' ) with pytest.raises(AssertionError): XPublicKey(pubkey_bytes=public_key)
def test_hash160(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) assert output.hash160() == hash160(bytes.fromhex(pubkey_hex))