def check_password(self, password): xprv = pw_decode(self.xprv, password) try: assert (bip32_key_from_string(xprv).derivation().chain_code == bip32_key_from_string(self.xpub).derivation().chain_code) except (ValueError, AssertionError): raise InvalidPassword()
def check_password(self, password: Optional[str]) -> None: assert self.xprv is not None xprv = pw_decode(self.xprv, password) try: assert (bip32_key_from_string(xprv).derivation().chain_code == bip32_key_from_string(self.xpub).derivation().chain_code) except (ValueError, AssertionError, Base58Error): raise InvalidPassword()
def get_private_key(self, derivation_path: Sequence[int], password: str) -> Tuple[bytes, bool]: xprv = self.get_master_private_key(password) privkey = bip32_key_from_string(xprv) for n in derivation_path: privkey = privkey.child_safe(n) return privkey.to_bytes(), True
def derive_pubkey(self, for_change, n): xpub = self.xpub_change if for_change else self.xpub_receive if xpub is None: xpub = bip32_key_from_string(self.xpub) xpub = xpub.child(1 if for_change else 0).to_extended_key_string() if for_change: self.xpub_change = xpub else: self.xpub_receive = xpub return self.get_pubkey_from_xpub(xpub, (n,))
def derive_pubkey(self, derivation_path: Sequence[int]) -> PublicKey: parent_path = derivation_path[:-1] xpub = self._child_xpubs.get(parent_path) if xpub is None: xpubkey = bip32_key_from_string(self.xpub) for n in parent_path: xpubkey = xpubkey.child_safe(n) xpub = xpubkey.to_extended_key_string() self._child_xpubs[parent_path] = xpub return self.get_pubkey_from_xpub(xpub, derivation_path[-1:])
def _make_node_path(self, xpub, address_n): pubkey = bip32_key_from_string(xpub) derivation = pubkey.derivation() node = HDNodeType( depth=derivation.depth, fingerprint=be_bytes_to_int(pubkey.fingerprint()), child_num=derivation.n, chain_code=derivation.chain_code, public_key=pubkey.to_bytes(), ) return HDNodePathType(node=node, address_n=address_n)
def from_master_key(text: str) -> Union[BIP32_KeyStore, Old_KeyStore]: if is_xprv(text): k = BIP32_KeyStore({}) k.add_xprv(bip32_key_from_string(text)) elif Old_KeyStore.is_hex_mpk(text): k = Old_KeyStore.from_mpk(text) elif is_xpub(text): k = from_xpub(text) else: raise Exception('Invalid key') return k
def window_opened(self, window): wallet = window.wallet if cosigner_pool.is_enabled() and type(wallet) == Multisig_Wallet: items = [] for key, keystore in wallet.keystores.items(): xpub = keystore.get_master_public_key() pubkey = bip32_key_from_string(xpub) K = pubkey.to_bytes() K_hash = bh2u(sha256d(K)) items.append( CosignerItem(window, xpub, K, K_hash, keystore.is_watching_only())) # Presumably atomic self.items.extend(items)
def on_receive(self, keyhash, message): logger.debug("signal arrived for '%s'", keyhash) for item in self.items: if item.hash == keyhash and not item.watching_only: window = item.window break else: logger.error("keyhash not found") return parent_wallet = window.parent_wallet wallet = parent_wallet.get_default_wallet() if isinstance(wallet.get_keystore(), keystore.Hardware_KeyStore): window.show_warning( _('An encrypted transaction was retrieved from cosigning pool.' ) + '\n' + _('However, hardware wallets do not support message decryption, ' 'which makes them not compatible with the current design of cosigner pool.' )) self.listener.clear(keyhash) return if parent_wallet.has_password(): password = window.password_dialog( _('An encrypted transaction was retrieved from cosigning pool.' ) + '\n' + _('Please enter your password to decrypt it.')) if not password: return else: password = None if not window.question( _("An encrypted transaction was retrieved from cosigning pool." ) + '\n' + _("Do you want to open it now?")): return self.listener.clear(keyhash) xprv = wallet.get_keystore().get_master_private_key(password) if not xprv: return privkey = bip32_key_from_string(xprv) try: message = bh2u(privkey.decrypt_message(message)) except Exception as e: logger.exception("") window.show_error(_('Error decrypting message') + ':\n' + str(e)) return tx = Transaction.from_hex(message) window.show_transaction(tx, prompt_if_unsaved=True)
def test_bip32_extended_keys(self, raw_hex, path, coin): # see test_keystore.py xpub = ('xpub661MyMwAqRbcH1RHYeZc1zgwYLJ1dNozE8npCe81pnNYtN6e5KsF6cmt17Fv8w' 'GvJrRiv6Kewm8ggBG6N3XajhoioH3stUmLRi53tk46CiA') root_key = bip32_key_from_string(xpub) True_10_public_key = root_key.child(path[0]).child(path[1]) x_pubkey = XPublicKey.from_bytes(bytes.fromhex(raw_hex)) # assert x_pubkey.to_bytes() == bytes.fromhex(raw_hex) # assert x_pubkey.to_hex() == raw_hex assert x_pubkey.is_bip32_key() assert x_pubkey.bip32_extended_key_and_path() == (xpub, path) assert x_pubkey.to_public_key() == True_10_public_key assert x_pubkey.to_address() == True_10_public_key.to_address(coin=coin) assert x_pubkey.to_address().coin() is coin
def _event_text_changed(self) -> None: if self._key_edit.isReadOnly(): return text = self._key_edit.toPlainText() try: key = bip32_key_from_string(text) except ValueError: return else: if not isinstance(key, BIP32PublicKey): return password = None keystore = instantiate_keystore_from_text( KeystoreTextType.EXTENDED_PUBLIC_KEY, text, password) self._update_keystore(keystore)
def _on_receive(self, item: CosignerItem, message: str) -> None: logger.debug("signal arrived for '%s'", item.keyhash_hex) window = item.window account = window._wallet.get_account(item.account_id) for keystore in account.get_keystores(): if keystore.get_master_public_key() == item.xpub: break else: window.show_error( _('Message for non-existent non-watching cosigner')) return if isinstance(keystore, Hardware_KeyStore): window.show_warning( _('An encrypted transaction was retrieved from cosigning pool.' ) + '\n' + _('However, hardware wallets do not support message decryption, ' 'which makes them incompatible with the current design of cosigner pool.' )) self._listener.clear(item.keyhash_hex) return password = window.password_dialog( _('An encrypted transaction was retrieved from cosigning pool.') + '\n' + _('Please enter your password to decrypt it.')) if not password: return self._listener.clear(item.keyhash_hex) xprv = keystore.get_master_private_key(password) if not xprv: return privkey = bip32_key_from_string(xprv) try: message = privkey.decrypt_message(message).decode() except Exception as e: logger.exception("") window.show_error(_('Error decrypting message') + ':\n' + str(e)) return txdict = json.loads(message) tx = Transaction.from_dict(txdict) window.show_transaction(account, tx, prompt_if_unsaved=True)
def _window_opened(self, window: 'ElectrumWindow') -> None: if not cosigner_pool.is_enabled(): return for account in window._wallet.get_accounts(): if type(account) is not MultisigAccount: continue account_id = account.get_id() items = [] for keystore in account.get_keystores(): xpub = keystore.get_master_public_key() pubkey = bip32_key_from_string(xpub) pubkey_bytes = pubkey.to_bytes() keyhash_hex = sha256d(pubkey_bytes).hex() items.append(CosignerItem(window, account_id, xpub, pubkey_bytes, keyhash_hex, keystore.is_watching_only())) self._items.extend(items)
def to_public_key(self) -> Union[BIP32PublicKey, PublicKey]: '''Returns a PublicKey instance or an Address instance.''' kind = self.kind() if self._pubkey_bytes is not None: return PublicKey.from_bytes(self._pubkey_bytes) elif self._bip32_xpub is not None: assert self._derivation_path is not None result = bip32_key_from_string(self._bip32_xpub) for n in self._derivation_path: result = result.child(n) return result elif self._old_mpk is not None: assert self._derivation_path is not None path = self._derivation_path pubkey = PublicKey.from_bytes(pack_byte(4) + self._old_mpk) # pylint: disable=unsubscriptable-object delta = double_sha256(f'{path[1]}:{path[0]}:'.encode() + self._old_mpk) return pubkey.add(delta) raise ValueError("invalid key data")
def get_pubkey_from_xpub(self, xpub, sequence): pubkey = bip32_key_from_string(xpub) for n in sequence: pubkey = pubkey.child_safe(n) return pubkey.to_hex()
def is_xpub(text): try: key = bip32_key_from_string(text) return isinstance(key, BIP32PublicKey) except Exception: return False
def get_pubkey_from_xpub(self, xpub: str, sequence: Sequence[int]) -> PublicKey: pubkey = bip32_key_from_string(xpub) for n in sequence: pubkey = pubkey.child_safe(n) return pubkey
def __init__(self, main_window: ElectrumWindow, parent: QWidget, keystore: KeyStore, password: str) -> None: super().__init__(parent) self._main_window = main_window self.setWindowTitle(_("Secured Account Data")) self.setMinimumSize(500, 200) vbox = QVBoxLayout() self._form = form = FormSectionWidget(minimum_label_width=120) assert keystore.derivation_type in (DerivationType.BIP32, DerivationType.ELECTRUM_OLD) self._seed_edit = None if keystore.seed is not None: seed_text = keystore.get_seed(password) seed_type_text = _("Unknown") if keystore.derivation_type == DerivationType.BIP32: if is_new_seed(seed_text): seed_type_text = _("Electrum") is_checksum_valid, is_wordlist_valid = bip39_is_checksum_valid( seed_text) if is_checksum_valid and is_wordlist_valid: seed_type_text = _("BIP39") elif keystore.derivation_type == DerivationType.ELECTRUM_OLD: seed_type_text = _("Old-style Electrum") form.add_row(_("Seed type"), QLabel(seed_type_text)) seed_edit = ShowQRTextEdit(self) seed_edit.setFixedHeight(80) seed_edit.addCopyButton(self._main_window.app) seed_edit.setText(seed_text) form.add_row(_("Seed phrase"), seed_edit, True) self._seed_edit = seed_edit # Ambiguous if empty string or None. passphrase_widget: QWidget if keystore.passphrase: passphrase_text = keystore.get_passphrase(password) passphrase_edit = ShowQRTextEdit(self) passphrase_edit.setFixedHeight(80) passphrase_edit.addCopyButton(self._main_window.app) passphrase_edit.setText(passphrase_text) passphrase_widget = passphrase_edit else: passphrase_widget = QLabel(_("None")) form.add_row(_("Passphrase"), passphrase_widget, True) if keystore.derivation_type == DerivationType.BIP32: if keystore.xprv is not None: xprv_text = keystore.get_master_private_key(password) private_key = bip32_key_from_string(xprv_text) xprv_edit = ShowQRTextEdit(self) xprv_edit.setFixedHeight(80) xprv_edit.addCopyButton(self._main_window.app) xprv_edit.setText(private_key.to_extended_key_string()) form.add_row(_("Master private key"), xprv_edit, True) vbox.addWidget(form) vbox.addStretch(1) vbox.addLayout(Buttons(CloseButton(self))) self.setLayout(vbox)
def get_fingerprint(self) -> bytes: return bip32_key_from_string(self.xpub).fingerprint()
def instantiate_keystore_from_text(text_type: KeystoreTextType, text_match: Union[str, List[str]], password: Optional[str], derivation_text: Optional[str] = None, passphrase: Optional[str] = None, watch_only: bool = False) -> KeyStore: derivation_type: Optional[DerivationType] = None data: Dict[str, Any] = {} if text_type == KeystoreTextType.EXTENDED_PUBLIC_KEY: derivation_type = DerivationType.BIP32 assert isinstance(text_match, str) assert passphrase is None # `watch_only` is ignored. data['xpub'] = text_match elif text_type == KeystoreTextType.EXTENDED_PRIVATE_KEY: derivation_type = DerivationType.BIP32 assert isinstance(text_match, str) assert passphrase is None if not watch_only: assert password is not None data['xprv'] = pw_encode(text_match, password) private_key = bip32_key_from_string(text_match) data['xpub'] = private_key.public_key.to_extended_key_string() elif text_type == KeystoreTextType.PRIVATE_KEYS: derivation_type = DerivationType.IMPORTED # watch_only? elif text_type == KeystoreTextType.ADDRESSES: derivation_type = DerivationType.IMPORTED # All address types have to be the same. pass elif text_type == KeystoreTextType.BIP39_SEED_WORDS: derivation_type = DerivationType.BIP32 if derivation_text is None: derivation_text = bip44_derivation_cointype(0, 0) assert isinstance(text_match, str) bip32_seed = bip39_to_seed(text_match, passphrase) xprv = BIP32PrivateKey.from_seed(bip32_seed, Net.COIN) for n in bip32_decompose_chain_string(derivation_text): xprv = xprv.child_safe(n) if not watch_only: assert password is not None data['xprv'] = pw_encode(xprv.to_extended_key_string(), password) data['seed'] = pw_encode(text_match, password) if passphrase is not None: data['passphrase'] = pw_encode(passphrase, password) data['derivation'] = derivation_text data['xpub'] = xprv.public_key.to_extended_key_string() elif text_type == KeystoreTextType.ELECTRUM_SEED_WORDS: derivation_type = DerivationType.BIP32 assert isinstance(text_match, str) bip32_seed = Mnemonic.mnemonic_to_seed(text_match, passphrase or '') derivation_text = "m" xprv = BIP32PrivateKey.from_seed(bip32_seed, Net.COIN) for n in bip32_decompose_chain_string(derivation_text): xprv = private_key.child_safe(n) if not watch_only: assert password is not None data['xprv'] = pw_encode(xprv.to_extended_key_string(), password) data['seed'] = pw_encode(text_match, password) if passphrase is not None: data['passphrase'] = pw_encode(passphrase, password) data['derivation'] = derivation_text data['xpub'] = xprv.public_key.to_extended_key_string() elif text_type == KeystoreTextType.ELECTRUM_OLD_SEED_WORDS: derivation_type = DerivationType.ELECTRUM_OLD assert isinstance(text_match, str) assert passphrase is None # `watch_only` is ignored. hex_seed = Old_KeyStore._seed_to_hex(text_match) assert password is not None data['seed'] = pw_encode(hex_seed, password) data['mpk'] = Old_KeyStore._mpk_from_hex_seed(hex_seed) else: raise NotImplementedError("Unsupported text match type", text_type) return instantiate_keystore(derivation_type, data)
def is_xprv(text: str) -> bool: try: key = bip32_key_from_string(text) return isinstance(key, BIP32PrivateKey) except Exception: return False
def get_master_public_key(self, bip32_path): reply = self._get_xpub(bip32_path) if reply: return bip32_key_from_string(reply['xpub']) else: raise Exception('no reply')
def get_private_key(self, sequence, password): xprv = self.get_master_private_key(password) privkey = bip32_key_from_string(xprv) for n in sequence: privkey = privkey.child_safe(n) return privkey.to_bytes(), True
def _bip32_public_key(self): extended_key, path = self.bip32_extended_key_and_path() result = bip32_key_from_string(extended_key) for n in path: result = result.child(n) return result
from typing import Sequence from bitcoinx import bip32_key_from_string, BIP32PublicKey, PublicKey from .constants import XPUB_TEST XPUB_INDEX = 0 XPUB_OBJ = bip32_key_from_string(XPUB_TEST) def derive_pubkey(xpub: BIP32PublicKey, sequence: Sequence[int]) -> PublicKey: pubkey = xpub for n in sequence: pubkey = pubkey.child_safe(n) return pubkey def get_next_script() -> bytes: global XPUB_INDEX derivation = (0, XPUB_INDEX) XPUB_INDEX += 1 pubkey = derive_pubkey(XPUB_OBJ, derivation) return pubkey.P2PKH_script().to_bytes()