Commit Graph

73 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
SomberNight
ba3783f998 refactor qt.util.ChoiceWidget: introduce ChoiceItem 2025-05-06 18:12:37 +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
f321x
a9f8048251 use manifest.json instead of loading init file for plugin registration 2025-03-19 10:38:20 +01:00
ThomasV
eccc5900e0 move plugin icons to plugins 2024-10-17 13:32:30 +02:00
SomberNight
48661b5913 follow-up electrum_ecc: fix some import names
ref https://github.com/spesmilo/electrum/pull/9234
2024-10-10 19:24:27 +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
Sander van Grieken
0277950247 qt: factor out remaining ChoicesLayout uses 2024-09-13 17:10:52 +02:00
SomberNight
a674a22155 follow-up moving some funcs from ecc.py to bitcoin.py
follow-up 2f3d89f415
2024-09-03 16:58:41 +00:00
Sander van Grieken
295ea97f1f digitalbitbox: follow-up 2f3d89f415 2024-07-03 10:53:16 +02:00
SomberNight
13e2949088 rm some legacy cruft for old python versions 2024-06-05 14:55:48 +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
SomberNight
bd9d0ccc33 ecc: refactor/clean-up sign/verify APIs 2024-04-11 15:25:45 +00:00
Sander van Grieken
643fbecc15 wizard: fix co-signing hardware wallets data incorrectly referenced 2024-02-14 12:42:15 +01:00
Sander van Grieken
4101946ff5 wizard: add non-hardened derivation path check for digital bitbox, re-add rescan button in choose hw device,
clear clipboard before confirming seed.
2023-09-20 14:34:31 +02:00
Sander van Grieken
b7612605c5 wizard: add Digital Bitbox initialization to new wizard, remove rescan button
Note: the option to load a backup from SD card when the device already has a seed
has been removed. The device always returns an error when attempting this.
2023-09-20 14:34:31 +02:00
Sander van Grieken
087718f3a7 hww: mark device_model_name(self) as @abstractmethod and override in hww clients that did not define it. 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
d70831392d wizard: add keepkey to new wizard 2023-09-20 14:34:31 +02:00
Sander van Grieken
48fb4911a3 wizard: add digital bitbox to new wizard 2023-09-20 14:34:31 +02:00
SomberNight
22b8c4e397 hww: fix digitalbitbox(1) support
regression from cea4238b81

```
975.04 | E | plugin.DeviceMgr | failed to create client for digitalbitbox at <REDACTED>: AttributeError("'NoneType' object has no attribute 'get_passphrase'")
Traceback (most recent call last):
  File "...\electrum\electrum\plugin.py", line 620, in list_pairable_device_infos
    soft_device_id = client.get_soft_device_id()
  File "...\electrum\electrum\plugins\hw_wallet\plugin.py", line 251, in get_soft_device_id
    root_fp = self.request_root_fingerprint_from_device()
  File "...\electrum\electrum\plugin.py", line 362, in wrapper
    return run_in_hwd_thread(partial(func, *args, **kwargs))
  File "...\electrum\electrum\plugin.py", line 352, in run_in_hwd_thread
    return func()
  File "...\electrum\electrum\plugins\hw_wallet\plugin.py", line 264, in request_root_fingerprint_from_device
    child_of_root_xpub = self.get_xpub("m/0'", xtype='standard')
  File "...\electrum\electrum\plugins\digitalbitbox\digitalbitbox.py", line 115, in get_xpub
    reply = self._get_xpub(bip32_path)
  File "...\electrum\electrum\plugins\digitalbitbox\digitalbitbox.py", line 110, in _get_xpub
    if self.check_device_dialog():
  File "...\electrum\electrum\plugins\digitalbitbox\digitalbitbox.py", line 197, in check_device_dialog
    if not self.password_dialog(msg):
  File "...\electrum\electrum\plugins\digitalbitbox\digitalbitbox.py", line 159, in password_dialog
    password = self.handler.get_passphrase(msg, False)
AttributeError: 'NoneType' object has no attribute 'get_passphrase'
```
2023-04-27 17:33:54 +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
312f2641e7 don't use bare except
use "except Exception", or if really needed explicitly "except BaseException"
2023-04-24 12:58:01 +00:00
SomberNight
be159b5b95 bugfix: assert walrus (":=") combo side-eff. breaks w/ asserts disabled
```
$ python3 -O
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> assert (x := 2)
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
```

