Commit Graph

117 Commits

Author SHA1 Message Date
SomberNight
3e4601c61d base64.b64decode: always set validate=True
Notably verifymessage and decrypt(message) were silently ignoring trailing garbage
or inserted non-base64 characters present in signatures/ciphertext.
(both the CLI commands and in the GUI)
I think it is much cleaner and preferable to treat such signatures/ciphertext as invalid.

In fact I find it surprising that base64.b64decode(validate=False) is the default.
Perhaps we should create a helper function for it that set validate=True and use that.
2025-06-03 18:58:05 +00:00
SomberNight
0508625afc transaction: add method verify_sig_for_txin
This new `Transaction.verify_sig_for_txin` function is an instance method of `Transaction` instead of `PartialTransaction`.
It takes a complete txin, a pubkey and a signature, and verifies the signature.

- `get_preimage_script` is renamed to `get_scriptcode_for_sighash` and now effectively has two implementations:
  - the old impl became `PartialTxInput.get_scriptcode_for_sighash`
    - this assumes we are the ones constructing a spending txin and can have knowledge beyond what will be revealed onchain
  - the new impl is in the base class, `TxInput.get_scriptcode_for_sighash`
    - this assumes the txin is already "complete", and mimics a consensus-verifier by extracting the required fields
      from the already complete witness/scriptSig and the scriptpubkey of the funding utxo
- `serialize_preimage` now does not require a PartialTransaction, it also works on the base class Transaction

-----

I intend to use this for debugging only atm: I noticed TxBatcher sometimes creates invalid signatures by seeing
that bitcoind rejects txs with `mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)`.
However the txs in question have multiple txins, with some txins containing multiple signatures, and bitcoind does not tell us
which txin/signature is invalid. Knowing which signature is invalid would be a start, but I can now add some temp debug logging
to `serialize_preimage` to compare the message being signed with the message being verified.

As can be seen from the tests, the signature and the pubkey needs to be manually extracted from the txin to be verified:
we still don't have a script interpreter so we don't have logic to "verify a txin". However this new code adds logic
to verify a signature for a txin/pubkey combo (which is a small part of an interpreter/verifier).
2025-05-18 15:20:19 +00:00
ThomasV
b86be552e7 hardware wallets: show address on device also from tx dialog 2025-05-06 18:22:07 +00:00
ThomasV
c93b13f6d9 Make it possible to create zip plugins from internal plugins
specifically:
 - add 'name' field to manifest.json
 - make 'version' optional in contrib/make_plugin
 - fix import in jade plugin
2025-04-14 11:54:04 +02:00
ThomasV
6e087950cf move hw_wallet.py from plugins to electrum library 2025-04-10 10:19:15 +02:00
SomberNight
245853ff4f plugins: ledger: bump max supported ledger_bitcoin version
ledger-bitcoin 0.4 was just released (seemingly without breaking changes)
the changelog claims they want to uphold semver
2025-03-19 17:29:40 +00:00
ThomasV
647ae49451 Merge pull request #9651 from f321x/plugin_manifest_json
Use manifest.json instead of loading init file for plugin registration
2025-03-19 10:52:02 +01:00
f321x
a9f8048251 use manifest.json instead of loading init file for plugin registration 2025-03-19 10:38:20 +01:00
SomberNight
4c970fd8fa plugins: ledger: better error msg for hw.1 2025-03-18 17:26:12 +00:00
SomberNight
154adf0081 plugins: ledger: rm support for hw.1
This removes support for Ledger HW.1 and "Nano" (non-S) devices.
These were manufactured/sold around 2015-2016, and are long unsupported by the upstream vendor.

We previously added a deprecation warning to the GUI [0] released in 4.3.3 (2023-01-02), to warn owners of these devices.
This PR now fully removes support.

As a consequence, the unmaintained btchip-python dependency can now be removed, which solves [1].

