From 25c3a2b0ecf3d2041b360c192c06eef28e20c10d Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Tue, 16 Sep 2025 09:12:11 +0200 Subject: [PATCH 1/2] bitcoin/signtx: remove `pub` from test functions Not needed and not idiomatic. --- .../src/hww/api/bitcoin/signtx.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs index c7f8d37ae2..a231a31a50 100644 --- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs +++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs @@ -1659,7 +1659,7 @@ mod tests { } #[test] - pub fn test_sign_init_fail() { + fn test_sign_init_fail() { *crate::hww::MOCK_NEXT_REQUEST.0.borrow_mut() = None; let init_req_valid = pb::BtcSignInitRequest { @@ -1895,7 +1895,7 @@ mod tests { } #[test] - pub fn test_process() { + fn test_process() { static mut UI_COUNTER: u32 = 0; static mut PREVTX_REQUESTED: u32 = 0; @@ -2042,7 +2042,7 @@ mod tests { /// Test that receiving an unexpected message from the host results in an invalid state error. #[test] - pub fn test_invalid_state() { + fn test_invalid_state() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); mock_unlocked(); @@ -2066,7 +2066,7 @@ mod tests { /// Test signing if all inputs are of type P2WPKH-P2SH. #[test] - pub fn test_script_type_p2wpkh_p2sh() { + fn test_script_type_p2wpkh_p2sh() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); for input in transaction.borrow_mut().inputs.iter_mut() { @@ -2101,7 +2101,7 @@ mod tests { /// Test signing if all inputs are of type P2TR. #[test] - pub fn test_script_type_p2tr() { + fn test_script_type_p2tr() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); for input in transaction.borrow_mut().inputs.iter_mut() { @@ -2150,7 +2150,7 @@ mod tests { /// Test signing if with mixed inputs, one of them being taproot. Previous transactions of all /// inputs should be streamed in this case. #[test] - pub fn test_script_type_p2tr_mixed() { + fn test_script_type_p2tr_mixed() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); transaction.borrow_mut().inputs[0].input.script_config_index = 1; @@ -2191,7 +2191,7 @@ mod tests { /// receive addresses at these indices (to mitigate ransom attacks), we should still be able to /// spend them. #[test] - pub fn test_spend_high_address_index() { + fn test_spend_high_address_index() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); transaction.borrow_mut().inputs[0].input.keypath[4] = 100000; @@ -2208,7 +2208,7 @@ mod tests { /// Test invalid input cases. #[test] - pub fn test_invalid_input() { + fn test_invalid_input() { enum TestCase { // all inputs should be the same coin type. WrongCoinInput, @@ -2319,7 +2319,7 @@ mod tests { /// Test signing with mixed input types. #[test] - pub fn test_mixed_inputs() { + fn test_mixed_inputs() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); transaction.borrow_mut().inputs[0].input.script_config_index = 1; @@ -3588,7 +3588,7 @@ mod tests { } #[test] - pub fn test_payment_request() { + fn test_payment_request() { let transaction = alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); From 8f986e2370033928faf350b59b9bf5774dc9f699 Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Tue, 16 Sep 2025 09:54:35 +0200 Subject: [PATCH 2/2] btc: fix requesting previous transactions when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous transaction of every input in a Bitcoin transaction needs to be streamed to the BitBox, unless all inputs are Taproot inputs. They are needed for the BitBox to verify the input amount. Since Taproot, that is not necessary because all input amounts are part of the sighash. The firmware currently inspects the "scriptConfigs" to determine if all inputs are taproot. Bug: the scriptConfigs is also used to indicate outputs belonging to the same account (either change outputs or outputs verified as "This BitBox (same account): …". As a result, if all inputs are Taproot, but the change output is not Taproot (or coins are sent to a non-Taproot address of the same account), then previous transactions are requested/streamed even if they don't need to be. Fix: we let the client libraries set the flag if prevtxs are required or not, and reject the transaction if they set it to "not required" even if there is a non-Taproot input present. The previous way is preserved for backwards compatibility with client libraries that do not set this new flag. --- CHANGELOG.md | 2 + messages/btc.proto | 13 +++ py/bitbox02/bitbox02/bitbox02/bitbox02.py | 8 ++ .../communication/generated/btc_pb2.py | 102 +++++++++--------- .../communication/generated/btc_pb2.pyi | 27 ++++- .../src/hww/api/bitcoin/signtx.rs | 99 ++++++++++++++++- .../bitbox02-rust/src/shiftcrypto.bitbox02.rs | 47 ++++++++ 7 files changed, 244 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e00c3c6e..5135a28a54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ customers cannot upgrade their bootloader, its changes are recorded separately. - simulator: simulate a Nova device - Add API call to fetch multiple xpubs at once - Add the option for the simulator to write its memory to file. +- Bitcoin: do not request previous transactions if all inputs are Taproot, even if an output paying + to the same account is not Taproot ### 9.23.1 - EVM: add HyperEVM (HYPE) and SONIC (S) to known networks diff --git a/messages/btc.proto b/messages/btc.proto index 24669fff78..51e521eb85 100644 --- a/messages/btc.proto +++ b/messages/btc.proto @@ -129,6 +129,19 @@ message BTCSignInitRequest { // used script configs for outputs that send to an address of the same keystore, but not // necessarily the same account (as defined by `script_configs` above). repeated BTCScriptConfigWithKeypath output_script_configs = 10; + + enum PrevTxs { + PREV_TXS_DEFAULT = 0; + PREV_TXS_REQUIRED = 1; + PREV_TXS_NOT_REQUIRED = 2; + } + // Set this to: + // - `PREV_TXS_DEFAULT` for compatibility mode, the value will be determined using `script_configs`. + // This is not robust, as non-Taproot change outputs are included there and falsely leads to + // previous transactions being required. + // - `PREV_TXS_REQUIRED` if not all transaction inputs are Taproot. + // - `PREV_TXS_NOT_REQUIRED` if all transaction inputs are Taproot. + PrevTxs prev_txs = 11; } message BTCSignNextResponse { diff --git a/py/bitbox02/bitbox02/bitbox02/bitbox02.py b/py/bitbox02/bitbox02/bitbox02/bitbox02.py index 753cde5116..dc4b52a208 100644 --- a/py/bitbox02/bitbox02/bitbox02/bitbox02.py +++ b/py/bitbox02/bitbox02/bitbox02/bitbox02.py @@ -471,6 +471,9 @@ def btc_sign( sigs: List[Tuple[int, bytes]] = [] + all_inputs_are_taproot = all( + is_taproot(script_configs[inp["script_config_index"]]) for inp in inputs + ) # Init request request = hww.Request() request.btc_sign_init.CopyFrom( @@ -483,6 +486,11 @@ def btc_sign( locktime=locktime, format_unit=format_unit, output_script_configs=output_script_configs, + prev_txs=( + btc.BTCSignInitRequest.PrevTxs.PREV_TXS_NOT_REQUIRED + if all_inputs_are_taproot + else btc.BTCSignInitRequest.PrevTxs.PREV_TXS_REQUIRED + ), ) ) next_response = self._msg_query(request, expected_response="btc_sign_next").btc_sign_next diff --git a/py/bitbox02/bitbox02/communication/generated/btc_pb2.py b/py/bitbox02/bitbox02/communication/generated/btc_pb2.py index 45148fdd3e..158ad7d7ba 100644 --- a/py/bitbox02/bitbox02/communication/generated/btc_pb2.py +++ b/py/bitbox02/bitbox02/communication/generated/btc_pb2.py @@ -15,17 +15,17 @@ from . import antiklepto_pb2 as antiklepto__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tbtc.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\x1a\x10\x61ntiklepto.proto\"\xc6\x04\n\x0f\x42TCScriptConfig\x12G\n\x0bsimple_type\x18\x01 \x01(\x0e\x32\x30.shiftcrypto.bitbox02.BTCScriptConfig.SimpleTypeH\x00\x12\x42\n\x08multisig\x18\x02 \x01(\x0b\x32..shiftcrypto.bitbox02.BTCScriptConfig.MultisigH\x00\x12>\n\x06policy\x18\x03 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCScriptConfig.PolicyH\x00\x1a\xd9\x01\n\x08Multisig\x12\x11\n\tthreshold\x18\x01 \x01(\r\x12)\n\x05xpubs\x18\x02 \x03(\x0b\x32\x1a.shiftcrypto.bitbox02.XPub\x12\x16\n\x0eour_xpub_index\x18\x03 \x01(\r\x12N\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x39.shiftcrypto.bitbox02.BTCScriptConfig.Multisig.ScriptType\"\'\n\nScriptType\x12\t\n\x05P2WSH\x10\x00\x12\x0e\n\nP2WSH_P2SH\x10\x01\x1aK\n\x06Policy\x12\x0e\n\x06policy\x18\x01 \x01(\t\x12\x31\n\x04keys\x18\x02 \x03(\x0b\x32#.shiftcrypto.bitbox02.KeyOriginInfo\"3\n\nSimpleType\x12\x0f\n\x0bP2WPKH_P2SH\x10\x00\x12\n\n\x06P2WPKH\x10\x01\x12\x08\n\x04P2TR\x10\x02\x42\x08\n\x06\x63onfig\"\xfc\x02\n\rBTCPubRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\x41\n\txpub_type\x18\x03 \x01(\x0e\x32,.shiftcrypto.bitbox02.BTCPubRequest.XPubTypeH\x00\x12>\n\rscript_config\x18\x04 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfigH\x00\x12\x0f\n\x07\x64isplay\x18\x05 \x01(\x08\"\x8e\x01\n\x08XPubType\x12\x08\n\x04TPUB\x10\x00\x12\x08\n\x04XPUB\x10\x01\x12\x08\n\x04YPUB\x10\x02\x12\x08\n\x04ZPUB\x10\x03\x12\x08\n\x04VPUB\x10\x04\x12\x08\n\x04UPUB\x10\x05\x12\x10\n\x0c\x43\x41PITAL_VPUB\x10\x06\x12\x10\n\x0c\x43\x41PITAL_ZPUB\x10\x07\x12\x10\n\x0c\x43\x41PITAL_UPUB\x10\x08\x12\x10\n\x0c\x43\x41PITAL_YPUB\x10\tB\x08\n\x06output\"\xdf\x01\n\x0f\x42TCXpubsRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12\x41\n\txpub_type\x18\x02 \x01(\x0e\x32..shiftcrypto.bitbox02.BTCXpubsRequest.XPubType\x12/\n\x08keypaths\x18\x03 \x03(\x0b\x32\x1d.shiftcrypto.bitbox02.Keypath\"+\n\x08XPubType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04XPUB\x10\x01\x12\x08\n\x04TPUB\x10\x02\"k\n\x1a\x42TCScriptConfigWithKeypath\x12<\n\rscript_config\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfig\x12\x0f\n\x07keypath\x18\x03 \x03(\r\"\xbf\x03\n\x12\x42TCSignInitRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12H\n\x0escript_configs\x18\x02 \x03(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\x12\x0f\n\x07version\x18\x04 \x01(\r\x12\x12\n\nnum_inputs\x18\x05 \x01(\r\x12\x13\n\x0bnum_outputs\x18\x06 \x01(\r\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12H\n\x0b\x66ormat_unit\x18\x08 \x01(\x0e\x32\x33.shiftcrypto.bitbox02.BTCSignInitRequest.FormatUnit\x12\'\n\x1f\x63ontains_silent_payment_outputs\x18\t \x01(\x08\x12O\n\x15output_script_configs\x18\n \x03(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\"\"\n\nFormatUnit\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x07\n\x03SAT\x10\x01\"\xc4\x03\n\x13\x42TCSignNextResponse\x12<\n\x04type\x18\x01 \x01(\x0e\x32..shiftcrypto.bitbox02.BTCSignNextResponse.Type\x12\r\n\x05index\x18\x02 \x01(\r\x12\x15\n\rhas_signature\x18\x03 \x01(\x08\x12\x11\n\tsignature\x18\x04 \x01(\x0c\x12\x12\n\nprev_index\x18\x05 \x01(\r\x12W\n\x1d\x61nti_klepto_signer_commitment\x18\x06 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitment\x12!\n\x19generated_output_pkscript\x18\x07 \x01(\x0c\x12!\n\x19silent_payment_dleq_proof\x18\x08 \x01(\x0c\"\x82\x01\n\x04Type\x12\t\n\x05INPUT\x10\x00\x12\n\n\x06OUTPUT\x10\x01\x12\x08\n\x04\x44ONE\x10\x02\x12\x0f\n\x0bPREVTX_INIT\x10\x03\x12\x10\n\x0cPREVTX_INPUT\x10\x04\x12\x11\n\rPREVTX_OUTPUT\x10\x05\x12\x0e\n\nHOST_NONCE\x10\x06\x12\x13\n\x0fPAYMENT_REQUEST\x10\x07\"\xea\x01\n\x13\x42TCSignInputRequest\x12\x13\n\x0bprevOutHash\x18\x01 \x01(\x0c\x12\x14\n\x0cprevOutIndex\x18\x02 \x01(\r\x12\x14\n\x0cprevOutValue\x18\x03 \x01(\x04\x12\x10\n\x08sequence\x18\x04 \x01(\r\x12\x0f\n\x07keypath\x18\x06 \x03(\r\x12\x1b\n\x13script_config_index\x18\x07 \x01(\r\x12R\n\x15host_nonce_commitment\x18\x08 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\"\x9f\x03\n\x14\x42TCSignOutputRequest\x12\x0c\n\x04ours\x18\x01 \x01(\x08\x12\x31\n\x04type\x18\x02 \x01(\x0e\x32#.shiftcrypto.bitbox02.BTCOutputType\x12\r\n\x05value\x18\x03 \x01(\x04\x12\x0f\n\x07payload\x18\x04 \x01(\x0c\x12\x0f\n\x07keypath\x18\x05 \x03(\r\x12\x1b\n\x13script_config_index\x18\x06 \x01(\r\x12\"\n\x15payment_request_index\x18\x07 \x01(\rH\x00\x88\x01\x01\x12P\n\x0esilent_payment\x18\x08 \x01(\x0b\x32\x38.shiftcrypto.bitbox02.BTCSignOutputRequest.SilentPayment\x12\'\n\x1aoutput_script_config_index\x18\t \x01(\rH\x01\x88\x01\x01\x1a \n\rSilentPayment\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\tB\x18\n\x16_payment_request_indexB\x1d\n\x1b_output_script_config_index\"\x99\x01\n\x1b\x42TCScriptConfigRegistration\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12<\n\rscript_config\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfig\x12\x0f\n\x07keypath\x18\x03 \x03(\r\"\x0c\n\nBTCSuccess\"m\n\"BTCIsScriptConfigRegisteredRequest\x12G\n\x0cregistration\x18\x01 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.BTCScriptConfigRegistration\"<\n#BTCIsScriptConfigRegisteredResponse\x12\x15\n\ris_registered\x18\x01 \x01(\x08\"\xfc\x01\n\x1e\x42TCRegisterScriptConfigRequest\x12G\n\x0cregistration\x18\x01 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.BTCScriptConfigRegistration\x12\x0c\n\x04name\x18\x02 \x01(\t\x12P\n\txpub_type\x18\x03 \x01(\x0e\x32=.shiftcrypto.bitbox02.BTCRegisterScriptConfigRequest.XPubType\"1\n\x08XPubType\x12\x11\n\rAUTO_ELECTRUM\x10\x00\x12\x12\n\x0e\x41UTO_XPUB_TPUB\x10\x01\"b\n\x14\x42TCPrevTxInitRequest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x12\n\nnum_inputs\x18\x02 \x01(\r\x12\x13\n\x0bnum_outputs\x18\x03 \x01(\r\x12\x10\n\x08locktime\x18\x04 \x01(\r\"r\n\x15\x42TCPrevTxInputRequest\x12\x15\n\rprev_out_hash\x18\x01 \x01(\x0c\x12\x16\n\x0eprev_out_index\x18\x02 \x01(\r\x12\x18\n\x10signature_script\x18\x03 \x01(\x0c\x12\x10\n\x08sequence\x18\x04 \x01(\r\">\n\x16\x42TCPrevTxOutputRequest\x12\r\n\x05value\x18\x01 \x01(\x04\x12\x15\n\rpubkey_script\x18\x02 \x01(\x0c\"\xab\x02\n\x18\x42TCPaymentRequestRequest\x12\x16\n\x0erecipient_name\x18\x01 \x01(\t\x12\x42\n\x05memos\x18\x02 \x03(\x0b\x32\x33.shiftcrypto.bitbox02.BTCPaymentRequestRequest.Memo\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12\x14\n\x0ctotal_amount\x18\x04 \x01(\x04\x12\x11\n\tsignature\x18\x05 \x01(\x0c\x1a{\n\x04Memo\x12Q\n\ttext_memo\x18\x01 \x01(\x0b\x32<.shiftcrypto.bitbox02.BTCPaymentRequestRequest.Memo.TextMemoH\x00\x1a\x18\n\x08TextMemo\x12\x0c\n\x04note\x18\x01 \x01(\tB\x06\n\x04memo\"\xee\x01\n\x15\x42TCSignMessageRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12G\n\rscript_config\x18\x02 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\x12\x0b\n\x03msg\x18\x03 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\x04 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\"+\n\x16\x42TCSignMessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"\xb9\x05\n\nBTCRequest\x12_\n\x1bis_script_config_registered\x18\x01 \x01(\x0b\x32\x38.shiftcrypto.bitbox02.BTCIsScriptConfigRegisteredRequestH\x00\x12V\n\x16register_script_config\x18\x02 \x01(\x0b\x32\x34.shiftcrypto.bitbox02.BTCRegisterScriptConfigRequestH\x00\x12\x41\n\x0bprevtx_init\x18\x03 \x01(\x0b\x32*.shiftcrypto.bitbox02.BTCPrevTxInitRequestH\x00\x12\x43\n\x0cprevtx_input\x18\x04 \x01(\x0b\x32+.shiftcrypto.bitbox02.BTCPrevTxInputRequestH\x00\x12\x45\n\rprevtx_output\x18\x05 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCPrevTxOutputRequestH\x00\x12\x43\n\x0csign_message\x18\x06 \x01(\x0b\x32+.shiftcrypto.bitbox02.BTCSignMessageRequestH\x00\x12P\n\x14\x61ntiklepto_signature\x18\x07 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignatureRequestH\x00\x12I\n\x0fpayment_request\x18\x08 \x01(\x0b\x32..shiftcrypto.bitbox02.BTCPaymentRequestRequestH\x00\x12\x36\n\x05xpubs\x18\t \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCXpubsRequestH\x00\x42\t\n\x07request\"\xc4\x03\n\x0b\x42TCResponse\x12\x33\n\x07success\x18\x01 \x01(\x0b\x32 .shiftcrypto.bitbox02.BTCSuccessH\x00\x12`\n\x1bis_script_config_registered\x18\x02 \x01(\x0b\x32\x39.shiftcrypto.bitbox02.BTCIsScriptConfigRegisteredResponseH\x00\x12>\n\tsign_next\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.BTCSignNextResponseH\x00\x12\x44\n\x0csign_message\x18\x04 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCSignMessageResponseH\x00\x12X\n\x1c\x61ntiklepto_signer_commitment\x18\x05 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitmentH\x00\x12\x32\n\x04pubs\x18\x06 \x01(\x0b\x32\".shiftcrypto.bitbox02.PubsResponseH\x00\x42\n\n\x08response*9\n\x07\x42TCCoin\x12\x07\n\x03\x42TC\x10\x00\x12\x08\n\x04TBTC\x10\x01\x12\x07\n\x03LTC\x10\x02\x12\x08\n\x04TLTC\x10\x03\x12\x08\n\x04RBTC\x10\x04*R\n\rBTCOutputType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05P2PKH\x10\x01\x12\x08\n\x04P2SH\x10\x02\x12\n\n\x06P2WPKH\x10\x03\x12\t\n\x05P2WSH\x10\x04\x12\x08\n\x04P2TR\x10\x05\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tbtc.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\x1a\x10\x61ntiklepto.proto\"\xc6\x04\n\x0f\x42TCScriptConfig\x12G\n\x0bsimple_type\x18\x01 \x01(\x0e\x32\x30.shiftcrypto.bitbox02.BTCScriptConfig.SimpleTypeH\x00\x12\x42\n\x08multisig\x18\x02 \x01(\x0b\x32..shiftcrypto.bitbox02.BTCScriptConfig.MultisigH\x00\x12>\n\x06policy\x18\x03 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCScriptConfig.PolicyH\x00\x1a\xd9\x01\n\x08Multisig\x12\x11\n\tthreshold\x18\x01 \x01(\r\x12)\n\x05xpubs\x18\x02 \x03(\x0b\x32\x1a.shiftcrypto.bitbox02.XPub\x12\x16\n\x0eour_xpub_index\x18\x03 \x01(\r\x12N\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x39.shiftcrypto.bitbox02.BTCScriptConfig.Multisig.ScriptType\"\'\n\nScriptType\x12\t\n\x05P2WSH\x10\x00\x12\x0e\n\nP2WSH_P2SH\x10\x01\x1aK\n\x06Policy\x12\x0e\n\x06policy\x18\x01 \x01(\t\x12\x31\n\x04keys\x18\x02 \x03(\x0b\x32#.shiftcrypto.bitbox02.KeyOriginInfo\"3\n\nSimpleType\x12\x0f\n\x0bP2WPKH_P2SH\x10\x00\x12\n\n\x06P2WPKH\x10\x01\x12\x08\n\x04P2TR\x10\x02\x42\x08\n\x06\x63onfig\"\xfc\x02\n\rBTCPubRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12\x0f\n\x07keypath\x18\x02 \x03(\r\x12\x41\n\txpub_type\x18\x03 \x01(\x0e\x32,.shiftcrypto.bitbox02.BTCPubRequest.XPubTypeH\x00\x12>\n\rscript_config\x18\x04 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfigH\x00\x12\x0f\n\x07\x64isplay\x18\x05 \x01(\x08\"\x8e\x01\n\x08XPubType\x12\x08\n\x04TPUB\x10\x00\x12\x08\n\x04XPUB\x10\x01\x12\x08\n\x04YPUB\x10\x02\x12\x08\n\x04ZPUB\x10\x03\x12\x08\n\x04VPUB\x10\x04\x12\x08\n\x04UPUB\x10\x05\x12\x10\n\x0c\x43\x41PITAL_VPUB\x10\x06\x12\x10\n\x0c\x43\x41PITAL_ZPUB\x10\x07\x12\x10\n\x0c\x43\x41PITAL_UPUB\x10\x08\x12\x10\n\x0c\x43\x41PITAL_YPUB\x10\tB\x08\n\x06output\"\xdf\x01\n\x0f\x42TCXpubsRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12\x41\n\txpub_type\x18\x02 \x01(\x0e\x32..shiftcrypto.bitbox02.BTCXpubsRequest.XPubType\x12/\n\x08keypaths\x18\x03 \x03(\x0b\x32\x1d.shiftcrypto.bitbox02.Keypath\"+\n\x08XPubType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04XPUB\x10\x01\x12\x08\n\x04TPUB\x10\x02\"k\n\x1a\x42TCScriptConfigWithKeypath\x12<\n\rscript_config\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfig\x12\x0f\n\x07keypath\x18\x03 \x03(\r\"\xd6\x04\n\x12\x42TCSignInitRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12H\n\x0escript_configs\x18\x02 \x03(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\x12\x0f\n\x07version\x18\x04 \x01(\r\x12\x12\n\nnum_inputs\x18\x05 \x01(\r\x12\x13\n\x0bnum_outputs\x18\x06 \x01(\r\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12H\n\x0b\x66ormat_unit\x18\x08 \x01(\x0e\x32\x33.shiftcrypto.bitbox02.BTCSignInitRequest.FormatUnit\x12\'\n\x1f\x63ontains_silent_payment_outputs\x18\t \x01(\x08\x12O\n\x15output_script_configs\x18\n \x03(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\x12\x42\n\x08prev_txs\x18\x0b \x01(\x0e\x32\x30.shiftcrypto.bitbox02.BTCSignInitRequest.PrevTxs\"\"\n\nFormatUnit\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x07\n\x03SAT\x10\x01\"Q\n\x07PrevTxs\x12\x14\n\x10PREV_TXS_DEFAULT\x10\x00\x12\x15\n\x11PREV_TXS_REQUIRED\x10\x01\x12\x19\n\x15PREV_TXS_NOT_REQUIRED\x10\x02\"\xc4\x03\n\x13\x42TCSignNextResponse\x12<\n\x04type\x18\x01 \x01(\x0e\x32..shiftcrypto.bitbox02.BTCSignNextResponse.Type\x12\r\n\x05index\x18\x02 \x01(\r\x12\x15\n\rhas_signature\x18\x03 \x01(\x08\x12\x11\n\tsignature\x18\x04 \x01(\x0c\x12\x12\n\nprev_index\x18\x05 \x01(\r\x12W\n\x1d\x61nti_klepto_signer_commitment\x18\x06 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitment\x12!\n\x19generated_output_pkscript\x18\x07 \x01(\x0c\x12!\n\x19silent_payment_dleq_proof\x18\x08 \x01(\x0c\"\x82\x01\n\x04Type\x12\t\n\x05INPUT\x10\x00\x12\n\n\x06OUTPUT\x10\x01\x12\x08\n\x04\x44ONE\x10\x02\x12\x0f\n\x0bPREVTX_INIT\x10\x03\x12\x10\n\x0cPREVTX_INPUT\x10\x04\x12\x11\n\rPREVTX_OUTPUT\x10\x05\x12\x0e\n\nHOST_NONCE\x10\x06\x12\x13\n\x0fPAYMENT_REQUEST\x10\x07\"\xea\x01\n\x13\x42TCSignInputRequest\x12\x13\n\x0bprevOutHash\x18\x01 \x01(\x0c\x12\x14\n\x0cprevOutIndex\x18\x02 \x01(\r\x12\x14\n\x0cprevOutValue\x18\x03 \x01(\x04\x12\x10\n\x08sequence\x18\x04 \x01(\r\x12\x0f\n\x07keypath\x18\x06 \x03(\r\x12\x1b\n\x13script_config_index\x18\x07 \x01(\r\x12R\n\x15host_nonce_commitment\x18\x08 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\"\x9f\x03\n\x14\x42TCSignOutputRequest\x12\x0c\n\x04ours\x18\x01 \x01(\x08\x12\x31\n\x04type\x18\x02 \x01(\x0e\x32#.shiftcrypto.bitbox02.BTCOutputType\x12\r\n\x05value\x18\x03 \x01(\x04\x12\x0f\n\x07payload\x18\x04 \x01(\x0c\x12\x0f\n\x07keypath\x18\x05 \x03(\r\x12\x1b\n\x13script_config_index\x18\x06 \x01(\r\x12\"\n\x15payment_request_index\x18\x07 \x01(\rH\x00\x88\x01\x01\x12P\n\x0esilent_payment\x18\x08 \x01(\x0b\x32\x38.shiftcrypto.bitbox02.BTCSignOutputRequest.SilentPayment\x12\'\n\x1aoutput_script_config_index\x18\t \x01(\rH\x01\x88\x01\x01\x1a \n\rSilentPayment\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\tB\x18\n\x16_payment_request_indexB\x1d\n\x1b_output_script_config_index\"\x99\x01\n\x1b\x42TCScriptConfigRegistration\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12<\n\rscript_config\x18\x02 \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCScriptConfig\x12\x0f\n\x07keypath\x18\x03 \x03(\r\"\x0c\n\nBTCSuccess\"m\n\"BTCIsScriptConfigRegisteredRequest\x12G\n\x0cregistration\x18\x01 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.BTCScriptConfigRegistration\"<\n#BTCIsScriptConfigRegisteredResponse\x12\x15\n\ris_registered\x18\x01 \x01(\x08\"\xfc\x01\n\x1e\x42TCRegisterScriptConfigRequest\x12G\n\x0cregistration\x18\x01 \x01(\x0b\x32\x31.shiftcrypto.bitbox02.BTCScriptConfigRegistration\x12\x0c\n\x04name\x18\x02 \x01(\t\x12P\n\txpub_type\x18\x03 \x01(\x0e\x32=.shiftcrypto.bitbox02.BTCRegisterScriptConfigRequest.XPubType\"1\n\x08XPubType\x12\x11\n\rAUTO_ELECTRUM\x10\x00\x12\x12\n\x0e\x41UTO_XPUB_TPUB\x10\x01\"b\n\x14\x42TCPrevTxInitRequest\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x12\n\nnum_inputs\x18\x02 \x01(\r\x12\x13\n\x0bnum_outputs\x18\x03 \x01(\r\x12\x10\n\x08locktime\x18\x04 \x01(\r\"r\n\x15\x42TCPrevTxInputRequest\x12\x15\n\rprev_out_hash\x18\x01 \x01(\x0c\x12\x16\n\x0eprev_out_index\x18\x02 \x01(\r\x12\x18\n\x10signature_script\x18\x03 \x01(\x0c\x12\x10\n\x08sequence\x18\x04 \x01(\r\">\n\x16\x42TCPrevTxOutputRequest\x12\r\n\x05value\x18\x01 \x01(\x04\x12\x15\n\rpubkey_script\x18\x02 \x01(\x0c\"\xab\x02\n\x18\x42TCPaymentRequestRequest\x12\x16\n\x0erecipient_name\x18\x01 \x01(\t\x12\x42\n\x05memos\x18\x02 \x03(\x0b\x32\x33.shiftcrypto.bitbox02.BTCPaymentRequestRequest.Memo\x12\r\n\x05nonce\x18\x03 \x01(\x0c\x12\x14\n\x0ctotal_amount\x18\x04 \x01(\x04\x12\x11\n\tsignature\x18\x05 \x01(\x0c\x1a{\n\x04Memo\x12Q\n\ttext_memo\x18\x01 \x01(\x0b\x32<.shiftcrypto.bitbox02.BTCPaymentRequestRequest.Memo.TextMemoH\x00\x1a\x18\n\x08TextMemo\x12\x0c\n\x04note\x18\x01 \x01(\tB\x06\n\x04memo\"\xee\x01\n\x15\x42TCSignMessageRequest\x12+\n\x04\x63oin\x18\x01 \x01(\x0e\x32\x1d.shiftcrypto.bitbox02.BTCCoin\x12G\n\rscript_config\x18\x02 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.BTCScriptConfigWithKeypath\x12\x0b\n\x03msg\x18\x03 \x01(\x0c\x12R\n\x15host_nonce_commitment\x18\x04 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.AntiKleptoHostNonceCommitment\"+\n\x16\x42TCSignMessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"\xb9\x05\n\nBTCRequest\x12_\n\x1bis_script_config_registered\x18\x01 \x01(\x0b\x32\x38.shiftcrypto.bitbox02.BTCIsScriptConfigRegisteredRequestH\x00\x12V\n\x16register_script_config\x18\x02 \x01(\x0b\x32\x34.shiftcrypto.bitbox02.BTCRegisterScriptConfigRequestH\x00\x12\x41\n\x0bprevtx_init\x18\x03 \x01(\x0b\x32*.shiftcrypto.bitbox02.BTCPrevTxInitRequestH\x00\x12\x43\n\x0cprevtx_input\x18\x04 \x01(\x0b\x32+.shiftcrypto.bitbox02.BTCPrevTxInputRequestH\x00\x12\x45\n\rprevtx_output\x18\x05 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCPrevTxOutputRequestH\x00\x12\x43\n\x0csign_message\x18\x06 \x01(\x0b\x32+.shiftcrypto.bitbox02.BTCSignMessageRequestH\x00\x12P\n\x14\x61ntiklepto_signature\x18\x07 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignatureRequestH\x00\x12I\n\x0fpayment_request\x18\x08 \x01(\x0b\x32..shiftcrypto.bitbox02.BTCPaymentRequestRequestH\x00\x12\x36\n\x05xpubs\x18\t \x01(\x0b\x32%.shiftcrypto.bitbox02.BTCXpubsRequestH\x00\x42\t\n\x07request\"\xc4\x03\n\x0b\x42TCResponse\x12\x33\n\x07success\x18\x01 \x01(\x0b\x32 .shiftcrypto.bitbox02.BTCSuccessH\x00\x12`\n\x1bis_script_config_registered\x18\x02 \x01(\x0b\x32\x39.shiftcrypto.bitbox02.BTCIsScriptConfigRegisteredResponseH\x00\x12>\n\tsign_next\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.BTCSignNextResponseH\x00\x12\x44\n\x0csign_message\x18\x04 \x01(\x0b\x32,.shiftcrypto.bitbox02.BTCSignMessageResponseH\x00\x12X\n\x1c\x61ntiklepto_signer_commitment\x18\x05 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.AntiKleptoSignerCommitmentH\x00\x12\x32\n\x04pubs\x18\x06 \x01(\x0b\x32\".shiftcrypto.bitbox02.PubsResponseH\x00\x42\n\n\x08response*9\n\x07\x42TCCoin\x12\x07\n\x03\x42TC\x10\x00\x12\x08\n\x04TBTC\x10\x01\x12\x07\n\x03LTC\x10\x02\x12\x08\n\x04TLTC\x10\x03\x12\x08\n\x04RBTC\x10\x04*R\n\rBTCOutputType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05P2PKH\x10\x01\x12\x08\n\x04P2SH\x10\x02\x12\n\n\x06P2WPKH\x10\x03\x12\t\n\x05P2WSH\x10\x04\x12\x08\n\x04P2TR\x10\x05\x62\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'btc_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _BTCCOIN._serialized_start=5551 - _BTCCOIN._serialized_end=5608 - _BTCOUTPUTTYPE._serialized_start=5610 - _BTCOUTPUTTYPE._serialized_end=5692 + _BTCCOIN._serialized_start=5702 + _BTCCOIN._serialized_end=5759 + _BTCOUTPUTTYPE._serialized_start=5761 + _BTCOUTPUTTYPE._serialized_end=5843 _BTCSCRIPTCONFIG._serialized_start=68 _BTCSCRIPTCONFIG._serialized_end=650 _BTCSCRIPTCONFIG_MULTISIG._serialized_start=293 @@ -47,49 +47,51 @@ _BTCSCRIPTCONFIGWITHKEYPATH._serialized_start=1261 _BTCSCRIPTCONFIGWITHKEYPATH._serialized_end=1368 _BTCSIGNINITREQUEST._serialized_start=1371 - _BTCSIGNINITREQUEST._serialized_end=1818 - _BTCSIGNINITREQUEST_FORMATUNIT._serialized_start=1784 - _BTCSIGNINITREQUEST_FORMATUNIT._serialized_end=1818 - _BTCSIGNNEXTRESPONSE._serialized_start=1821 - _BTCSIGNNEXTRESPONSE._serialized_end=2273 - _BTCSIGNNEXTRESPONSE_TYPE._serialized_start=2143 - _BTCSIGNNEXTRESPONSE_TYPE._serialized_end=2273 - _BTCSIGNINPUTREQUEST._serialized_start=2276 - _BTCSIGNINPUTREQUEST._serialized_end=2510 - _BTCSIGNOUTPUTREQUEST._serialized_start=2513 - _BTCSIGNOUTPUTREQUEST._serialized_end=2928 - _BTCSIGNOUTPUTREQUEST_SILENTPAYMENT._serialized_start=2839 - _BTCSIGNOUTPUTREQUEST_SILENTPAYMENT._serialized_end=2871 - _BTCSCRIPTCONFIGREGISTRATION._serialized_start=2931 - _BTCSCRIPTCONFIGREGISTRATION._serialized_end=3084 - _BTCSUCCESS._serialized_start=3086 - _BTCSUCCESS._serialized_end=3098 - _BTCISSCRIPTCONFIGREGISTEREDREQUEST._serialized_start=3100 - _BTCISSCRIPTCONFIGREGISTEREDREQUEST._serialized_end=3209 - _BTCISSCRIPTCONFIGREGISTEREDRESPONSE._serialized_start=3211 - _BTCISSCRIPTCONFIGREGISTEREDRESPONSE._serialized_end=3271 - _BTCREGISTERSCRIPTCONFIGREQUEST._serialized_start=3274 - _BTCREGISTERSCRIPTCONFIGREQUEST._serialized_end=3526 - _BTCREGISTERSCRIPTCONFIGREQUEST_XPUBTYPE._serialized_start=3477 - _BTCREGISTERSCRIPTCONFIGREQUEST_XPUBTYPE._serialized_end=3526 - _BTCPREVTXINITREQUEST._serialized_start=3528 - _BTCPREVTXINITREQUEST._serialized_end=3626 - _BTCPREVTXINPUTREQUEST._serialized_start=3628 - _BTCPREVTXINPUTREQUEST._serialized_end=3742 - _BTCPREVTXOUTPUTREQUEST._serialized_start=3744 - _BTCPREVTXOUTPUTREQUEST._serialized_end=3806 - _BTCPAYMENTREQUESTREQUEST._serialized_start=3809 - _BTCPAYMENTREQUESTREQUEST._serialized_end=4108 - _BTCPAYMENTREQUESTREQUEST_MEMO._serialized_start=3985 - _BTCPAYMENTREQUESTREQUEST_MEMO._serialized_end=4108 - _BTCPAYMENTREQUESTREQUEST_MEMO_TEXTMEMO._serialized_start=4076 - _BTCPAYMENTREQUESTREQUEST_MEMO_TEXTMEMO._serialized_end=4100 - _BTCSIGNMESSAGEREQUEST._serialized_start=4111 - _BTCSIGNMESSAGEREQUEST._serialized_end=4349 - _BTCSIGNMESSAGERESPONSE._serialized_start=4351 - _BTCSIGNMESSAGERESPONSE._serialized_end=4394 - _BTCREQUEST._serialized_start=4397 - _BTCREQUEST._serialized_end=5094 - _BTCRESPONSE._serialized_start=5097 - _BTCRESPONSE._serialized_end=5549 + _BTCSIGNINITREQUEST._serialized_end=1969 + _BTCSIGNINITREQUEST_FORMATUNIT._serialized_start=1852 + _BTCSIGNINITREQUEST_FORMATUNIT._serialized_end=1886 + _BTCSIGNINITREQUEST_PREVTXS._serialized_start=1888 + _BTCSIGNINITREQUEST_PREVTXS._serialized_end=1969 + _BTCSIGNNEXTRESPONSE._serialized_start=1972 + _BTCSIGNNEXTRESPONSE._serialized_end=2424 + _BTCSIGNNEXTRESPONSE_TYPE._serialized_start=2294 + _BTCSIGNNEXTRESPONSE_TYPE._serialized_end=2424 + _BTCSIGNINPUTREQUEST._serialized_start=2427 + _BTCSIGNINPUTREQUEST._serialized_end=2661 + _BTCSIGNOUTPUTREQUEST._serialized_start=2664 + _BTCSIGNOUTPUTREQUEST._serialized_end=3079 + _BTCSIGNOUTPUTREQUEST_SILENTPAYMENT._serialized_start=2990 + _BTCSIGNOUTPUTREQUEST_SILENTPAYMENT._serialized_end=3022 + _BTCSCRIPTCONFIGREGISTRATION._serialized_start=3082 + _BTCSCRIPTCONFIGREGISTRATION._serialized_end=3235 + _BTCSUCCESS._serialized_start=3237 + _BTCSUCCESS._serialized_end=3249 + _BTCISSCRIPTCONFIGREGISTEREDREQUEST._serialized_start=3251 + _BTCISSCRIPTCONFIGREGISTEREDREQUEST._serialized_end=3360 + _BTCISSCRIPTCONFIGREGISTEREDRESPONSE._serialized_start=3362 + _BTCISSCRIPTCONFIGREGISTEREDRESPONSE._serialized_end=3422 + _BTCREGISTERSCRIPTCONFIGREQUEST._serialized_start=3425 + _BTCREGISTERSCRIPTCONFIGREQUEST._serialized_end=3677 + _BTCREGISTERSCRIPTCONFIGREQUEST_XPUBTYPE._serialized_start=3628 + _BTCREGISTERSCRIPTCONFIGREQUEST_XPUBTYPE._serialized_end=3677 + _BTCPREVTXINITREQUEST._serialized_start=3679 + _BTCPREVTXINITREQUEST._serialized_end=3777 + _BTCPREVTXINPUTREQUEST._serialized_start=3779 + _BTCPREVTXINPUTREQUEST._serialized_end=3893 + _BTCPREVTXOUTPUTREQUEST._serialized_start=3895 + _BTCPREVTXOUTPUTREQUEST._serialized_end=3957 + _BTCPAYMENTREQUESTREQUEST._serialized_start=3960 + _BTCPAYMENTREQUESTREQUEST._serialized_end=4259 + _BTCPAYMENTREQUESTREQUEST_MEMO._serialized_start=4136 + _BTCPAYMENTREQUESTREQUEST_MEMO._serialized_end=4259 + _BTCPAYMENTREQUESTREQUEST_MEMO_TEXTMEMO._serialized_start=4227 + _BTCPAYMENTREQUESTREQUEST_MEMO_TEXTMEMO._serialized_end=4251 + _BTCSIGNMESSAGEREQUEST._serialized_start=4262 + _BTCSIGNMESSAGEREQUEST._serialized_end=4500 + _BTCSIGNMESSAGERESPONSE._serialized_start=4502 + _BTCSIGNMESSAGERESPONSE._serialized_end=4545 + _BTCREQUEST._serialized_start=4548 + _BTCREQUEST._serialized_end=5245 + _BTCRESPONSE._serialized_start=5248 + _BTCRESPONSE._serialized_end=5700 # @@protoc_insertion_point(module_scope) diff --git a/py/bitbox02/bitbox02/communication/generated/btc_pb2.pyi b/py/bitbox02/bitbox02/communication/generated/btc_pb2.pyi index 05022bdd11..3d86c54bce 100644 --- a/py/bitbox02/bitbox02/communication/generated/btc_pb2.pyi +++ b/py/bitbox02/bitbox02/communication/generated/btc_pb2.pyi @@ -342,6 +342,21 @@ class BTCSignInitRequest(google.protobuf.message.Message): SAT: BTCSignInitRequest.FormatUnit.ValueType # 1 """Only valid for BTC/TBTC, formats as "sat"/"tsat".""" + class _PrevTxs: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _PrevTxsEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[BTCSignInitRequest._PrevTxs.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + PREV_TXS_DEFAULT: BTCSignInitRequest._PrevTxs.ValueType # 0 + PREV_TXS_REQUIRED: BTCSignInitRequest._PrevTxs.ValueType # 1 + PREV_TXS_NOT_REQUIRED: BTCSignInitRequest._PrevTxs.ValueType # 2 + + class PrevTxs(_PrevTxs, metaclass=_PrevTxsEnumTypeWrapper): ... + PREV_TXS_DEFAULT: BTCSignInitRequest.PrevTxs.ValueType # 0 + PREV_TXS_REQUIRED: BTCSignInitRequest.PrevTxs.ValueType # 1 + PREV_TXS_NOT_REQUIRED: BTCSignInitRequest.PrevTxs.ValueType # 2 + COIN_FIELD_NUMBER: builtins.int SCRIPT_CONFIGS_FIELD_NUMBER: builtins.int VERSION_FIELD_NUMBER: builtins.int @@ -351,6 +366,7 @@ class BTCSignInitRequest(google.protobuf.message.Message): FORMAT_UNIT_FIELD_NUMBER: builtins.int CONTAINS_SILENT_PAYMENT_OUTPUTS_FIELD_NUMBER: builtins.int OUTPUT_SCRIPT_CONFIGS_FIELD_NUMBER: builtins.int + PREV_TXS_FIELD_NUMBER: builtins.int coin: global___BTCCoin.ValueType version: builtins.int """must be 1 or 2""" @@ -360,6 +376,14 @@ class BTCSignInitRequest(google.protobuf.message.Message): """must be <500000000""" format_unit: global___BTCSignInitRequest.FormatUnit.ValueType contains_silent_payment_outputs: builtins.bool + prev_txs: global___BTCSignInitRequest.PrevTxs.ValueType + """Set this to: + - `PREV_TXS_DEFAULT` for compatibility mode, the value will be determined using `script_configs`. + This is not robust, as non-Taproot change outputs are included there and falsely leads to + previous transactions being required. + - `PREV_TXS_REQUIRED` if not all transaction inputs are Taproot. + - `PREV_TXS_NOT_REQUIRED` if all transaction inputs are Taproot. + """ @property def script_configs(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___BTCScriptConfigWithKeypath]: """used script configs in inputs and changes""" @@ -382,8 +406,9 @@ class BTCSignInitRequest(google.protobuf.message.Message): format_unit: global___BTCSignInitRequest.FormatUnit.ValueType = ..., contains_silent_payment_outputs: builtins.bool = ..., output_script_configs: collections.abc.Iterable[global___BTCScriptConfigWithKeypath] | None = ..., + prev_txs: global___BTCSignInitRequest.PrevTxs.ValueType = ..., ) -> None: ... - def ClearField(self, field_name: typing.Literal["coin", b"coin", "contains_silent_payment_outputs", b"contains_silent_payment_outputs", "format_unit", b"format_unit", "locktime", b"locktime", "num_inputs", b"num_inputs", "num_outputs", b"num_outputs", "output_script_configs", b"output_script_configs", "script_configs", b"script_configs", "version", b"version"]) -> None: ... + def ClearField(self, field_name: typing.Literal["coin", b"coin", "contains_silent_payment_outputs", b"contains_silent_payment_outputs", "format_unit", b"format_unit", "locktime", b"locktime", "num_inputs", b"num_inputs", "num_outputs", b"num_outputs", "output_script_configs", b"output_script_configs", "prev_txs", b"prev_txs", "script_configs", b"script_configs", "version", b"version"]) -> None: ... global___BTCSignInitRequest = BTCSignInitRequest diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs index a231a31a50..eb4f1f8811 100644 --- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs +++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs @@ -717,8 +717,20 @@ async fn _process( let mut hasher_amounts = Sha256::new(); let mut hasher_scriptpubkeys = Sha256::new(); - // Are all inputs taproot? - let taproot_only = validated_script_configs.iter().all(is_taproot); + let prev_txs = pb::btc_sign_init_request::PrevTxs::try_from(request.prev_txs)?; + + // We will request to stream previous transactions if not all inputs are Taproot. + let prevtxs_required: bool = match prev_txs { + // For backwards compatibility for client's that don't provide the `prev_txs` field: handle + // it like before `prev_txs` was introduced by inspecting the script configs and seeing if + // all of them are taproot. This is not robust, as non-Taproot change outputs are included + // there and falsely leads to previous transactions being required. + pb::btc_sign_init_request::PrevTxs::Default => { + !validated_script_configs.iter().all(is_taproot) + } + pb::btc_sign_init_request::PrevTxs::Required => true, + pb::btc_sign_init_request::PrevTxs::NotRequired => false, + }; let mut silent_payment = if request.contains_silent_payment_outputs { Some(SilentPayment::new(SECP256K1, coin.try_into()?)) @@ -775,7 +787,7 @@ async fn _process( hasher_scriptpubkeys.update(serialize_varint(pk_script.len() as u64).as_slice()); hasher_scriptpubkeys.update(pk_script.as_slice()); - if !taproot_only { + if prevtxs_required { handle_prevtx( input_index, &tx_input, @@ -784,6 +796,8 @@ async fn _process( &mut next_response, ) .await?; + } else if !is_taproot(script_config_account) { + return Err(Error::InvalidInput); } if let Some(ref mut silent_payment) = silent_payment { @@ -1572,6 +1586,7 @@ mod tests { .outputs .iter() .any(|output| output.silent_payment.is_some()), + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } } @@ -1595,6 +1610,7 @@ mod tests { locktime: self.locktime, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } } @@ -1679,6 +1695,7 @@ mod tests { locktime: 0, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, }; { @@ -1871,6 +1888,7 @@ mod tests { locktime: 0, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } )), Err(Error::InvalidInput) @@ -2147,6 +2165,57 @@ mod tests { assert!(unsafe { !PREVTX_REQUESTED }); } + /// Test signing if all inputs are of type P2TR, but change is not of type P2TR. + /// Previous transactions are requested for backwards compatibility when + #[test] + fn test_script_type_p2tr_different_change() { + let transaction = + alloc::rc::Rc::new(core::cell::RefCell::new(Transaction::new(pb::BtcCoin::Btc))); + for input in transaction.borrow_mut().inputs.iter_mut() { + input.input.keypath[0] = 86 + HARDENED; + input.input.script_config_index = 1; + } + + let tx = transaction.clone(); + // Check that previous transactions are not streamed, as all inputs are taproot. + static mut PREVTX_REQUESTED: bool = false; + *crate::hww::MOCK_NEXT_REQUEST.0.borrow_mut() = + Some(Box::new(move |response: Response| { + let next = extract_next(&response); + if NextType::try_from(next.r#type).unwrap() == NextType::PrevtxInit { + unsafe { PREVTX_REQUESTED = true } + } + Ok(tx.borrow().make_host_request(response)) + })); + + mock_unlocked(); + bitbox02::random::fake_reset(); + let mut init_request = transaction.borrow().init_request(); + init_request + .script_configs + .push(pb::BtcScriptConfigWithKeypath { + script_config: Some(pb::BtcScriptConfig { + config: Some(pb::btc_script_config::Config::SimpleType( + SimpleType::P2tr as _, + )), + }), + keypath: vec![86 + HARDENED, 0 + HARDENED, 10 + HARDENED], + }); + + init_request.prev_txs = pb::btc_sign_init_request::PrevTxs::NotRequired as _; + assert!(block_on(process(&mut TestingHal::new(), &init_request)).is_ok()); + assert!(unsafe { !PREVTX_REQUESTED }); + + // Also test compatibility mode - before the introduction of `prev_txs`, the previous + // transactions were wrongly requested in this case. + unsafe { + PREVTX_REQUESTED = false; + } + init_request.prev_txs = pb::btc_sign_init_request::PrevTxs::Default as _; + assert!(block_on(process(&mut TestingHal::new(), &init_request)).is_ok()); + assert!(unsafe { PREVTX_REQUESTED }); + } + /// Test signing if with mixed inputs, one of them being taproot. Previous transactions of all /// inputs should be streamed in this case. #[test] @@ -2180,11 +2249,31 @@ mod tests { }), keypath: vec![86 + HARDENED, 0 + HARDENED, 10 + HARDENED], }); + + // In compatibility mode, prevtxs are correctly requested. + init_request.prev_txs = pb::btc_sign_init_request::PrevTxs::Default as _; + unsafe { PREVTX_REQUESTED = 0 }; assert!(block_on(process(&mut TestingHal::new(), &init_request)).is_ok()); assert_eq!( unsafe { PREVTX_REQUESTED }, transaction.borrow().inputs.len() as _ ); + + // Same as when the client explicitly states it. + init_request.prev_txs = pb::btc_sign_init_request::PrevTxs::Required as _; + unsafe { PREVTX_REQUESTED = 0 }; + assert!(block_on(process(&mut TestingHal::new(), &init_request)).is_ok()); + assert_eq!( + unsafe { PREVTX_REQUESTED }, + transaction.borrow().inputs.len() as _ + ); + + // Client can't lie about it. + init_request.prev_txs = pb::btc_sign_init_request::PrevTxs::NotRequired as _; + assert_eq!( + block_on(process(&mut TestingHal::new(), &init_request)), + Err(Error::InvalidInput) + ); } /// Test signing UTXOs with high keypath address indices. Even though we don't support verifying @@ -2881,6 +2970,7 @@ mod tests { locktime: tx.locktime, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } }; @@ -2976,6 +3066,7 @@ mod tests { locktime: tx.locktime, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } }; assert_eq!( @@ -3047,6 +3138,7 @@ mod tests { locktime: tx.locktime, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } }; let result = block_on(process(&mut TestingHal::new(), &init_request)); @@ -3124,6 +3216,7 @@ mod tests { locktime: tx.locktime, format_unit: FormatUnit::Default as _, contains_silent_payment_outputs: false, + prev_txs: pb::btc_sign_init_request::PrevTxs::Default as _, } }; let result = block_on(process(&mut TestingHal::new(), &init_request)); diff --git a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs index 018adf9595..75cfeb5eaf 100644 --- a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs +++ b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs @@ -599,6 +599,14 @@ pub struct BtcSignInitRequest { /// necessarily the same account (as defined by `script_configs` above). #[prost(message, repeated, tag = "10")] pub output_script_configs: ::prost::alloc::vec::Vec, + /// Set this to: + /// - `PREV_TXS_DEFAULT` for compatibility mode, the value will be determined using `script_configs`. + /// This is not robust, as non-Taproot change outputs are included there and falsely leads to + /// previous transactions being required. + /// - `PREV_TXS_REQUIRED` if not all transaction inputs are Taproot. + /// - `PREV_TXS_NOT_REQUIRED` if all transaction inputs are Taproot. + #[prost(enumeration = "btc_sign_init_request::PrevTxs", tag = "11")] + pub prev_txs: i32, } /// Nested message and enum types in `BTCSignInitRequest`. pub mod btc_sign_init_request { @@ -640,6 +648,45 @@ pub mod btc_sign_init_request { } } } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum PrevTxs { + Default = 0, + Required = 1, + NotRequired = 2, + } + impl PrevTxs { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PrevTxs::Default => "PREV_TXS_DEFAULT", + PrevTxs::Required => "PREV_TXS_REQUIRED", + PrevTxs::NotRequired => "PREV_TXS_NOT_REQUIRED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PREV_TXS_DEFAULT" => Some(Self::Default), + "PREV_TXS_REQUIRED" => Some(Self::Required), + "PREV_TXS_NOT_REQUIRED" => Some(Self::NotRequired), + _ => None, + } + } + } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)]