Skip to content

Commit

Permalink
Merge #627: devices/bitbox02: add taproot keypath spending support fo…
Browse files Browse the repository at this point in the history
…r bitbox02

59379b3 devices/bitbox02: add taproot keypath spending support for bitbox02 (beerosagos)

Pull request description:

ACKs for top commit:
  achow101:
    Did not test, Code Review ACK 59379b3

Tree-SHA512: 0832d113be40bc7afba7006418e9fec0144cbc2f4ecf811c0c95566c597c0366290b1af51840ee960c9331cc0f0c263fd66fffb856dcbd7778ab2695221bfeed
  • Loading branch information
achow101 committed Aug 23, 2022
2 parents d6bebd2 + 59379b3 commit 2b8d341
Showing 1 changed file with 42 additions and 11 deletions.
53 changes: 42 additions & 11 deletions hwilib/devices/bitbox02.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@
BitBoxNoiseConfig,
)


class BitBox02Error(UnavailableActionError):
def __init__(self, msg: str):
"""
Expand Down Expand Up @@ -603,6 +602,13 @@ def script_config_from_utxo(
),
keypath=_keypath_hardened_prefix(keypath),
)
if is_p2tr(output.scriptPubKey):
return bitbox02.btc.BTCScriptConfigWithKeypath(
script_config=bitbox02.btc.BTCScriptConfig(
simple_type=bitbox02.btc.BTCScriptConfig.P2TR
),
keypath=_keypath_hardened_prefix(keypath),
)
# Check for segwit multisig (p2wsh or p2wsh-p2sh).
is_p2wsh_p2sh = output.is_p2sh() and is_p2wsh(redeem_script)
if output.is_p2wsh() or is_p2wsh_p2sh:
Expand Down Expand Up @@ -656,7 +662,7 @@ def script_config_from_utxo(
# - https://medium.com/shiftcrypto/bitbox-app-firmware-update-6-2020-c70f733a5330
# - https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd.
# - https://github.com/zkSNACKs/WalletWasabi/pull/3822
# The BitBox02 for now requires the prevtx, at least until Taproot activates.
# The BitBox02 requires all prevtxs if not all of the inputs are taproot.

if psbt_in.non_witness_utxo:
assert psbt_in.non_witness_utxo.sha256 is not None
Expand All @@ -673,12 +679,20 @@ def script_config_from_utxo(
utxo = psbt_in.witness_utxo
if utxo is None:
raise BadArgumentError("No utxo found for input {}".format(input_index))
if prevtx is None:
raise BadArgumentError(
"Previous transaction missing for input {}".format(input_index)
)

found_pubkey, keypath = find_our_key(psbt_in.hd_keypaths)
key_origin_infos = psbt_in.hd_keypaths.copy()
if len(psbt_in.tap_internal_key) > 0:
# adding taproot keys to the keypaths to be checked
for pubkey, (leaf_hashes, key_origin_info) in psbt_in.tap_bip32_paths.items():
if len(leaf_hashes) > 0:
raise BadArgumentError(
"The BitBox02 does not support Taproot script path spending. Found leaf hashes: {}"
.format(leaf_hashes)
)
key_origin_infos[pubkey] = key_origin_info

found_pubkey, keypath = find_our_key(key_origin_infos)

if not found_pubkey:
raise BadArgumentError("No key found for input {}".format(input_index))
assert keypath is not None
Expand All @@ -704,7 +718,7 @@ def script_config_from_utxo(
"sequence": psbt_in.sequence,
"keypath": keypath,
"script_config_index": script_config_index,
"prev_tx": {
"prev_tx": None if prevtx is None else {
"version": prevtx.nVersion,
"locktime": prevtx.nLockTime,
"inputs": [
Expand Down Expand Up @@ -732,7 +746,19 @@ def script_config_from_utxo(
for output_index, psbt_out in builtins.enumerate(psbt.outputs):
tx_out = psbt_out.get_txout()

_, keypath = find_our_key(psbt_out.hd_keypaths)
key_origin_infos = psbt_out.hd_keypaths.copy()
if len(psbt_out.tap_internal_key) > 0:
# adding taproot keys to the keypaths to be checked
for pubkey, (leaf_hashes, key_origin_info) in psbt_out.tap_bip32_paths.items():
if len(leaf_hashes) > 0:
raise BadArgumentError(
"The BitBox02 does not support Taproot script path spending. Found leaf hashes: {}"
.format(leaf_hashes)
)
key_origin_infos.update({pubkey: key_origin_info})

_, keypath = find_our_key(key_origin_infos)

is_change = keypath and keypath[-2] == 1
if is_change:
assert keypath is not None
Expand Down Expand Up @@ -798,8 +824,13 @@ def script_config_from_utxo(

for (_, sig), pubkey, psbt_in in zip(sigs, found_pubkeys, psbt.inputs):
r, s = sig[:32], sig[32:64]
# ser_sig_der() adds SIGHASH_ALL
psbt_in.partial_sigs[pubkey] = ser_sig_der(r, s)

if len(psbt_in.tap_internal_key) > 0:
# taproot keypath input
psbt_in.tap_key_sig = sig
else:
# ser_sig_der() adds SIGHASH_ALL
psbt_in.partial_sigs[pubkey] = ser_sig_der(r, s)

return psbt

Expand Down

0 comments on commit 2b8d341

Please sign in to comment.