[0]: 9b82eb6d06
[1]: https://github.com/spesmilo/electrum/issues/9370#issuecomment-2593675364
2025-03-18 16:18:49 +00:00
SomberNight
7737dbf795 plugins: ledger: fix Ledger_Client_Legacy.sign_transaction
regression from 2f1095510c
2025-03-18 15:34:17 +00:00
ThomasV
eccc5900e0 move plugin icons to plugins 2024-10-17 13:32:30 +02:00
SomberNight
225ed079a9 hw plugins: ledger: bump pinned lib to 0.3.0, raise max_lib to <0.4
closes https://github.com/spesmilo/electrum/issues/9035
2024-10-11 15:13:34 +00:00
SomberNight
15d5b96dda hw plugins: ledger: minor fix re qt6 migration
follow-up https://github.com/spesmilo/electrum/pull/9189
2024-10-10 20:12:09 +00:00
ThomasV
3721f04ac8 replace electrum/ecc with electrum_ecc package 2024-10-10 15:46:00 +00:00
SomberNight
383f99796a qt gui: follow-up qt6: fix args for QWidget.setFocus()
Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\main_window.py", line 1797, in toggle_search
    self.search_box.setFocus(1)
TypeError: arguments did not match any overloaded call:
  setFocus(self): too many arguments
  setFocus(self, reason: Qt.FocusReason): argument 1 has unexpected type 'int'
2024-09-18 17:39:46 +00:00
SomberNight
cfe8502f96 qt desktop gui: upgrade qt5->qt6
closes https://github.com/spesmilo/electrum/issues/8007
2024-09-18 15:48:38 +00:00
SomberNight
5ad8c97c1d hww: ledger: update udev rules and model ids
see https://github.com/bitcoin-core/HWI/pull/746

maybe closes https://github.com/spesmilo/electrum/issues/9179
2024-09-02 13:50:35 +00:00
SomberNight
2f1095510c bitcoin.py/transaction.py: API changes: rm most hex usage
Instead of some functions operating with hex strings,
and others using bytes, this consolidates most things to use bytes.

This mainly focuses on bitcoin.py and transaction.py,
and then adapts the API usages in other files.

Notably,
- scripts,
- pubkeys,
- signatures
should be bytes in almost all places now.
2024-04-29 17:10:26 +00:00
Sander van Grieken
d8f579ccfc Consistently use translated strings for UserFacingException raises 2024-01-16 16:25:33 +01:00
Sander van Grieken
22d3a5edbb wizard: fix trezor initialisation/recover not setting page valid to True
add auto-proceed to next page after init to trezor, safe_t, keepkey
2023-09-20 14:34:31 +02:00
Sander van Grieken
0aebc1a31e qt+plugins: cleanup. remove all old wizard code 2023-09-20 14:34:31 +02:00
Sander van Grieken
656442ce64 wizard: add missing imports 2023-09-20 14:34:31 +02:00
Sander van Grieken
46c60c9f09 wizard: add ledger 2023-09-20 14:34:31 +02:00
SomberNight
201309a7f0 ledger plugin: fix Ledger_Client.construct_new on very old btc app ver
related: https://github.com/spesmilo/electrum/issues/8568#issuecomment-1710162955
2023-09-07 14:47:55 +00:00
SomberNight
24980feab7 config: introduce ConfigVars
A new config API is introduced, and ~all of the codebase is adapted to it.
The old API is kept but mainly only for dynamic usage where its extra flexibility is needed.

Using examples, the old config API looked this:
```
>>> config.get("request_expiry", 86400)
604800
>>> config.set_key("request_expiry", 86400)
>>>
```

The new config API instead:
```
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS
604800
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS = 86400
>>>
```

The old API operated on arbitrary string keys, the new one uses
a static ~enum-like list of variables.

With the new API:
- there is a single centralised list of config variables, as opposed to
  these being scattered all over
- no more duplication of default values (in the getters)
- there is now some (minimal for now) type-validation/conversion for
  the config values

closes https://github.com/spesmilo/electrum/pull/5640
closes https://github.com/spesmilo/electrum/pull/5649

