From c1101ee25877fd01509c01496735f8e269f9b884 Mon Sep 17 00:00:00 2001 From: BTChip github Date: Sat, 27 Jun 2020 18:26:54 +0200 Subject: [PATCH 1/3] Remove warning on Segwit inputs and newer Bitcoin application, use generic signing for P2SH inputs --- electrum/plugins/ledger/ledger.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index 393a0c369..b4ab4eb72 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -44,6 +44,8 @@ MSG_NEEDS_FW_UPDATE_SEGWIT = _('Firmware version (or "Bitcoin" app) too old for MULTI_OUTPUT_SUPPORT = '1.1.4' SEGWIT_SUPPORT = '1.1.10' SEGWIT_SUPPORT_SPECIAL = '1.0.4' +SEGWIT_TRUSTEDINPUTS = '1.4.0' +UTIL_SEGWIT_TRUSTEDINPUTS = '0.1.29' def test_pin_unlocked(func): @@ -176,6 +178,9 @@ class Ledger_Client(HardwareClientBase): def supports_native_segwit(self): return self.nativeSegwitSupported + def supports_segwit_trustedInputs(self): + return self.segwitTrustedInputs + def perform_hw1_preflight(self): try: firmwareInfo = self.dongleObject.getFirmwareVersion() @@ -183,6 +188,12 @@ class Ledger_Client(HardwareClientBase): self.multiOutputSupported = versiontuple(firmware) >= versiontuple(MULTI_OUTPUT_SUPPORT) self.nativeSegwitSupported = versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT) self.segwitSupported = self.nativeSegwitSupported or (firmwareInfo['specialVersion'] == 0x20 and versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT_SPECIAL)) + try: + import btchip + utilVersion = btchip.__version__ + except: + utilVersion = "0.0.0" + self.segwitTrustedInputs = versiontuple(firmware) >= versiontuple(SEGWIT_TRUSTEDINPUTS) and versiontuple(utilVersion) >= versiontuple(UTIL_SEGWIT_TRUSTEDINPUTS) if not checkFirmware(firmwareInfo): self.close() @@ -437,18 +448,23 @@ class Ledger_KeyStore(Hardware_KeyStore): # Get trusted inputs from the original transactions for utxo in inputs: sequence = int_to_hex(utxo[5], 4) - if segwitTransaction: + if segwitTransaction and not client_electrum.supports_segwit_trustedInputs(): tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) tmp += bfh(int_to_hex(utxo[6], 8)) # txin['value'] chipInputs.append({'value' : tmp, 'witness' : True, 'sequence' : sequence}) redeemScripts.append(bfh(utxo[2])) - elif not p2shTransaction: + elif (not p2shTransaction) or (p2shTransaction and client_electrum.supports_multi_output()): txtmp = bitcoinTransaction(bfh(utxo[0])) trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1]) trustedInput['sequence'] = sequence + if segwitTransaction: + trustedInput['witness'] = True chipInputs.append(trustedInput) - redeemScripts.append(txtmp.outputs[utxo[1]].script) + if p2shTransaction or segwitTransaction: + redeemScripts.append(bfh(utxo[2])) + else: + redeemScripts.append(txtmp.outputs[utxo[1]].script) else: tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) From 48993118addadeefe204c772c2decab0a1742c7c Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 1 Jul 2020 16:13:38 +0200 Subject: [PATCH 2/3] ledger: bump min btchip-python version and minor simplification --- contrib/requirements/requirements-hw.txt | 2 +- electrum/plugins/ledger/ledger.py | 33 +++++++++++++++--------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt index 78260336b..a026e34a5 100644 --- a/contrib/requirements/requirements-hw.txt +++ b/contrib/requirements/requirements-hw.txt @@ -11,7 +11,7 @@ Cython>=0.27 trezor[hidapi]>=0.12.0 safet>=0.1.5 keepkey>=6.3.1 -btchip-python>=0.1.26 +btchip-python>=0.1.30 ckcc-protocol>=0.7.7 bitbox02>=3.0.0 hidapi diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index b4ab4eb72..8dcd4f0f3 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -18,7 +18,7 @@ from electrum.base_wizard import ScriptTypeNotSupported from electrum.logging import get_logger from ..hw_wallet import HW_PluginBase, HardwareClientBase -from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, validate_op_return_output +from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, validate_op_return_output, LibraryFoundButUnusable _logger = get_logger(__name__) @@ -45,7 +45,6 @@ MULTI_OUTPUT_SUPPORT = '1.1.4' SEGWIT_SUPPORT = '1.1.10' SEGWIT_SUPPORT_SPECIAL = '1.0.4' SEGWIT_TRUSTEDINPUTS = '1.4.0' -UTIL_SEGWIT_TRUSTEDINPUTS = '0.1.29' def test_pin_unlocked(func): @@ -188,12 +187,7 @@ class Ledger_Client(HardwareClientBase): self.multiOutputSupported = versiontuple(firmware) >= versiontuple(MULTI_OUTPUT_SUPPORT) self.nativeSegwitSupported = versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT) self.segwitSupported = self.nativeSegwitSupported or (firmwareInfo['specialVersion'] == 0x20 and versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT_SPECIAL)) - try: - import btchip - utilVersion = btchip.__version__ - except: - utilVersion = "0.0.0" - self.segwitTrustedInputs = versiontuple(firmware) >= versiontuple(SEGWIT_TRUSTEDINPUTS) and versiontuple(utilVersion) >= versiontuple(UTIL_SEGWIT_TRUSTEDINPUTS) + self.segwitTrustedInputs = versiontuple(firmware) >= versiontuple(SEGWIT_TRUSTEDINPUTS) if not checkFirmware(firmwareInfo): self.close() @@ -454,7 +448,7 @@ class Ledger_KeyStore(Hardware_KeyStore): tmp += bfh(int_to_hex(utxo[6], 8)) # txin['value'] chipInputs.append({'value' : tmp, 'witness' : True, 'sequence' : sequence}) redeemScripts.append(bfh(utxo[2])) - elif (not p2shTransaction) or (p2shTransaction and client_electrum.supports_multi_output()): + elif (not p2shTransaction) or client_electrum.supports_multi_output(): txtmp = bitcoinTransaction(bfh(utxo[0])) trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1]) trustedInput['sequence'] = sequence @@ -573,8 +567,8 @@ class Ledger_KeyStore(Hardware_KeyStore): self.handler.finished() class LedgerPlugin(HW_PluginBase): - libraries_available = BTCHIP keystore_class = Ledger_KeyStore + minimum_library = (0, 1, 30) client = None DEVICE_IDS = [ (0x2581, 0x1807), # HW.1 legacy btchip @@ -596,8 +590,23 @@ class LedgerPlugin(HW_PluginBase): def __init__(self, parent, config, name): self.segwit = config.get("segwit") HW_PluginBase.__init__(self, parent, config, name) - if self.libraries_available: - self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) + self.libraries_available = self.check_libraries_available() + if not self.libraries_available: + return + self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) + + def get_library_version(self): + try: + import btchip + version = btchip.__version__ + except ImportError: + raise + except: + version = "unknown" + if BTCHIP: + return version + else: + raise LibraryFoundButUnusable(library_version=version) def get_btchip_device(self, device): ledger = False From b042c4118f663ebd910461270229bdaf6802d7d6 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 1 Jul 2020 16:15:13 +0200 Subject: [PATCH 3/3] ledger: speed-up sign_transaction really slow to scan usb devices for e.g. every tx input... if user disconnects mid-signing, we would fail anyway. --- electrum/plugins/ledger/ledger.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index 8dcd4f0f3..0b125c712 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -351,7 +351,7 @@ class Ledger_KeyStore(Hardware_KeyStore): p2shTransaction = False segwitTransaction = False pin = "" - self.get_client() # prompt for the PIN before displaying the dialog if necessary + client_ledger = self.get_client() # prompt for the PIN before displaying the dialog if necessary client_electrum = self.get_client_electrum() assert client_electrum @@ -450,13 +450,13 @@ class Ledger_KeyStore(Hardware_KeyStore): redeemScripts.append(bfh(utxo[2])) elif (not p2shTransaction) or client_electrum.supports_multi_output(): txtmp = bitcoinTransaction(bfh(utxo[0])) - trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1]) + trustedInput = client_ledger.getTrustedInput(txtmp, utxo[1]) trustedInput['sequence'] = sequence if segwitTransaction: trustedInput['witness'] = True chipInputs.append(trustedInput) if p2shTransaction or segwitTransaction: - redeemScripts.append(bfh(utxo[2])) + redeemScripts.append(bfh(utxo[2])) else: redeemScripts.append(txtmp.outputs[utxo[1]].script) else: @@ -469,13 +469,13 @@ class Ledger_KeyStore(Hardware_KeyStore): firstTransaction = True inputIndex = 0 rawTx = tx.serialize_to_network() - self.get_client().enableAlternate2fa(False) + client_ledger.enableAlternate2fa(False) if segwitTransaction: - self.get_client().startUntrustedTransaction(True, inputIndex, + client_ledger.startUntrustedTransaction(True, inputIndex, chipInputs, redeemScripts[inputIndex], version=tx.version) # we don't set meaningful outputAddress, amount and fees # as we only care about the alternateEncoding==True branch - outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx)) + outputData = client_ledger.finalizeInput(b'', 0, 0, changePath, bfh(rawTx)) outputData['outputData'] = txOutput if outputData['confirmationNeeded']: outputData['address'] = output @@ -486,9 +486,9 @@ class Ledger_KeyStore(Hardware_KeyStore): self.handler.show_message(_("Confirmed. Signing Transaction...")) while inputIndex < len(inputs): singleInput = [ chipInputs[inputIndex] ] - self.get_client().startUntrustedTransaction(False, 0, + client_ledger.startUntrustedTransaction(False, 0, singleInput, redeemScripts[inputIndex], version=tx.version) - inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime) + inputSignature = client_ledger.untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ my_pubkey = inputs[inputIndex][4] tx.add_signature_to_txin(txin_idx=inputIndex, @@ -497,11 +497,11 @@ class Ledger_KeyStore(Hardware_KeyStore): inputIndex = inputIndex + 1 else: while inputIndex < len(inputs): - self.get_client().startUntrustedTransaction(firstTransaction, inputIndex, + client_ledger.startUntrustedTransaction(firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex], version=tx.version) # we don't set meaningful outputAddress, amount and fees # as we only care about the alternateEncoding==True branch - outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx)) + outputData = client_ledger.finalizeInput(b'', 0, 0, changePath, bfh(rawTx)) outputData['outputData'] = txOutput if outputData['confirmationNeeded']: outputData['address'] = output @@ -512,7 +512,7 @@ class Ledger_KeyStore(Hardware_KeyStore): self.handler.show_message(_("Confirmed. Signing Transaction...")) else: # Sign input with the provided PIN - inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime) + inputSignature = client_ledger.untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ my_pubkey = inputs[inputIndex][4] tx.add_signature_to_txin(txin_idx=inputIndex,