pity. it looked to be a neat and concise pattern.
2023-04-20 15:17:36 +00:00
SomberNight
0647a2cf9f transaction.py: rm PartialTxInput.{num_sig, script_type} 2023-03-03 16:40:12 +00:00
SomberNight
1ce37c8bb1 transaction: rm hardcoded sighash magic numbers 2023-02-17 11:40:12 +00:00
SomberNight
01b5e3f8e0 flake8: enable more mandatory tests 2022-10-31 16:13:22 +00:00
SomberNight
79fec3417a crypto.py: rm {En,De}codeAES_base64. instead use {En,De}codeAES_bytes 2022-07-12 15:50:42 +02:00
SomberNight
6c50d3b0a3 hw plugins: (cleanup) rm no-op clear_client argument from keystore.give_error
The keystore does not have a "client" field.
One is supposed to use the "get_client" method instead (the generic API is `plugin.get_client(keystore)`)
Remnants of old code.
2022-05-11 19:30:14 +02:00
SomberNight
aab8e664ed hw plugins: (cleanup) Plugin objects should not have a Client field
Clients are per-connected-device, plugins are ~singletons.
These were mostly remnants of old code.
2022-05-11 19:16:18 +02:00
SomberNight
30623c3529 hw plugins: (cleanup) Plugin objects should not have a Handler field
Handlers are per-client (connected device), plugins are ~singletons.
These were mostly remnants of old code.
2022-05-11 19:13:00 +02:00
SomberNight
9599254d43 hw: rm dead code from Hardware_KeyStore subclasses
- force_watching_only is long since unused
- comment was just duplicated from the base class
2022-05-09 20:09:10 +02:00
SomberNight
376fc01b27 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
2022-02-22 19:20:03 +01:00
SomberNight
5cdb4471ec signmessage: also accept Trezor-type sigs for p2wpkh and p2wpkh-p2sh addrs
The signatures we create are unchanged but we now also accept signatures created by Trezor and others.

see https://github.com/spesmilo/electrum/issues/3861
2022-02-16 19:25:46 +01:00
ghost43
21c3572600 hardware devices: run all device communication on dedicated thread (#6561)
hidapi/libusb etc are not thread-safe.

related: #6554
2020-09-08 15:52:53 +00:00
SomberNight
2cfa3bd6c8 hww hidapi usage: try to mitigate some thread-safety issues
related: #6097
2020-04-17 19:53:39 +02:00
SomberNight
98d2ab5bd6 hww: fix HardwareClientBase not having reference to plugin
it was incorrectly documented that it did (previously only for some plugins)
2020-04-17 19:53:35 +02:00
SomberNight
e830ef309f hww: factor out part of hid scan code to HW_PluginBase
so that bitbox02 can override it
2020-04-12 15:34:19 +02:00
SomberNight
4b1d835304 wizard hww: scan devices fewer times and move away from GUI thread 2020-04-09 19:45:31 +02:00
SomberNight
bf067f7558 HardwareClientBase: provide default implementation for label
and add warning about placeholders
2020-04-08 18:28:21 +02:00
SomberNight
4ef313a1ac hww: smarter auto-selection of which device to pair with
scenario1:
- 2of2 multisig wallet with trezor1 and trezor2 keystores
- only trezor2 connected
- previously we would pair first keystore with connected device and then display error.
  now we will pair the device with the correct keystore on the first try

scenario2:
- standard wallet with trezor1 keystore
- trezor2 connected (different device)
- previously we would pair trezor2 with the keystore and then display error.
  now we will prompt the user to select which device to pair with (out of one)

related: #5789
2020-04-08 17:53:33 +02:00
SomberNight
371f55a0f9 hww: fix some threading issues in wizard
fixes #3377
related: #6064  (passphrase dialog not rendered correctly)
2020-04-01 21:09:17 +02:00
SomberNight
81fc3fcce2 hww: rm some code duplication: add "scan_and_create_client_for_device" 2020-04-01 21:09:14 +02:00
SomberNight
276631fab7 digitalbitbox: (trivial) user handler instead of handler.win 2020-04-01 21:09:03 +02:00
SomberNight
7f1c7955dc DeviceMgr: clean-up locks a bit 2020-04-01 21:09:00 +02:00
SomberNight
d2f132738a wallet: only select mature coins by default
this is a regression from #5721

Removed the `TxInput.is_coinbase` method as I think it is a confusing API,
instead we now have `TxInput.is_coinbase_input` and `TxInput.is_coinbase_output`.

related #5872
2020-01-02 00:43:49 +01:00