Note: there is yet a third API added here, for certain niche/abstract use-cases,
where we need a reference to the config variable itself.
It should only be used when needed:
```
>>> var = config.cv.WALLET_PAYREQ_EXPIRY_SECONDS
>>> var
<ConfigVarWithConfig key='request_expiry'>
>>> var.get()
604800
>>> var.set(3600)
>>> var.get_default_value()
86400
>>> var.is_set()
True
>>> var.is_modifiable()
True
```
2023-05-25 17:39:48 +00:00
SomberNight
9e13246be8 ledger: fix Ledger_Client_Legacy.sign_transaction()
fix signing txs when using old "bitcoin app" (pre-2.1) on the ledger device

```
 33.36 | W | transaction | heyheyhey. cp1. include_sigs=True force_legacy=False use_segwit_ser=True
 33.36 | W | transaction | heyheyhey. cp2. branch1
 33.37 | E | plugins.ledger.ledger |
Traceback (most recent call last):
  File "...\electrum\electrum\plugins\ledger\ledger.py", line 669, in sign_transaction
    rawTx = tx.serialize_to_network()
  File "...\electrum\electrum\transaction.py", line 945, in serialize_to_network
    witness = ''.join(self.serialize_witness(x, estimate_size=estimate_size) for x in inputs)
  File "...\electrum\electrum\transaction.py", line 945, in <genexpr>
    witness = ''.join(self.serialize_witness(x, estimate_size=estimate_size) for x in inputs)
  File "...\electrum\electrum\transaction.py", line 839, in serialize_witness
    sol = desc.satisfy(allow_dummy=estimate_size, sigdata=txin.part_sigs)
  File "...\electrum\electrum\descriptor.py", line 378, in satisfy
    sol = self._satisfy_inner(sigdata=sigdata, allow_dummy=allow_dummy)
  File "...\electrum\electrum\descriptor.py", line 574, in _satisfy_inner
    raise MissingSolutionPiece(f"no sig for {pubkey.hex()}")
electrum.descriptor.MissingSolutionPiece: no sig for 033e92e55923ea25809790f292ee9bd410355ee02492472d9a1ff1b364874d0679
 33.38 | I | plugins.ledger.ledger | no sig for 033e92e55923ea25809790f292ee9bd410355ee02492472d9a1ff1b364874d0679
```

fixes https://github.com/spesmilo/electrum/issues/8365
regression from https://github.com/spesmilo/electrum/pull/8230
2023-05-09 16:17:04 +00:00
SomberNight
3020499199 hww: ledger: bump required ledger-bitcoin and adapt to API change 2023-05-05 15:02:34 +00:00
SomberNight
33d394c9d7 ledger: fix scan_devices for certain devices with multiple interfaces
regression from https://github.com/spesmilo/electrum/pull/8041 (4.3.3)

maybe fixes https://github.com/spesmilo/electrum/issues/8293

-----

Testing with a "Ledger Nano S", btc app version 1.6.3.
btchip-python==0.1.32
ledgercomm==1.1.1
ledger-bitcoin==0.1.1

Trying to scan devices hangs/blocks forever on Linux (ubuntu 22.04).

