diff --git a/electrum/ecc.py b/electrum/ecc.py index a8faeaf81..d00a11f16 100644 --- a/electrum/ecc.py +++ b/electrum/ecc.py @@ -499,7 +499,12 @@ class ECPrivkey(ECPubkey): def sign_transaction(self, hashed_preimage: bytes) -> bytes: return self.sign(hashed_preimage, sigencode=der_sig_from_r_and_s) - def sign_message(self, message: bytes, is_compressed: bool, algo=lambda x: sha256d(msg_magic(x))) -> bytes: + def sign_message( + self, + message: Union[bytes, str], + is_compressed: bool, + algo=lambda x: sha256d(msg_magic(x)), + ) -> bytes: def bruteforce_recid(sig_string): for recid in range(4): sig65 = construct_sig65(sig_string, recid, is_compressed) diff --git a/electrum/keystore.py b/electrum/keystore.py index 0765809c5..985654aa6 100644 --- a/electrum/keystore.py +++ b/electrum/keystore.py @@ -127,7 +127,14 @@ class KeyStore(Logger, ABC): pass @abstractmethod - def sign_message(self, sequence: 'AddressIndexGeneric', message, password) -> bytes: + def sign_message( + self, + sequence: 'AddressIndexGeneric', + message: str, + password, + *, + script_type: Optional[str] = None, + ) -> bytes: pass @abstractmethod @@ -175,7 +182,7 @@ class Software_KeyStore(KeyStore): def may_have_password(self): return not self.is_watching_only() - def sign_message(self, sequence, message, password) -> bytes: + def sign_message(self, sequence, message, password, *, script_type=None) -> bytes: privkey, compressed = self.get_private_key(sequence, password) key = ecc.ECPrivkey(privkey) return key.sign_message(message, compressed) diff --git a/electrum/plugins/bitbox02/bitbox02.py b/electrum/plugins/bitbox02/bitbox02.py index 97750bb30..7ce1114c8 100644 --- a/electrum/plugins/bitbox02/bitbox02.py +++ b/electrum/plugins/bitbox02/bitbox02.py @@ -524,7 +524,7 @@ class BitBox02Client(HardwareClientBase): signatures = [bh2u(ecc.der_sig_from_sig_string(x[1])) + "01" for x in sigs] tx.update_signatures(signatures) - def sign_message(self, keypath: str, message: bytes, xtype: str) -> bytes: + def sign_message(self, keypath: str, message: bytes, script_type: str) -> bytes: if self.bitbox02_device is None: raise Exception( "Need to setup communication first before attempting any BitBox02 calls" @@ -534,9 +534,9 @@ class BitBox02Client(HardwareClientBase): simple_type = { "p2wpkh-p2sh":bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH, "p2wpkh": bitbox02.btc.BTCScriptConfig.P2WPKH, - }[xtype] + }[script_type] except KeyError: - raise UserFacingException("The BitBox02 does not support signing messages for this address type: {}".format(xtype)) + raise UserFacingException("The BitBox02 does not support signing messages for this address type: {}".format(script_type)) _, _, signature = self.bitbox02_device.btc_sign_msg( self._get_coin(), @@ -560,7 +560,7 @@ class BitBox02_KeyStore(Hardware_KeyStore): self.force_watching_only = False self.ux_busy = False - def get_client(self): + def get_client(self) -> Optional['BitBox02Client']: return self.plugin.get_client(self) def give_error(self, message: Exception, clear_client: bool = False): @@ -580,13 +580,12 @@ class BitBox02_KeyStore(Hardware_KeyStore): ).format(self.device) ) - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): if password: raise Exception("BitBox02 does not accept a password from the host") client = self.get_client() keypath = self.get_derivation_prefix() + "/%d/%d" % sequence - xtype = self.get_bip32_node_for_xpub().xtype - return client.sign_message(keypath, message.encode("utf-8"), xtype) + return client.sign_message(keypath, message.encode("utf-8"), script_type) @runs_in_hwd_thread diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py index 6ac910138..5e9339c1e 100644 --- a/electrum/plugins/coldcard/coldcard.py +++ b/electrum/plugins/coldcard/coldcard.py @@ -308,7 +308,7 @@ class Coldcard_KeyStore(Hardware_KeyStore): raise UserFacingException(_('Encryption and decryption are currently not supported for {}').format(self.device)) @wrap_busy - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): # Sign a message on device. Since we have big screen, of course we # have to show the message unabiguously there first! try: diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py index e745d08d7..1b9b27340 100644 --- a/electrum/plugins/digitalbitbox/digitalbitbox.py +++ b/electrum/plugins/digitalbitbox/digitalbitbox.py @@ -455,7 +455,7 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore): raise RuntimeError(_('Encryption and decryption are currently not supported for {}').format(self.device)) - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): sig = None try: message = message.encode('utf8') diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py index 8296ff58a..8a76c2d45 100644 --- a/electrum/plugins/keepkey/keepkey.py +++ b/electrum/plugins/keepkey/keepkey.py @@ -38,7 +38,7 @@ class KeepKey_KeyStore(Hardware_KeyStore): raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device)) @runs_in_hwd_thread - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): client = self.get_client() address_path = self.get_derivation_prefix() + "/%d/%d"%sequence address_n = client.expand_path(address_path) diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index 5f825b313..3fcfc93bf 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -290,7 +290,7 @@ class Ledger_KeyStore(Hardware_KeyStore): @runs_in_hwd_thread @test_pin_unlocked @set_and_unset_signing - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): message = message.encode('utf8') message_hash = hashlib.sha256(message).hexdigest().upper() # prompt for the PIN before displaying the dialog if necessary diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py index 1b47d86cf..829c9fea6 100644 --- a/electrum/plugins/safe_t/safe_t.py +++ b/electrum/plugins/safe_t/safe_t.py @@ -36,7 +36,7 @@ class SafeTKeyStore(Hardware_KeyStore): raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device)) @runs_in_hwd_thread - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): client = self.get_client() address_path = self.get_derivation_prefix() + "/%d/%d"%sequence address_n = client.expand_path(address_path) diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py index c6730085e..d3297bcfb 100644 --- a/electrum/plugins/trezor/clientbase.py +++ b/electrum/plugins/trezor/clientbase.py @@ -228,7 +228,7 @@ class TrezorClientBase(HardwareClientBase, Logger): multisig=multisig) @runs_in_hwd_thread - def sign_message(self, address_str, message): + def sign_message(self, address_str, message, *, script_type): coin_name = self.plugin.get_coin_name() address_n = parse_path(address_str) with self.run_flow(): @@ -236,7 +236,9 @@ class TrezorClientBase(HardwareClientBase, Logger): self.client, coin_name, address_n, - message) + message, + script_type=script_type, + no_script_type=True) @runs_in_hwd_thread def recover_device(self, recovery_type, *args, **kwargs): diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index 0456b8975..c5e258a51 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -77,10 +77,11 @@ class TrezorKeyStore(Hardware_KeyStore): def decrypt_message(self, sequence, message, password): raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device)) - def sign_message(self, sequence, message, password): + def sign_message(self, sequence, message, password, *, script_type=None): client = self.get_client() address_path = self.get_derivation_prefix() + "/%d/%d"%sequence - msg_sig = client.sign_message(address_path, message) + script_type = self.plugin.get_trezor_input_script_type(script_type) + msg_sig = client.sign_message(address_path, message, script_type=script_type) return msg_sig.signature def sign_transaction(self, tx, password): diff --git a/electrum/wallet.py b/electrum/wallet.py index f6ba10675..dbedb9d80 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -2452,9 +2452,11 @@ class Abstract_Wallet(AddressSynchronizer, ABC): def _update_password_for_keystore(self, old_pw: Optional[str], new_pw: Optional[str]) -> None: pass - def sign_message(self, address, message, password): + def sign_message(self, address: str, message: str, password) -> bytes: index = self.get_address_index(address) - return self.keystore.sign_message(index, message, password) + script_type = self.get_txin_type(address) + assert script_type != "address" + return self.keystore.sign_message(index, message, password, script_type=script_type) def decrypt_message(self, pubkey: str, message, password) -> bytes: addr = self.pubkeys_to_address([pubkey])