keystore.sign_message: add optional script_type argument
this is used by trezor (and also by bitbox02, which was using a workaround previously) fixes https://github.com/spesmilo/electrum/issues/7670
This commit is contained in:
@@ -499,7 +499,12 @@ class ECPrivkey(ECPubkey):
|
|||||||
def sign_transaction(self, hashed_preimage: bytes) -> bytes:
|
def sign_transaction(self, hashed_preimage: bytes) -> bytes:
|
||||||
return self.sign(hashed_preimage, sigencode=der_sig_from_r_and_s)
|
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):
|
def bruteforce_recid(sig_string):
|
||||||
for recid in range(4):
|
for recid in range(4):
|
||||||
sig65 = construct_sig65(sig_string, recid, is_compressed)
|
sig65 = construct_sig65(sig_string, recid, is_compressed)
|
||||||
|
|||||||
@@ -127,7 +127,14 @@ class KeyStore(Logger, ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@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
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -175,7 +182,7 @@ class Software_KeyStore(KeyStore):
|
|||||||
def may_have_password(self):
|
def may_have_password(self):
|
||||||
return not self.is_watching_only()
|
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)
|
privkey, compressed = self.get_private_key(sequence, password)
|
||||||
key = ecc.ECPrivkey(privkey)
|
key = ecc.ECPrivkey(privkey)
|
||||||
return key.sign_message(message, compressed)
|
return key.sign_message(message, compressed)
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ class BitBox02Client(HardwareClientBase):
|
|||||||
signatures = [bh2u(ecc.der_sig_from_sig_string(x[1])) + "01" for x in sigs]
|
signatures = [bh2u(ecc.der_sig_from_sig_string(x[1])) + "01" for x in sigs]
|
||||||
tx.update_signatures(signatures)
|
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:
|
if self.bitbox02_device is None:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"Need to setup communication first before attempting any BitBox02 calls"
|
"Need to setup communication first before attempting any BitBox02 calls"
|
||||||
@@ -534,9 +534,9 @@ class BitBox02Client(HardwareClientBase):
|
|||||||
simple_type = {
|
simple_type = {
|
||||||
"p2wpkh-p2sh":bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH,
|
"p2wpkh-p2sh":bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH,
|
||||||
"p2wpkh": bitbox02.btc.BTCScriptConfig.P2WPKH,
|
"p2wpkh": bitbox02.btc.BTCScriptConfig.P2WPKH,
|
||||||
}[xtype]
|
}[script_type]
|
||||||
except KeyError:
|
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(
|
_, _, signature = self.bitbox02_device.btc_sign_msg(
|
||||||
self._get_coin(),
|
self._get_coin(),
|
||||||
@@ -560,7 +560,7 @@ class BitBox02_KeyStore(Hardware_KeyStore):
|
|||||||
self.force_watching_only = False
|
self.force_watching_only = False
|
||||||
self.ux_busy = False
|
self.ux_busy = False
|
||||||
|
|
||||||
def get_client(self):
|
def get_client(self) -> Optional['BitBox02Client']:
|
||||||
return self.plugin.get_client(self)
|
return self.plugin.get_client(self)
|
||||||
|
|
||||||
def give_error(self, message: Exception, clear_client: bool = False):
|
def give_error(self, message: Exception, clear_client: bool = False):
|
||||||
@@ -580,13 +580,12 @@ class BitBox02_KeyStore(Hardware_KeyStore):
|
|||||||
).format(self.device)
|
).format(self.device)
|
||||||
)
|
)
|
||||||
|
|
||||||
def sign_message(self, sequence, message, password):
|
def sign_message(self, sequence, message, password, *, script_type=None):
|
||||||
if password:
|
if password:
|
||||||
raise Exception("BitBox02 does not accept a password from the host")
|
raise Exception("BitBox02 does not accept a password from the host")
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
keypath = self.get_derivation_prefix() + "/%d/%d" % sequence
|
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"), script_type)
|
||||||
return client.sign_message(keypath, message.encode("utf-8"), xtype)
|
|
||||||
|
|
||||||
|
|
||||||
@runs_in_hwd_thread
|
@runs_in_hwd_thread
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ class Coldcard_KeyStore(Hardware_KeyStore):
|
|||||||
raise UserFacingException(_('Encryption and decryption are currently not supported for {}').format(self.device))
|
raise UserFacingException(_('Encryption and decryption are currently not supported for {}').format(self.device))
|
||||||
|
|
||||||
@wrap_busy
|
@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
|
# Sign a message on device. Since we have big screen, of course we
|
||||||
# have to show the message unabiguously there first!
|
# have to show the message unabiguously there first!
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
|
|||||||
raise RuntimeError(_('Encryption and decryption are currently not supported for {}').format(self.device))
|
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
|
sig = None
|
||||||
try:
|
try:
|
||||||
message = message.encode('utf8')
|
message = message.encode('utf8')
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class KeepKey_KeyStore(Hardware_KeyStore):
|
|||||||
raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device))
|
raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device))
|
||||||
|
|
||||||
@runs_in_hwd_thread
|
@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()
|
client = self.get_client()
|
||||||
address_path = self.get_derivation_prefix() + "/%d/%d"%sequence
|
address_path = self.get_derivation_prefix() + "/%d/%d"%sequence
|
||||||
address_n = client.expand_path(address_path)
|
address_n = client.expand_path(address_path)
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||||||
@runs_in_hwd_thread
|
@runs_in_hwd_thread
|
||||||
@test_pin_unlocked
|
@test_pin_unlocked
|
||||||
@set_and_unset_signing
|
@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 = message.encode('utf8')
|
||||||
message_hash = hashlib.sha256(message).hexdigest().upper()
|
message_hash = hashlib.sha256(message).hexdigest().upper()
|
||||||
# prompt for the PIN before displaying the dialog if necessary
|
# prompt for the PIN before displaying the dialog if necessary
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class SafeTKeyStore(Hardware_KeyStore):
|
|||||||
raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device))
|
raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device))
|
||||||
|
|
||||||
@runs_in_hwd_thread
|
@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()
|
client = self.get_client()
|
||||||
address_path = self.get_derivation_prefix() + "/%d/%d"%sequence
|
address_path = self.get_derivation_prefix() + "/%d/%d"%sequence
|
||||||
address_n = client.expand_path(address_path)
|
address_n = client.expand_path(address_path)
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ class TrezorClientBase(HardwareClientBase, Logger):
|
|||||||
multisig=multisig)
|
multisig=multisig)
|
||||||
|
|
||||||
@runs_in_hwd_thread
|
@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()
|
coin_name = self.plugin.get_coin_name()
|
||||||
address_n = parse_path(address_str)
|
address_n = parse_path(address_str)
|
||||||
with self.run_flow():
|
with self.run_flow():
|
||||||
@@ -236,7 +236,9 @@ class TrezorClientBase(HardwareClientBase, Logger):
|
|||||||
self.client,
|
self.client,
|
||||||
coin_name,
|
coin_name,
|
||||||
address_n,
|
address_n,
|
||||||
message)
|
message,
|
||||||
|
script_type=script_type,
|
||||||
|
no_script_type=True)
|
||||||
|
|
||||||
@runs_in_hwd_thread
|
@runs_in_hwd_thread
|
||||||
def recover_device(self, recovery_type, *args, **kwargs):
|
def recover_device(self, recovery_type, *args, **kwargs):
|
||||||
|
|||||||
@@ -77,10 +77,11 @@ class TrezorKeyStore(Hardware_KeyStore):
|
|||||||
def decrypt_message(self, sequence, message, password):
|
def decrypt_message(self, sequence, message, password):
|
||||||
raise UserFacingException(_('Encryption and decryption are not implemented by {}').format(self.device))
|
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()
|
client = self.get_client()
|
||||||
address_path = self.get_derivation_prefix() + "/%d/%d"%sequence
|
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
|
return msg_sig.signature
|
||||||
|
|
||||||
def sign_transaction(self, tx, password):
|
def sign_transaction(self, tx, password):
|
||||||
|
|||||||
@@ -2452,9 +2452,11 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
|||||||
def _update_password_for_keystore(self, old_pw: Optional[str], new_pw: Optional[str]) -> None:
|
def _update_password_for_keystore(self, old_pw: Optional[str], new_pw: Optional[str]) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def sign_message(self, address, message, password):
|
def sign_message(self, address: str, message: str, password) -> bytes:
|
||||||
index = self.get_address_index(address)
|
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:
|
def decrypt_message(self, pubkey: str, message, password) -> bytes:
|
||||||
addr = self.pubkeys_to_address([pubkey])
|
addr = self.pubkeys_to_address([pubkey])
|
||||||
|
|||||||
Reference in New Issue
Block a user