```patch
diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
index 17c1caca48..ba5ae2e3ee 100644
--- a/electrum/plugins/ledger/ledger.py
+++ b/electrum/plugins/ledger/ledger.py
@@ -306,17 +306,25 @@ class Ledger_Client(HardwareClientBase, ABC):
     @staticmethod
     def construct_new(*args, device: Device, **kwargs) -> 'Ledger_Client':
         """The 'real' constructor, that automatically decides which subclass to use."""
+        _logger.info(f"xxx construct_new(). cp1. {device.path=}. {device=}")
         if LedgerPlugin.is_hw1(device.product_key):
             return Ledger_Client_Legacy_HW1(*args, **kwargs, device=device)
         # for nano S or newer hw, decide which client impl to use based on software/firmware version:
+        _logger.info(f"xxx construct_new(). cp2.")
         hid_device = HID()
         hid_device.path = device.path
+        _logger.info(f"xxx construct_new(). cp3.")
         hid_device.open()
+        _logger.info(f"xxx construct_new(). cp4.")
         transport = ledger_bitcoin.TransportClient('hid', hid=hid_device)
-        cl = ledger_bitcoin.createClient(transport, chain=get_chain())
+        _logger.info(f"xxx construct_new(). cp5.")
+        cl = ledger_bitcoin.createClient(transport, chain=get_chain(), debug=True)
+        _logger.info(f"xxx construct_new(). cp6.")
         if isinstance(cl, ledger_bitcoin.client.NewClient):
+            _logger.info(f"xxx construct_new(). cp7. trying Ledger_Client_New")
             return Ledger_Client_New(hid_device, *args, **kwargs)
         else:
+            _logger.info(f"xxx construct_new(). cp7. trying Ledger_Client_Legacy")
             return Ledger_Client_Legacy(hid_device, *args, **kwargs)

     def __init__(self, *, plugin: HW_PluginBase):
@@ -1416,7 +1424,7 @@ class LedgerPlugin(HW_PluginBase):
         try:
             return Ledger_Client.construct_new(device=device, product_key=device.product_key, plugin=self)
         except Exception as e:
-            self.logger.info(f"cannot connect at {device.path} {e}")
+            self.logger.info(f"cannot connect at {device.path} {e}")  #
         return None

     def setup_device(self, device_info, wizard, purpose):
```

scanning devices freezes... log:
```
  8.94 | I | plugin.DeviceMgr | scanning devices...
  9.18 | D | util.profiler | DeviceMgr.scan_devices 0.2357 sec
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp1. device.path=b'0001:0008:00'. device=Device(path=b'0001:0008:00', interface_number=0, id_="b'0001:0008:00',0001,0,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp2.
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp3.
heyheyhey. cp1. self.path=b'0001:0008:00'
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp4.
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp5.
=> b001000000
<= 010c426974636f696e205465737405312e362e3301029000
  9.22 | I | plugins.ledger.ledger | xxx construct_new(). cp6.
  9.22 | I | plugins.ledger.ledger | xxx construct_new(). cp7. trying Ledger_Client_Legacy
  9.29 | I | plugin.DeviceMgr | Registering <electrum.plugins.ledger.ledger.Ledger_Client_Legacy object at 0x7f4369e6e380>
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp1. device.path=b'0001:0008:01'. device=Device(path=b'0001:0008:01', interface_number=1, id_="b'0001:0008:01',0001,1,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp2.
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp3.
heyheyhey. cp1. self.path=b'0001:0008:01'
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp4.
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp5.
=> b001000000
```

in Qt console (before change):
```
>>> lp = plugins.get_plugin("ledger")
>>> plugins.device_manager.scan_devices()
[Device(path=b'0001:000a:00', interface_number=0, id_="b'0001:000a:00',0001,0,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid'), Device(path=b'0001:000a:01', interface_number=1, id_="b'0001:000a:01',0001,1,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')]
```
2023-05-02 17:23:07 +00:00
SomberNight
499f51535f bip32: fix hardened char "h" vs "'" compatibility for some hw wallets
in particular, ledger: fix sign_message for some wallets

```
156.02 | E | plugins.ledger.ledger |
Traceback (most recent call last):
  File "...\electrum\electrum\plugins\ledger\ledger.py", line 1265, in sign_message
    result = base64.b64decode(self.client.sign_message(message, address_path))
  File "...\Python310\site-packages\ledger_bitcoin\client.py", line 230, in sign_message
    sw, response = self._make_request(self.builder.sign_message(message_bytes, bip32_path), client_intepreter)
  File "...\Python310\site-packages\ledger_bitcoin\command_builder.py", line 176, in sign_message
    bip32_path: List[bytes] = bip32_path_from_string(bip32_path)
  File "...\Python310\site-packages\ledger_bitcoin\common.py", line 68, in bip32_path_from_string
    return [int(p).to_bytes(4, byteorder="big") if "'" not in p
  File "...\Python310\site-packages\ledger_bitcoin\common.py", line 68, in <listcomp>
    return [int(p).to_bytes(4, byteorder="big") if "'" not in p
ValueError: invalid literal for int() with base 10: '84h'
```

