def update(self, window): wallet = window.wallet self.window = window if type(wallet) != Multisig_Wallet: return if self.listener is None: self.print_error("starting listener") self.listener = Listener(self) self.listener.start() elif self.listener: self.print_error("shutting down listener") self.listener.stop() self.listener = None self.keys = [] self.cosigner_list = [] for key, keystore in wallet.keystores.items(): xpub = keystore.get_master_public_key() K = bip32.deserialize_xpub(xpub)[-1] _hash = bh2u(crypto.sha256d(K)) if not keystore.is_watching_only(): self.keys.append((key, _hash, window)) else: self.cosigner_list.append((window, xpub, K, _hash)) if self.listener: self.listener.set_keyhashes([t[1] for t in self.keys])
def _make_node_path(self, xpub, address_n): _, depth, fingerprint, child_num, chain_code, key = deserialize_xpub(xpub) node = self.types.HDNodeType( depth=depth, fingerprint=int.from_bytes(fingerprint, 'big'), child_num=int.from_bytes(child_num, 'big'), chain_code=chain_code, public_key=key, ) return self.types.HDNodePathType(node=node, address_n=address_n)
def make_billing_address(wallet, num, addr_type): long_id, short_id = wallet.get_user_id() xpub = make_xpub(get_billing_xpub(), long_id) version, _, _, _, c, cK = deserialize_xpub(xpub) cK, c = CKD_pub(cK, c, num) if addr_type == 'legacy': return bitcoin.public_key_to_p2pkh(cK) elif addr_type == 'segwit': return bitcoin.public_key_to_p2wpkh(cK) else: raise ValueError(f'unexpected billing type: {addr_type}')
def get_signing_xpub(xtype): if not constants.net.TESTNET: xpub = "xpub661MyMwAqRbcGnMkaTx2594P9EDuiEqMq25PM2aeG6UmwzaohgA6uDmNsvSUV8ubqwA3Wpste1hg69XHgjUuCD5HLcEp2QPzyV1HMrPppsL" else: xpub = "tpubD6NzVbkrYhZ4XdmyJQcCPjQfg6RXVUzGFhPjZ7uvRC8JLcS7Hw1i7UTpyhp9grHpak4TyK2hzBJrujDVLXQ6qB5tNpVx9rC6ixijUXadnmY" if xtype not in ('standard', 'p2wsh'): raise NotImplementedError('xtype: {}'.format(xtype)) if xtype == 'standard': return xpub _, depth, fingerprint, child_number, c, cK = bip32.deserialize_xpub(xpub) xpub = bip32.serialize_xpub(xtype, c, cK, depth, fingerprint, child_number) return xpub
def get_xpub(self, bip32_path, xtype): assert xtype in self.plugin.SUPPORTED_XTYPES reply = self._get_xpub(bip32_path) if reply: xpub = reply['xpub'] # Change type of xpub to the requested type. The firmware # only ever returns the mainnet standard type, but it is agnostic # to the type when signing. if xtype != 'standard' or constants.net.TESTNET: _, depth, fingerprint, child_number, c, cK = deserialize_xpub(xpub, net=constants.BitcoinMainnet) xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number) return xpub else: raise Exception('no reply')
def mitm_verify(self, sig, expect_xpub): # verify a signature (65 bytes) over the session key, using the master bip32 node # - customized to use specific EC library of Electrum. from electrum_exos.ecc import ECPubkey xtype, depth, parent_fingerprint, child_number, chain_code, K_or_k \ = deserialize_xpub(expect_xpub) pubkey = ECPubkey(K_or_k) try: pubkey.verify_message_hash(sig[1:65], self.session_key) return True except: return False
def get_xpub(self, bip32_path, xtype): assert xtype in ColdcardPlugin.SUPPORTED_XTYPES print_error('[coldcard]', 'Derive xtype = %r' % xtype) xpub = self.dev.send_recv(CCProtocolPacker.get_xpub(bip32_path), timeout=5000) # TODO handle timeout? # change type of xpub to the requested type try: __, depth, fingerprint, child_number, c, cK = deserialize_xpub(xpub) except InvalidMasterKeyVersionBytes: raise UserFacingException(_('Invalid xpub magic. Make sure your {} device is set to the correct chain.') .format(self.device)) from None if xtype != 'standard': xpub = serialize_xpub(xtype, c, cK, depth, fingerprint, child_number) return xpub
def __init__(self, tx, parent, desc, prompt_if_unsaved): '''Transactions in the wallet will show their description. Pass desc to give a description for txs not yet in the wallet. ''' # We want to be a top-level window QDialog.__init__(self, parent=None) # Take a copy; it might get updated in the main window by # e.g. the FX plugin. If this happens during or after a long # sign operation the signatures are lost. self.tx = tx = copy.deepcopy(tx) # type: Transaction try: self.tx.deserialize() except BaseException as e: raise SerializationError(e) self.main_window = parent self.wallet = parent.wallet self.prompt_if_unsaved = prompt_if_unsaved self.saved = False self.desc = desc # store the keyhash and cosigners for current wallet self.keyhashes = set() self.cosigner_list = set() if type(self.wallet) == Multisig_Wallet: for key, keystore in self.wallet.keystores.items(): xpub = keystore.get_master_public_key() K = bip32.deserialize_xpub(xpub)[-1] _hash = bh2u(crypto.sha256d(K)) if not keystore.is_watching_only(): self.keyhashes.add(_hash) else: self.cosigner_list.add(_hash) # if the wallet can populate the inputs with more info, do it now. # as a result, e.g. we might learn an imported address tx is segwit, # in which case it's ok to display txid tx.add_inputs_info(self.wallet) self.setMinimumWidth(950) self.setWindowTitle(_("Transaction")) vbox = QVBoxLayout() self.setLayout(vbox) vbox.addWidget(QLabel(_("Transaction ID:"))) self.tx_hash_e = ButtonsLineEdit() qr_show = lambda: parent.show_qrcode( str(self.tx_hash_e.text()), 'Transaction ID', parent=self) qr_icon = "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png" self.tx_hash_e.addButton(qr_icon, qr_show, _("Show as QR code")) self.tx_hash_e.setReadOnly(True) vbox.addWidget(self.tx_hash_e) self.tx_desc = QLabel() vbox.addWidget(self.tx_desc) self.status_label = QLabel() vbox.addWidget(self.status_label) self.date_label = QLabel() vbox.addWidget(self.date_label) self.amount_label = QLabel() vbox.addWidget(self.amount_label) self.size_label = QLabel() vbox.addWidget(self.size_label) self.fee_label = QLabel() vbox.addWidget(self.fee_label) self.add_io(vbox) self.sign_button = b = QPushButton(_("Sign")) b.clicked.connect(self.sign) self.broadcast_button = b = QPushButton(_("Broadcast")) b.clicked.connect(self.do_broadcast) self.save_button = b = QPushButton(_("Save")) save_button_disabled = not tx.is_complete() b.setDisabled(save_button_disabled) if save_button_disabled: b.setToolTip(SAVE_BUTTON_DISABLED_TOOLTIP) else: b.setToolTip(SAVE_BUTTON_ENABLED_TOOLTIP) b.clicked.connect(self.save) self.export_button = b = QPushButton(_("Export")) b.clicked.connect(self.export) self.cancel_button = b = QPushButton(_("Close")) b.clicked.connect(self.close) b.setDefault(True) self.qr_button = b = QPushButton() b.setIcon(read_QIcon(qr_icon)) b.clicked.connect(self.show_qr) self.copy_button = CopyButton(lambda: str(self.tx), parent.app) # Action buttons self.buttons = [ self.sign_button, self.broadcast_button, self.cancel_button ] # Transaction sharing buttons self.sharing_buttons = [ self.copy_button, self.qr_button, self.export_button, self.save_button ] run_hook('transaction_dialog', self) hbox = QHBoxLayout() hbox.addLayout(Buttons(*self.sharing_buttons)) hbox.addStretch(1) hbox.addLayout(Buttons(*self.buttons)) vbox.addLayout(hbox) self.update()
def make_xpub(xpub, s): version, _, _, _, c, cK = deserialize_xpub(xpub) cK2, c2 = bip32._CKD_pub(cK, c, s) return serialize_xpub(version, c2, cK2)
def __init__(self, tx, parent, desc, prompt_if_unsaved): '''Transactions in the wallet will show their description. Pass desc to give a description for txs not yet in the wallet. ''' # We want to be a top-level window QDialog.__init__(self, parent=None) self.tx = tx = copy.deepcopy(tx) # type: Transaction try: self.tx.deserialize() except BaseException as e: raise SerializationError(e) self.main_window = parent self.wallet = parent.wallet self.prompt_if_unsaved = prompt_if_unsaved self.saved = False self.desc = desc self.locks = {} self.currently_signing = None # Set timeout flag self.timed_out = False self.main_window = parent self.wallet = parent.wallet # store the keyhash and cosigners for current wallet self.keyhashes = set() self.cosigner_list = set() if type(self.wallet) == Multisig_Wallet: for key, keystore in self.wallet.keystores.items(): xpub = keystore.get_master_public_key() K = bip32.deserialize_xpub(xpub)[-1] _hash = bh2u(crypto.sha256d(K)) if not keystore.is_watching_only(): self.keyhashes.add(_hash) else: self.cosigner_list.add(_hash) self.locks[_hash] = server.get(_hash + '_lock') if self.locks[_hash]: name = server.get(_hash + '_name') if name: self.currently_signing = name self.setMinimumWidth(200) self.setWindowTitle(_("Information")) vbox = QVBoxLayout() self.setLayout(vbox) self.warning = QLabel() vbox.addWidget(self.warning) warning_text = (_( 'A transaction with the following information is currently being signed' ) + '\n' + _( 'by a cosigner. A notification will appear within 30 seconds of either signing' ) + '\n' + _('or the transaction window expiring.')) self.warning.setText(warning_text) self.tx_desc = QLabel() vbox.addWidget(self.tx_desc) self.status_label = QLabel() vbox.addWidget(self.status_label) self.date_label = QLabel() vbox.addWidget(self.date_label) self.amount_label = QLabel() vbox.addWidget(self.amount_label) self.size_label = QLabel() vbox.addWidget(self.size_label) self.fee_label = QLabel() vbox.addWidget(self.fee_label) self.cancel_button = b = QPushButton(_("Close")) b.clicked.connect(self.close) b.setDefault(True) # Action buttons self.buttons = [self.cancel_button] # Add label for countdown timer self.time_out_label = QLabel() vbox.addWidget(self.time_out_label) run_hook('transaction_dialog', self) hbox = QHBoxLayout() hbox.addLayout(Buttons(*self.buttons)) vbox.addLayout(hbox) for _hash, expire in self.locks.items(): if expire: # Set time left to desired duration self.time_left_int = int(DURATION_INT - (int(server.get_current_time()) - int(expire))) self.timer_start() self.update()