commit 97c79d52f96cfcb191b75439185e068d37ca9f90
parent a59aec91946fb81fe5b265aa62a26efe60019f83
Author: ghost43 <somber.night@protonmail.com>
Date: Thu, 15 Oct 2020 10:08:24 +0000
Merge pull request #6649 from benma/bitbox02-9.2.0
BitBox02 v9.2.0: support for signing messages and for p2wsh-p2sh legacy multisig accounts
Diffstat:
2 files changed, 59 insertions(+), 22 deletions(-)
diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt
@@ -4,4 +4,4 @@ safet>=0.1.5
keepkey>=6.3.1
btchip-python>=0.1.30
ckcc-protocol>=0.7.7
-bitbox02>=4.0.0
+bitbox02>=5.0.0
diff --git a/electrum/plugins/bitbox02/bitbox02.py b/electrum/plugins/bitbox02/bitbox02.py
@@ -229,6 +229,11 @@ class BitBox02Client(HardwareClientBase):
out_type = bitbox02.btc.BTCPubRequest.YPUB
else:
out_type = bitbox02.btc.BTCPubRequest.UPUB
+ elif xtype == "p2wsh-p2sh":
+ if coin_network == bitbox02.btc.BTC:
+ out_type = bitbox02.btc.BTCPubRequest.CAPITAL_YPUB
+ else:
+ out_type = bitbox02.btc.BTCPubRequest.CAPITAL_UPUB
elif xtype == "p2wsh":
if coin_network == bitbox02.btc.BTC:
out_type = bitbox02.btc.BTCPubRequest.CAPITAL_ZPUB
@@ -276,13 +281,14 @@ class BitBox02Client(HardwareClientBase):
@runs_in_hwd_thread
def btc_multisig_config(
- self, coin, bip32_path: List[int], wallet: Multisig_Wallet
+ self, coin, bip32_path: List[int], wallet: Multisig_Wallet, xtype: str,
):
"""
Set and get a multisig config with the current device and some other arbitrary xpubs.
Registers it on the device if not already registered.
+ xtype: 'p2wsh' | 'p2wsh-p2sh'
"""
-
+ assert xtype in ("p2wsh", "p2wsh-p2sh")
if self.bitbox02_device is None:
raise Exception(
"Need to setup communication first before attempting any BitBox02 calls"
@@ -291,7 +297,7 @@ class BitBox02Client(HardwareClientBase):
account_keypath = bip32_path[:4]
xpubs = wallet.get_master_public_keys()
our_xpub = self.get_xpub(
- bip32.convert_bip32_intpath_to_strpath(account_keypath), "p2wsh"
+ bip32.convert_bip32_intpath_to_strpath(account_keypath), xtype
)
multisig_config = bitbox02.btc.BTCScriptConfig(
@@ -299,6 +305,10 @@ class BitBox02Client(HardwareClientBase):
threshold=wallet.m,
xpubs=[util.parse_xpub(xpub) for xpub in xpubs],
our_xpub_index=xpubs.index(our_xpub),
+ script_type={
+ "p2wsh": bitbox02.btc.BTCScriptConfig.Multisig.P2WSH,
+ "p2wsh-p2sh": bitbox02.btc.BTCScriptConfig.Multisig.P2WSH_P2SH,
+ }[xtype]
)
)
@@ -341,13 +351,13 @@ class BitBox02Client(HardwareClientBase):
script_config = bitbox02.btc.BTCScriptConfig(
simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH
)
- elif address_type == "p2wsh":
+ elif address_type in ("p2wsh-p2sh", "p2wsh"):
if type(wallet) is Multisig_Wallet:
script_config = self.btc_multisig_config(
- coin_network, address_keypath, wallet
+ coin_network, address_keypath, wallet, address_type,
)
else:
- raise Exception("Can only use p2wsh with multisig wallets")
+ raise Exception("Can only use p2wsh-p2sh or p2wsh with multisig wallets")
else:
raise Exception(
"invalid address xtype: {} is not supported by the BitBox02".format(
@@ -362,6 +372,9 @@ class BitBox02Client(HardwareClientBase):
display=True,
)
+ def _get_coin(self):
+ return bitbox02.btc.TBTC if constants.net.TESTNET else bitbox02.btc.BTC
+
@runs_in_hwd_thread
def sign_transaction(
self,
@@ -377,10 +390,7 @@ class BitBox02Client(HardwareClientBase):
"Need to setup communication first before attempting any BitBox02 calls"
)
- coin = bitbox02.btc.BTC
- if constants.net.TESTNET:
- coin = bitbox02.btc.TBTC
-
+ coin = self._get_coin()
tx_script_type = None
# Build BTCInputType list
@@ -446,11 +456,11 @@ class BitBox02Client(HardwareClientBase):
tx_script_type = bitbox02.btc.BTCScriptConfig(
simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH
)
- elif tx_script_type == "p2wsh":
+ elif tx_script_type in ("p2wsh-p2sh", "p2wsh"):
if type(wallet) is Multisig_Wallet:
- tx_script_type = self.btc_multisig_config(coin, full_path, wallet)
+ tx_script_type = self.btc_multisig_config(coin, full_path, wallet, tx_script_type)
else:
- raise Exception("Can only use p2wsh with multisig wallets")
+ raise Exception("Can only use p2wsh-p2sh or p2wsh with multisig wallets")
else:
raise UserFacingException(
"invalid input script type: {} is not supported by the BitBox02".format(
@@ -521,6 +531,31 @@ 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:
+ if self.bitbox02_device is None:
+ raise Exception(
+ "Need to setup communication first before attempting any BitBox02 calls"
+ )
+
+ try:
+ simple_type = {
+ "p2wpkh-p2sh":bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH,
+ "p2wpkh": bitbox02.btc.BTCScriptConfig.P2WPKH,
+ }[xtype]
+ except KeyError:
+ raise UserFacingException("The BitBox02 does not support signing messages for this address type: {}".format(xtype))
+
+ _, _, signature = self.bitbox02_device.btc_sign_msg(
+ self._get_coin(),
+ bitbox02.btc.BTCScriptConfigWithKeypath(
+ script_config=bitbox02.btc.BTCScriptConfig(
+ simple_type=simple_type,
+ ),
+ keypath=bip32.convert_bip32_path_to_list_of_uint32(keypath),
+ ),
+ message,
+ )
+ return signature
class BitBox02_KeyStore(Hardware_KeyStore):
hw_type = "bitbox02"
@@ -553,11 +588,13 @@ class BitBox02_KeyStore(Hardware_KeyStore):
)
def sign_message(self, sequence, message, password):
- raise UserFacingException(
- _(
- "Message encryption, decryption and signing are currently not supported for {}"
- ).format(self.device)
- )
+ 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)
+
@runs_in_hwd_thread
def sign_transaction(self, tx: PartialTransaction, password: str):
@@ -599,10 +636,10 @@ class BitBox02_KeyStore(Hardware_KeyStore):
class BitBox02Plugin(HW_PluginBase):
keystore_class = BitBox02_KeyStore
- minimum_library = (4, 0, 0)
+ minimum_library = (5, 0, 0)
DEVICE_IDS = [(0x03EB, 0x2403)]
- SUPPORTED_XTYPES = ("p2wpkh-p2sh", "p2wpkh", "p2wsh")
+ SUPPORTED_XTYPES = ("p2wpkh-p2sh", "p2wpkh", "p2wsh", "p2wsh-p2sh")
def __init__(self, parent: HW_PluginBase, config: SimpleConfig, name: str):
super().__init__(parent, config, name)
@@ -647,7 +684,7 @@ class BitBox02Plugin(HW_PluginBase):
):
if xtype not in self.SUPPORTED_XTYPES:
raise ScriptTypeNotSupported(
- _("This type of script is not supported with {}.").format(self.device)
+ _("This type of script is not supported with {}: {}").format(self.device, xtype)
)
client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
assert isinstance(client, BitBox02Client)