Regression from df2bd61de6, where the
default hardened char was changed from "'" to "h". Note that there was
no corresponding wallet db upgrade, so some files use one char and
others use the other.
2023-04-27 17:03:16 +00:00
SomberNight
4219022c2e fix flake8-bugbear B023
B023 Function definition does not bind loop variable 'already_selected_buckets_value_sum'

in keepkey/qt.py, looks like this was an actual bug
(fixed in trezor plugin already: 52a4810752 )
2023-04-24 13:00:07 +00:00
SomberNight
312f2641e7 don't use bare except
use "except Exception", or if really needed explicitly "except BaseException"
2023-04-24 12:58:01 +00:00
Victor Forgeoux
ee61f99c22 Add support for Ledger Stax (#8308)
* Add support for Ledger Stax
2023-04-18 13:11:49 +00:00
SomberNight
7746cc8e60 bip32: (trivial) rename method strpath_to_intpath, for symmetry
Required a much higher mental load to parse the name "convert_bip32_path_to_list_of_uint32"
than to parse "convert_bip32_strpath_to_intpath".
And we already have the ~inverse: "convert_bip32_intpath_to_strpath".
2023-03-10 14:23:17 +00:00
SomberNight
0647a2cf9f transaction.py: rm PartialTxInput.{num_sig, script_type} 2023-03-03 16:40:12 +00:00
SomberNight
2242a506a9 ledger: fix sign_transaction for Ypub / sh(wsh(multi())) wallets
regression from https://github.com/spesmilo/electrum/pull/8041
2023-02-22 14:02:24 +00:00
ghost43
ac239a81b8 Merge pull request #8041 from bigspider/app-bitcoin-new
Modify Ledger plugin to support the new bitcoin app v2.1.0
2022-11-10 14:24:14 +00:00
SomberNight
e75110ec04 hw_wallet: de-dupe "message_dialog" code, make text selectable 2022-11-09 21:10:52 +00:00
SomberNight
9b82eb6d06 ledger: re-add support for HW.1, and add a deprecation warning 2022-11-09 20:42:55 +00:00
SomberNight
3cac7e9a61 ledger: minor clean-up 2022-11-09 20:11:08 +00:00
Salvatore Ingala
e47270daa5 Fix multiple signing 2022-11-09 13:21:14 +01:00
Salvatore Ingala
3c0e3eb7e2 Refactored LedgerPlugin::create_client, and handle errors when creating the client. 2022-11-09 11:34:41 +01:00
Salvatore Ingala
7c80779903 Replace print() with logger 2022-11-09 11:21:21 +01:00
Salvatore Ingala
80e214d465 - Remove code calling hw1-related features, not supported in the version of btchip embedded in ledger_bitcoin
- Fix signature of sign_message in Ledger_Client_Legacy
2022-11-09 10:59:12 +01:00
Salvatore Ingala
f3eb492dca Update Ledger website to ledger.com in error message 2022-11-08 17:44:09 +01:00
Salvatore Ingala
c401f84aa7 Avoid relying on old btchip package; improve missing library error handling 2022-11-08 17:44:06 +01:00
Salvatore Ingala
2d64dc13c9 Modify Ledger plugin to support the new bitcoin app v2.1.0 2022-11-08 17:44:05 +01:00
SomberNight
01b5e3f8e0 flake8: enable more mandatory tests 2022-10-31 16:13:22 +00:00
SomberNight
574243b897 hww ledger: call scan_devices fewer times 2022-06-03 17:14:51 +02:00
SomberNight
b5d3f1458a hww: impl get_client in Hardware_KeyStore instead of subclasses 2022-06-03 17:14:44 +02:00