diff --git a/ci/build.yml b/ci/build.yml index d804dd647..4ea2ee801 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -214,10 +214,12 @@ core unix regular asan build: variables: ADDRESS_SANITIZER: "1" script: + - $NIX_SHELL --run "poetry run make -C core build_bootloader_emu" - $NIX_SHELL --run "poetry run make -C core build_unix" artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA" paths: + - core/build/bootloader_emu/bootloader.elf - core/build/unix # most of it needed by test_rust expire_in: 1 week @@ -229,10 +231,12 @@ core unix frozen regular build: <<: *gitlab_caching needs: [] script: + - $NIX_SHELL --run "poetry run make -C core build_bootloader_emu" - $NIX_SHELL --run "poetry run make -C core build_unix_frozen" artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA" paths: + - core/build/bootloader_emu/bootloader.elf - core/build/unix/trezor-emu-core expire_in: 1 week @@ -301,7 +305,8 @@ core unix frozen R debug build: PYOPT: "0" TREZOR_MODEL: "R" script: - - nix-shell --run "poetry run make -C core build_unix_frozen" + - $NIX_SHELL --run "poetry run make -C core build_bootloader_emu" + - $NIX_SHELL --run "poetry run make -C core build_unix_frozen" artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA" untracked: true @@ -316,7 +321,7 @@ core unix frozen R debug build arm: PYOPT: "0" TREZOR_MODEL: "R" script: - - nix-shell --run "poetry run make -C core build_unix_frozen" + - $NIX_SHELL --run "poetry run make -C core build_unix_frozen" - mv core/build/unix/trezor-emu-core core/build/unix/trezor-emu-core-arm artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA" diff --git a/common/defs/README.md b/common/defs/README.md index 9e35918a4..7c9b43144 100644 --- a/common/defs/README.md +++ b/common/defs/README.md @@ -86,7 +86,7 @@ If you want to add a **wallet link**, modify the file [`wallets.json`](wallets.j # Support Information We keep track of support status of each built-in coin over our devices. That is -`trezor1` for Trezor One, `trezor2` for Trezor T, `connect` for [Connect](https://github.com/trezor/connect) +`T1B1` for Trezor One, `T2T1` for Trezor T, `T2B1` for Trezor R, `connect` for [Connect](https://github.com/trezor/connect) and `suite` for [Trezor Suite](https://suite.trezor.io/). In further description, the word "device" applies to Connect and Suite as well. diff --git a/common/defs/support.json b/common/defs/support.json index 381267c56..b049e6275 100644 --- a/common/defs/support.json +++ b/common/defs/support.json @@ -1,88 +1,5 @@ { - "connect": { - "supported": { - "bitcoin:ACM": true, - "bitcoin:AXE": true, - "bitcoin:BCH": true, - "bitcoin:BTC": true, - "bitcoin:BTCP": true, - "bitcoin:BTG": true, - "bitcoin:BTX": true, - "bitcoin:DASH": true, - "bitcoin:DCR": true, - "bitcoin:DGB": true, - "bitcoin:DOGE": true, - "bitcoin:FIRO": true, - "bitcoin:FJC": true, - "bitcoin:FLO": true, - "bitcoin:FTC": true, - "bitcoin:KMD": true, - "bitcoin:KOTO": true, - "bitcoin:LTC": true, - "bitcoin:MONA": true, - "bitcoin:NMC": true, - "bitcoin:PPC": true, - "bitcoin:REGTEST": true, - "bitcoin:RITO": true, - "bitcoin:RVN": true, - "bitcoin:SYS": true, - "bitcoin:TAZ": true, - "bitcoin:TBCH": true, - "bitcoin:TBTG": true, - "bitcoin:TDCR": true, - "bitcoin:TEST": true, - "bitcoin:UNO": true, - "bitcoin:VIA": true, - "bitcoin:VTC": true, - "bitcoin:XPM": true, - "bitcoin:XRC": true, - "bitcoin:XSN": true, - "bitcoin:XVG": true, - "bitcoin:ZCR": true, - "bitcoin:ZEC": true, - "bitcoin:tDASH": true, - "bitcoin:tFIRO": true, - "bitcoin:tLTC": true, - "bitcoin:tPPC": true, - "eth:tETH:3": true, - "misc:ADA": true, - "misc:BNB": true, - "misc:EOS": true, - "misc:XLM": true, - "misc:XRP": true, - "misc:XTZ": true, - "misc:tADA": true, - "misc:tXRP": true, - "nem:BREEZE": true, - "nem:DIM": true, - "nem:DIMTOK": true, - "nem:PAC:CHS": true, - "nem:PAC:HRT": true, - "nem:XEM": true - }, - "unsupported": {} - }, - "suite": { - "supported": { - "bitcoin:BCH": true, - "bitcoin:BTC": true, - "bitcoin:BTG": true, - "bitcoin:DASH": true, - "bitcoin:DGB": true, - "bitcoin:DOGE": true, - "bitcoin:LTC": true, - "bitcoin:NMC": true, - "bitcoin:REGTEST": true, - "bitcoin:TEST": true, - "bitcoin:VTC": true, - "bitcoin:ZEC": true, - "eth:tETH:3": true, - "misc:XRP": true, - "misc:tXRP": true - }, - "unsupported": {} - }, - "trezor1": { + "T1B1": { "supported": { "bitcoin:ACM": "1.7.2", "bitcoin:AXE": "1.7.3", @@ -195,7 +112,120 @@ "misc:tXRP": "not implemented" } }, - "trezor2": { + "T2B1": { + "supported": { + "bitcoin:ACM": "2.6.1", + "bitcoin:AXE": "2.6.1", + "bitcoin:BCH": "2.6.1", + "bitcoin:BTC": "2.6.1", + "bitcoin:BTCP": "2.6.1", + "bitcoin:BTX": "2.6.1", + "bitcoin:CPU": "2.6.1", + "bitcoin:CRW": "2.6.1", + "bitcoin:DOGE": "2.6.1", + "bitcoin:ELEMENTS": "2.6.1", + "bitcoin:FIRO": "2.6.1", + "bitcoin:FJC": "2.6.1", + "bitcoin:FLO": "2.6.1", + "bitcoin:FTC": "2.6.1", + "bitcoin:GRS": "2.6.1", + "bitcoin:KMD": "2.6.1", + "bitcoin:KOTO": "2.6.1", + "bitcoin:LTC": "2.6.1", + "bitcoin:MONA": "2.6.1", + "bitcoin:PPC": "2.6.1", + "bitcoin:QTUM": "2.6.1", + "bitcoin:REGTEST": "2.6.1", + "bitcoin:RITO": "2.6.1", + "bitcoin:RVN": "2.6.1", + "bitcoin:SMART": "2.6.1", + "bitcoin:SYS": "2.6.1", + "bitcoin:TAZ": "2.6.1", + "bitcoin:TBCH": "2.6.1", + "bitcoin:TEST": "2.6.1", + "bitcoin:UNO": "2.6.1", + "bitcoin:VIA": "2.6.1", + "bitcoin:VIPS": "2.6.1", + "bitcoin:XPM": "2.6.1", + "bitcoin:XRC": "2.6.1", + "bitcoin:XSN": "2.6.1", + "bitcoin:XVG": "2.6.1", + "bitcoin:ZCR": "2.6.1", + "bitcoin:ZEC": "2.6.1", + "bitcoin:tFIRO": "2.6.1", + "bitcoin:tGRS": "2.6.1", + "bitcoin:tLTC": "2.6.1", + "bitcoin:tPPC": "2.6.1", + "bitcoin:tQTUM": "2.6.1", + "bitcoin:tRVN": "2.6.1", + "bitcoin:tSMART": "2.6.1", + "erc20:bnb:ATOM": "2.6.1", + "erc20:eth:AAVE": "2.6.1", + "erc20:eth:APE": "2.6.1", + "erc20:eth:AXS": "2.6.1", + "erc20:eth:BUSD": "2.6.1", + "erc20:eth:CHZ": "2.6.1", + "erc20:eth:CRO": "2.6.1", + "erc20:eth:DAI": "2.6.1", + "erc20:eth:FRAX": "2.6.1", + "erc20:eth:LEO": "2.6.1", + "erc20:eth:LINK": "2.6.1", + "erc20:eth:MANA": "2.6.1", + "erc20:eth:MATIC": "2.6.1", + "erc20:eth:OKB": "2.6.1", + "erc20:eth:QNT": "2.6.1", + "erc20:eth:SAND": "2.6.1", + "erc20:eth:SHIB": "2.6.1", + "erc20:eth:STETH": "2.6.1", + "erc20:eth:UNI": "2.6.1", + "erc20:eth:USDC": "2.6.1", + "erc20:eth:USDT": "2.6.1", + "erc20:eth:WBTC": "2.6.1", + "erc20:eth:XCN": "2.6.1", + "erc20:matic:WAVAX": "2.6.1", + "eth:BNB:56": "2.6.1", + "eth:ETC:61": "2.6.1", + "eth:ETH:1": "2.6.1", + "eth:MATIC:137": "2.6.1", + "eth:tETH:3": "2.6.1", + "eth:tETH:4": "2.6.1", + "eth:tETH:5": "2.6.1", + "misc:ADA": "2.6.1", + "misc:BNB": "2.6.1", + "misc:MAID": "2.6.1", + "misc:OMNI": "2.6.1", + "misc:USDT": "2.6.1", + "misc:XLM": "2.6.1", + "misc:XMR": "2.6.1", + "misc:XRP": "2.6.1", + "misc:XTZ": "2.6.1", + "misc:tADA": "2.6.1", + "misc:tXRP": "2.6.1", + "nem:BREEZE": "2.6.1", + "nem:DIM": "2.6.1", + "nem:DIMTOK": "2.6.1", + "nem:PAC:CHS": "2.6.1", + "nem:PAC:HRT": "2.6.1" + }, + "unsupported": { + "bitcoin:BTG": "not for T2B1 (#2793)", + "bitcoin:DASH": "not for T2B1 (#2793)", + "bitcoin:DCR": "not for T2B1 (#2793)", + "bitcoin:DGB": "not for T2B1 (#2793)", + "bitcoin:NMC": "not for T2B1 (#2793)", + "bitcoin:PART": "incompatible fork", + "bitcoin:TBTG": "not for T2B1 (#2793)", + "bitcoin:TDCR": "not for T2B1 (#2793)", + "bitcoin:TRC": "address_type collides with Bitcoin", + "bitcoin:VTC": "not for T2B1 (#2793)", + "bitcoin:tDASH": "not for T2B1 (#2793)", + "bitcoin:tPART": "incompatible fork", + "misc:EOS": "not for T2B1 (#2793)", + "misc:LSK": "Incompatible mainnet hard-fork", + "nem:XEM": "not for T2B1 (#2793)" + } + }, + "T2T1": { "supported": { "bitcoin:ACM": "2.0.10", "bitcoin:AXE": "2.0.11", @@ -307,5 +337,88 @@ "bitcoin:tPART": "incompatible fork", "misc:LSK": "Incompatible mainnet hard-fork" } + }, + "connect": { + "supported": { + "bitcoin:ACM": true, + "bitcoin:AXE": true, + "bitcoin:BCH": true, + "bitcoin:BTC": true, + "bitcoin:BTCP": true, + "bitcoin:BTG": true, + "bitcoin:BTX": true, + "bitcoin:DASH": true, + "bitcoin:DCR": true, + "bitcoin:DGB": true, + "bitcoin:DOGE": true, + "bitcoin:FIRO": true, + "bitcoin:FJC": true, + "bitcoin:FLO": true, + "bitcoin:FTC": true, + "bitcoin:KMD": true, + "bitcoin:KOTO": true, + "bitcoin:LTC": true, + "bitcoin:MONA": true, + "bitcoin:NMC": true, + "bitcoin:PPC": true, + "bitcoin:REGTEST": true, + "bitcoin:RITO": true, + "bitcoin:RVN": true, + "bitcoin:SYS": true, + "bitcoin:TAZ": true, + "bitcoin:TBCH": true, + "bitcoin:TBTG": true, + "bitcoin:TDCR": true, + "bitcoin:TEST": true, + "bitcoin:UNO": true, + "bitcoin:VIA": true, + "bitcoin:VTC": true, + "bitcoin:XPM": true, + "bitcoin:XRC": true, + "bitcoin:XSN": true, + "bitcoin:XVG": true, + "bitcoin:ZCR": true, + "bitcoin:ZEC": true, + "bitcoin:tDASH": true, + "bitcoin:tFIRO": true, + "bitcoin:tLTC": true, + "bitcoin:tPPC": true, + "eth:tETH:3": true, + "misc:ADA": true, + "misc:BNB": true, + "misc:EOS": true, + "misc:XLM": true, + "misc:XRP": true, + "misc:XTZ": true, + "misc:tADA": true, + "misc:tXRP": true, + "nem:BREEZE": true, + "nem:DIM": true, + "nem:DIMTOK": true, + "nem:PAC:CHS": true, + "nem:PAC:HRT": true, + "nem:XEM": true + }, + "unsupported": {} + }, + "suite": { + "supported": { + "bitcoin:BCH": true, + "bitcoin:BTC": true, + "bitcoin:BTG": true, + "bitcoin:DASH": true, + "bitcoin:DGB": true, + "bitcoin:DOGE": true, + "bitcoin:LTC": true, + "bitcoin:NMC": true, + "bitcoin:REGTEST": true, + "bitcoin:TEST": true, + "bitcoin:VTC": true, + "bitcoin:ZEC": true, + "eth:tETH:3": true, + "misc:XRP": true, + "misc:tXRP": true + }, + "unsupported": {} } } diff --git a/common/models.json b/common/models.json new file mode 100644 index 000000000..cb36fbd84 --- /dev/null +++ b/common/models.json @@ -0,0 +1,17 @@ +{ + "T1B1": { + "name": "Trezor Model One", + "colors": {} + }, + "T2T1": { + "name": "Trezor Model T", + "colors": {} + }, + "T2B1": { + "name": "Trezor Model R", + "colors": { + "0": "Black", + "1": "White" + } + } +} diff --git a/common/protob/messages-binance.proto b/common/protob/messages-binance.proto index 531a2bea3..6a46c1015 100644 --- a/common/protob/messages-binance.proto +++ b/common/protob/messages-binance.proto @@ -22,6 +22,7 @@ chance that somebody is relying on the behavior. message BinanceGetAddress { repeated uint32 address_n = 1; // BIP-32-style path to derive the key from master node optional bool show_display = 2; // optionally prompt for confirmation on trezor display + optional bool chunkify = 3; // display the address in chunks of 4 characters } /** @@ -66,6 +67,7 @@ message BinanceSignTx { optional string memo = 5; required sint64 sequence = 6; required sint64 source = 7; + optional bool chunkify = 8; // display the address in chunks of 4 characters } /** @@ -85,6 +87,7 @@ message BinanceTxRequest { message BinanceTransferMsg { repeated BinanceInputOutput inputs = 1; repeated BinanceInputOutput outputs = 2; + optional bool chunkify = 3; // display the address in chunks of 4 characters message BinanceInputOutput { required string address = 1; diff --git a/common/protob/messages-bitcoin.proto b/common/protob/messages-bitcoin.proto index 772fec186..ad9a4e670 100644 --- a/common/protob/messages-bitcoin.proto +++ b/common/protob/messages-bitcoin.proto @@ -110,6 +110,7 @@ message GetAddress { optional MultisigRedeemScriptType multisig = 4; // filled if we are showing a multisig address optional InputScriptType script_type = 5 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.) optional bool ignore_xpub_magic = 6; // ignore SLIP-0132 XPUB magic, use xpub/tpub prefix for all account types + optional bool chunkify = 7; // display the address in chunks of 4 characters } /** @@ -199,6 +200,7 @@ message SignTx { optional bool decred_staking_ticket = 12 [default=false]; // only for Decred, this is signing a ticket purchase optional bool serialize = 13 [default=true]; // serialize the full transaction, as opposed to only outputting the signatures optional CoinJoinRequest coinjoin_request = 14; // only for preauthorized CoinJoins + optional bool chunkify = 15; // display the address in chunks of 4 characters /** * Signing request for a CoinJoin transaction. diff --git a/common/protob/messages-cardano.proto b/common/protob/messages-cardano.proto index 9be21e0bf..b1331beee 100644 --- a/common/protob/messages-cardano.proto +++ b/common/protob/messages-cardano.proto @@ -164,6 +164,7 @@ message CardanoGetAddress { required uint32 network_id = 4; // network id - mainnet or testnet required CardanoAddressParametersType address_parameters = 5; // parameters used to derive the address required CardanoDerivationType derivation_type = 6; + optional bool chunkify = 7; // display the address in chunks of 4 characters } /** @@ -223,6 +224,7 @@ message CardanoSignTxInit { optional bool has_collateral_return = 19 [default=false]; optional uint64 total_collateral = 20; optional uint32 reference_inputs_count = 21 [default=0]; + optional bool chunkify = 22; // display the address in chunks of 4 characters } /** diff --git a/common/protob/messages-eos.proto b/common/protob/messages-eos.proto index fdeda0c9d..ff4095ad6 100644 --- a/common/protob/messages-eos.proto +++ b/common/protob/messages-eos.proto @@ -14,6 +14,7 @@ option java_outer_classname = "TrezorMessageEos"; message EosGetPublicKey { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node 44'/194'/0' optional bool show_display = 2; // optionally show on display before sending the result + optional bool chunkify = 3; // display the address in chunks of 4 characters } /** @@ -36,6 +37,7 @@ message EosSignTx { required bytes chain_id = 2; // 256-bit long chain id required EosTxHeader header = 3; // EOS transaction header required uint32 num_actions = 4; // number of actions + optional bool chunkify = 5; // display the address in chunks of 4 characters /** * Structure representing EOS transaction header diff --git a/common/protob/messages-ethereum.proto b/common/protob/messages-ethereum.proto index 3909ec7f7..dae98de86 100644 --- a/common/protob/messages-ethereum.proto +++ b/common/protob/messages-ethereum.proto @@ -39,6 +39,7 @@ message EthereumGetAddress { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node optional bool show_display = 2; // optionally show on display before sending the result optional bytes encoded_network = 3; // encoded Ethereum network, see ethereum-definitions.md for details + optional bool chunkify = 4; // display the address in chunks of 4 characters } /** @@ -71,6 +72,7 @@ message EthereumSignTx { required uint64 chain_id = 9; // Chain Id for EIP 155 optional uint32 tx_type = 10; // Used for Wanchain optional ethereum_definitions.EthereumDefinitions definitions = 12; // network and/or token definitions for tx + optional bool chunkify = 13; // display the address in chunks of 4 characters } /** @@ -93,6 +95,7 @@ message EthereumSignTxEIP1559 { required uint64 chain_id = 10; // Chain Id for EIP 155 repeated EthereumAccessList access_list = 11; // Access List optional ethereum_definitions.EthereumDefinitions definitions = 12; // network and/or token definitions for tx + optional bool chunkify = 13; // display the address in chunks of 4 characters message EthereumAccessList { required string address = 1; diff --git a/common/protob/messages-management.proto b/common/protob/messages-management.proto index 4656ebd5d..cfe1c2cce 100644 --- a/common/protob/messages-management.proto +++ b/common/protob/messages-management.proto @@ -129,6 +129,7 @@ message Features { optional bool unit_btconly = 46; // unit/device is intended as bitcoin only optional uint32 homescreen_width = 47; // homescreen width in pixels optional uint32 homescreen_height = 48; // homescreen height in pixels + optional bool bootloader_locked = 49; // bootloader is locked } /** @@ -280,6 +281,25 @@ message FirmwareHash { required bytes hash = 1; } +/** + * Request: Request a signature of the provided challenge. + * @start + * @next AuthenticityProof + * @next Failure + */ +message AuthenticateDevice { + required bytes challenge = 1; // A random challenge to sign. +} + +/** + * Response: Signature of the provided challenge along with a certificate issued by the Trezor company. + * @end + */ +message AuthenticityProof { + repeated bytes certificates = 1; // A certificate chain starting with the device certificate, followed by intermediate CA certificates, the last of which is signed by Trezor company's root CA. + required bytes signature = 2; // A DER-encoded signature of "\0x13AuthenticateDevice:" + length-prefixed challenge that should be verified using the device certificate. +} + /** * Request: Request device to wipe all sensitive data and settings * @start diff --git a/common/protob/messages-monero.proto b/common/protob/messages-monero.proto index c88218d3b..30f13e05d 100644 --- a/common/protob/messages-monero.proto +++ b/common/protob/messages-monero.proto @@ -90,6 +90,7 @@ message MoneroGetAddress { optional uint32 account = 4; // Major subaddr index optional uint32 minor = 5; // Minor subaddr index optional bytes payment_id = 6; // Payment ID for integrated address + optional bool chunkify = 7; // display the address in chunks of 4 characters } /** @@ -149,6 +150,7 @@ message MoneroTransactionInitRequest { optional uint32 client_version = 13; // connected client version optional uint32 hard_fork = 14; // transaction hard fork number optional bytes monero_version = 15; // monero software version + optional bool chunkify = 16; // display the address in chunks of 4 characters } } diff --git a/common/protob/messages-nem.proto b/common/protob/messages-nem.proto index 803312a14..74bb3418a 100644 --- a/common/protob/messages-nem.proto +++ b/common/protob/messages-nem.proto @@ -15,6 +15,7 @@ message NEMGetAddress { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node optional uint32 network = 2 [default=0x68]; // Network ID (0x68 = Mainnet, 0x98 = Testnet, 0x60 = Mijin) optional bool show_display = 3; // Optionally show on display before sending the result + optional bool chunkify = 4; // display the address in chunks of 4 characters } /** @@ -41,6 +42,8 @@ message NEMSignTx { optional NEMMosaicSupplyChange supply_change = 7; // Mosaic supply change part optional NEMAggregateModification aggregate_modification = 8; // Aggregate modification part optional NEMImportanceTransfer importance_transfer = 9; // Importance transfer part + optional bool chunkify = 10; // display the address in chunks of 4 characters + /** * Structure representing the common part for NEM transactions */ diff --git a/common/protob/messages-ripple.proto b/common/protob/messages-ripple.proto index 658e5ec23..37d5d020b 100644 --- a/common/protob/messages-ripple.proto +++ b/common/protob/messages-ripple.proto @@ -13,6 +13,7 @@ option java_outer_classname = "TrezorMessageRipple"; message RippleGetAddress { repeated uint32 address_n = 1; // BIP-32 path. For compatibility with other wallets, must be m/44'/144'/index' optional bool show_display = 2; // optionally show on display before sending the result + optional bool chunkify = 3; // display the address in chunks of 4 characters } /** @@ -35,6 +36,7 @@ message RippleSignTx { required uint32 sequence = 4; // transaction sequence number optional uint32 last_ledger_sequence = 5; // see https://developers.ripple.com/reliable-transaction-submission.html#lastledgersequence required RipplePayment payment = 6; // Payment transaction type + optional bool chunkify = 7; // display the address in chunks of 4 characters /** * Payment transaction type diff --git a/common/protob/messages-stellar.proto b/common/protob/messages-stellar.proto index 8970a3300..ca7fedc21 100644 --- a/common/protob/messages-stellar.proto +++ b/common/protob/messages-stellar.proto @@ -31,6 +31,7 @@ message StellarAsset { message StellarGetAddress { repeated uint32 address_n = 1; // BIP-32 path. For compatibility with other wallets, must be m/44'/148'/index' optional bool show_display = 2; // optionally show on display before sending the result + optional bool chunkify = 3; // display the address in chunks of 4 characters } /** diff --git a/common/protob/messages-tezos.proto b/common/protob/messages-tezos.proto index 07edccf6f..c24587609 100644 --- a/common/protob/messages-tezos.proto +++ b/common/protob/messages-tezos.proto @@ -14,6 +14,7 @@ option java_outer_classname = "TrezorMessageTezos"; message TezosGetAddress { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node optional bool show_display = 2; // optionally show on display before sending the result + optional bool chunkify = 3; // display the address in chunks of 4 characters } /** @@ -32,6 +33,7 @@ message TezosAddress { message TezosGetPublicKey { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node optional bool show_display = 2; // Optionally show on display before sending the result + optional bool chunkify = 3; // display the public key in chunks of 4 characters } /** @@ -57,6 +59,8 @@ message TezosSignTx { optional TezosDelegationOp delegation = 6; // Tezos delegation operation optional TezosProposalOp proposal = 7; // Tezos proposal operation optional TezosBallotOp ballot = 8; // Tezos ballot operation + optional bool chunkify = 9; // display the address in chunks of 4 characters + /* * Tezos contract ID */ diff --git a/common/protob/messages.proto b/common/protob/messages.proto index 632c733c0..ae9637e06 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -122,6 +122,8 @@ enum MessageType { MessageType_UnlockedPathRequest = 94 [(bitcoin_only) = true, (wire_out) = true]; MessageType_ShowDeviceTutorial = 95 [(bitcoin_only) = true, (wire_in) = true]; MessageType_UnlockBootloader = 96 [(bitcoin_only) = true, (wire_in) = true]; + MessageType_AuthenticateDevice = 97 [(bitcoin_only) = true, (wire_out) = true]; + MessageType_AuthenticityProof = 98 [(bitcoin_only) = true, (wire_in) = true]; MessageType_SetU2FCounter = 63 [(wire_in) = true]; MessageType_GetNextU2FCounter = 80 [(wire_in) = true]; diff --git a/common/tools/README.md b/common/tools/README.md index 2aed7c592..b0cf350e4 100644 --- a/common/tools/README.md +++ b/common/tools/README.md @@ -55,7 +55,7 @@ for token in defs.erc20: support_info = coin_info.support_info(defs.misc) for key, support in support_info.values(): - t2_support = support["trezor2"] + t2_support = support["T2T1"] coin_name = dict_by_coin_key[key] if t2_support: print(coin_name, "is supported since version", t2_support) @@ -94,15 +94,15 @@ support statuses at the same time: $ ./support.py show Ontology misc:ONT - Ontology (ONT) * connect : NO - * trezor1 : support info missing - * trezor2 : support info missing + * T1B1 : support info missing + * T2T1 : support info missing * suite : NO -$ ./support.py set misc:ONT trezor1=no -r "not planned on T1" trezor2=2.4.7 +$ ./support.py set misc:ONT T1B1=no -r "not planned on T1" T2T1=2.4.7 misc:ONT - Ontology (ONT) * connect : NO - * trezor1 : NO (reason: not planned on T1) - * trezor2 : 2.4.7 + * T1B1 : NO (reason: not planned on T1) + * T2T1 : 2.4.7 * suite : NO ``` diff --git a/common/tools/coin_info.py b/common/tools/coin_info.py index 1ea7c38c8..0b8e65fba 100755 --- a/common/tools/coin_info.py +++ b/common/tools/coin_info.py @@ -39,15 +39,17 @@ class SupportItemVersion(TypedDict): class SupportData(TypedDict): connect: SupportItemBool suite: SupportItemBool - trezor1: SupportItemVersion - trezor2: SupportItemVersion + t1b1: SupportItemVersion + t2t1: SupportItemVersion + t2b1: SupportItemVersion class SupportInfoItem(TypedDict): connect: bool suite: bool - trezor1: Literal[False] | str - trezor2: Literal[False] | str + t1b1: Literal[False] | str + t2t1: Literal[False] | str + t2b1: Literal[False] | str SupportInfo = Dict[str, SupportInfoItem] @@ -452,7 +454,7 @@ def _load_fido_apps() -> FidoApps: RELEASES_URL = "https://data.trezor.io/firmware/{}/releases.json" MISSING_SUPPORT_MEANS_NO = ("connect", "suite") -VERSIONED_SUPPORT_INFO = ("trezor1", "trezor2") +VERSIONED_SUPPORT_INFO = ("T1B1", "T2T1", "T2B1") def get_support_data() -> SupportData: @@ -461,14 +463,16 @@ def get_support_data() -> SupportData: def latest_releases() -> dict[str, Any]: - """Get latest released firmware versions for Trezor 1 and 2""" + """Get latest released firmware versions for all models""" if not requests: raise RuntimeError("requests library is required for getting release info") latest: dict[str, Any] = {} - for v in ("1", "2"): - releases = requests.get(RELEASES_URL.format(v)).json() - latest["trezor" + v] = max(tuple(r["version"]) for r in releases) + for model in VERSIONED_SUPPORT_INFO: + # TODO: support new UPPERCASE model names in RELEASES_URL + url_model = model.lower() # need to be e.g. t1b1 for now + releases = requests.get(RELEASES_URL.format(url_model)).json() + latest[model] = max(tuple(r["version"]) for r in releases) return latest @@ -505,7 +509,7 @@ def support_info(coins: Iterable[Coin] | CoinsInfo | dict[str, Coin]) -> Support Takes a collection of coins and generates a support-info entry for each. The support-info is a dict with keys based on `support.json` keys. - These are usually: "trezor1", "trezor2", "connect" and "suite". + These are usually: "T1B1", "T2T1", "T2B1", "connect" and "suite". The `coins` argument can be a `CoinsInfo` object, a list or a dict of coin items. diff --git a/common/tools/cointool.py b/common/tools/cointool.py index 67e9f9449..8eb8fc1e7 100755 --- a/common/tools/cointool.py +++ b/common/tools/cointool.py @@ -675,7 +675,7 @@ def check(backend: bool, icons: bool) -> None: type_choice = click.Choice(["bitcoin", "eth", "erc20", "nem", "misc"]) -device_choice = click.Choice(["connect", "suite", "trezor1", "trezor2"]) +device_choice = click.Choice(["connect", "suite", "T1B1", "T2T1", "T2B1"]) @cli.command() @@ -692,8 +692,8 @@ device_choice = click.Choice(["connect", "suite", "trezor1", "trezor2"]) @click.option("-f", "--filter", metavar="FIELD=FILTER", multiple=True, help="Include only coins that match a filter (-f taproot=true -f maintainer='*stick*')") @click.option("-F", "--filter-exclude", metavar="FIELD=FILTER", multiple=True, help="Exclude coins that match a filter (-F 'blockbook=[]' -F 'slip44=*')") @click.option("-t", "--exclude-tokens", is_flag=True, help="Exclude ERC20 tokens. Equivalent to '-E erc20'") -@click.option("-d", "--device-include", metavar="NAME", multiple=True, type=device_choice, help="Only include coins supported on these given devices (-d connect -d trezor1)") -@click.option("-D", "--device-exclude", metavar="NAME", multiple=True, type=device_choice, help="Only include coins not supported on these given devices (-D suite -D trezor2)") +@click.option("-d", "--device-include", metavar="NAME", multiple=True, type=device_choice, help="Only include coins supported on these given devices (-d connect -d T1B1)") +@click.option("-D", "--device-exclude", metavar="NAME", multiple=True, type=device_choice, help="Only include coins not supported on these given devices (-D suite -D T2T1)") # fmt: on def dump( outfile: TextIO, @@ -742,7 +742,7 @@ def dump( Also devices can be used as filters. For example to find out which coins are supported in Suite and connect but not on Trezor 1, it is possible to say - '-d suite -d connect -D trezor1'. + '-d suite -d connect -D T1B1'. Includes even the wallet data, unless turned off by '-W'. These can be filtered by using '-f', for example `-f 'wallet=*exodus*'` (* are necessary) diff --git a/common/tools/support.py b/common/tools/support.py index 332dbc69c..01605f0c4 100755 --- a/common/tools/support.py +++ b/common/tools/support.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import json import os import re @@ -225,8 +227,7 @@ def check(ignore_missing): @cli.command() # fmt: off -@click.option("--v1", help="Version for T1 release (default: guess from latest)") -@click.option("--v2", help="Version for TT release (default: guess from latest)") +@click.option("-r", '--releases', multiple=True, type=str, help='Key-value pairs of model and version. E.g. "T2B1=2.6.1"') @click.option("-n", "--dry-run", is_flag=True, help="Do not write changes") @click.option("-f", "--force", is_flag=True, help="Proceed even with bad version/device info") @click.option("--skip-testnets/--no-skip-testnets", default=True, help="Automatically exclude testnets") @@ -234,11 +235,10 @@ def check(ignore_missing): @click.pass_context def release( ctx, - v1, - v2, - dry_run, - force, - skip_testnets, + releases: list[str], + dry_run: bool, + force: bool, + skip_testnets: bool, ): """Release a new Trezor firmware. @@ -248,27 +248,36 @@ def release( The tool will ask you to confirm each added coin. """ - latest_releases = coin_info.latest_releases() + # Transforming the user release input into a dict and validating + user_releases_dict = { + key: val for key, val in (release.split("=") for release in releases) + } + for key in user_releases_dict: + if key not in coin_info.VERSIONED_SUPPORT_INFO: + raise click.ClickException( + f"Unknown device: {key} - allowed are: {coin_info.VERSIONED_SUPPORT_INFO}" + ) - def bump_version(version_tuple): + def bump_version(version_tuple: tuple[int]) -> str: version_list = list(version_tuple) version_list[-1] += 1 return ".".join(str(n) for n in version_list) - # guess `version` if not given - if not v1: - v1 = bump_version(latest_releases["trezor1"]) - if not v2: - v2 = bump_version(latest_releases["trezor2"]) + latest_releases = coin_info.latest_releases() - versions = {"trezor1": v1, "trezor2": v2} + # Take version either from user or guess it from latest releases info + device_release_version: dict[str, str] = {} + for device in coin_info.VERSIONED_SUPPORT_INFO: + if device in user_releases_dict: + device_release_version[device] = user_releases_dict[device] + else: + device_release_version[device] = bump_version(latest_releases[device]) - for number in "1", "2": - device = f"trezor{number}" - version = versions[device] - if not force and not version.startswith(number + "."): + for device, version in device_release_version.items(): + version_starting_num = device[1] # "T1B1" -> "1", "T2B1" -> "2" + if not force and not version.startswith(version_starting_num + "."): raise click.ClickException( - f"Device trezor{device} should not be version {version}. " + f"Device {device} should not be version {version}. " "Use --force to proceed anyway." ) @@ -295,7 +304,7 @@ def release( if not unsupport_reason: return - for device, version in versions.items(): + for device, version in device_release_version.items(): if add: support_setdefault(device, coin["key"], version) else: @@ -311,7 +320,7 @@ def release( for coin in missing_list: if skip_testnets and coin["is_testnet"]: - for device, version in versions.items(): + for device, version in device_release_version.items(): support_setdefault(device, coin["key"], False, "(AUTO) exclude testnet") else: maybe_add(coin) @@ -346,13 +355,13 @@ def set_support_value(key, entries, reason): """Set a support info variable. Examples: - support.py set coin:BTC trezor1=1.10.5 trezor2=2.4.7 suite=yes connect=no - support.py set coin:LTC trezor1=yes connect= + support.py set coin:BTC T1B1=1.10.5 T2T1=2.4.7 suite=yes connect=no + support.py set coin:LTC T1B1=yes connect= Setting a variable to "yes", "true" or "1" sets support to true. Setting a variable to "no", "false" or "0" sets support to false. - (or null, in case of trezor1/2) - Setting variable to empty ("trezor1=") will set to null, or clear the entry. + (or null, in case of T1B1/T2T1) + Setting variable to empty ("T1B1=") will set to null, or clear the entry. Setting a variable to a particular version string (e.g., "2.4.7") will set that particular version. """ diff --git a/core/.changelog.d/2161.changed b/core/.changelog.d/2161.changed new file mode 100644 index 000000000..7adcda321 --- /dev/null +++ b/core/.changelog.d/2161.changed @@ -0,0 +1 @@ +Changed design of the path warning screen (model T only). diff --git a/core/.changelog.d/2937.changed b/core/.changelog.d/2937.changed new file mode 100644 index 000000000..104e40f2d --- /dev/null +++ b/core/.changelog.d/2937.changed @@ -0,0 +1 @@ +Introduce multiple account warning to BTC send flow. diff --git a/core/.changelog.d/2937.changed.1 b/core/.changelog.d/2937.changed.1 new file mode 100644 index 000000000..d9b55d755 --- /dev/null +++ b/core/.changelog.d/2937.changed.1 @@ -0,0 +1 @@ +Introduce multisig warning to BTC receive flow. diff --git a/core/.changelog.d/3047.added b/core/.changelog.d/3047.added new file mode 100644 index 000000000..32c4b05e2 --- /dev/null +++ b/core/.changelog.d/3047.added @@ -0,0 +1 @@ +QR code display when exporting XPUBs. diff --git a/core/.changelog.d/3205.added b/core/.changelog.d/3205.added new file mode 100644 index 000000000..fe4468f37 --- /dev/null +++ b/core/.changelog.d/3205.added @@ -0,0 +1,2 @@ +Added firmware update without interaction. +Split builds of different parts to use simple util.s assembler, while FW+bootloader use interconnected ones. diff --git a/core/.changelog.d/3218.fixed b/core/.changelog.d/3218.fixed new file mode 100644 index 000000000..67e778caa --- /dev/null +++ b/core/.changelog.d/3218.fixed @@ -0,0 +1 @@ +Fix more info button on shamir recovery screen. diff --git a/core/.changelog.d/3237.added b/core/.changelog.d/3237.added new file mode 100644 index 000000000..08672d1dc --- /dev/null +++ b/core/.changelog.d/3237.added @@ -0,0 +1 @@ +Add support for address chunkification in Receive and Sign flow. diff --git a/core/.changelog.d/3255.added b/core/.changelog.d/3255.added new file mode 100644 index 000000000..77f420f8f --- /dev/null +++ b/core/.changelog.d/3255.added @@ -0,0 +1 @@ +Implement device authentication for Model R. diff --git a/core/.changelog.d/3256.added b/core/.changelog.d/3256.added new file mode 100644 index 000000000..90dad1fff --- /dev/null +++ b/core/.changelog.d/3256.added @@ -0,0 +1 @@ +Use Optiga as a source of randomness in seed generation for Model R. diff --git a/core/Makefile b/core/Makefile index 3cbbdccb2..2f5624f4b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -141,7 +141,7 @@ test_emu_ui_record: ## record and hash screens for ui integration tests test_emu_ui_record_multicore: ## quickly record all screens make test_emu_ui_multicore || echo "All errors are recorded in fixtures.json" - ../tests/update_fixtures.py -r + ../tests/update_fixtures.py local -r pylint: ## run pylint on application sources and tests pylint -E $(shell find src tests -name *.py) diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 2e2e69c7e..3622d842a 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -22,7 +22,7 @@ FEATURES_WANTED = ["sd_card"] CCFLAGS_MOD = '' CPPPATH_MOD = [] -CPPDEFINES_MOD = [] +CPPDEFINES_MOD = ["BOARDLOADER"] SOURCE_MOD = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] @@ -71,7 +71,7 @@ SOURCE_BOARDLOADER = [ 'embed/boardloader/main.c', ] -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) @@ -95,7 +95,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index bb6f685a4..f408f1280 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -140,7 +140,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index 181f91402..afffdbc86 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -133,7 +133,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 025ea3f5a..710ab376f 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -128,9 +128,16 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/usb.c', 'embed/trezorhal/unix/random_delays.c', - 'embed/trezorhal/unix/secret.c', ] +if TREZOR_MODEL in ('R', ): + CPPDEFINES_MOD += [ + ('USE_OPTIGA', '1'), + ] + SOURCE_TREZORHAL += [ + 'embed/trezorhal/unix/secret.c', + ] + SOURCE_UNIX = [ 'embed/unix/profile.c', ] @@ -176,7 +183,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 80d905229..55f33fd4e 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -70,8 +70,8 @@ CPPDEFINES_MOD += [ ('USE_ETHEREUM', '1' if EVERYTHING else '0'), ('USE_MONERO', '1' if EVERYTHING else '0'), ('USE_CARDANO', '1' if EVERYTHING else '0'), - ('USE_NEM', '1' if EVERYTHING else '0'), - ('USE_EOS', '1' if EVERYTHING else '0'), + ('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL != "R") else '0'), + ('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL != "R") else '0'), ] SOURCE_MOD += [ 'embed/extmod/trezorobj.c', @@ -80,6 +80,7 @@ SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/rand.c', 'vendor/trezor-crypto/address.c', 'vendor/trezor-crypto/aes/aes_modes.c', + 'vendor/trezor-crypto/aes/aesccm.c', 'vendor/trezor-crypto/aes/aescrypt.c', 'vendor/trezor-crypto/aes/aeskey.c', 'vendor/trezor-crypto/aes/aestab.c', @@ -127,6 +128,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/shamir.c', 'vendor/trezor-crypto/slip39.c', 'vendor/trezor-crypto/slip39_english.c', + 'vendor/trezor-crypto/tls_prf.c', ] if EVERYTHING: SOURCE_MOD += [ @@ -406,7 +408,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' @@ -599,9 +601,10 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/cardano/*/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Cardano*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Eos*.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Eos*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ethereum/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Ethereum*.py')) @@ -612,9 +615,10 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/DebugMonero*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Monero*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/NEM*.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/NEM*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ripple/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Ripple*.py')) @@ -630,7 +634,8 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/webauthn/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/decred.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/decred.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/bitcoinlike.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/zcash_v4.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Zcash*.py')) @@ -639,7 +644,8 @@ if FROZEN: source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY, - backlight='backlight' in FEATURES_AVAILABLE + backlight='backlight' in FEATURES_AVAILABLE, + optiga='optiga' in FEATURES_AVAILABLE ) source_mpyc = env.FrozenCFile( @@ -744,12 +750,12 @@ cmake_gen = env.Command( MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) BOOTLOADER_SUFFIX = MODEL_IDENTIFIER if BOOTLOADER_QA: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin' + VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin' BOOTLOADER_SUFFIX = MODEL_IDENTIFIER + '_qa' elif PRODUCTION: VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_satoshilabs_signed_prod.bin' elif BOOTLOADER_DEVEL: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_unsafe_signed_dev.bin' + VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin' else: VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_unsafe_signed_prod.bin' diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 91ca10753..2cafbd9a1 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -24,6 +24,7 @@ FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mas CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [ + 'AES_128', 'USE_INSECURE_PRNG', ] SOURCE_MOD = [] @@ -50,11 +51,24 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] SOURCE_MOD += [ + 'vendor/trezor-crypto/aes/aes_modes.c', + 'vendor/trezor-crypto/aes/aesccm.c', + 'vendor/trezor-crypto/aes/aescrypt.c', + 'vendor/trezor-crypto/aes/aeskey.c', + 'vendor/trezor-crypto/aes/aestab.c', + 'vendor/trezor-crypto/bignum.c', 'vendor/trezor-crypto/chacha_drbg.c', 'vendor/trezor-crypto/chacha20poly1305/chacha_merged.c', + 'vendor/trezor-crypto/ecdsa.c', + 'vendor/trezor-crypto/hmac.c', + 'vendor/trezor-crypto/hmac_drbg.c', 'vendor/trezor-crypto/memzero.c', + 'vendor/trezor-crypto/nist256p1.c', 'vendor/trezor-crypto/rand.c', + 'vendor/trezor-crypto/rfc6979.c', + 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', + 'vendor/trezor-crypto/tls_prf.c', ] # modtrezorui @@ -80,8 +94,14 @@ SOURCE_PRODTEST = [ 'embed/prodtest/startup.s', 'embed/prodtest/header.S', 'embed/prodtest/main.c', + 'embed/prodtest/prodtest_common.c', ] +if TREZOR_MODEL in ('R',): + SOURCE_PRODTEST += [ + 'embed/prodtest/optiga_prodtest.c', + ] + # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -89,7 +109,7 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) @@ -113,7 +133,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' @@ -167,7 +187,7 @@ MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) if PRODUCTION: VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_prodtest_signed_prod.bin' elif BOOTLOADER_DEVEL: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_unsafe_signed_dev.bin' + VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin' else: VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_unsafe_signed_prod.bin' diff --git a/core/SConscript.reflash b/core/SConscript.reflash index ea2cb2a1f..7e84ceb6f 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -79,7 +79,7 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) @@ -103,7 +103,7 @@ env.Replace( CCFLAGS='$COPT ' '-g3 ' '-nostdlib ' - '-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' + '-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -fno-common ' '-fsingle-precision-constant -fdata-sections -ffunction-sections ' '-ffreestanding ' '-fstack-protector-all ' diff --git a/core/SConscript.unix b/core/SConscript.unix index 2ec3ef33a..e3d9f329e 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -75,8 +75,8 @@ CPPDEFINES_MOD += [ ('USE_ETHEREUM', '1' if EVERYTHING else '0'), ('USE_MONERO', '1' if EVERYTHING else '0'), ('USE_CARDANO', '1' if EVERYTHING else '0'), - ('USE_NEM', '1' if EVERYTHING else '0'), - ('USE_EOS', '1' if EVERYTHING else '0'), + ('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL != "R") else '0'), + ('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL != "R") else '0'), ] SOURCE_MOD += [ 'embed/extmod/trezorobj.c', @@ -390,6 +390,14 @@ if TREZOR_MODEL in ('T', 'R'): 'embed/trezorhal/unix/sdcard.c', ] +if TREZOR_MODEL == 'R': + CPPDEFINES_MOD += [ + ('USE_OPTIGA', '1'), + ] + SOURCE_UNIX += [ + 'embed/trezorhal/unix/optiga.c', + ] + if DMA2D: CPPDEFINES_MOD += [ 'USE_DMA2D', @@ -476,7 +484,7 @@ else: env.Replace( CCFLAGS='$COPT ' '-g3 ' - '-std=gnu99 -Wall -Werror -Wuninitialized -Wno-missing-braces ' + '-std=gnu11 -Wall -Werror -Wuninitialized -Wno-missing-braces ' '-fdata-sections -ffunction-sections -fPIE ' + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', LIBS=['m'], @@ -653,7 +661,9 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/management/*.py', exclude=[ SOURCE_PY_DIR + 'apps/management/sd_protect.py', - ] if TREZOR_MODEL not in ('T',) else []) + ] if TREZOR_MODEL not in ('T',) else [] + [ + SOURCE_PY_DIR + 'apps/management/authenticate_device.py', + ] if TREZOR_MODEL not in ('R',) else []) ) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/management/*/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/misc/*.py')) @@ -674,9 +684,10 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/cardano/*/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Cardano*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Eos*.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/eos/*/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Eos*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ethereum/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Ethereum*.py')) @@ -687,9 +698,10 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/DebugMonero*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Monero*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/NEM*.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/nem/*/*.py')) + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/NEM*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ripple/*.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Ripple*.py')) @@ -705,7 +717,8 @@ if FROZEN: SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/webauthn/*.py')) - SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/decred.py')) + if TREZOR_MODEL != "R": + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/decred.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/bitcoinlike.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/zcash_v4.py')) SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Zcash*.py')) @@ -714,7 +727,8 @@ if FROZEN: source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY, - backlight=TREZOR_MODEL in ('T',) + backlight=TREZOR_MODEL in ('T',), + optiga=TREZOR_MODEL in ('R',) ) source_mpyc = env.FrozenCFile( diff --git a/core/embed/boardloader/.changelog.d/2955.fixed b/core/embed/boardloader/.changelog.d/2955.fixed deleted file mode 100644 index 4f9a09693..000000000 --- a/core/embed/boardloader/.changelog.d/2955.fixed +++ /dev/null @@ -1 +0,0 @@ -Fixed gamma correction settings for Model T diff --git a/core/embed/boardloader/.changelog.d/2989.added b/core/embed/boardloader/.changelog.d/2989.added deleted file mode 100644 index cd2d6b57a..000000000 --- a/core/embed/boardloader/.changelog.d/2989.added +++ /dev/null @@ -1 +0,0 @@ -Added support for STM32F429I-DISC1 board diff --git a/core/embed/boardloader/.changelog.d/3205.added b/core/embed/boardloader/.changelog.d/3205.added new file mode 100644 index 000000000..fe4468f37 --- /dev/null +++ b/core/embed/boardloader/.changelog.d/3205.added @@ -0,0 +1,2 @@ +Added firmware update without interaction. +Split builds of different parts to use simple util.s assembler, while FW+bootloader use interconnected ones. diff --git a/core/embed/boardloader/CHANGELOG.md b/core/embed/boardloader/CHANGELOG.md index 72063b6b1..e46b6e4e9 100644 --- a/core/embed/boardloader/CHANGELOG.md +++ b/core/embed/boardloader/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.1.1 [September 2023] + +### Added +- Added support for STM32F429I-DISC1 board [#2989] + +### Fixed +- Fixed gamma correction settings for Model T [#2955] +- Removed unwanted delay when resetting LCD on the Model R. [#3222] + + ## 2.1.0 [June 2023] Internal only release for Model R prototypes. @@ -30,4 +40,7 @@ Internal only release for Model R prototypes. [#2587]: https://github.com/trezor/trezor-firmware/pull/2587 [#2595]: https://github.com/trezor/trezor-firmware/pull/2595 [#2623]: https://github.com/trezor/trezor-firmware/pull/2623 +[#2955]: https://github.com/trezor/trezor-firmware/pull/2955 +[#2989]: https://github.com/trezor/trezor-firmware/pull/2989 [#3048]: https://github.com/trezor/trezor-firmware/pull/3048 +[#3222]: https://github.com/trezor/trezor-firmware/pull/3222 diff --git a/core/embed/boardloader/version.h b/core/embed/boardloader/version.h index b1e973b88..293ab7ea7 100644 --- a/core/embed/boardloader/version.h +++ b/core/embed/boardloader/version.h @@ -1,4 +1,4 @@ #define VERSION_MAJOR 2 #define VERSION_MINOR 1 -#define VERSION_PATCH 0 +#define VERSION_PATCH 2 #define VERSION_BUILD 0 diff --git a/core/embed/bootloader/.changelog.d/3205.added b/core/embed/bootloader/.changelog.d/3205.added new file mode 100644 index 000000000..fe4468f37 --- /dev/null +++ b/core/embed/bootloader/.changelog.d/3205.added @@ -0,0 +1,2 @@ +Added firmware update without interaction. +Split builds of different parts to use simple util.s assembler, while FW+bootloader use interconnected ones. diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index 68c8f5ab0..065c465de 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -7,6 +7,9 @@ #include "flash.h" #include "model.h" #include "rust_ui.h" +#ifdef USE_OPTIGA +#include "secret.h" +#endif #include "emulator.h" @@ -40,9 +43,17 @@ __attribute__((noreturn)) int main(int argc, char **argv) { (void)ret; } - if (argc == 2 && argv[1][0] == 's') { - // Run the firmware - stay_in_bootloader_flag = STAY_IN_BOOTLOADER_FLAG; + if (argc == 2) { + if (argv[1][0] == 's') { + // Run the firmware + stay_in_bootloader_flag = STAY_IN_BOOTLOADER_FLAG; + } +#ifdef USE_OPTIGA + else if (argv[1][0] == 'l') { + // write bootloader-lock secret + secret_write_header(); + } +#endif } else if (argc == 4) { display_init(); display_backlight(180); diff --git a/core/embed/bootloader/memory.ld b/core/embed/bootloader/memory.ld index 5010b5814..bec4f5080 100644 --- a/core/embed/bootloader/memory.ld +++ b/core/embed/bootloader/memory.ld @@ -23,6 +23,9 @@ ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); sram_start = ORIGIN(SRAM); sram_end = ORIGIN(SRAM) + LENGTH(SRAM); +/* IMAGE_HEADER_SIZE is 0x400, this is for interaction-less firmware update start */ +firmware_header_start = ccmram_end - 0x400; + _codelen = SIZEOF(.flash) + SIZEOF(.data); SECTIONS { diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index c6860b58b..9226b1b80 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -44,6 +44,10 @@ #include "emulator.h" #endif +#if USE_OPTIGA +#include "secret.h" +#endif + #define MSG_HEADER1_LEN 9 #define MSG_HEADER2_LEN 1 @@ -311,6 +315,11 @@ static void send_msg_features(uint8_t iface_num, MSG_SEND_ASSIGN_VALUE(unit_color, unit_variant_get_color()); MSG_SEND_ASSIGN_VALUE(unit_btconly, unit_variant_get_btconly()); } + +#if USE_OPTIGA + MSG_SEND_ASSIGN_VALUE(bootloader_locked, + (secret_bootloader_locked() == sectrue)); +#endif MSG_SEND(Features); } diff --git a/core/embed/bootloader/protob/messages.pb.h b/core/embed/bootloader/protob/messages.pb.h index 9b85a9f31..563cebcaf 100644 --- a/core/embed/bootloader/protob/messages.pb.h +++ b/core/embed/bootloader/protob/messages.pb.h @@ -103,6 +103,8 @@ typedef struct _Features { uint32_t unit_color; bool has_unit_btconly; bool unit_btconly; + bool has_bootloader_locked; + bool bootloader_locked; } Features; typedef struct _FirmwareErase { @@ -154,7 +156,7 @@ extern "C" { /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} +#define Features_init_default {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} #define Ping_init_default {false, ""} #define Success_init_default {false, ""} #define Failure_init_default {false, _FailureType_MIN, false, ""} @@ -166,7 +168,7 @@ extern "C" { #define UnlockBootloader_init_default {0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} +#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} #define Ping_init_zero {false, ""} #define Success_init_zero {false, ""} #define Failure_init_zero {false, _FailureType_MIN, false, ""} @@ -200,6 +202,7 @@ extern "C" { #define Features_internal_model_tag 44 #define Features_unit_color_tag 45 #define Features_unit_btconly_tag 46 +#define Features_bootloader_locked_tag 49 #define FirmwareErase_length_tag 1 #define FirmwareRequest_offset_tag 1 #define FirmwareRequest_length_tag 2 @@ -238,7 +241,8 @@ X(a, STATIC, OPTIONAL, UINT32, fw_patch, 24) \ X(a, STATIC, OPTIONAL, STRING, fw_vendor, 25) \ X(a, STATIC, OPTIONAL, STRING, internal_model, 44) \ X(a, STATIC, OPTIONAL, UINT32, unit_color, 45) \ -X(a, STATIC, OPTIONAL, BOOL, unit_btconly, 46) +X(a, STATIC, OPTIONAL, BOOL, unit_btconly, 46) \ +X(a, STATIC, OPTIONAL, BOOL, bootloader_locked, 49) #define Features_CALLBACK NULL #define Features_DEFAULT NULL @@ -322,7 +326,7 @@ extern const pb_msgdesc_t UnlockBootloader_msg; #define ButtonAck_size 0 #define ButtonRequest_size 2 #define Failure_size 260 -#define Features_size 487 +#define Features_size 490 #define FirmwareErase_size 6 #define FirmwareRequest_size 12 #define GetFeatures_size 0 diff --git a/core/embed/bootloader/protob/messages.proto b/core/embed/bootloader/protob/messages.proto index 4149460d6..bfe08db48 100644 --- a/core/embed/bootloader/protob/messages.proto +++ b/core/embed/bootloader/protob/messages.proto @@ -61,6 +61,7 @@ message Features { optional string internal_model = 44; // internal model name optional uint32 unit_color = 45; // color of the unit/device optional bool unit_btconly = 46; // unit/device is intended as bitcoin only + optional bool bootloader_locked = 49; // bootloader is locked } /** diff --git a/core/embed/bootloader/startup.s b/core/embed/bootloader/startup.s index 5104f0db9..20044d5a9 100644 --- a/core/embed/bootloader/startup.s +++ b/core/embed/bootloader/startup.s @@ -7,7 +7,7 @@ reset_handler: // setup environment for subsequent stage of code ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM + ldr r1, =firmware_header_start // r1 - point to byte where firmware image header might start ldr r2, =0 // r2 - the word-sized value to be written bl memset_reg diff --git a/core/embed/bootloader_ci/.changelog.d/3205.added b/core/embed/bootloader_ci/.changelog.d/3205.added new file mode 100644 index 000000000..fe4468f37 --- /dev/null +++ b/core/embed/bootloader_ci/.changelog.d/3205.added @@ -0,0 +1,2 @@ +Added firmware update without interaction. +Split builds of different parts to use simple util.s assembler, while FW+bootloader use interconnected ones. diff --git a/core/embed/bootloader_ci/memory.ld b/core/embed/bootloader_ci/memory.ld index 2015d0f9b..9c89cc634 100644 --- a/core/embed/bootloader_ci/memory.ld +++ b/core/embed/bootloader_ci/memory.ld @@ -23,6 +23,9 @@ ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); sram_start = ORIGIN(SRAM); sram_end = ORIGIN(SRAM) + LENGTH(SRAM); +/* IMAGE_HEADER_SIZE is 0x400, this is for interaction-less firmware update start */ +firmware_header_start = ccmram_end - 0x400; + _codelen = SIZEOF(.flash) + SIZEOF(.data); SECTIONS { diff --git a/core/embed/bootloader_ci/startup.s b/core/embed/bootloader_ci/startup.s index 5104f0db9..101e222c5 100644 --- a/core/embed/bootloader_ci/startup.s +++ b/core/embed/bootloader_ci/startup.s @@ -7,7 +7,7 @@ reset_handler: // setup environment for subsequent stage of code ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM + ldr r1, =firmware_header_start // r1 - point to byte where firmware header starts ldr r2, =0 // r2 - the word-sized value to be written bl memset_reg diff --git a/core/embed/extmod/modtrezorconfig/norcow_config.h b/core/embed/extmod/modtrezorconfig/norcow_config.h index 7b43fa41b..5104f1023 100644 --- a/core/embed/extmod/modtrezorconfig/norcow_config.h +++ b/core/embed/extmod/modtrezorconfig/norcow_config.h @@ -26,15 +26,6 @@ #define NORCOW_HEADER_LEN 0 #define NORCOW_SECTOR_COUNT 2 -#if defined TREZOR_MODEL_T || defined TREZOR_MODEL_R || \ - defined TREZOR_MODEL_DISC1 -#define NORCOW_SECTOR_SIZE (64 * 1024) -#elif defined TREZOR_MODEL_1 -#define NORCOW_SECTOR_SIZE (16 * 1024) -#else -#error Unknown Trezor model -#endif - /* * Current storage version. */ diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h index c946ea380..afae08650 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h @@ -358,6 +358,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj, #if !BITCOIN_ONLY +#if USE_NEM /// def nem_address(self, network: int) -> str: /// """ /// Compute a NEM address string from the HD node. @@ -425,6 +426,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( mod_trezorcrypto_HDNode_nem_encrypt_obj, 5, 5, mod_trezorcrypto_HDNode_nem_encrypt); +#endif + /// def ethereum_pubkeyhash(self) -> bytes: /// """ /// Compute an Ethereum pubkeyhash (aka address) from the HD node. @@ -484,10 +487,12 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj)}, #if !BITCOIN_ONLY +#if USE_NEM {MP_ROM_QSTR(MP_QSTR_nem_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_address_obj)}, {MP_ROM_QSTR(MP_QSTR_nem_encrypt), MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_encrypt_obj)}, +#endif {MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash), MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj)}, #endif diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h new file mode 100644 index 000000000..08a77d8a4 --- /dev/null +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h @@ -0,0 +1,134 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if USE_OPTIGA + +#include "py/objstr.h" + +#include "optiga.h" +#include "optiga_commands.h" + +/// package: trezorcrypto.optiga + +#define MAX_DER_SIGNATURE_SIZE 72 + +/// class OptigaError(Exception): +/// """Error returned by the Optiga chip.""" +MP_DEFINE_EXCEPTION(OptigaError, Exception) +/// class SigningInaccessible(OptigaError): +/// """The signing key is inaccessible. +/// Typically, this will happen after the bootloader has been unlocked. +/// """ +MP_DEFINE_EXCEPTION(SigningInaccessible, OptigaError) + +/// mock:global +/// def get_certificate(cert_index: int) -> bytes: +/// """ +/// Return the certificate stored at the given index. +/// """ +STATIC mp_obj_t mod_trezorcrypto_optiga_get_certificate(mp_obj_t cert_index) { + mp_int_t idx = mp_obj_get_int(cert_index); + if (idx < 0 || idx >= OPTIGA_CERT_COUNT) { + mp_raise_ValueError("Invalid index."); + } + + size_t cert_size = 0; + if (!optiga_cert_size(idx, &cert_size)) { + mp_raise_msg(&mp_type_OptigaError, "Failed to get certificate size."); + } + + vstr_t cert = {0}; + vstr_init_len(&cert, cert_size); + if (!optiga_read_cert(idx, (uint8_t *)cert.buf, cert.alloc, &cert_size)) { + vstr_clear(&cert); + mp_raise_msg(&mp_type_OptigaError, "Failed to read certificate."); + } + + cert.len = cert_size; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &cert); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_optiga_get_certificate_obj, + mod_trezorcrypto_optiga_get_certificate); + +/// def sign( +/// key_index: int, +/// digest: bytes, +/// ) -> bytes: +/// """ +/// Uses the private key at key_index to produce a DER-encoded signature of +/// the digest. +/// """ +STATIC mp_obj_t mod_trezorcrypto_optiga_sign(mp_obj_t key_index, + mp_obj_t digest) { + mp_int_t idx = mp_obj_get_int(key_index); + if (idx < 0 || idx >= OPTIGA_ECC_KEY_COUNT) { + mp_raise_ValueError("Invalid index."); + } + + mp_buffer_info_t dig = {0}; + mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ); + if (dig.len != 32) { + mp_raise_ValueError("Invalid length of digest."); + } + + vstr_t sig = {0}; + vstr_init_len(&sig, MAX_DER_SIGNATURE_SIZE); + size_t sig_size = 0; + int ret = optiga_sign(idx, (const uint8_t *)dig.buf, dig.len, + ((uint8_t *)sig.buf), sig.alloc, &sig_size); + if (ret != 0) { + vstr_clear(&sig); + if (ret == OPTIGA_ERR_ACCESS_COND_NOT_SAT) { + mp_raise_msg(&mp_type_SigningInaccessible, "Signing inaccessible."); + } else { + mp_raise_msg(&mp_type_OptigaError, "Signing failed."); + } + } + + sig.len = sig_size; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_optiga_sign_obj, + mod_trezorcrypto_optiga_sign); + +/// DEVICE_CERT_INDEX: int +/// DEVICE_ECC_KEY_INDEX: int + +STATIC const mp_rom_map_elem_t mod_trezorcrypto_optiga_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_optiga)}, + {MP_ROM_QSTR(MP_QSTR_get_certificate), + MP_ROM_PTR(&mod_trezorcrypto_optiga_get_certificate_obj)}, + {MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_optiga_sign_obj)}, + {MP_ROM_QSTR(MP_QSTR_DEVICE_CERT_INDEX), + MP_ROM_INT(OPTIGA_DEVICE_CERT_INDEX)}, + {MP_ROM_QSTR(MP_QSTR_DEVICE_ECC_KEY_INDEX), + MP_ROM_INT(OPTIGA_DEVICE_ECC_KEY_INDEX)}, + {MP_ROM_QSTR(MP_QSTR_OptigaError), MP_ROM_PTR(&mp_type_OptigaError)}, + {MP_ROM_QSTR(MP_QSTR_SigningInaccessible), + MP_ROM_PTR(&mp_type_SigningInaccessible)}}; +STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_optiga_globals, + mod_trezorcrypto_optiga_globals_table); + +STATIC const mp_obj_module_t mod_trezorcrypto_optiga_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&mod_trezorcrypto_optiga_globals, +}; + +#endif diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h index 61030ffc4..ecfba7eb2 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h @@ -23,6 +23,10 @@ #include "rand.h" +#if USE_OPTIGA +#include "optiga.h" +#endif + /// package: trezorcrypto.random /// def uniform(n: int) -> int: @@ -40,22 +44,52 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_uniform_obj, mod_trezorcrypto_random_uniform); /// import builtins -/// def bytes(len: int) -> builtins.bytes: +/// def bytes(len: int, strong: bool = False) -> builtins.bytes: /// """ -/// Generate random bytes sequence of length len. +/// Generate random bytes sequence of length len. If `strong` is set then +/// maximum sources of entropy are used. /// """ -STATIC mp_obj_t mod_trezorcrypto_random_bytes(mp_obj_t len) { - uint32_t l = trezor_obj_get_uint(len); - if (l > 1024) { +STATIC mp_obj_t mod_trezorcrypto_random_bytes(size_t n_args, + const mp_obj_t *args) { + uint32_t len = trezor_obj_get_uint(args[0]); + if (len > 1024) { mp_raise_ValueError("Maximum requested size is 1024"); } vstr_t vstr = {0}; - vstr_init_len(&vstr, l); - random_buffer((uint8_t *)vstr.buf, l); + vstr_init_len(&vstr, len); +#if USE_OPTIGA + if (n_args > 1 && mp_obj_is_true(args[1])) { + uint8_t *dest = (uint8_t *)vstr.buf; + if (!optiga_random_buffer(dest, len)) { + vstr_clear(&vstr); + mp_raise_msg(&mp_type_RuntimeError, + "Failed to get randomness from Optiga."); + } + + uint8_t buffer[4] = {0}; + while (len > sizeof(buffer)) { + random_buffer(buffer, sizeof(buffer)); + for (int i = 0; i < sizeof(buffer); ++i) { + *dest ^= buffer[i]; + ++dest; + } + len -= sizeof(buffer); + } + + random_buffer(buffer, len); + for (int i = 0; i < len; ++i) { + *dest ^= buffer[i]; + ++dest; + } + } else +#endif + { + random_buffer((uint8_t *)vstr.buf, len); + } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_bytes_obj, - mod_trezorcrypto_random_bytes); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_random_bytes_obj, 1, + 2, mod_trezorcrypto_random_bytes); /// def shuffle(data: list) -> None: /// """ diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c index 8faec791a..78357644b 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c @@ -64,6 +64,9 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) { #include "modtrezorcrypto-sha512.h" #include "modtrezorcrypto-shamir.h" #include "modtrezorcrypto-slip39.h" +#ifdef USE_OPTIGA +#include "modtrezorcrypto-optiga.h" +#endif #if !BITCOIN_ONLY #include "modtrezorcrypto-cardano.h" #include "modtrezorcrypto-monero.h" @@ -120,6 +123,9 @@ STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = { MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_type)}, {MP_ROM_QSTR(MP_QSTR_shamir), MP_ROM_PTR(&mod_trezorcrypto_shamir_module)}, {MP_ROM_QSTR(MP_QSTR_slip39), MP_ROM_PTR(&mod_trezorcrypto_slip39_module)}, +#if USE_OPTIGA + {MP_ROM_QSTR(MP_QSTR_optiga), MP_ROM_PTR(&mod_trezorcrypto_optiga_module)}, +#endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_trezorcrypto_globals, mp_module_trezorcrypto_globals_table); diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c index fc9161543..4a38864b0 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils.c +++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c @@ -43,6 +43,10 @@ #include "image.h" #endif +#if USE_OPTIGA && !defined(TREZOR_EMULATOR) +#include "secret.h" +#endif + static void ui_progress(mp_obj_t ui_wait_callback, uint32_t current, uint32_t total) { if (mp_obj_is_callable(ui_wait_callback)) { @@ -254,6 +258,26 @@ STATIC mp_obj_t mod_trezorutils_reboot_to_bootloader() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_reboot_to_bootloader_obj, mod_trezorutils_reboot_to_bootloader); +/// def bootloader_locked() -> bool | None: +/// """ +/// Returns True/False if the the bootloader is locked/unlocked and None if +/// the feature is not supported. +/// """ +STATIC mp_obj_t mod_trezorutils_bootloader_locked() { +#if USE_OPTIGA +#ifdef TREZOR_EMULATOR + return mp_const_true; +#else + return (secret_bootloader_locked() == sectrue) ? mp_const_true + : mp_const_false; +#endif +#else + return mp_const_none; +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_bootloader_locked_obj, + mod_trezorutils_bootloader_locked); + STATIC mp_obj_str_t mod_trezorutils_revision_obj = { {&mp_type_bytes}, 0, sizeof(SCM_REVISION) - 1, (const byte *)SCM_REVISION}; @@ -266,6 +290,7 @@ STATIC mp_obj_str_t mod_trezorutils_model_name_obj = { /// VERSION_PATCH: int /// USE_SD_CARD: bool /// USE_BACKLIGHT: bool +/// USE_OPTIGA: bool /// MODEL: str /// INTERNAL_MODEL: str /// EMULATOR: bool @@ -282,6 +307,8 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { MP_ROM_PTR(&mod_trezorutils_firmware_vendor_obj)}, {MP_ROM_QSTR(MP_QSTR_reboot_to_bootloader), MP_ROM_PTR(&mod_trezorutils_reboot_to_bootloader_obj)}, + {MP_ROM_QSTR(MP_QSTR_bootloader_locked), + MP_ROM_PTR(&mod_trezorutils_bootloader_locked_obj)}, {MP_ROM_QSTR(MP_QSTR_unit_color), MP_ROM_PTR(&mod_trezorutils_unit_color_obj)}, {MP_ROM_QSTR(MP_QSTR_unit_btconly), @@ -301,6 +328,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_USE_BACKLIGHT), mp_const_true}, #else {MP_ROM_QSTR(MP_QSTR_USE_BACKLIGHT), mp_const_false}, +#endif +#ifdef USE_OPTIGA + {MP_ROM_QSTR(MP_QSTR_USE_OPTIGA), mp_const_true}, +#else + {MP_ROM_QSTR(MP_QSTR_USE_OPTIGA), mp_const_false}, #endif {MP_ROM_QSTR(MP_QSTR_MODEL), MP_ROM_PTR(&mod_trezorutils_model_name_obj)}, {MP_ROM_QSTR(MP_QSTR_INTERNAL_MODEL), diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index 7674d0fff..b3d206d89 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -43,6 +43,7 @@ #include "display.h" #include "flash.h" #include "image.h" +#include "memzero.h" #include "model.h" #include "mpu.h" #include "random_delays.h" @@ -71,7 +72,9 @@ #include "sdcard.h" #endif #ifdef USE_OPTIGA +#include "optiga_commands.h" #include "optiga_transport.h" +#include "secret.h" #endif #include "unit_variant.h" @@ -113,6 +116,12 @@ int main(void) { unit_variant_init(); +#ifdef USE_OPTIGA + uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; + secbool secret_ok = + secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); +#endif + #if PRODUCTION || BOOTLOADER_QA check_and_replace_bootloader(); #endif @@ -162,6 +171,11 @@ int main(void) { #ifdef USE_OPTIGA optiga_init(); + optiga_open_application(); + if (sectrue == secret_ok) { + optiga_sec_chan_handshake(secret, sizeof(secret)); + } + memzero(secret, sizeof(secret)); #endif #if !defined TREZOR_MODEL_1 @@ -231,14 +245,20 @@ void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } __attribute__((noreturn)) void reboot_to_bootloader() { + mpu_config_bootloader(); jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, STAY_IN_BOOTLOADER_FLAG); for (;;) ; } +void copy_image_header_for_bootloader(const uint8_t *image_header) { + memcpy(&firmware_header_start, image_header, IMAGE_HEADER_SIZE); +} + void SVC_C_Handler(uint32_t *stack) { uint8_t svc_number = ((uint8_t *)stack[6])[-2]; + bool clear_firmware_header = true; switch (svc_number) { case SVC_ENABLE_IRQ: HAL_NVIC_EnableIRQ(stack[0]); @@ -259,9 +279,19 @@ void SVC_C_Handler(uint32_t *stack) { for (;;) ; break; + case SVC_REBOOT_COPY_IMAGE_HEADER: + copy_image_header_for_bootloader((uint8_t *)stack[0]); + clear_firmware_header = false; + // break is omitted here because we want to continue to reboot below case SVC_REBOOT_TO_BOOTLOADER: + // if not going from copy image header & reboot, clean preventively this + // part of CCMRAM + if (clear_firmware_header) { + explicit_bzero(&firmware_header_start, IMAGE_HEADER_SIZE); + } + ensure_compatible_settings(); - mpu_config_bootloader(); + __asm__ volatile("msr control, %0" ::"r"(0x0)); __asm__ volatile("isb"); // See stack layout in diff --git a/core/embed/firmware/memory_T.ld b/core/embed/firmware/memory_T.ld index 454daa953..82008aaad 100644 --- a/core/embed/firmware/memory_T.ld +++ b/core/embed/firmware/memory_T.ld @@ -22,6 +22,9 @@ data_size = SIZEOF(.data); ccmram_start = ORIGIN(CCMRAM); ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); +/* IMAGE_HEADER_SIZE is 0x400, this is for interaction-less firmware update start */ +firmware_header_start = ccmram_end - 0x400; + /* used by the startup code to wipe memory */ sram_start = ORIGIN(SRAM); sram_end = ORIGIN(SRAM) + LENGTH(SRAM); diff --git a/core/embed/models/model_D001.h b/core/embed/models/model_D001.h index e0af43663..1d7ddac43 100644 --- a/core/embed/models/model_D001.h +++ b/core/embed/models/model_D001.h @@ -23,5 +23,6 @@ #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB +#define NORCOW_SECTOR_SIZE (64 * 1024) #endif diff --git a/core/embed/models/model_T1B1.h b/core/embed/models/model_T1B1.h index e9f3230c7..36cf6f591 100644 --- a/core/embed/models/model_T1B1.h +++ b/core/embed/models/model_T1B1.h @@ -11,5 +11,6 @@ #define BOOTLOADER_IMAGE_MAXSIZE (32 * 1024 * 1) // 32 KB #define FIRMWARE_IMAGE_MAXSIZE (64 * 1024 * 15) // 960 KB +#define NORCOW_SECTOR_SIZE (16 * 1024) #endif diff --git a/core/embed/models/model_T2B1.h b/core/embed/models/model_T2B1.h index 5657e4a50..e04b34914 100644 --- a/core/embed/models/model_T2B1.h +++ b/core/embed/models/model_T2B1.h @@ -23,5 +23,6 @@ #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB +#define NORCOW_SECTOR_SIZE (64 * 1024) #endif diff --git a/core/embed/models/model_T2T1.h b/core/embed/models/model_T2T1.h index c79da28f8..68b57d190 100644 --- a/core/embed/models/model_T2T1.h +++ b/core/embed/models/model_T2T1.h @@ -23,5 +23,6 @@ #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB +#define NORCOW_SECTOR_SIZE (64 * 1024) #endif diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 399a8d9bc..98d3f028a 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -28,17 +28,24 @@ #include "display.h" #include "flash.h" #include "i2c.h" -#include "mini_printf.h" #include "model.h" +#include "mpu.h" +#include "prodtest_common.h" #include "random_delays.h" -#include "rng.h" #include "sbu.h" #include "sdcard.h" #include "secbool.h" #include "touch.h" #include "usb.h" +#ifdef USE_OPTIGA +#include "optiga_commands.h" +#include "optiga_prodtest.h" +#include "optiga_transport.h" +#endif + #include "memzero.h" +#include "stm32f4xx_ll_utils.h" #ifdef TREZOR_MODEL_T #define MODEL_IDENTIFIER "TREZOR2-" @@ -46,8 +53,6 @@ #define MODEL_IDENTIFIER "T2B1-" #endif -enum { VCP_IFACE = 0x00 }; - static secbool startswith(const char *s, const char *prefix) { return sectrue * (0 == strncmp(s, prefix, strlen(prefix))); } @@ -57,11 +62,6 @@ static void vcp_intr(void) { ensure(secfalse, "vcp_intr"); } -static void vcp_puts(const char *s, size_t len) { - int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *)s, len, -1); - (void)r; -} - static char vcp_getchar(void) { uint8_t c = 0; int r = usb_vcp_read_blocking(VCP_IFACE, &c, 1, -1); @@ -91,16 +91,6 @@ static void vcp_readline(char *buf, size_t len) { } } -static void vcp_printf(const char *fmt, ...) { - static char buf[128]; - va_list va; - va_start(va, fmt); - int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); - va_end(va); - vcp_puts(buf, r); - vcp_puts("\r\n", 2); -} - static void usb_init_all(void) { enum { VCP_PACKET_LEN = 64, @@ -160,7 +150,7 @@ static void draw_border(int width, int padding) { static void test_border(void) { draw_border(2, 0); - vcp_printf("OK"); + vcp_println("OK"); } static void test_display(const char *colors) { @@ -185,10 +175,10 @@ static void test_display(const char *colors) { c = 0xFFFF; break; } - display_bar(i * w, 0, i * w + w, 240, c); + display_bar(i * w, 0, i * w + w, DISPLAY_RESY, c); } display_refresh(); - vcp_printf("OK"); + vcp_println("OK"); } #ifdef USE_BUTTON @@ -196,13 +186,13 @@ static void test_display(const char *colors) { static secbool test_btn_press(uint32_t deadline, uint32_t btn) { while (button_read() != (btn | BTN_EVT_DOWN)) { if (HAL_GetTick() > deadline) { - vcp_printf("ERROR TIMEOUT"); + vcp_println("ERROR TIMEOUT"); return secfalse; } } while (button_read() != (btn | BTN_EVT_UP)) { if (HAL_GetTick() > deadline) { - vcp_printf("ERROR TIMEOUT"); + vcp_println("ERROR TIMEOUT"); return secfalse; } } @@ -231,7 +221,7 @@ static secbool test_btn_all(uint32_t deadline) { break; } if (HAL_GetTick() > deadline) { - vcp_printf("ERROR TIMEOUT"); + vcp_println("ERROR TIMEOUT"); return secfalse; } } @@ -254,7 +244,7 @@ static secbool test_btn_all(uint32_t deadline) { break; } if (HAL_GetTick() > deadline) { - vcp_printf("ERROR TIMEOUT"); + vcp_println("ERROR TIMEOUT"); return secfalse; } } @@ -268,21 +258,21 @@ static void test_button(const char *args) { timeout = args[5] - '0'; uint32_t deadline = HAL_GetTick() + timeout * 1000; secbool r = test_btn_press(deadline, BTN_LEFT); - if (r == sectrue) vcp_printf("OK"); + if (r == sectrue) vcp_println("OK"); } if (startswith(args, "RIGHT ")) { timeout = args[6] - '0'; uint32_t deadline = HAL_GetTick() + timeout * 1000; secbool r = test_btn_press(deadline, BTN_RIGHT); - if (r == sectrue) vcp_printf("OK"); + if (r == sectrue) vcp_println("OK"); } if (startswith(args, "BOTH ")) { timeout = args[5] - '0'; uint32_t deadline = HAL_GetTick() + timeout * 1000; secbool r = test_btn_all(deadline); - if (r == sectrue) vcp_printf("OK"); + if (r == sectrue) vcp_println("OK"); } } @@ -335,9 +325,9 @@ static void test_touch(const char *args) { if (touch_click_timeout(&evt, timeout * 1000)) { uint16_t x = touch_unpack_x(evt); uint16_t y = touch_unpack_y(evt); - vcp_printf("OK %d %d", x, y); + vcp_println("OK %d %d", x, y); } else { - vcp_printf("ERROR TIMEOUT"); + vcp_println("ERROR TIMEOUT"); } display_clear(); display_refresh(); @@ -377,7 +367,7 @@ static void test_pwm(const char *args) { display_backlight(v); display_refresh(); - vcp_printf("OK"); + vcp_println("OK"); } #ifdef USE_SD_CARD @@ -387,13 +377,13 @@ static void test_sd(void) { static uint32_t buf2[BLOCK_SIZE / sizeof(uint32_t)]; if (sectrue != sdcard_is_present()) { - vcp_printf("ERROR NOCARD"); + vcp_println("ERROR NOCARD"); return; } ensure(sdcard_power_on(), NULL); if (sectrue != sdcard_read_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) { - vcp_printf("ERROR sdcard_read_blocks (0)"); + vcp_println("ERROR sdcard_read_blocks (0)"); goto power_off; } for (int j = 1; j <= 2; j++) { @@ -402,21 +392,21 @@ static void test_sd(void) { } if (sectrue != sdcard_write_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) { - vcp_printf("ERROR sdcard_write_blocks (%d)", j); + vcp_println("ERROR sdcard_write_blocks (%d)", j); goto power_off; } HAL_Delay(1000); if (sectrue != sdcard_read_blocks(buf2, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) { - vcp_printf("ERROR sdcard_read_blocks (%d)", j); + vcp_println("ERROR sdcard_read_blocks (%d)", j); goto power_off; } if (0 != memcmp(buf1, buf2, sizeof(buf1))) { - vcp_printf("ERROR DATA MISMATCH"); + vcp_println("ERROR DATA MISMATCH"); goto power_off; } } - vcp_printf("OK"); + vcp_println("OK"); power_off: sdcard_power_off(); @@ -436,7 +426,7 @@ static void test_wipe(void) { display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); display_refresh(); - vcp_printf("OK"); + vcp_println("OK"); } #ifdef USE_SBU @@ -444,7 +434,7 @@ static void test_sbu(const char *args) { secbool sbu1 = sectrue * (args[0] == '1'); secbool sbu2 = sectrue * (args[1] == '1'); sbu_set(sbu1, sbu2); - vcp_printf("OK"); + vcp_println("OK"); } #endif @@ -463,9 +453,9 @@ static void test_otp_read(void) { // use (null) for empty data if (data[0] == 0x00) { - vcp_printf("OK (null)"); + vcp_println("OK (null)"); } else { - vcp_printf("OK %s", (const char *)data); + vcp_println("OK %s", (const char *)data); } } @@ -477,10 +467,23 @@ static void test_otp_write(const char *args) { sizeof(data)), NULL); ensure(flash_otp_lock(FLASH_OTP_BLOCK_BATCH), NULL); - vcp_printf("OK"); + vcp_println("OK"); } static void test_otp_write_device_variant(const char *args) { +#ifdef USE_OPTIGA + optiga_locked_status status = get_optiga_locked_status(); + if (status == OPTIGA_LOCKED_FALSE) { + vcp_println("ERROR NOT LOCKED"); + return; + } + + if (status != OPTIGA_LOCKED_TRUE) { + // Error reported by get_optiga_locked_status(). + return; + } +#endif + volatile char data[32]; memzero((char *)data, sizeof(data)); data[0] = 1; @@ -513,7 +516,17 @@ static void test_otp_write_device_variant(const char *args) { (const uint8_t *)data, sizeof(data)), NULL); ensure(flash_otp_lock(FLASH_OTP_BLOCK_DEVICE_VARIANT), NULL); - vcp_printf("OK"); + vcp_println("OK"); +} + +void cpuid_read(void) { + uint32_t cpuid[3]; + cpuid[0] = LL_GetUID_Word0(); + cpuid[1] = LL_GetUID_Word1(); + cpuid[2] = LL_GetUID_Word2(); + + vcp_print("OK "); + vcp_println_hex((uint8_t *)cpuid, sizeof(cpuid)); } #define BACKLIGHT_NORMAL 150 @@ -528,8 +541,10 @@ int main(void) { #ifdef USE_BUTTON button_init(); #endif -#ifdef USE_TOUCH +#ifdef USE_I2C i2c_init(); +#endif +#ifdef USE_TOUCH touch_init(); #endif #ifdef USE_SBU @@ -537,6 +552,15 @@ int main(void) { #endif usb_init_all(); +#ifdef USE_OPTIGA + optiga_init(); + optiga_open_application(); + pair_optiga(); +#endif + + mpu_config_prodtest(); + drop_privileges(); + display_clear(); draw_border(1, 3); @@ -551,13 +575,17 @@ int main(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); - char line[128]; + char line[2048]; // expecting hundreds of bytes represented as hexadecimal + // characters for (;;) { vcp_readline(line, sizeof(line)); if (startswith(line, "PING")) { - vcp_printf("OK"); + vcp_println("OK"); + + } else if (startswith(line, "CPUID READ")) { + cpuid_read(); } else if (startswith(line, "BORDER")) { test_border(); @@ -584,6 +612,29 @@ int main(void) { #ifdef USE_SBU } else if (startswith(line, "SBU ")) { test_sbu(line + 4); +#endif +#ifdef USE_OPTIGA + } else if (startswith(line, "OPTIGAID READ")) { + optigaid_read(); + } else if (startswith(line, "CERTINF READ")) { + cert_read(OID_CERT_INF); + } else if (startswith(line, "CERTDEV WRITE ")) { + cert_write(OID_CERT_DEV, line + 14); + } else if (startswith(line, "CERTDEV READ")) { + cert_read(OID_CERT_DEV); + } else if (startswith(line, "CERTFIDO WRITE ")) { + cert_write(OID_CERT_FIDO, line + 15); + } else if (startswith(line, "CERTFIDO READ")) { + cert_read(OID_CERT_FIDO); + } else if (startswith(line, "KEYFIDO WRITE ")) { + keyfido_write(line + 14); + } else if (startswith(line, "KEYFIDO READ")) { + pubkey_read(OID_KEY_FIDO); + } else if (startswith(line, "LOCK")) { + optiga_lock(); + } else if (startswith(line, "CHECK LOCKED")) { + check_locked(); + #endif } else if (startswith(line, "OTP READ")) { @@ -599,7 +650,7 @@ int main(void) { test_wipe(); } else { - vcp_printf("UNKNOWN"); + vcp_println("UNKNOWN"); } } diff --git a/core/embed/prodtest/optiga_prodtest.c b/core/embed/prodtest/optiga_prodtest.c new file mode 100644 index 000000000..924659a65 --- /dev/null +++ b/core/embed/prodtest/optiga_prodtest.c @@ -0,0 +1,500 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "optiga_prodtest.h" +#include "aes/aes.h" +#include "ecdsa.h" +#include "memzero.h" +#include "nist256p1.h" +#include "optiga_commands.h" +#include "optiga_transport.h" +#include "prodtest_common.h" +#include "rand.h" +#include "secret.h" +#include "sha2.h" + +typedef enum { + OPTIGA_PAIRING_UNPAIRED = 0, + OPTIGA_PAIRING_PAIRED, + OPTIGA_PAIRING_ERR_RNG, + OPTIGA_PAIRING_ERR_READ, + OPTIGA_PAIRING_ERR_HANDSHAKE, +} optiga_pairing; + +static optiga_pairing optiga_pairing_state = OPTIGA_PAIRING_UNPAIRED; + +// Data object access conditions. +static const optiga_metadata_item ACCESS_PAIRED = + OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_CONF, OID_KEY_PAIRING); +static const optiga_metadata_item KEY_USE_SIGN = { + (const uint8_t[]){OPTIGA_KEY_USAGE_SIGN}, 1}; +static const optiga_metadata_item TYPE_PTFBIND = { + (const uint8_t[]){OPTIGA_DATA_TYPE_PTFBIND}, 1}; + +static bool optiga_paired(void) { + const char *details = ""; + + switch (optiga_pairing_state) { + case OPTIGA_PAIRING_PAIRED: + return true; + case OPTIGA_PAIRING_ERR_RNG: + details = "optiga_get_random error"; + break; + case OPTIGA_PAIRING_ERR_READ: + details = "failed to read pairing secret"; + break; + case OPTIGA_PAIRING_ERR_HANDSHAKE: + details = "optiga_sec_chan_handshake"; + break; + default: + break; + } + + vcp_println("ERROR Optiga not paired (%s).", details); + return false; +} + +static bool set_metadata(uint16_t oid, const optiga_metadata *metadata) { + uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0}; + size_t size = 0; + optiga_result ret = optiga_serialize_metadata(metadata, serialized, + sizeof(serialized), &size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_serialize_metadata error %d for OID 0x%04x.", ret, + oid); + return false; + } + + optiga_set_data_object(oid, true, serialized, size); + + ret = + optiga_get_data_object(oid, true, serialized, sizeof(serialized), &size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_get_metadata error %d for OID 0x%04x.", ret, oid); + return false; + } + + optiga_metadata metadata_stored = {0}; + ret = optiga_parse_metadata(serialized, size, &metadata_stored); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_parse_metadata error %d.", ret); + return false; + } + + if (!optiga_compare_metadata(metadata, &metadata_stored)) { + vcp_println("ERROR optiga_compare_metadata failed."); + return false; + } + + return true; +} + +void pair_optiga(void) { + // The pairing key may already be written and locked. The success of the + // pairing procedure is determined by optiga_sec_chan_handshake(). Therefore + // it is OK for some of the intermediate operations to fail. + + // Enable writing the pairing secret to OPTIGA. + optiga_metadata metadata = {0}; + metadata.change = OPTIGA_ACCESS_ALWAYS; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + metadata.data_type = TYPE_PTFBIND; + set_metadata(OID_KEY_PAIRING, &metadata); // Ignore result. + + // Generate pairing secret. + uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; + optiga_result ret = optiga_get_random(secret, sizeof(secret)); + if (OPTIGA_SUCCESS != ret) { + optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG; + return; + } + + // Store pairing secret. + ret = optiga_set_data_object(OID_KEY_PAIRING, false, secret, sizeof(secret)); + if (OPTIGA_SUCCESS == ret) { + secret_erase(); + secret_write_header(); + secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + } + + // Verify whether the secret was stored correctly in flash and OPTIGA. + memzero(secret, sizeof(secret)); + if (secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN) != + sectrue) { + optiga_pairing_state = OPTIGA_PAIRING_ERR_READ; + return; + } + + ret = optiga_sec_chan_handshake(secret, sizeof(secret)); + memzero(secret, sizeof(secret)); + if (OPTIGA_SUCCESS != ret) { + optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE; + return; + } + + optiga_pairing_state = OPTIGA_PAIRING_PAIRED; + return; +} + +void optiga_lock(void) { + if (!optiga_paired()) return; + + // Delete trust anchor. + optiga_result ret = + optiga_set_data_object(OID_TRUST_ANCHOR, false, (const uint8_t *)"\0", 1); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_set_data error %d for 0x%04x.", ret, + OID_TRUST_ANCHOR); + return; + } + + // Set data object metadata. + optiga_metadata metadata = {0}; + + // Set metadata for device certificate. + memzero(&metadata, sizeof(metadata)); + metadata.lcso = OPTIGA_LCS_OPERATIONAL; + metadata.change = OPTIGA_ACCESS_NEVER; + metadata.read = OPTIGA_ACCESS_ALWAYS; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + if (!set_metadata(OID_CERT_DEV, &metadata)) { + return; + } + + // Set metadata for FIDO attestation certificate. + memzero(&metadata, sizeof(metadata)); + metadata.lcso = OPTIGA_LCS_OPERATIONAL; + metadata.change = OPTIGA_ACCESS_NEVER; + metadata.read = OPTIGA_ACCESS_ALWAYS; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + if (!set_metadata(OID_CERT_FIDO, &metadata)) { + return; + } + + // Set metadata for device private key. + memzero(&metadata, sizeof(metadata)); + metadata.lcso = OPTIGA_LCS_OPERATIONAL; + metadata.change = OPTIGA_ACCESS_NEVER; + metadata.read = OPTIGA_ACCESS_NEVER; + metadata.execute = ACCESS_PAIRED; + metadata.key_usage = KEY_USE_SIGN; + if (!set_metadata(OID_KEY_DEV, &metadata)) { + return; + } + + // Set metadata for FIDO attestation private key. + memzero(&metadata, sizeof(metadata)); + metadata.lcso = OPTIGA_LCS_OPERATIONAL; + metadata.change = OPTIGA_ACCESS_NEVER; + metadata.read = OPTIGA_ACCESS_NEVER; + metadata.execute = ACCESS_PAIRED; + metadata.key_usage = KEY_USE_SIGN; + if (!set_metadata(OID_KEY_FIDO, &metadata)) { + return; + } + + // Set metadata for pairing key. + memzero(&metadata, sizeof(metadata)); + metadata.lcso = OPTIGA_LCS_OPERATIONAL; + metadata.change = OPTIGA_ACCESS_NEVER; + metadata.read = OPTIGA_ACCESS_NEVER; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + metadata.data_type = TYPE_PTFBIND; + if (!set_metadata(OID_KEY_PAIRING, &metadata)) { + return; + } + + vcp_println("OK"); +} + +optiga_locked_status get_optiga_locked_status(void) { + if (!optiga_paired()) return OPTIGA_LOCKED_ERROR; + + const uint16_t oids[] = {OID_CERT_DEV, OID_CERT_FIDO, OID_KEY_DEV, + OID_KEY_FIDO, OID_KEY_PAIRING}; + + optiga_metadata locked_metadata = {0}; + locked_metadata.lcso = OPTIGA_LCS_OPERATIONAL; + for (size_t i = 0; i < sizeof(oids) / sizeof(oids[0]); ++i) { + uint8_t metadata_buffer[OPTIGA_MAX_METADATA_SIZE] = {0}; + size_t metadata_size = 0; + optiga_result ret = + optiga_get_data_object(oids[i], true, metadata_buffer, + sizeof(metadata_buffer), &metadata_size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_get_metadata error %d for OID 0x%04x.", ret, + oids[i]); + return OPTIGA_LOCKED_ERROR; + } + + optiga_metadata stored_metadata = {0}; + ret = + optiga_parse_metadata(metadata_buffer, metadata_size, &stored_metadata); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_parse_metadata error %d.", ret); + return OPTIGA_LOCKED_ERROR; + } + + if (!optiga_compare_metadata(&locked_metadata, &stored_metadata)) { + return OPTIGA_LOCKED_FALSE; + } + } + + return OPTIGA_LOCKED_TRUE; +} + +void check_locked(void) { + switch (get_optiga_locked_status()) { + case OPTIGA_LOCKED_TRUE: + vcp_println("OK YES"); + break; + case OPTIGA_LOCKED_FALSE: + vcp_println("OK NO"); + break; + default: + // Error reported by get_optiga_locked_status(). + break; + } +} + +void optigaid_read(void) { + if (!optiga_paired()) return; + + uint8_t optiga_id[27] = {0}; + size_t optiga_id_size = 0; + + optiga_result ret = + optiga_get_data_object(OPTIGA_OID_COPROC_UID, false, optiga_id, + sizeof(optiga_id), &optiga_id_size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_get_data_object error %d for 0x%04x.", ret, + OPTIGA_OID_COPROC_UID); + return; + } + + vcp_print("OK "); + vcp_println_hex(optiga_id, optiga_id_size); +} + +void cert_read(uint16_t oid) { + if (!optiga_paired()) return; + + static uint8_t cert[2048] = {0}; + size_t cert_size = 0; + optiga_result ret = + optiga_get_data_object(oid, false, cert, sizeof(cert), &cert_size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_get_data_object error %d for 0x%04x.", ret, oid); + return; + } + + size_t offset = 0; + if (cert[0] == 0xC0) { + // TLS identity certificate chain. + size_t tls_identity_size = (cert[1] << 8) + cert[2]; + size_t cert_chain_size = (cert[3] << 16) + (cert[4] << 8) + cert[5]; + size_t first_cert_size = (cert[6] << 16) + (cert[7] << 8) + cert[8]; + if (tls_identity_size + 3 > cert_size || + cert_chain_size + 3 > tls_identity_size || + first_cert_size > cert_chain_size) { + vcp_println("ERROR invalid TLS identity in 0x%04x.", oid); + return; + } + offset = 9; + cert_size = first_cert_size; + } + + if (cert_size == 0) { + vcp_println("ERROR no certificate in 0x%04x.", oid); + return; + } + + vcp_print("OK "); + vcp_println_hex(cert + offset, cert_size); +} + +void cert_write(uint16_t oid, char *data) { + if (!optiga_paired()) return; + + // Enable writing to the certificate slot. + optiga_metadata metadata = {0}; + metadata.change = OPTIGA_ACCESS_ALWAYS; + set_metadata(oid, &metadata); // Ignore result. + + uint8_t data_bytes[1024]; + + int len = get_from_hex(data_bytes, sizeof(data_bytes), data); + if (len < 0) { + vcp_println("ERROR Hexadecimal decoding error %d.", len); + return; + } + + optiga_result ret = optiga_set_data_object(oid, false, data_bytes, len); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_set_data error %d for 0x%04x.", ret, oid); + return; + } + + vcp_println("OK"); +} + +void pubkey_read(uint16_t oid) { + if (!optiga_paired()) return; + + // Enable key agreement usage. + + optiga_metadata metadata = {0}; + uint8_t key_usage = OPTIGA_KEY_USAGE_KEYAGREE; + metadata.key_usage.ptr = &key_usage; + metadata.key_usage.len = 1; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + + if (!set_metadata(oid, &metadata)) { + return; + } + + // Execute ECDH with base point to get the x-coordinate of the public key. + static const uint8_t BASE_POINT[] = { + 0x03, 0x42, 0x00, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, + 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, + 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}; + uint8_t public_key[32] = {0}; + size_t public_key_size = 0; + optiga_result ret = + optiga_calc_ssec(OPTIGA_CURVE_P256, oid, BASE_POINT, sizeof(BASE_POINT), + public_key, sizeof(public_key), &public_key_size); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_calc_ssec error %d.", ret); + return; + } + + vcp_print("OK "); + vcp_println_hex(public_key, public_key_size); +} + +void keyfido_write(char *data) { + if (!optiga_paired()) return; + + const size_t EPH_PUB_KEY_SIZE = 33; + const size_t PAYLOAD_SIZE = 32; + const size_t CIPHERTEXT_OFFSET = EPH_PUB_KEY_SIZE; + const size_t EXPECTED_SIZE = EPH_PUB_KEY_SIZE + PAYLOAD_SIZE; + + // Enable key agreement usage for device key. + + optiga_metadata metadata = {0}; + uint8_t key_usage = OPTIGA_KEY_USAGE_KEYAGREE; + metadata.key_usage.ptr = &key_usage; + metadata.key_usage.len = 1; + metadata.execute = OPTIGA_ACCESS_ALWAYS; + + if (!set_metadata(OID_KEY_DEV, &metadata)) { + return; + } + + // Read encrypted FIDO attestation private key. + + uint8_t data_bytes[EXPECTED_SIZE]; + int len = get_from_hex(data_bytes, sizeof(data_bytes), data); + if (len < 0) { + vcp_println("ERROR Hexadecimal decoding error %d.", len); + return; + } + + if (len != EXPECTED_SIZE) { + vcp_println("ERROR Unexpected input length."); + return; + } + + // Expand sender's ephemeral public key. + uint8_t public_key[3 + 65] = {0x03, 0x42, 0x00}; + if (ecdsa_uncompress_pubkey(&nist256p1, data_bytes, &public_key[3]) != 1) { + vcp_println("ERROR Failed to decode public key."); + return; + } + + // Execute ECDH with device private key. + uint8_t secret[32] = {0}; + size_t secret_size = 0; + optiga_result ret = optiga_calc_ssec(OPTIGA_CURVE_P256, OID_KEY_DEV, + public_key, sizeof(public_key), secret, + sizeof(secret), &secret_size); + if (OPTIGA_SUCCESS != ret) { + memzero(secret, sizeof(secret)); + vcp_println("ERROR optiga_calc_ssec error %d.", ret); + return; + } + + // Hash the shared secret. Use the result as the decryption key. + sha256_Raw(secret, secret_size, secret); + aes_decrypt_ctx ctx = {0}; + AES_RETURN aes_ret = aes_decrypt_key256(secret, &ctx); + if (EXIT_SUCCESS != aes_ret) { + vcp_println("ERROR aes_decrypt_key256 error."); + memzero(&ctx, sizeof(ctx)); + memzero(secret, sizeof(secret)); + return; + } + + // Decrypt the FIDO attestation key. + uint8_t fido_key[PAYLOAD_SIZE]; + + // The IV is intentionally all-zero, which is not a problem, because the + // encryption key is unique for each ciphertext. + uint8_t iv[AES_BLOCK_SIZE] = {0}; + aes_ret = aes_cbc_decrypt(&data_bytes[CIPHERTEXT_OFFSET], fido_key, + sizeof(fido_key), iv, &ctx); + memzero(&ctx, sizeof(ctx)); + memzero(secret, sizeof(secret)); + if (EXIT_SUCCESS != aes_ret) { + memzero(fido_key, sizeof(fido_key)); + vcp_println("ERROR aes_cbc_decrypt error."); + return; + } + + // Write trust anchor certificate to OID 0xE0E8 + ret = optiga_set_trust_anchor(); + if (OPTIGA_SUCCESS != ret) { + memzero(fido_key, sizeof(fido_key)); + vcp_println("ERROR optiga_set_trust_anchor error %d.", ret); + return; + } + + // Set change access condition for the FIDO key to Int(0xE0E8), so that we + // can write the FIDO key using the trust anchor in OID 0xE0E8. + memzero(&metadata, sizeof(metadata)); + metadata.change.ptr = (const uint8_t *)"\x21\xe0\xe8"; + metadata.change.len = 3; + if (!set_metadata(OID_KEY_FIDO, &metadata)) { + return; + } + + // Store the FIDO attestation key. + ret = optiga_set_priv_key(OID_KEY_FIDO, fido_key); + memzero(fido_key, sizeof(fido_key)); + if (OPTIGA_SUCCESS != ret) { + vcp_println("ERROR optiga_set_priv_key error %d.", ret); + return; + } + + vcp_println("OK"); +} diff --git a/core/embed/prodtest/optiga_prodtest.h b/core/embed/prodtest/optiga_prodtest.h new file mode 100644 index 000000000..516e1b845 --- /dev/null +++ b/core/embed/prodtest/optiga_prodtest.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PRODTEST_OPTIGA_PRODTESTS_H +#define PRODTEST_OPTIGA_PRODTEST_H + +#include +#include +#include + +#define OID_CERT_INF OPTIGA_OID_CERT + 0 +#define OID_CERT_DEV OPTIGA_OID_CERT + 1 +#define OID_CERT_FIDO OPTIGA_OID_CERT + 2 +#define OID_KEY_DEV OPTIGA_OID_ECC_KEY + 0 +#define OID_KEY_FIDO OPTIGA_OID_ECC_KEY + 2 +#define OID_KEY_PAIRING OPTIGA_OID_PTFBIND_SECRET +#define OID_TRUST_ANCHOR OPTIGA_OID_CA_CERT + 0 + +typedef enum { + OPTIGA_LOCKED_TRUE, + OPTIGA_LOCKED_FALSE, + OPTIGA_LOCKED_ERROR, +} optiga_locked_status; + +void pair_optiga(void); +void optigaid_read(void); +void cert_read(uint16_t oid); +void cert_write(uint16_t oid, char *data); +void keyfido_write(char *data); +void pubkey_read(uint16_t oid); +void optiga_lock(void); +optiga_locked_status get_optiga_locked_status(void); +void check_locked(void); + +#endif diff --git a/core/embed/prodtest/prodtest_common.c b/core/embed/prodtest/prodtest_common.c new file mode 100644 index 000000000..a56607a0c --- /dev/null +++ b/core/embed/prodtest/prodtest_common.c @@ -0,0 +1,102 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "prodtest_common.h" +#include "mini_printf.h" +#include "usb.h" + +void vcp_puts(const char *s, size_t len) { + int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *)s, len, -1); + (void)r; +} + +void vcp_print(const char *fmt, ...) { + static char buf[128]; + va_list va; + va_start(va, fmt); + int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); + va_end(va); + vcp_puts(buf, r); +} + +void vcp_println(const char *fmt, ...) { + static char buf[128]; + va_list va; + va_start(va, fmt); + int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); + va_end(va); + vcp_puts(buf, r); + vcp_puts("\r\n", 2); +} + +void vcp_println_hex(uint8_t *data, uint16_t len) { + for (int i = 0; i < len; i++) { + vcp_print("%02X", data[i]); + } + vcp_puts("\r\n", 2); +} + +static uint16_t get_byte_from_hex(const char **hex) { + uint8_t result = 0; + + // Skip whitespace. + while (**hex == ' ') { + *hex += 1; + } + + for (int i = 0; i < 2; i++) { + result <<= 4; + char c = **hex; + if (c >= '0' && c <= '9') { + result |= c - '0'; + } else if (c >= 'A' && c <= 'F') { + result |= c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + result |= c - 'a' + 10; + } else if (c == '\0') { + return 0x100; + } else { + return 0xFFFF; + } + *hex += 1; + } + return result; +} + +int get_from_hex(uint8_t *buf, uint16_t buf_len, const char *hex) { + int len = 0; + uint16_t b = get_byte_from_hex(&hex); + for (len = 0; len < buf_len && b <= 0xff; ++len) { + buf[len] = b; + b = get_byte_from_hex(&hex); + } + + if (b == 0x100) { + // Success. + return len; + } + + if (b > 0xff) { + // Non-hexadecimal character. + return -1; + } + + // Buffer too small. + return -2; +} diff --git a/core/embed/prodtest/prodtest_common.h b/core/embed/prodtest/prodtest_common.h new file mode 100644 index 000000000..bd0f33747 --- /dev/null +++ b/core/embed/prodtest/prodtest_common.h @@ -0,0 +1,34 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PRODTEST_COMMON_H +#define PRODTEST_COMMON_H + +#include +#include + +enum { VCP_IFACE = 0x00 }; + +void vcp_puts(const char *s, size_t len); +void vcp_print(const char *fmt, ...); +void vcp_println(const char *fmt, ...); +void vcp_println_hex(uint8_t *data, uint16_t len); +int get_from_hex(uint8_t *buf, uint16_t buf_len, const char *hex); + +#endif diff --git a/core/embed/prodtest/version.h b/core/embed/prodtest/version.h index 2279c0cc0..542679e59 100644 --- a/core/embed/prodtest/version.h +++ b/core/embed/prodtest/version.h @@ -1,10 +1,10 @@ #define VERSION_MAJOR 0 -#define VERSION_MINOR 1 -#define VERSION_PATCH 0 +#define VERSION_MINOR 2 +#define VERSION_PATCH 2 #define VERSION_BUILD 0 #define FIX_VERSION_MAJOR 0 -#define FIX_VERSION_MINOR 1 +#define FIX_VERSION_MINOR 2 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index 46e4e011e..ae829ef74 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -29,6 +29,7 @@ sd_card = [] rgb_led = [] backlight = [] usb = [] +optiga = [] test = [ "button", "cc", @@ -39,7 +40,8 @@ test = [ "ui", "dma2d", "touch", - "backlight" + "backlight", + "optiga" ] [lib] diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 4bb44c74f..e7e25f32f 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -94,7 +94,7 @@ fn prepare_bindings() -> bindgen::Builder { let mut clang_args: Vec<&str> = Vec::new(); let includes = env::var("RUST_INCLUDES").unwrap(); - let args = includes.split(";"); + let args = includes.split(';'); for arg in args { clang_args.push(arg); diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 7fcddbeb5..ae99c4fe5 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -34,20 +34,24 @@ static void _librust_qstrs(void) { MP_QSTR_bounds; MP_QSTR_button; MP_QSTR_button_event; + MP_QSTR_cancel_arrow; MP_QSTR_case_sensitive; + MP_QSTR_chunkify; MP_QSTR_confirm_action; MP_QSTR_confirm_address; MP_QSTR_confirm_backup; MP_QSTR_confirm_blob; MP_QSTR_confirm_coinjoin; MP_QSTR_confirm_emphasized; + MP_QSTR_confirm_ethereum_tx; MP_QSTR_confirm_fido; MP_QSTR_confirm_homescreen; MP_QSTR_confirm_joint_total; MP_QSTR_confirm_modify_fee; MP_QSTR_confirm_modify_output; MP_QSTR_confirm_more; - MP_QSTR_confirm_output; + MP_QSTR_confirm_output_address; + MP_QSTR_confirm_output_amount; MP_QSTR_confirm_properties; MP_QSTR_confirm_recovery; MP_QSTR_confirm_reset_device; @@ -58,6 +62,7 @@ static void _librust_qstrs(void) { MP_QSTR_data; MP_QSTR_decode; MP_QSTR_description; + MP_QSTR_details_title; MP_QSTR_disable_animation; MP_QSTR_draw_welcome_screen; MP_QSTR_dry_run; @@ -66,9 +71,7 @@ static void _librust_qstrs(void) { MP_QSTR_extra; MP_QSTR_fee_amount; MP_QSTR_fee_label; - MP_QSTR_fee_rate; MP_QSTR_fee_rate_amount; - MP_QSTR_fee_rate_title; MP_QSTR_hold; MP_QSTR_hold_danger; MP_QSTR_icon_name; @@ -85,6 +88,7 @@ static void _librust_qstrs(void) { MP_QSTR_max_feerate; MP_QSTR_max_len; MP_QSTR_max_rounds; + MP_QSTR_maximum_fee; MP_QSTR_min_count; MP_QSTR_multiple_pages_texts; MP_QSTR_notification; @@ -95,6 +99,8 @@ static void _librust_qstrs(void) { MP_QSTR_path; MP_QSTR_progress_event; MP_QSTR_prompt; + MP_QSTR_qr_title; + MP_QSTR_recipient; MP_QSTR_request_bip39; MP_QSTR_request_complete_repaint; MP_QSTR_request_number; @@ -111,6 +117,7 @@ static void _librust_qstrs(void) { MP_QSTR_show_group_share_success; MP_QSTR_show_homescreen; MP_QSTR_show_info; + MP_QSTR_show_info_with_cancel; MP_QSTR_show_lockscreen; MP_QSTR_show_mismatch; MP_QSTR_show_passphrase; @@ -119,7 +126,6 @@ static void _librust_qstrs(void) { MP_QSTR_show_remaining_shares; MP_QSTR_show_share_words; MP_QSTR_show_simple; - MP_QSTR_show_spending_details; MP_QSTR_show_success; MP_QSTR_show_warning; MP_QSTR_sign; diff --git a/core/embed/rust/src/ui/component/text/layout.rs b/core/embed/rust/src/ui/component/text/layout.rs index 954cbcd06..d713e9b0e 100644 --- a/core/embed/rust/src/ui/component/text/layout.rs +++ b/core/embed/rust/src/ui/component/text/layout.rs @@ -52,6 +52,40 @@ pub struct TextLayout { pub continues_from_prev_page: bool, } +/// Configuration for chunkifying the text into smaller parts. +#[derive(Copy, Clone)] +pub struct Chunks { + /// How many characters will be grouped in one chunk. + pub chunk_size: usize, + /// How big will be the space between chunks (in pixels). + pub x_offset: i16, + /// Optional characters that are wider and should be accounted for + pub wider_chars: Option<&'static str>, +} + +impl Chunks { + pub const fn new(chunk_size: usize, x_offset: i16) -> Self { + Chunks { + chunk_size, + x_offset, + wider_chars: None, + } + } + + pub const fn with_wider_chars(mut self, wider_chars: &'static str) -> Self { + self.wider_chars = Some(wider_chars); + self + } + + pub fn is_char_wider(self, ch: char) -> bool { + if let Some(wider_chars) = self.wider_chars { + wider_chars.contains(ch) + } else { + false + } + } +} + #[derive(Copy, Clone)] pub struct TextStyle { /// Text font ID. @@ -76,6 +110,14 @@ pub struct TextStyle { pub line_breaking: LineBreaking, /// Specifies what to do at the end of the page. pub page_breaking: PageBreaking, + + /// Optionally chunkify all the text with a specified chunk + /// size and pixel offset for the next chunk. + pub chunks: Option, + + /// Optionally increase the vertical space between text lines + /// (can be even negative, in which case it will decrease it). + pub line_spacing: i16, } impl TextStyle { @@ -96,6 +138,8 @@ impl TextStyle { prev_page_ellipsis_icon: None, line_breaking: LineBreaking::BreakAtWhitespace, page_breaking: PageBreaking::CutAndInsertEllipsis, + chunks: None, + line_spacing: 0, } } @@ -121,6 +165,18 @@ impl TextStyle { self } + /// Adding optional chunkification to the text. + pub const fn with_chunks(mut self, chunks: Chunks) -> Self { + self.chunks = Some(chunks); + self + } + + /// Adding optional change of vertical line spacing. + pub const fn with_line_spacing(mut self, line_spacing: i16) -> Self { + self.line_spacing = line_spacing; + self + } + fn ellipsis_width(&self) -> i16 { if let Some((icon, margin)) = self.ellipsis_icon { icon.toif.width() + margin @@ -220,12 +276,13 @@ impl TextLayout { }; let remaining_width = self.bounds.x1 - cursor.x; - let span = Span::fit_horizontally( + let mut span = Span::fit_horizontally( remaining_text, remaining_width, self.style.text_font, self.style.line_breaking, line_ending_space, + self.style.chunks, ); cursor.x += match self.align { @@ -251,6 +308,9 @@ impl TextLayout { if span.advance.y > 0 { // We're advancing to the next line. + // Possibly making a bigger/smaller vertical jump + span.advance.y += self.style.line_spacing; + // Check if we should be appending a hyphen at this point. if span.insert_hyphen_before_line_break { sink.hyphen(*cursor, self); @@ -488,6 +548,7 @@ impl Span { text_font: impl GlyphMetrics, breaking: LineBreaking, line_ending_space: i16, + chunks: Option, ) -> Self { const ASCII_LF: char = '\n'; const ASCII_CR: char = '\r'; @@ -537,6 +598,7 @@ impl Span { let mut span_width = 0; let mut found_any_whitespace = false; + let mut chunks_wider_chars = 0; let mut char_indices_iter = text.char_indices().peekable(); // Iterating manually because we need a reference to the iterator inside the @@ -544,6 +606,22 @@ impl Span { while let Some((i, ch)) = char_indices_iter.next() { let char_width = text_font.char_width(ch); + // When there is a set chunk size and we reach it, + // adjust the line advances and return the line. + if let Some(chunkify_config) = chunks { + if i == chunkify_config.chunk_size { + line.advance.y = 0; + // Decreasing the offset for each wider character in the chunk + line.advance.x += chunkify_config.x_offset - chunks_wider_chars; + return line; + } else { + // Counting all the wider characters in the chunk + if chunkify_config.is_char_wider(ch) { + chunks_wider_chars += 1; + } + } + } + // Consider if we could be breaking the line at this position. if is_whitespace(ch) && span_width + complete_word_end_width <= max_width { // Break before the whitespace, without hyphen. @@ -679,6 +757,7 @@ mod tests { FIXED_FONT, LineBreaking::BreakAtWhitespace, 0, + None, ); spans.push(( &remaining_text[..span.length], diff --git a/core/embed/rust/src/ui/component/text/op.rs b/core/embed/rust/src/ui/component/text/op.rs index b7ececf66..a008100b6 100644 --- a/core/embed/rust/src/ui/component/text/op.rs +++ b/core/embed/rust/src/ui/component/text/op.rs @@ -8,7 +8,7 @@ use crate::{ }; use super::{ - layout::{LayoutFit, LayoutSink, TextLayout}, + layout::{Chunks, LayoutFit, LayoutSink, TextLayout}, LineBreaking, TextStyle, }; @@ -16,7 +16,7 @@ use heapless::Vec; // So that there is only one implementation, and not multiple generic ones // as would be via `const N: usize` generics. -const MAX_OPS: usize = 15; +const MAX_OPS: usize = 20; /// To account for operations that are not made of characters /// but need to be accounted for somehow. @@ -39,6 +39,10 @@ impl<'a, T: StringType + Clone + 'a> OpTextLayout { } } + pub fn is_empty(&self) -> bool { + self.ops.len() == 0 + } + pub fn place(&mut self, bounds: Rect) -> Rect { self.layout.bounds = bounds; bounds @@ -86,6 +90,12 @@ impl<'a, T: StringType + Clone + 'a> OpTextLayout { cursor.x += offset.x; cursor.y += offset.y; } + Op::Chunkify(chunks) => { + self.layout.style.chunks = chunks; + } + Op::LineSpacing(line_spacing) => { + self.layout.style.line_spacing = line_spacing; + } // Moving to the next page Op::NextPage => { // Pretending that nothing more fits on current page to force @@ -215,6 +225,14 @@ impl OpTextLayout { pub fn line_breaking(self, line_breaking: LineBreaking) -> Self { self.with_new_item(Op::LineBreaking(line_breaking)) } + + pub fn chunks(self, chunks: Option) -> Self { + self.with_new_item(Op::Chunkify(chunks)) + } + + pub fn line_spacing(self, spacing: i16) -> Self { + self.with_new_item(Op::LineSpacing(spacing)) + } } // Op-adding aggregation operations @@ -234,6 +252,14 @@ impl OpTextLayout { pub fn text_demibold(self, text: T) -> Self { self.font(Font::DEMIBOLD).text(text) } + + pub fn chunkify_text(self, chunks: Option<(Chunks, i16)>) -> Self { + if let Some(chunks) = chunks { + self.chunks(Some(chunks.0)).line_spacing(chunks.1) + } else { + self.chunks(None).line_spacing(0) + } + } } #[derive(Clone)] @@ -254,4 +280,8 @@ pub enum Op { CursorOffset(Offset), /// Force continuing on the next page. NextPage, + /// Render the following text in a chunkified way. None will disable that. + Chunkify(Option), + /// Change the line vertical line spacing. + LineSpacing(i16), } diff --git a/core/embed/rust/src/ui/model_tr/component/address_details.rs b/core/embed/rust/src/ui/model_tr/component/address_details.rs index 65ef446f0..c4b47a246 100644 --- a/core/embed/rust/src/ui/model_tr/component/address_details.rs +++ b/core/embed/rust/src/ui/model_tr/component/address_details.rs @@ -108,7 +108,7 @@ where /// Button layout for the current page. /// Normally there are arrows everywhere, apart from the right side of the - /// last page. On xpub pages there is VIEW FULL middle button when it + /// last page. On xpub pages there is SHOW ALL middle button when it /// cannot fit one page. On xpub subpages there are wide arrows to /// scroll. fn get_button_layout(&mut self) -> ButtonLayout { @@ -123,7 +123,7 @@ where } else { let left = Some(ButtonDetails::left_arrow_icon()); let middle = if self.is_xpub_page() && self.subpages_in_current_page() > 1 { - Some(ButtonDetails::armed_text("VIEW FULL".into())) + Some(ButtonDetails::armed_text("SHOW ALL".into())) } else { None }; diff --git a/core/embed/rust/src/ui/model_tr/component/button.rs b/core/embed/rust/src/ui/model_tr/component/button.rs index 25bace910..0b414920e 100644 --- a/core/embed/rust/src/ui/model_tr/component/button.rs +++ b/core/embed/rust/src/ui/model_tr/component/button.rs @@ -13,7 +13,7 @@ use super::{loader::DEFAULT_DURATION_MS, theme}; const HALF_SCREEN_BUTTON_WIDTH: i16 = constant::WIDTH / 2 - 1; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] pub enum ButtonPos { Left, Middle, @@ -351,7 +351,10 @@ pub struct ButtonDetails { offset: Offset, } -impl ButtonDetails { +impl ButtonDetails +where + T: StringType, +{ /// Text button. pub fn text(text: T) -> Self { Self { @@ -376,6 +379,16 @@ impl ButtonDetails { } } + /// Resolves text and finds possible icon names. + pub fn from_text_possible_icon(text: T) -> Self { + match text.as_ref() { + "" => Self::cancel_icon(), + "<" => Self::left_arrow_icon(), + "^" => Self::up_arrow_icon(), + _ => Self::text(text), + } + } + /// Text with arms signalling double press. pub fn armed_text(text: T) -> Self { Self::text(text).with_arms() @@ -399,7 +412,7 @@ impl ButtonDetails { /// Up arrow to signal paginating back. No outline. Offsetted little right /// to not be on the boundary. pub fn up_arrow_icon() -> Self { - Self::icon(theme::ICON_ARROW_UP).with_offset(Offset::new(2, -3)) + Self::icon(theme::ICON_ARROW_UP).with_offset(Offset::new(3, -4)) } /// Down arrow to signal paginating forward. Takes half the screen's width @@ -529,6 +542,15 @@ where ) } + /// Left text, armed text and right info icon/text. + pub fn text_armed_info(left: T, middle: T) -> Self { + Self::new( + Some(ButtonDetails::from_text_possible_icon(left)), + Some(ButtonDetails::armed_text(middle)), + Some(ButtonDetails::text("i".into()).with_fixed_width(theme::BUTTON_ICON_WIDTH)), + ) + } + /// Left cancel, armed text and right info icon/text. pub fn cancel_armed_info(middle: T) -> Self { Self::new( @@ -559,16 +581,16 @@ where /// Left and right texts. pub fn text_none_text(left: T, right: T) -> Self { Self::new( - Some(ButtonDetails::text(left)), + Some(ButtonDetails::from_text_possible_icon(left)), None, - Some(ButtonDetails::text(right)), + Some(ButtonDetails::from_text_possible_icon(right)), ) } /// Left text and right arrow. pub fn text_none_arrow(text: T) -> Self { Self::new( - Some(ButtonDetails::text(text)), + Some(ButtonDetails::from_text_possible_icon(text)), None, Some(ButtonDetails::right_arrow_icon()), ) @@ -577,7 +599,7 @@ where /// Left text and WIDE right arrow. pub fn text_none_arrow_wide(text: T) -> Self { Self::new( - Some(ButtonDetails::text(text)), + Some(ButtonDetails::from_text_possible_icon(text)), None, Some(ButtonDetails::down_arrow_icon_wide()), ) @@ -585,7 +607,11 @@ where /// Only right text. pub fn none_none_text(text: T) -> Self { - Self::new(None, None, Some(ButtonDetails::text(text))) + Self::new( + None, + None, + Some(ButtonDetails::from_text_possible_icon(text)), + ) } /// Left and right arrow icons for navigation. @@ -602,7 +628,7 @@ where Self::new( Some(ButtonDetails::left_arrow_icon()), None, - Some(ButtonDetails::text(text)), + Some(ButtonDetails::from_text_possible_icon(text)), ) } @@ -611,7 +637,7 @@ where Self::new( Some(ButtonDetails::up_arrow_icon()), None, - Some(ButtonDetails::text(text)), + Some(ButtonDetails::from_text_possible_icon(text)), ) } @@ -633,7 +659,7 @@ where ) } - /// Cancel cross on left and right arrow facing down. + /// Up arrow on left and right arrow facing down. pub fn up_arrow_none_arrow_wide() -> Self { Self::new( Some(ButtonDetails::up_arrow_icon()), @@ -642,6 +668,15 @@ where ) } + /// Up arrow on left, middle text and info on the right. + pub fn up_arrow_armed_info(text: T) -> Self { + Self::new( + Some(ButtonDetails::up_arrow_icon()), + Some(ButtonDetails::armed_text(text)), + Some(ButtonDetails::text("i".into()).with_fixed_width(theme::BUTTON_ICON_WIDTH)), + ) + } + /// Cancel cross on left and right arrow facing down. pub fn cancel_none_arrow_down() -> Self { Self::new( @@ -656,7 +691,7 @@ where Self::new( Some(ButtonDetails::cancel_icon()), None, - Some(ButtonDetails::text(text)), + Some(ButtonDetails::from_text_possible_icon(text)), ) } diff --git a/core/embed/rust/src/ui/model_tr/component/button_controller.rs b/core/embed/rust/src/ui/model_tr/component/button_controller.rs index 638b1284c..618b4e674 100644 --- a/core/embed/rust/src/ui/model_tr/component/button_controller.rs +++ b/core/embed/rust/src/ui/model_tr/component/button_controller.rs @@ -3,8 +3,9 @@ use super::{ }; use crate::{ strutil::StringType, + time::Duration, ui::{ - component::{base::Event, Component, EventCtx, Pad}, + component::{base::Event, Component, EventCtx, Pad, TimerToken}, event::{ButtonEvent, PhysicalButton}, geometry::Rect, }, @@ -195,6 +196,9 @@ where /// /// Only "final" button events are returned in `ButtonControllerMsg::Triggered`, /// based upon the buttons being long-press or not. +/// +/// There is optional complexity with IgnoreButtonDelay, which gets executed +/// only in cases where clients request it. pub struct ButtonController where T: StringType, @@ -204,10 +208,12 @@ where middle_btn: ButtonContainer, right_btn: ButtonContainer, state: ButtonState, - // Button area is needed so the buttons - // can be "re-placed" after their text is changed - // Will be set in `place` + /// Button area is needed so the buttons + /// can be "re-placed" after their text is changed + /// Will be set in `place` button_area: Rect, + /// Handling optional ignoring of buttons after pressing the other button. + ignore_btn_delay: Option, } impl ButtonController @@ -222,9 +228,17 @@ where right_btn: ButtonContainer::new(ButtonPos::Right, btn_layout.btn_right), state: ButtonState::Nothing, button_area: Rect::zero(), + ignore_btn_delay: None, } } + /// Set up the logic to ignore a button after some time from pressing + /// the other button. + pub fn with_ignore_btn_delay(mut self, delay_ms: u32) -> Self { + self.ignore_btn_delay = Some(IgnoreButtonDelay::new(delay_ms)); + self + } + /// Updating all the three buttons to the wanted states. pub fn set(&mut self, btn_layout: ButtonLayout) { self.pad.clear(); @@ -240,6 +254,14 @@ where self.right_btn.set_pressed(ctx, right); } + pub fn highlight_button(&mut self, ctx: &mut EventCtx, pos: ButtonPos) { + match pos { + ButtonPos::Left => self.left_btn.set_pressed(ctx, true), + ButtonPos::Middle => self.middle_btn.set_pressed(ctx, true), + ButtonPos::Right => self.right_btn.set_pressed(ctx, true), + } + } + /// Handle middle button hold-to-confirm start. /// We need to cancel possible holds in both other buttons. fn middle_hold_started(&mut self, ctx: &mut EventCtx) { @@ -291,22 +313,29 @@ where // _ _ ButtonState::Nothing => match button_event { // ▼ * | * ▼ - ButtonEvent::ButtonPressed(which) => ( + ButtonEvent::ButtonPressed(which) => { // ↓ _ | _ ↓ - ButtonState::OneDown(which), - match which { - // ▼ * - PhysicalButton::Left => { - self.left_btn.hold_started(ctx); - Some(ButtonControllerMsg::Pressed(ButtonPos::Left)) - } - // * ▼ - PhysicalButton::Right => { - self.right_btn.hold_started(ctx); - Some(ButtonControllerMsg::Pressed(ButtonPos::Right)) - } - }, - ), + // Initial button press will set the timer for second button, + // and after some delay, it will become un-clickable + if let Some(ignore_btn_delay) = &mut self.ignore_btn_delay { + ignore_btn_delay.handle_button_press(ctx, which); + } + ( + ButtonState::OneDown(which), + match which { + // ▼ * + PhysicalButton::Left => { + self.left_btn.hold_started(ctx); + Some(ButtonControllerMsg::Pressed(ButtonPos::Left)) + } + // * ▼ + PhysicalButton::Right => { + self.right_btn.hold_started(ctx); + Some(ButtonControllerMsg::Pressed(ButtonPos::Right)) + } + }, + ) + } _ => (self.state, None), }, // ↓ _ | _ ↓ @@ -314,18 +343,32 @@ where // ▲ * | * ▲ ButtonEvent::ButtonReleased(b) if b == which_down => match which_down { // ▲ * + // Trigger the button and make the second one clickable in all cases PhysicalButton::Left => { + if let Some(ignore_btn_delay) = &mut self.ignore_btn_delay { + ignore_btn_delay.make_button_clickable(ButtonPos::Right); + } // _ _ (ButtonState::Nothing, self.left_btn.maybe_trigger(ctx)) } // * ▲ PhysicalButton::Right => { + if let Some(ignore_btn_delay) = &mut self.ignore_btn_delay { + ignore_btn_delay.make_button_clickable(ButtonPos::Left); + } // _ _ (ButtonState::Nothing, self.right_btn.maybe_trigger(ctx)) } }, // * ▼ | ▼ * ButtonEvent::ButtonPressed(b) if b != which_down => { + // Buttons may be non-clickable (caused by long-holding the other + // button) + if let Some(ignore_btn_delay) = &self.ignore_btn_delay { + if ignore_btn_delay.ignore_button(b) { + return None; + } + } self.middle_hold_started(ctx); ( // ↓ ↓ @@ -356,6 +399,11 @@ where // ▲ * | * ▲ ButtonEvent::ButtonReleased(b) if b != which_up => { // _ _ + // Both button needs to be clickable now + if let Some(ignore_btn_delay) = &mut self.ignore_btn_delay { + ignore_btn_delay.make_button_clickable(ButtonPos::Left); + ignore_btn_delay.make_button_clickable(ButtonPos::Right); + } (ButtonState::Nothing, self.middle_btn.maybe_trigger(ctx)) } _ => (self.state, None), @@ -394,8 +442,13 @@ where self.state = new_state; event } - // HoldToConfirm expiration - Event::Timer(_) => self.handle_htc_expiration(ctx, event), + // Timer - handle clickable properties and HoldToConfirm expiration + Event::Timer(token) => { + if let Some(ignore_btn_delay) = &mut self.ignore_btn_delay { + ignore_btn_delay.handle_timer_token(token); + } + self.handle_htc_expiration(ctx, event) + } _ => None, } } @@ -421,6 +474,179 @@ where } } +/// When one button is pressed, the other one becomes un-clickable after some +/// small time period. This is to prevent accidental clicks when user is holding +/// the button to automatically move through items. +struct IgnoreButtonDelay { + /// How big is the delay after the button is inactive + delay: Duration, + /// Whether left button is currently clickable + left_clickable: bool, + /// Whether right button is currently clickable + right_clickable: bool, + /// Timer for setting the left_clickable + left_clickable_timer: Option, + /// Timer for setting the right_clickable + right_clickable_timer: Option, +} + +impl IgnoreButtonDelay { + pub fn new(delay_ms: u32) -> Self { + Self { + delay: Duration::from_millis(delay_ms), + left_clickable: true, + right_clickable: true, + left_clickable_timer: None, + right_clickable_timer: None, + } + } + + pub fn make_button_clickable(&mut self, pos: ButtonPos) { + match pos { + ButtonPos::Left => { + self.left_clickable = true; + self.left_clickable_timer = None; + } + ButtonPos::Right => { + self.right_clickable = true; + self.right_clickable_timer = None; + } + ButtonPos::Middle => {} + } + } + + pub fn handle_button_press(&mut self, ctx: &mut EventCtx, button: PhysicalButton) { + if matches!(button, PhysicalButton::Left) { + self.right_clickable_timer = Some(ctx.request_timer(self.delay)); + } + if matches!(button, PhysicalButton::Right) { + self.left_clickable_timer = Some(ctx.request_timer(self.delay)); + } + } + + pub fn ignore_button(&self, button: PhysicalButton) -> bool { + if matches!(button, PhysicalButton::Left) && !self.left_clickable { + return true; + } + if matches!(button, PhysicalButton::Right) && !self.right_clickable { + return true; + } + false + } + + pub fn handle_timer_token(&mut self, token: TimerToken) { + if self.left_clickable_timer == Some(token) { + self.left_clickable = false; + self.left_clickable_timer = None; + } + if self.right_clickable_timer == Some(token) { + self.right_clickable = false; + self.right_clickable_timer = None; + } + } +} + +/// Component allowing for automatically moving through items (e.g. Choice +/// items). +/// +/// Users are in full control of starting/stopping the movement. +/// +/// Can be started e.g. by holding left/right button. +pub struct AutomaticMover { + /// For requesting timer events repeatedly + timer_token: Option, + /// Which direction should we go (which button is down) + moving_direction: Option, + /// How many screens were moved automatically + auto_moved_screens: usize, + /// Function to get duration of each movement according to the already moved + /// steps + duration_func: fn(usize) -> u32, +} + +impl AutomaticMover { + pub fn new() -> Self { + fn default_duration_func(steps: usize) -> u32 { + match steps { + x if x < 3 => 200, + x if x < 10 => 150, + _ => 100, + } + } + + Self { + timer_token: None, + moving_direction: None, + auto_moved_screens: 0, + duration_func: default_duration_func, + } + } + + pub fn with_duration_func(mut self, duration_func: fn(usize) -> u32) -> Self { + self.duration_func = duration_func; + self + } + + /// Determines how long to wait between automatic movements. + /// Moves quicker with increasing number of screens moved. + /// Can be forced to be always the same (e.g. for animation purposes). + fn get_auto_move_duration(&self) -> Duration { + // Calculating duration from function + let ms_duration = (self.duration_func)(self.auto_moved_screens); + Duration::from_millis(ms_duration) + } + + /// In which direction we are moving, if any + pub fn moving_direction(&self) -> Option { + self.moving_direction + } + + // Whether we are currently moving. + pub fn is_moving(&self) -> bool { + self.moving_direction.is_some() + } + + /// Whether we have done at least one automatic movement. + pub fn was_moving(&self) -> bool { + self.auto_moved_screens > 0 + } + + pub fn start_moving(&mut self, ctx: &mut EventCtx, button: ButtonPos) { + self.auto_moved_screens = 0; + self.moving_direction = Some(button); + self.timer_token = Some(ctx.request_timer(self.get_auto_move_duration())); + } + + pub fn stop_moving(&mut self) { + self.moving_direction = None; + self.timer_token = None; + } +} + +impl Component for AutomaticMover { + type Msg = ButtonPos; + + fn place(&mut self, bounds: Rect) -> Rect { + bounds + } + + fn paint(&mut self) {} + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + // Moving automatically only when we receive a TimerToken that we have + // requested before + if let Event::Timer(token) = event { + if self.timer_token == Some(token) && self.moving_direction.is_some() { + // Request new token and send the appropriate button trigger event + self.timer_token = Some(ctx.request_timer(self.get_auto_move_duration())); + self.auto_moved_screens += 1; + return self.moving_direction; + } + } + None + } +} + // DEBUG-ONLY SECTION BELOW #[cfg(feature = "ui_debug")] @@ -443,3 +669,10 @@ impl crate::trace::Trace for ButtonController { t.child("right_btn", &self.right_btn); } } + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for AutomaticMover { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("AutomaticMover"); + } +} diff --git a/core/embed/rust/src/ui/model_tr/component/changing_text.rs b/core/embed/rust/src/ui/model_tr/component/changing_text.rs index 7a7893232..35ec84457 100644 --- a/core/embed/rust/src/ui/model_tr/component/changing_text.rs +++ b/core/embed/rust/src/ui/model_tr/component/changing_text.rs @@ -19,6 +19,8 @@ pub struct ChangingTextLine { /// What to show in front of the text if it doesn't fit. ellipsis: &'static str, alignment: Alignment, + /// Whether to show the text completely aligned to the top of the bounds + text_at_the_top: bool, } impl ChangingTextLine @@ -33,6 +35,7 @@ where show_content: true, ellipsis: "...", alignment, + text_at_the_top: false, } } @@ -50,6 +53,12 @@ where self } + /// Showing text at the very top + pub fn with_text_at_the_top(mut self) -> Self { + self.text_at_the_top = true; + self + } + /// Update the text to be displayed in the line. pub fn update_text(&mut self, text: T) { self.text = text; @@ -60,6 +69,11 @@ where &self.text } + /// Changing the current font + pub fn update_font(&mut self, font: Font) { + self.font = font; + } + /// Whether we should display the text content. /// If not, the whole area (Pad) will still be cleared. /// Is valid until this function is called again. @@ -76,7 +90,13 @@ where /// Y coordinate of text baseline, is the same for all paints. fn y_baseline(&self) -> i16 { - self.pad.area.y0 + self.font.line_height() + let y_coord = self.pad.area.y0 + self.font.line_height(); + if self.text_at_the_top { + // Shifting the text up by 2 pixels. + y_coord - 2 + } else { + y_coord + } } /// Whether the whole text can be painted in the available space diff --git a/core/embed/rust/src/ui/model_tr/component/flow.rs b/core/embed/rust/src/ui/model_tr/component/flow.rs index 3a4d8956f..25dad7859 100644 --- a/core/embed/rust/src/ui/model_tr/component/flow.rs +++ b/core/embed/rust/src/ui/model_tr/component/flow.rs @@ -30,6 +30,9 @@ where page_counter: usize, return_confirmed_index: bool, show_scrollbar: bool, + /// Possibly enforcing the second button to be ignored after some time after + /// pressing the first button + ignore_second_button_ms: Option, } impl Flow @@ -55,6 +58,7 @@ where page_counter: 0, return_confirmed_index: false, show_scrollbar: true, + ignore_second_button_ms: None, } } @@ -77,6 +81,12 @@ where self } + /// Ignoring the second button duration + pub fn with_ignore_second_button_ms(mut self, ignore_second_button_ms: u32) -> Self { + self.ignore_second_button_ms = Some(ignore_second_button_ms); + self + } + pub fn confirmed_index(&self) -> Option { self.return_confirmed_index.then_some(self.page_counter) } @@ -225,7 +235,14 @@ where // We finally found how long is the first page, and can set its button layout. self.current_page.place(content_area); - self.buttons = Child::new(ButtonController::new(self.current_page.btn_layout())); + if let Some(ignore_ms) = self.ignore_second_button_ms { + self.buttons = Child::new( + ButtonController::new(self.current_page.btn_layout()) + .with_ignore_btn_delay(ignore_ms), + ); + } else { + self.buttons = Child::new(ButtonController::new(self.current_page.btn_layout())); + } self.pad.place(title_content_area); self.buttons.place(button_area); diff --git a/core/embed/rust/src/ui/model_tr/component/flow_pages.rs b/core/embed/rust/src/ui/model_tr/component/flow_pages.rs index c488b93e5..a4cf0b19d 100644 --- a/core/embed/rust/src/ui/model_tr/component/flow_pages.rs +++ b/core/embed/rust/src/ui/model_tr/component/flow_pages.rs @@ -84,6 +84,7 @@ where current_page: usize, page_count: usize, title: Option, + slim_arrows: bool, } // For `layout.rs` @@ -103,6 +104,7 @@ where current_page: 0, page_count: 1, title: None, + slim_arrows: false, } } } @@ -118,6 +120,12 @@ where self } + /// Using slim arrows instead of wide buttons. + pub fn with_slim_arrows(mut self) -> Self { + self.slim_arrows = true; + self + } + pub fn paint(&mut self) { self.change_page(self.current_page); self.formatted.paint(); @@ -137,17 +145,29 @@ where // On the last page showing only the narrow arrow, so the right // button with possibly long text has enough space. let btn_left = if self.has_prev_page() && !self.has_next_page() { - Some(ButtonDetails::up_arrow_icon()) + if self.slim_arrows { + Some(ButtonDetails::left_arrow_icon()) + } else { + Some(ButtonDetails::up_arrow_icon()) + } } else if self.has_prev_page() { - Some(ButtonDetails::up_arrow_icon_wide()) + if self.slim_arrows { + Some(ButtonDetails::left_arrow_icon()) + } else { + Some(ButtonDetails::up_arrow_icon_wide()) + } } else { current.btn_left }; // Middle button should be shown only on the last page, not to collide - // with the fat right button. + // with the possible fat right button. let (btn_middle, btn_right) = if self.has_next_page() { - (None, Some(ButtonDetails::down_arrow_icon_wide())) + if self.slim_arrows { + (None, Some(ButtonDetails::right_arrow_icon())) + } else { + (None, Some(ButtonDetails::down_arrow_icon_wide())) + } } else { (current.btn_middle, current.btn_right) }; diff --git a/core/embed/rust/src/ui/model_tr/component/homescreen.rs b/core/embed/rust/src/ui/model_tr/component/homescreen.rs index f941d4ffa..61ca4c969 100644 --- a/core/embed/rust/src/ui/model_tr/component/homescreen.rs +++ b/core/embed/rust/src/ui/model_tr/component/homescreen.rs @@ -102,7 +102,7 @@ where let mut outset = Insets::uniform(LABEL_OUTSET); // the margin at top is bigger (caused by text-height vs line-height?) // compensate by shrinking the outset - outset.top -= 1; + outset.top -= 2; rect_fill(self.label.text_area().outset(outset), theme::BG); self.label.paint(); } diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/choice.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/choice.rs index 117297647..21d45d752 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/choice.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/choice.rs @@ -3,10 +3,13 @@ use crate::{ ui::{ component::{Child, Component, Event, EventCtx, Pad}, geometry::{Insets, Offset, Rect}, + util::animation_disabled, }, }; -use super::super::{theme, ButtonController, ButtonControllerMsg, ButtonLayout, ButtonPos}; +use super::super::{ + constant, theme, AutomaticMover, ButtonController, ButtonControllerMsg, ButtonLayout, ButtonPos, +}; const DEFAULT_ITEMS_DISTANCE: i16 = 10; @@ -79,6 +82,13 @@ where /// Whether the middle selected item should be painted with /// inverse colors - black on white. inverse_selected_item: bool, + /// For moving through the items when holding left/right button + holding_mover: AutomaticMover, + /// For doing quick animations when changing the page counter. + animation_mover: AutomaticMover, + /// How many animated steps we should still do (positive for right, negative + /// for left). + animated_steps_to_do: i16, } impl ChoicePage @@ -89,16 +99,30 @@ where pub fn new(choices: F) -> Self { let initial_btn_layout = choices.get(0).0.btn_layout(); + /// First move happens immediately, then in 35 ms intervals + fn animation_duration_func(steps: usize) -> u32 { + match steps { + 0 => 0, + _ => 35, + } + } + Self { choices, pad: Pad::with_background(theme::BG), - buttons: Child::new(ButtonController::new(initial_btn_layout)), + buttons: Child::new( + ButtonController::new(initial_btn_layout) + .with_ignore_btn_delay(constant::IGNORE_OTHER_BTN_MS), + ), page_counter: 0, items_distance: DEFAULT_ITEMS_DISTANCE, is_carousel: false, show_incomplete: false, show_only_one_item: false, inverse_selected_item: false, + holding_mover: AutomaticMover::new(), + animation_mover: AutomaticMover::new().with_duration_func(animation_duration_func), + animated_steps_to_do: 0, } } @@ -107,7 +131,10 @@ where pub fn with_initial_page_counter(mut self, page_counter: usize) -> Self { self.page_counter = page_counter; let initial_btn_layout = self.get_current_choice().0.btn_layout(); - self.buttons = Child::new(ButtonController::new(initial_btn_layout)); + self.buttons = Child::new( + ButtonController::new(initial_btn_layout) + .with_ignore_btn_delay(constant::IGNORE_OTHER_BTN_MS), + ); self } @@ -156,9 +183,33 @@ where } /// Navigating to the chosen page index. - pub fn set_page_counter(&mut self, ctx: &mut EventCtx, page_counter: usize) { - self.page_counter = page_counter; - self.update(ctx); + pub fn set_page_counter( + &mut self, + ctx: &mut EventCtx, + page_counter: usize, + do_animation: bool, + ) { + // Either moving with animation or just jumping to the final position directly. + if do_animation && !animation_disabled() { + let diff = page_counter as i16 - self.page_counter as i16; + // When there would be a small number of animation frames (3 or less), + // animating in the opposite direction to make the animation longer. + self.animated_steps_to_do = match diff { + -3..=0 => diff + self.choices.count() as i16, + 1..=3 => diff - self.choices.count() as i16, + _ => diff, + }; + // Starting the movement immediately - either left or right. + let pos = if self.animated_steps_to_do > 0 { + ButtonPos::Right + } else { + ButtonPos::Left + }; + self.animation_mover.start_moving(ctx, pos); + } else { + self.page_counter = page_counter; + self.update(ctx); + } } /// Display current, previous and next choices according to @@ -356,14 +407,66 @@ where /// whether they are long-pressed, and painting them. fn set_buttons(&mut self, ctx: &mut EventCtx) { let btn_layout = self.get_current_choice().0.btn_layout(); - self.buttons.mutate(ctx, |_ctx, buttons| { + self.buttons.mutate(ctx, |ctx, buttons| { buttons.set(btn_layout); + // When user holds one of the buttons, highlighting it. + if let Some(btn_down) = self.holding_mover.moving_direction() { + buttons.highlight_button(ctx, btn_down); + } + ctx.request_paint(); }); } pub fn choice_factory(&self) -> &F { &self.choices } + + /// Go to the choice visually on the left. + fn move_left(&mut self, ctx: &mut EventCtx) { + if self.has_previous_choice() { + self.decrease_page_counter(); + self.update(ctx); + } else if self.is_carousel { + self.page_counter_to_max(); + self.update(ctx); + } + } + + /// Go to the choice visually on the right. + fn move_right(&mut self, ctx: &mut EventCtx) { + if self.has_next_choice() { + self.increase_page_counter(); + self.update(ctx); + } else if self.is_carousel { + self.page_counter_to_zero(); + self.update(ctx); + } + } + + /// Possibly doing an animation movement with the choice - either left or + /// right. + fn animation_event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if animation_disabled() { + return None; + } + // Stopping the movement if it is moving and there are no steps left + if self.animated_steps_to_do == 0 { + if self.animation_mover.is_moving() { + self.animation_mover.stop_moving(); + } + return None; + } + let animation_result = self.animation_mover.event(ctx, event); + // When about to animate, decreasing the number of steps to do. + if animation_result.is_some() { + if self.animated_steps_to_do > 0 { + self.animated_steps_to_do -= 1; + } else { + self.animated_steps_to_do += 1; + } + } + animation_result + } } impl Component for ChoicePage @@ -381,32 +484,67 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + // Possible animation movement when setting (randomizing) the page counter. + if let Some(animation_direction) = self.animation_event(ctx, event) { + match animation_direction { + ButtonPos::Left => self.move_left(ctx), + ButtonPos::Right => self.move_right(ctx), + _ => {} + } + return None; + } + + // When animation is running, ignoring all user events + if self.animation_mover.is_moving() { + return None; + } + + // Possible automatic movement when user is holding left or right button. + if let Some(auto_move_direction) = self.holding_mover.event(ctx, event) { + match auto_move_direction { + ButtonPos::Left => self.move_left(ctx), + ButtonPos::Right => self.move_right(ctx), + _ => {} + } + return None; + } + let button_event = self.buttons.event(ctx, event); - // Button was "triggered" - released. Doing the appropriate action. + // Possibly stopping or starting the automatic mover. + if let Some(moving_direction) = self.holding_mover.moving_direction() { + // Stopping the automatic movement when the released button is the same as the + // direction we were moving, or when the pressed button is the + // opposite one (user does middle-click). + if matches!(button_event, Some(ButtonControllerMsg::Triggered(pos)) if pos == moving_direction) + || matches!(button_event, Some(ButtonControllerMsg::Pressed(pos)) if pos != moving_direction) + { + self.holding_mover.stop_moving(); + // Ignoring the event when it already did some automatic movements. (Otherwise + // it would do one more movement.) + if self.holding_mover.was_moving() { + return None; + } + } + } else if let Some(ButtonControllerMsg::Pressed(pos)) = button_event { + // Starting the movement when left/right button is pressed. + if matches!(pos, ButtonPos::Left | ButtonPos::Right) { + self.holding_mover.start_moving(ctx, pos); + } + } + + // There was a legitimate button event - doing some action if let Some(ButtonControllerMsg::Triggered(pos)) = button_event { match pos { ButtonPos::Left => { - if self.has_previous_choice() { - // Clicked BACK. Decrease the page counter. - self.decrease_page_counter(); - self.update(ctx); - } else if self.is_carousel { - // In case of carousel going to the right end. - self.page_counter_to_max(); - self.update(ctx); - } + // Clicked BACK. Decrease the page counter. + // In case of carousel going to the right end. + self.move_left(ctx); } ButtonPos::Right => { - if self.has_next_choice() { - // Clicked NEXT. Increase the page counter. - self.increase_page_counter(); - self.update(ctx); - } else if self.is_carousel { - // In case of carousel going to the left end. - self.page_counter_to_zero(); - self.update(ctx); - } + // Clicked NEXT. Increase the page counter. + // In case of carousel going to the left end. + self.move_right(ctx); } ButtonPos::Middle => { // Clicked SELECT. Send current choice index @@ -415,7 +553,7 @@ where } } }; - // The middle button was "pressed", highlighting the current choice by color + // The middle button was pressed, highlighting the current choice by color // inversion. if let Some(ButtonControllerMsg::Pressed(ButtonPos::Middle)) = button_event { self.inverse_selected_item = true; diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs index 9741852ed..c13e48036 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs @@ -236,6 +236,7 @@ pub struct PassphraseEntry { choice_page: ChoicePage, passphrase_dots: Child>>, show_plain_passphrase: bool, + show_last_digit: bool, textbox: TextBox, current_category: ChoiceCategory, } @@ -251,6 +252,7 @@ where .with_initial_page_counter(random_menu_position()), passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())), show_plain_passphrase: false, + show_last_digit: false, textbox: TextBox::empty(), current_category: ChoiceCategory::Menu, } @@ -259,11 +261,20 @@ where fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) { let text_to_show = if self.show_plain_passphrase { String::from(self.passphrase()) + } else if self.is_empty() { + String::from("") } else { + // Showing asterisks and possibly the last digit. let mut dots: String = String::new(); - for _ in 0..self.textbox.len() { - unwrap!(dots.push_str("*")); + for _ in 0..self.textbox.len() - 1 { + unwrap!(dots.push('*')); } + let last_char = if self.show_last_digit { + unwrap!(self.textbox.content().chars().last()) + } else { + '*' + }; + unwrap!(dots.push(last_char)); dots }; self.passphrase_dots.mutate(ctx, |ctx, passphrase_dots| { @@ -312,8 +323,11 @@ where /// Randomly choose an index in the current category fn randomize_category_position(&mut self, ctx: &mut EventCtx) { - self.choice_page - .set_page_counter(ctx, random_category_position(&self.current_category)); + self.choice_page.set_page_counter( + ctx, + random_category_position(&self.current_category), + true, + ); } } @@ -332,10 +346,17 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - // Any event when showing real passphrase should hide it - if self.show_plain_passphrase { - self.show_plain_passphrase = false; - self.update_passphrase_dots(ctx); + // Any non-timer event when showing real passphrase should hide it + // Same with showing last digit + if !matches!(event, Event::Timer(_)) { + if self.show_plain_passphrase { + self.show_plain_passphrase = false; + self.update_passphrase_dots(ctx); + } + if self.show_last_digit { + self.show_last_digit = false; + self.update_passphrase_dots(ctx); + } } if let Some(action) = self.choice_page.event(ctx, event) { @@ -373,6 +394,7 @@ where } PassphraseAction::Character(ch) if !self.is_full() => { self.append_char(ctx, ch); + self.show_last_digit = true; self.update_passphrase_dots(ctx); self.randomize_category_position(ctx); ctx.request_paint(); diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs index 5405b62e5..ef3495631 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs @@ -3,7 +3,7 @@ use crate::{ trezorhal::random, ui::{ component::{text::common::TextBox, Child, Component, ComponentExt, Event, EventCtx}, - display::Icon, + display::{Font, Icon}, geometry::Rect, }, }; @@ -80,8 +80,12 @@ impl ChoiceFactory for ChoiceFactoryPIN { /// Component for entering a PIN. pub struct PinEntry { choice_page: ChoicePage, + header_line: Child>>, pin_line: Child>>, + prompt: T, subprompt: T, + /// Whether we already show the "real" prompt (not the warning). + showing_real_prompt: bool, show_real_pin: bool, show_last_digit: bool, textbox: TextBox, @@ -91,22 +95,45 @@ impl PinEntry where T: StringType + Clone, { - pub fn new(subprompt: T) -> Self { - let pin_line_content = if !subprompt.as_ref().is_empty() { - String::from(subprompt.as_ref()) + pub fn new(prompt: T, subprompt: T) -> Self { + // When subprompt is not empty, it means that the user has entered bad PIN + // before. In this case we show the warning together with the subprompt + // at the beginning. (WRONG PIN will be replaced by real prompt after + // any button click.) + let show_subprompt = !subprompt.as_ref().is_empty(); + let (showing_real_prompt, header_line_content, pin_line_content) = if show_subprompt { + ( + false, + String::from("WRONG PIN"), + String::from(subprompt.as_ref()), + ) } else { - String::from(EMPTY_PIN_STR) + ( + true, + String::from(prompt.as_ref()), + String::from(EMPTY_PIN_STR), + ) }; + let mut pin_line = ChangingTextLine::center_bold(pin_line_content).without_ellipsis(); + if show_subprompt { + pin_line.update_font(Font::NORMAL); + } + Self { // Starting at a random digit. choice_page: ChoicePage::new(ChoiceFactoryPIN) .with_initial_page_counter(get_random_digit_position()) .with_carousel(true), - pin_line: Child::new( - ChangingTextLine::center_bold(pin_line_content).without_ellipsis(), + header_line: Child::new( + ChangingTextLine::center_bold(header_line_content) + .without_ellipsis() + .with_text_at_the_top(), ), + pin_line: Child::new(pin_line), subprompt, + prompt, + showing_real_prompt, show_real_pin: false, show_last_digit: false, textbox: TextBox::empty(), @@ -122,7 +149,10 @@ where /// Show updated content in the changing line. /// Many possibilities, according to the PIN state. fn update_pin_line(&mut self, ctx: &mut EventCtx) { + let mut used_font = Font::BOLD; let pin_line_text = if self.is_empty() && !self.subprompt.as_ref().is_empty() { + // Showing the subprompt in NORMAL font + used_font = Font::NORMAL; String::from(self.subprompt.as_ref()) } else if self.is_empty() { String::from(EMPTY_PIN_STR) @@ -144,11 +174,20 @@ where }; self.pin_line.mutate(ctx, |ctx, pin_line| { + pin_line.update_font(used_font); pin_line.update_text(pin_line_text); pin_line.request_complete_repaint(ctx); }); } + /// Showing the real prompt instead of WRONG PIN + fn show_prompt(&mut self, ctx: &mut EventCtx) { + self.header_line.mutate(ctx, |ctx, header_line| { + header_line.update_text(String::from(self.prompt.as_ref())); + header_line.request_complete_repaint(ctx); + }); + } + pub fn pin(&self) -> &str { self.textbox.content() } @@ -169,23 +208,36 @@ where type Msg = CancelConfirmMsg; fn place(&mut self, bounds: Rect) -> Rect { + let header_height = self.header_line.inner().needed_height(); + let (header_area, rest) = bounds.split_top(header_height); let pin_height = self.pin_line.inner().needed_height(); - let (pin_area, choice_area) = bounds.split_top(pin_height); + let (pin_area, choice_area) = rest.split_top(pin_height); + self.header_line.place(header_area); self.pin_line.place(pin_area); self.choice_page.place(choice_area); bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - // Any event when showing real PIN should hide it + // Any non-timer event when showing real PIN should hide it // Same with showing last digit - if self.show_real_pin { - self.show_real_pin = false; - self.update(ctx) + if !matches!(event, Event::Timer(_)) { + if self.show_real_pin { + self.show_real_pin = false; + self.update(ctx) + } + if self.show_last_digit { + self.show_last_digit = false; + self.update(ctx) + } } - if self.show_last_digit { - self.show_last_digit = false; - self.update(ctx) + + // Any button event will show the "real" prompt + if !self.showing_real_prompt { + if let Event::Button(_) = event { + self.show_prompt(ctx); + self.showing_real_prompt = true; + } } match self.choice_page.event(ctx, event) { @@ -204,7 +256,7 @@ where self.textbox.append(ctx, ch); // Choosing random digit to be shown next self.choice_page - .set_page_counter(ctx, get_random_digit_position()); + .set_page_counter(ctx, get_random_digit_position(), true); self.show_last_digit = true; self.update(ctx); None @@ -214,6 +266,7 @@ where } fn paint(&mut self) { + self.header_line.paint(); self.pin_line.paint(); self.choice_page.paint(); } diff --git a/core/embed/rust/src/ui/model_tr/component/mod.rs b/core/embed/rust/src/ui/model_tr/component/mod.rs index f2baee252..c11626577 100644 --- a/core/embed/rust/src/ui/model_tr/component/mod.rs +++ b/core/embed/rust/src/ui/model_tr/component/mod.rs @@ -13,7 +13,7 @@ pub use button::{ Button, ButtonAction, ButtonActions, ButtonContent, ButtonDetails, ButtonLayout, ButtonPos, ButtonStyle, ButtonStyleSheet, }; -pub use button_controller::{ButtonController, ButtonControllerMsg}; +pub use button_controller::{AutomaticMover, ButtonController, ButtonControllerMsg}; pub use common_messages::CancelConfirmMsg; pub use error::ErrorScreen; pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg}; diff --git a/core/embed/rust/src/ui/model_tr/component/show_more.rs b/core/embed/rust/src/ui/model_tr/component/show_more.rs index cca56bf7e..360f1d690 100644 --- a/core/embed/rust/src/ui/model_tr/component/show_more.rs +++ b/core/embed/rust/src/ui/model_tr/component/show_more.rs @@ -27,8 +27,12 @@ where T: Component, U: StringType + Clone, { - pub fn new(content: T) -> Self { - let btn_layout = ButtonLayout::cancel_armed_info("CONFIRM".into()); + pub fn new(content: T, cancel_button: Option, button: U) -> Self { + let btn_layout = if let Some(cancel_text) = cancel_button { + ButtonLayout::text_armed_info(cancel_text, button) + } else { + ButtonLayout::cancel_armed_info(button) + }; Self { content: Child::new(content), buttons: Child::new(ButtonController::new(btn_layout)), diff --git a/core/embed/rust/src/ui/model_tr/constant.rs b/core/embed/rust/src/ui/model_tr/constant.rs index c2f4ecc6b..b39257d86 100644 --- a/core/embed/rust/src/ui/model_tr/constant.rs +++ b/core/embed/rust/src/ui/model_tr/constant.rs @@ -22,3 +22,5 @@ pub const fn screen() -> Rect { Rect::from_top_left_and_size(Point::zero(), SIZE) } pub const SCREEN: Rect = screen(); + +pub const IGNORE_OTHER_BTN_MS: u32 = 200; diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 32532fc13..ee1b01538 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -22,7 +22,7 @@ use crate::{ }, TextStyle, }, - ComponentExt, FormattedText, LineBreaking, Timeout, + ComponentExt, FormattedText, Timeout, }, display, geometry, layout::{ @@ -254,15 +254,7 @@ fn content_in_button_page( hold: bool, ) -> Result { // Left button - icon, text or nothing. - let cancel_btn = if let Some(verb_cancel) = verb_cancel { - if !verb_cancel.is_empty() { - Some(ButtonDetails::text(verb_cancel)) - } else { - Some(ButtonDetails::cancel_icon()) - } - } else { - None - }; + let cancel_btn = verb_cancel.map(ButtonDetails::from_text_possible_icon); // Right button - text or nothing. // Optional HoldToConfirm @@ -407,8 +399,7 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: let ops = OpTextLayout::::new(theme::TEXT_NORMAL) .text_normal("By continuing you agree to Trezor Company's terms and conditions.".into()) - .newline() - .newline() + .next_page() .text_normal("More info at".into()) .newline() .text_bold("trezor.io/tos".into()); @@ -559,44 +550,61 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { +extern "C" fn new_confirm_output_address(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = |_args: &[Obj], kwargs: &Map| { let address: StrBuffer = kwargs.get(Qstr::MP_QSTR_address)?.try_into()?; let address_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_address_label)?.try_into()?; - let amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?; let address_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_address_title)?.try_into()?; - let amount_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount_title)?.try_into()?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; let get_page = move |page_index| { - // Showing two screens - the recipient address and summary confirmation - match page_index { - 0 => { - // RECIPIENT + address - let btn_layout = ButtonLayout::cancel_none_text("CONTINUE".into()); - let btn_actions = ButtonActions::cancel_none_next(); - // Not putting hyphens in the address. - // Potentially adding address label in different font. - let mut ops = OpTextLayout::new(theme::TEXT_MONO) - .line_breaking(LineBreaking::BreakWordsNoHyphen); - if !address_label.is_empty() { - ops = ops.text_normal(address_label.clone()).newline(); - } - ops = ops.text_mono(address.clone()); - let formatted = FormattedText::new(ops).vertically_centered(); - Page::new(btn_layout, btn_actions, formatted).with_title(address_title.clone()) - } - 1 => { - // AMOUNT + amount - let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into()); - let btn_actions = ButtonActions::prev_none_confirm(); - let ops = OpTextLayout::new(theme::TEXT_MONO).text_mono(amount.clone()); - let formatted = FormattedText::new(ops).vertically_centered(); - Page::new(btn_layout, btn_actions, formatted).with_title(amount_title.clone()) + assert!(page_index == 0); + // RECIPIENT + address + let btn_layout = ButtonLayout::cancel_none_text("CONTINUE".into()); + let btn_actions = ButtonActions::cancel_none_confirm(); + // Not putting hyphens in the address. + // Potentially adding address label in different font. + let mut ops = OpTextLayout::new(theme::TEXT_MONO_DATA); + if !address_label.is_empty() { + // NOTE: need to explicitly turn off the chunkification before rendering the + // address label (for some reason it does not help to turn it off after + // rendering the chunks) + if chunkify { + ops = ops.chunkify_text(None); } - _ => unreachable!(), + ops = ops.text_normal(address_label.clone()).newline(); } + if chunkify { + // Chunkifying the address into smaller pieces when requested + ops = ops.chunkify_text(Some((theme::MONO_CHUNKS, 2))); + } + ops = ops.text_mono(address.clone()); + let formatted = FormattedText::new(ops).vertically_centered(); + Page::new(btn_layout, btn_actions, formatted).with_title(address_title.clone()) }; - let pages = FlowPages::new(get_page, 2); + let pages = FlowPages::new(get_page, 1); + + let obj = LayoutObj::new(Flow::new(pages))?; + Ok(obj.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + +extern "C" fn new_confirm_output_amount(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = |_args: &[Obj], kwargs: &Map| { + let amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?; + let amount_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount_title)?.try_into()?; + + let get_page = move |page_index| { + assert!(page_index == 0); + // AMOUNT + amount + let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into()); + let btn_actions = ButtonActions::cancel_none_confirm(); + let ops = OpTextLayout::new(theme::TEXT_MONO).text_mono(amount.clone()); + let formatted = FormattedText::new(ops).vertically_centered(); + Page::new(btn_layout, btn_actions, formatted).with_title(amount_title.clone()) + }; + let pages = FlowPages::new(get_page, 1); let obj = LayoutObj::new(Flow::new(pages))?; Ok(obj.into()) @@ -687,20 +695,95 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_ethereum_tx(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = |_args: &[Obj], kwargs: &Map| { + let recipient: StrBuffer = kwargs.get(Qstr::MP_QSTR_recipient)?.try_into()?; + let total_amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_amount)?.try_into()?; + let maximum_fee: StrBuffer = kwargs.get(Qstr::MP_QSTR_maximum_fee)?.try_into()?; + let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; + + let get_page = move |page_index| { + match page_index { + 0 => { + // RECIPIENT + let btn_layout = ButtonLayout::cancel_none_text("CONTINUE".into()); + let btn_actions = ButtonActions::cancel_none_next(); + + let ops = OpTextLayout::new(theme::TEXT_MONO_DATA).text_mono(recipient.clone()); + + let formatted = FormattedText::new(ops).vertically_centered(); + Page::new(btn_layout, btn_actions, formatted).with_title("RECIPIENT".into()) + } + 1 => { + // Total amount + fee + let btn_layout = ButtonLayout::up_arrow_armed_info("CONFIRM".into()); + let btn_actions = ButtonActions::prev_confirm_next(); + + let ops = OpTextLayout::new(theme::TEXT_MONO) + .text_mono(total_amount.clone()) + .newline() + .newline_half() + .text_bold("Maximum fee:".into()) + .newline() + .text_mono(maximum_fee.clone()); + + let formatted = FormattedText::new(ops); + Page::new(btn_layout, btn_actions, formatted).with_title("Amount:".into()) + } + 2 => { + // Fee information + let btn_layout = ButtonLayout::arrow_none_none(); + let btn_actions = ButtonActions::prev_none_none(); + + let mut ops = OpTextLayout::new(theme::TEXT_MONO); + + for item in unwrap!(IterBuf::new().try_iterate(items)) { + let [key, value]: [Obj; 2] = unwrap!(iter_into_array(item)); + if !ops.is_empty() { + // Each key-value pair is on its own page + ops = ops.next_page(); + } + ops = ops + .text_bold(unwrap!(key.try_into())) + .newline() + .text_mono(unwrap!(value.try_into())); + } + + let formatted = FormattedText::new(ops).vertically_centered(); + Page::new(btn_layout, btn_actions, formatted) + .with_title("FEE INFORMATION".into()) + .with_slim_arrows() + } + _ => unreachable!(), + } + }; + let pages = FlowPages::new(get_page, 3); + + let obj = LayoutObj::new(Flow::new(pages).with_scrollbar(false))?; + Ok(obj.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let address: StrBuffer = kwargs.get(Qstr::MP_QSTR_data)?.try_into()?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; let get_page = move |page_index| { assert!(page_index == 0); let btn_layout = ButtonLayout::cancel_armed_info("CONFIRM".into()); let btn_actions = ButtonActions::cancel_confirm_info(); - let ops = OpTextLayout::new(theme::TEXT_MONO) - .line_breaking(LineBreaking::BreakWordsNoHyphen) - .text_mono(address.clone()); - let formatted = FormattedText::new(ops); + let style = if chunkify { + // Chunkifying the address into smaller pieces when requested + theme::TEXT_MONO_ADDRESS_CHUNKS + } else { + theme::TEXT_MONO_DATA + }; + let ops = OpTextLayout::new(style).text_mono(address.clone()); + let formatted = FormattedText::new(ops).vertically_centered(); Page::new(btn_layout, btn_actions, formatted).with_title(title.clone()) }; let pages = FlowPages::new(get_page, 1); @@ -798,7 +881,14 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj let pages = FlowPages::new(get_page, PAGE_COUNT); - let obj = LayoutObj::new(Flow::new(pages).with_scrollbar(false))?; + // Setting the ignore-second-button to mimic all the Choice pages, to teach user + // that they should really press both buttons at the same time to achieve + // middle-click. + let obj = LayoutObj::new( + Flow::new(pages) + .with_scrollbar(false) + .with_ignore_second_button_ms(constant::IGNORE_OTHER_BTN_MS), + )?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1028,15 +1118,16 @@ extern "C" fn new_show_passphrase() -> Obj { unsafe { util::try_or_raise(block) } } -extern "C" fn new_show_mismatch() -> Obj { - let block = move || { +extern "C" fn new_show_mismatch(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let get_page = move |page_index| { assert!(page_index == 0); let btn_layout = ButtonLayout::arrow_none_text("QUIT".into()); let btn_actions = ButtonActions::cancel_none_confirm(); let ops = OpTextLayout::::new(theme::TEXT_NORMAL) - .text_bold("ADDRESS MISMATCH?".into()) + .text_bold(title.clone()) .newline() .newline_half() .text_normal("Please contact Trezor support at".into()) @@ -1050,19 +1141,24 @@ extern "C" fn new_show_mismatch() -> Obj { let obj = LayoutObj::new(Flow::new(pages))?; Ok(obj.into()) }; - unsafe { util::try_or_raise(block) } + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?; + let verb_cancel: Option = kwargs + .get(Qstr::MP_QSTR_verb_cancel) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let mut paragraphs = ParagraphVecShort::new(); for para in IterBuf::new().try_iterate(items)? { let [font, text]: [Obj; 2] = iter_into_array(para)?; - let style: &TextStyle = theme::textstyle_number_bold_or_mono(font.try_into()?); + let style: &TextStyle = theme::textstyle_number(font.try_into()?); let text: StrBuffer = text.try_into()?; paragraphs.add(Paragraph::new(style, text)); if paragraphs.is_full() { @@ -1074,6 +1170,8 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu title, ShowMore::>, StrBuffer>::new( paragraphs.into_paragraphs(), + verb_cancel, + button, ), ))?; Ok(obj.into()) @@ -1081,6 +1179,32 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_more(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?; + let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; + + let mut paragraphs = ParagraphVecLong::new(); + + for para in IterBuf::new().try_iterate(items)? { + let [font, text]: [Obj; 2] = iter_into_array(para)?; + let style: &TextStyle = theme::textstyle_number(font.try_into()?); + let text: StrBuffer = text.try_into()?; + paragraphs.add(Paragraph::new(style, text)); + } + + content_in_button_page( + title, + paragraphs.into_paragraphs(), + button, + Some("<".into()), + false, + ) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let max_rounds: StrBuffer = kwargs.get(Qstr::MP_QSTR_max_rounds)?.try_into()?; @@ -1112,8 +1236,7 @@ extern "C" fn new_request_pin(n_args: usize, args: *const Obj, kwargs: *mut Map) let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?; let subprompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_subprompt)?.try_into()?; - let obj = - LayoutObj::new(Frame::new(prompt, PinEntry::new(subprompt)).with_title_centered())?; + let obj = LayoutObj::new(PinEntry::new(prompt, subprompt))?; Ok(obj.into()) }; @@ -1483,6 +1606,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// data: str, /// description: str | None, # unused on TR /// extra: str | None, # unused on TR + /// chunkify: bool = False, /// ) -> object: /// """Confirm address.""" Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(), @@ -1551,16 +1675,23 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Decrease or increase amount for given address.""" Qstr::MP_QSTR_confirm_modify_output => obj_fn_kw!(0, new_confirm_modify_output).as_obj(), - /// def confirm_output( + /// def confirm_output_address( /// *, /// address: str, /// address_label: str, - /// amount: str, /// address_title: str, + /// chunkify: bool = False, + /// ) -> object: + /// """Confirm output address.""" + Qstr::MP_QSTR_confirm_output_address => obj_fn_kw!(0, new_confirm_output_address).as_obj(), + + /// def confirm_output_amount( + /// *, + /// amount: str, /// amount_title: str, /// ) -> object: - /// """Confirm output.""" - Qstr::MP_QSTR_confirm_output => obj_fn_kw!(0, new_confirm_output).as_obj(), + /// """Confirm output amount.""" + Qstr::MP_QSTR_confirm_output_amount => obj_fn_kw!(0, new_confirm_output_amount).as_obj(), /// def confirm_total( /// *, @@ -1574,6 +1705,16 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm summary of a transaction.""" Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(), + /// def confirm_ethereum_tx( + /// *, + /// recipient: str, + /// total_amount: str, + /// maximum_fee: str, + /// items: Iterable[Tuple[str, str]], + /// ) -> object: + /// """Confirm details about Ethereum transaction.""" + Qstr::MP_QSTR_confirm_ethereum_tx => obj_fn_kw!(0, new_confirm_ethereum_tx).as_obj(), + /// def tutorial() -> object: /// """Show user how to interact with the device.""" Qstr::MP_QSTR_tutorial => obj_fn_kw!(0, tutorial).as_obj(), @@ -1633,21 +1774,32 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Show passphrase on host dialog.""" Qstr::MP_QSTR_show_passphrase => obj_fn_0!(new_show_passphrase).as_obj(), - /// def show_mismatch() -> object: + /// def show_mismatch(*, title: str) -> object: /// """Warning modal, receiving address mismatch.""" - Qstr::MP_QSTR_show_mismatch => obj_fn_0!(new_show_mismatch).as_obj(), + Qstr::MP_QSTR_show_mismatch => obj_fn_kw!(0, new_show_mismatch).as_obj(), /// def confirm_with_info( /// *, /// title: str, - /// button: str, # unused on TR + /// button: str, /// info_button: str, # unused on TR /// items: Iterable[Tuple[int, str]], + /// verb_cancel: str | None = None, /// ) -> object: /// """Confirm given items but with third button. Always single page /// without scrolling.""" Qstr::MP_QSTR_confirm_with_info => obj_fn_kw!(0, new_confirm_with_info).as_obj(), + /// def confirm_more( + /// *, + /// title: str, + /// button: str, + /// items: Iterable[tuple[int, str]], + /// ) -> object: + /// """Confirm long content with the possibility to go back from any page. + /// Meant to be used with confirm_with_info.""" + Qstr::MP_QSTR_confirm_more => obj_fn_kw!(0, new_confirm_more).as_obj(), + /// def confirm_coinjoin( /// *, /// max_rounds: str, diff --git a/core/embed/rust/src/ui/model_tr/theme.rs b/core/embed/rust/src/ui/model_tr/theme.rs index adbb14216..0dd5b1603 100644 --- a/core/embed/rust/src/ui/model_tr/theme.rs +++ b/core/embed/rust/src/ui/model_tr/theme.rs @@ -1,5 +1,8 @@ use crate::ui::{ - component::{text::TextStyle, LineBreaking, PageBreaking}, + component::{ + text::{layout::Chunks, TextStyle}, + LineBreaking, PageBreaking, + }, display::{toif::Icon, Color, Font}, geometry::Offset, }; @@ -35,15 +38,22 @@ pub const TEXT_MONO: TextStyle = TextStyle::new(Font::MONO, FG, BG, FG, FG) /// Mono data text does not have hyphens pub const TEXT_MONO_DATA: TextStyle = TEXT_MONO.with_line_breaking(LineBreaking::BreakWordsNoHyphen); +pub const TEXT_MONO_ADDRESS_CHUNKS: TextStyle = TEXT_MONO_DATA + .with_chunks(MONO_CHUNKS) + .with_line_spacing(2) + .with_ellipsis_icon(ICON_NEXT_PAGE, -2); + +// Chunks for this model, with accounting for some wider characters in MONO font +pub const MONO_CHUNKS: Chunks = Chunks::new(4, 4).with_wider_chars("mMwW"); /// Convert Python-side numeric id to a `TextStyle`. -/// Using only BOLD or MONO fonts. -pub fn textstyle_number_bold_or_mono(num: i32) -> &'static TextStyle { +pub fn textstyle_number(num: i32) -> &'static TextStyle { let font = Font::from_i32(-num); match font { Some(Font::BOLD) => &TEXT_BOLD, Some(Font::DEMIBOLD) => &TEXT_BOLD, - _ => &TEXT_MONO, + Some(Font::NORMAL) => &TEXT_NORMAL, + _ => &TEXT_MONO_DATA, } } diff --git a/core/embed/rust/src/ui/model_tt/component/address_details.rs b/core/embed/rust/src/ui/model_tt/component/address_details.rs index 1a099527f..c563c2c2f 100644 --- a/core/embed/rust/src/ui/model_tt/component/address_details.rs +++ b/core/embed/rust/src/ui/model_tt/component/address_details.rs @@ -30,8 +30,10 @@ where T: StringType, { pub fn new( + qr_title: T, qr_address: T, case_sensitive: bool, + details_title: T, account: Option, path: Option, ) -> Result @@ -53,14 +55,14 @@ where let result = Self { qr_code: Frame::left_aligned( theme::label_title(), - "RECEIVE ADDRESS".into(), + qr_title, Qr::new(qr_address, case_sensitive)?.with_border(7), ) .with_cancel_button() .with_border(theme::borders_horizontal_scroll()), details: Frame::left_aligned( theme::label_title(), - "RECEIVING TO".into(), + details_title, para.into_paragraphs(), ) .with_cancel_button() diff --git a/core/embed/rust/src/ui/model_tt/component/dialog.rs b/core/embed/rust/src/ui/model_tt/component/dialog.rs index 72f594930..2e7f409b6 100644 --- a/core/embed/rust/src/ui/model_tt/component/dialog.rs +++ b/core/embed/rust/src/ui/model_tt/component/dialog.rs @@ -119,19 +119,25 @@ where } } - pub fn with_text(mut self, style: &'static TextStyle, text: T) -> Self { - if !text.as_ref().is_empty() { - self.paragraphs - .inner_mut() - .add(Paragraph::new(style, text).centered()); + pub fn with_paragraph(mut self, para: Paragraph) -> Self { + if !para.content().as_ref().is_empty() { + self.paragraphs.inner_mut().add(para); } self } + pub fn with_text(self, style: &'static TextStyle, text: T) -> Self { + self.with_paragraph(Paragraph::new(style, text).centered()) + } + pub fn with_description(self, description: T) -> Self { self.with_text(&theme::TEXT_NORMAL_OFF_WHITE, description) } + pub fn with_value(self, value: T) -> Self { + self.with_text(&theme::TEXT_MONO, value) + } + pub fn new_shares(lines: [T; 4], controls: U) -> Self { let [l0, l1, l2, l3] = lines; Self { diff --git a/core/embed/rust/src/ui/model_tt/component/hold_to_confirm.rs b/core/embed/rust/src/ui/model_tt/component/hold_to_confirm.rs index 6650901bb..a5e56f166 100644 --- a/core/embed/rust/src/ui/model_tt/component/hold_to_confirm.rs +++ b/core/embed/rust/src/ui/model_tt/component/hold_to_confirm.rs @@ -133,6 +133,15 @@ impl CancelHold { }) } + pub fn with_cancel_arrow() -> FixedHeightBar { + theme::button_bar(Self { + cancel: Some(Button::with_icon(theme::ICON_UP).into_child()), + hold: Button::with_text("HOLD TO CONFIRM") + .styled(theme::button_confirm()) + .into_child(), + }) + } + pub fn without_cancel() -> FixedHeightBar { theme::button_bar(Self { cancel: None, diff --git a/core/embed/rust/src/ui/model_tt/component/page.rs b/core/embed/rust/src/ui/model_tt/component/page.rs index f16a81508..502b09088 100644 --- a/core/embed/rust/src/ui/model_tt/component/page.rs +++ b/core/embed/rust/src/ui/model_tt/component/page.rs @@ -404,6 +404,15 @@ where } } + pub fn with_cancel_arrow(content: T, background: Color) -> Self { + let buttons = CancelHold::with_cancel_arrow(); + Self { + inner: SwipePage::new(content, buttons, background), + loader: Loader::new(), + pad: Pad::with_background(background), + } + } + pub fn with_swipe_left(mut self) -> Self { self.inner = self.inner.with_swipe_left(); self diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index bc2dbbc63..fc9e602ac 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -496,6 +496,7 @@ struct ConfirmBlobParams { verb_cancel: Option, info_button: bool, hold: bool, + chunkify: bool, } impl ConfirmBlobParams { @@ -517,6 +518,7 @@ impl ConfirmBlobParams { verb_cancel, info_button: false, hold, + chunkify: false, } } @@ -535,6 +537,11 @@ impl ConfirmBlobParams { self } + fn with_chunkify(mut self, chunkify: bool) -> Self { + self.chunkify = chunkify; + self + } + fn into_layout(self) -> Result { let paragraphs = ConfirmBlob { description: self.description.unwrap_or_else(StrBuffer::empty), @@ -542,7 +549,11 @@ impl ConfirmBlobParams { data: self.data.try_into()?, description_font: &theme::TEXT_NORMAL, extra_font: &theme::TEXT_DEMIBOLD, - data_font: &theme::TEXT_MONO, + data_font: if self.chunkify { + &theme::TEXT_MONO_ADDRESS_CHUNKS + } else { + &theme::TEXT_MONO + }, } .into_paragraphs(); @@ -611,6 +622,21 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; let extra: Option = kwargs.get(Qstr::MP_QSTR_extra)?.try_into_option()?; let data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; + + let data_style = if chunkify { + // Longer addresses have smaller x_offset so they fit even with scrollbar + // (as they will be shown on more than one page) + const FITS_ON_ONE_PAGE: usize = 16 * 4; + let address: StrBuffer = data.try_into()?; + if address.len() <= FITS_ON_ONE_PAGE { + &theme::TEXT_MONO_ADDRESS_CHUNKS + } else { + &theme::TEXT_MONO_ADDRESS_CHUNKS_SMALLER_X_OFFSET + } + } else { + &theme::TEXT_MONO + }; let paragraphs = ConfirmBlob { description: description.unwrap_or_else(StrBuffer::empty), @@ -618,7 +644,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut data: data.try_into()?, description_font: &theme::TEXT_NORMAL, extra_font: &theme::TEXT_DEMIBOLD, - data_font: &theme::TEXT_MONO, + data_font: data_style, } .into_paragraphs(); @@ -730,6 +756,8 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { + let qr_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_qr_title)?.try_into()?; + let details_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_details_title)?.try_into()?; let address: StrBuffer = kwargs.get(Qstr::MP_QSTR_address)?.try_into()?; let case_sensitive: bool = kwargs.get(Qstr::MP_QSTR_case_sensitive)?.try_into()?; let account: Option = kwargs.get(Qstr::MP_QSTR_account)?.try_into_option()?; @@ -737,7 +765,14 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: let xpubs: Obj = kwargs.get(Qstr::MP_QSTR_xpubs)?; - let mut ad = AddressDetails::new(address, case_sensitive, account, path)?; + let mut ad = AddressDetails::new( + qr_title, + address, + case_sensitive, + details_title, + account, + path, + )?; for i in IterBuf::new().try_iterate(xpubs)? { let [xtitle, text]: [StrBuffer; 2] = iter_into_array(i)?; @@ -750,25 +785,19 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_show_spending_details(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { +extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { - let title: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_title, "INFORMATION".into())?; - let account: Option = kwargs.get(Qstr::MP_QSTR_account)?.try_into_option()?; - let fee_rate: Option = kwargs.get(Qstr::MP_QSTR_fee_rate)?.try_into_option()?; - let fee_rate_title: StrBuffer = - kwargs.get_or(Qstr::MP_QSTR_fee_rate_title, "Fee rate:".into())?; + let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let mut paragraphs = ParagraphVecShort::new(); - if let Some(a) = account { - paragraphs.add(Paragraph::new( - &theme::TEXT_NORMAL, - "Sending from account:".into(), - )); - paragraphs.add(Paragraph::new(&theme::TEXT_MONO, a)); - } - if let Some(f) = fee_rate { - paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, fee_rate_title)); - paragraphs.add(Paragraph::new(&theme::TEXT_MONO, f)); + + for para in IterBuf::new().try_iterate(items)? { + let [key, value]: [Obj; 2] = iter_into_array(para)?; + let key: StrBuffer = key.try_into()?; + let value: StrBuffer = value.try_into()?; + paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key)); + paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value)); } let obj = LayoutObj::new( @@ -802,10 +831,12 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma .unwrap_or_else(|_| Obj::const_none()) .try_into_option()?; let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold) .with_subtitle(subtitle) .with_info_button(info_button) + .with_chunkify(chunkify) .into_layout() }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -816,6 +847,7 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false)?; + let cancel_arrow: bool = kwargs.get_or(Qstr::MP_QSTR_cancel_arrow, false)?; let mut paragraphs = ParagraphVecShort::new(); @@ -824,8 +856,11 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label)); paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value)); } - - let mut page = SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG); + let mut page = if cancel_arrow { + SwipeHoldPage::with_cancel_arrow(paragraphs.into_paragraphs(), theme::BG) + } else { + SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG) + }; if info_button { page = page.with_swipe_left(); } @@ -912,6 +947,7 @@ fn new_show_modal( button_style: ButtonStyleSheet, ) -> Result { let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let value: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_value, StrBuffer::empty())?; let description: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_description, StrBuffer::empty())?; let button: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_button, "CONTINUE".into())?; let allow_cancel: bool = kwargs.get_or(Qstr::MP_QSTR_allow_cancel, true)?; @@ -921,7 +957,12 @@ fn new_show_modal( let obj = if no_buttons && time_ms == 0 { // No buttons and no timer, used when we only want to draw the dialog once and // then throw away the layout object. - LayoutObj::new(IconDialog::new(icon, title, Empty).with_description(description))?.into() + LayoutObj::new( + IconDialog::new(icon, title, Empty) + .with_value(value) + .with_description(description), + )? + .into() } else if no_buttons && time_ms > 0 { // Timeout, no buttons. LayoutObj::new( @@ -930,6 +971,7 @@ fn new_show_modal( title, Timeout::new(time_ms).map(|_| Some(CancelConfirmMsg::Confirmed)), ) + .with_value(value) .with_description(description), )? .into() @@ -945,6 +987,7 @@ fn new_show_modal( false, ), ) + .with_value(value) .with_description(description), )? .into() @@ -958,6 +1001,7 @@ fn new_show_modal( (matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed) })), ) + .with_value(value) .with_description(description), )? .into() @@ -1053,9 +1097,9 @@ extern "C" fn new_show_info(n_args: usize, args: *const Obj, kwargs: *mut Map) - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_show_mismatch() -> Obj { - let block = move || { - let title: StrBuffer = "Address mismatch?".into(); +extern "C" fn new_show_mismatch(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let description: StrBuffer = "Please contact Trezor support at".into(); let url: StrBuffer = "trezor.io/support".into(); let button = "QUIT"; @@ -1077,13 +1121,20 @@ extern "C" fn new_show_mismatch() -> Obj { true, ), ) - .with_description(description) + .with_paragraph( + Paragraph::new(&theme::TEXT_NORMAL, description) + .centered() + .with_bottom_padding( + theme::TEXT_NORMAL.text_font.text_height() + - theme::TEXT_DEMIBOLD.text_font.text_height(), + ), + ) .with_text(&theme::TEXT_DEMIBOLD, url), )?; Ok(obj.into()) }; - unsafe { util::try_or_raise(block) } + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } extern "C" fn new_show_simple(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { @@ -1657,6 +1708,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// data: str | bytes, /// description: str | None, /// extra: str | None, + /// chunkify: bool = False, /// ) -> object: /// """Confirm address. Similar to `confirm_blob` but has corner info button /// and allows left swipe which does the same thing as the button.""" @@ -1682,8 +1734,10 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def show_address_details( /// *, + /// qr_title: str, /// address: str, /// case_sensitive: bool, + /// details_title: str, /// account: str | None, /// path: str | None, /// xpubs: list[tuple[str, str]], @@ -1691,15 +1745,13 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Show address details - QR code, account, path, cosigner xpubs.""" Qstr::MP_QSTR_show_address_details => obj_fn_kw!(0, new_show_address_details).as_obj(), - /// def show_spending_details( + /// def show_info_with_cancel( /// *, - /// title: str = "INFORMATION", - /// account: str | None, - /// fee_rate: str | None, - /// fee_rate_title: str = "Fee rate:", + /// title: str, + /// items: Iterable[Tuple[str, str]], /// ) -> object: /// """Show metadata when for outgoing transaction.""" - Qstr::MP_QSTR_show_spending_details => obj_fn_kw!(0, new_show_spending_details).as_obj(), + Qstr::MP_QSTR_show_info_with_cancel => obj_fn_kw!(0, new_show_info_with_cancel).as_obj(), /// def confirm_value( /// *, @@ -1711,6 +1763,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// verb_cancel: str | None = None, /// info_button: bool = False, /// hold: bool = False, + /// chunkify: bool = False, /// ) -> object: /// """Confirm value. Merge of confirm_total and confirm_output.""" Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(), @@ -1720,6 +1773,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// title: str, /// items: list[tuple[str, str]], /// info_button: bool = False, + /// cancel_arrow: bool = False, /// ) -> object: /// """Transaction summary. Always hold to confirm.""" Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(), @@ -1773,6 +1827,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// *, /// title: str, /// button: str = "CONTINUE", + /// value: str = "", /// description: str = "", /// allow_cancel: bool = False, /// time_ms: int = 0, @@ -1802,9 +1857,9 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Info modal. No buttons shown when `button` is empty string.""" Qstr::MP_QSTR_show_info => obj_fn_kw!(0, new_show_info).as_obj(), - /// def show_mismatch() -> object: + /// def show_mismatch(*, title: str) -> object: /// """Warning modal, receiving address mismatch.""" - Qstr::MP_QSTR_show_mismatch => obj_fn_0!(new_show_mismatch).as_obj(), + Qstr::MP_QSTR_show_mismatch => obj_fn_kw!(0, new_show_mismatch).as_obj(), /// def show_simple( /// *, diff --git a/core/embed/rust/src/ui/model_tt/theme.rs b/core/embed/rust/src/ui/model_tt/theme.rs index 9abd85058..d3ca2c469 100644 --- a/core/embed/rust/src/ui/model_tt/theme.rs +++ b/core/embed/rust/src/ui/model_tt/theme.rs @@ -2,7 +2,7 @@ use crate::{ time::Duration, ui::{ component::{ - text::{LineBreaking, PageBreaking, TextStyle}, + text::{layout::Chunks, LineBreaking, PageBreaking, TextStyle}, FixedHeightBar, }, display::{Color, Font, Icon}, @@ -517,6 +517,18 @@ pub const TEXT_MONO: TextStyle = TextStyle::new(Font::MONO, FG, BG, GREY_LIGHT, .with_page_breaking(PageBreaking::CutAndInsertEllipsisBoth) .with_ellipsis_icon(ICON_PAGE_NEXT, 0) .with_prev_page_icon(ICON_PAGE_PREV, 0); +/// Makes sure that the displayed text (usually address) will get divided into +/// smaller chunks. +pub const TEXT_MONO_ADDRESS_CHUNKS: TextStyle = TEXT_MONO + .with_chunks(Chunks::new(4, 9)) + .with_line_spacing(5); +/// Smaller horizontal chunk offset, used e.g. for long Cardano addresses. +/// Also moving the next page ellipsis to the left (as there is a space on the +/// left). +pub const TEXT_MONO_ADDRESS_CHUNKS_SMALLER_X_OFFSET: TextStyle = TEXT_MONO + .with_chunks(Chunks::new(4, 7)) + .with_line_spacing(5) + .with_ellipsis_icon(ICON_PAGE_NEXT, -12); /// Convert Python-side numeric id to a `TextStyle`. pub fn textstyle_number(num: i32) -> &'static TextStyle { diff --git a/core/embed/trezorhal/common.h b/core/embed/trezorhal/common.h index 2ffe59d0e..1781ed4c8 100644 --- a/core/embed/trezorhal/common.h +++ b/core/embed/trezorhal/common.h @@ -53,6 +53,11 @@ #define STAY_IN_BOOTLOADER_FLAG 0x0FC35A96 +// from linker script +extern uint8_t firmware_header_start; +extern uint8_t ccmram_start; +extern uint8_t ccmram_end; + void __attribute__((noreturn)) trezor_shutdown(void); void __attribute__((noreturn)) diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index 9d30af77b..11db67559 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -23,5 +23,6 @@ void mpu_config_off(void); void mpu_config_bootloader(void); void mpu_config_firmware(void); +void mpu_config_prodtest(void); #endif diff --git a/core/embed/trezorhal/optiga.h b/core/embed/trezorhal/optiga.h new file mode 100644 index 000000000..83af3cc02 --- /dev/null +++ b/core/embed/trezorhal/optiga.h @@ -0,0 +1,44 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TREZORHAL_OPTIGA_H +#define TREZORHAL_OPTIGA_H + +#include +#include +#include + +#define OPTIGA_DEVICE_CERT_INDEX 1 +#define OPTIGA_DEVICE_ECC_KEY_INDEX 0 +#define OPTIGA_COMMAND_ERROR_OFFSET 0x100 + +// Error code 7: Access conditions not satisfied +#define OPTIGA_ERR_ACCESS_COND_NOT_SAT (OPTIGA_COMMAND_ERROR_OFFSET + 0x07) + +int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size, + uint8_t *signature, size_t max_sig_size, size_t *sig_size); + +bool optiga_cert_size(uint8_t index, size_t *cert_size); + +bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, + size_t *cert_size); + +bool optiga_random_buffer(uint8_t *dest, size_t size); + +#endif diff --git a/core/embed/trezorhal/optiga/optiga.c b/core/embed/trezorhal/optiga/optiga.c new file mode 100644 index 000000000..50e4cfed1 --- /dev/null +++ b/core/embed/trezorhal/optiga/optiga.c @@ -0,0 +1,111 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "optiga.h" +#include +#include "optiga_commands.h" + +int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size, + uint8_t *signature, size_t max_sig_size, size_t *sig_size) { + if (index >= OPTIGA_ECC_KEY_COUNT) { + return OPTIGA_ERR_PARAM; + } + + optiga_result ret = + optiga_calc_sign(OPTIGA_OID_ECC_KEY + index, digest, digest_size, + &signature[2], max_sig_size - 2, sig_size); + if (ret == OPTIGA_ERR_CMD) { + uint8_t error_code = 0; + optiga_get_error_code(&error_code); + return error_code + OPTIGA_COMMAND_ERROR_OFFSET; + } + + if (ret != OPTIGA_SUCCESS) { + return ret; + } + + // Add sequence tag and length. + if (*sig_size >= 0x80) { + // Length not supported. + return OPTIGA_ERR_SIZE; + } + signature[0] = 0x30; + signature[1] = *sig_size; + *sig_size += 2; + return OPTIGA_SUCCESS; +} + +bool optiga_cert_size(uint8_t index, size_t *cert_size) { + *cert_size = 0; + + if (index >= OPTIGA_CERT_COUNT) { + return false; + } + + uint8_t metadata_bytes[OPTIGA_MAX_METADATA_SIZE] = {0}; + size_t metadata_size = 0; + optiga_metadata metadata = {0}; + optiga_result ret = + optiga_get_data_object(OPTIGA_OID_CERT + index, true, metadata_bytes, + sizeof(metadata_bytes), &metadata_size); + if (OPTIGA_SUCCESS != ret) { + return false; + } + + ret = optiga_parse_metadata(metadata_bytes, metadata_size, &metadata); + if (OPTIGA_SUCCESS != ret || metadata.used_size.ptr == NULL) { + return false; + } + + for (int i = 0; i < metadata.used_size.len; ++i) { + *cert_size = (*cert_size << 8) + metadata.used_size.ptr[i]; + } + + return true; +} + +bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, + size_t *cert_size) { + if (index >= OPTIGA_CERT_COUNT) { + return false; + } + + optiga_result ret = optiga_get_data_object(OPTIGA_OID_CERT + index, false, + cert, max_cert_size, cert_size); + return OPTIGA_SUCCESS == ret; +} + +bool optiga_random_buffer(uint8_t *dest, size_t size) { + while (size > OPTIGA_RANDOM_MAX_SIZE) { + if (optiga_get_random(dest, OPTIGA_RANDOM_MAX_SIZE) != OPTIGA_SUCCESS) { + return false; + } + dest += OPTIGA_RANDOM_MAX_SIZE; + size -= OPTIGA_RANDOM_MAX_SIZE; + } + + if (size < OPTIGA_RANDOM_MIN_SIZE) { + static uint8_t buffer[OPTIGA_RANDOM_MIN_SIZE] = {0}; + optiga_result ret = optiga_get_random(buffer, OPTIGA_RANDOM_MIN_SIZE); + memcpy(dest, buffer, size); + return ret == OPTIGA_SUCCESS; + } + + return optiga_get_random(dest, size) == OPTIGA_SUCCESS; +} diff --git a/core/embed/trezorhal/optiga/optiga_commands.c b/core/embed/trezorhal/optiga/optiga_commands.c index d2af2d633..2aa4c12a4 100644 --- a/core/embed/trezorhal/optiga/optiga_commands.c +++ b/core/embed/trezorhal/optiga/optiga_commands.c @@ -33,9 +33,18 @@ #include "sha2.h" // Static buffer for commands and responses. -static uint8_t tx_buffer[1750] = {0}; +static uint8_t tx_buffer[OPTIGA_MAX_APDU_SIZE] = {0}; static size_t tx_size = 0; +const optiga_metadata_item OPTIGA_LCS_OPERATIONAL = {(const uint8_t *)"\x07", + 1}; +const optiga_metadata_item OPTIGA_ACCESS_ALWAYS = { + (const uint8_t[]){OPTIGA_ACCESS_COND_ALW}, 1}; +const optiga_metadata_item OPTIGA_ACCESS_NEVER = { + (const uint8_t[]){OPTIGA_ACCESS_COND_NEV}, 1}; +const optiga_metadata_item OPTIGA_VERSION_DEFAULT = { + (const uint8_t *)"\xC1\x02\x00\x00", 4}; + static optiga_result process_output_fixedlen(uint8_t *data, size_t data_size) { // Expecting data_size bytes of output data in the response. if (tx_size != 4 + data_size || @@ -78,6 +87,22 @@ static optiga_result process_output_varlen(uint8_t *data, size_t max_data_size, return OPTIGA_SUCCESS; } +static void write_uint16(uint8_t **ptr, uint16_t i) { + **ptr = i >> 8; + *ptr += 1; + **ptr = i & 0xff; + *ptr += 1; +} + +static void write_prefixed_data(uint8_t **ptr, const uint8_t *data, + size_t data_size) { + write_uint16(ptr, data_size); + if (data_size > 0) { + memcpy(*ptr, data, data_size); + *ptr += data_size; + } +} + /* * For metadata description see: * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#metadata-expression @@ -86,19 +111,20 @@ static optiga_result process_output_varlen(uint8_t *data, size_t max_data_size, static const struct { size_t offset; uint8_t tag; + const optiga_metadata_item *default_value; } METADATA_OFFSET_TAG_MAP[] = { - {offsetof(optiga_metadata, lcso), 0xC0}, - {offsetof(optiga_metadata, version), 0xC1}, - {offsetof(optiga_metadata, max_size), 0xC4}, - {offsetof(optiga_metadata, used_size), 0xC5}, - {offsetof(optiga_metadata, change), 0xD0}, - {offsetof(optiga_metadata, read), 0xD1}, - {offsetof(optiga_metadata, execute), 0xD3}, - {offsetof(optiga_metadata, meta_update), 0xD8}, - {offsetof(optiga_metadata, algorithm), 0xE0}, - {offsetof(optiga_metadata, key_usage), 0xE1}, - {offsetof(optiga_metadata, data_type), 0xE8}, - {offsetof(optiga_metadata, reset_type), 0xF0}, + {offsetof(optiga_metadata, lcso), 0xC0, &OPTIGA_LCS_OPERATIONAL}, + {offsetof(optiga_metadata, version), 0xC1, &OPTIGA_VERSION_DEFAULT}, + {offsetof(optiga_metadata, max_size), 0xC4, NULL}, + {offsetof(optiga_metadata, used_size), 0xC5, NULL}, + {offsetof(optiga_metadata, change), 0xD0, &OPTIGA_ACCESS_NEVER}, + {offsetof(optiga_metadata, read), 0xD1, &OPTIGA_ACCESS_NEVER}, + {offsetof(optiga_metadata, execute), 0xD3, &OPTIGA_ACCESS_NEVER}, + {offsetof(optiga_metadata, meta_update), 0xD8, NULL}, + {offsetof(optiga_metadata, algorithm), 0xE0, NULL}, + {offsetof(optiga_metadata, key_usage), 0xE1, NULL}, + {offsetof(optiga_metadata, data_type), 0xE8, NULL}, + {offsetof(optiga_metadata, reset_type), 0xF0, NULL}, }; static const size_t METADATA_TAG_COUNT = @@ -185,18 +211,47 @@ optiga_result optiga_serialize_metadata(const optiga_metadata *metadata, return OPTIGA_SUCCESS; } +// Returns true if all items defined in the expected metadata have the same +// value in the stored metadata, i.e. items that are not defined in the expected +// metadata may have arbitrary value in the stored metadata. +bool optiga_compare_metadata(const optiga_metadata *expected, + const optiga_metadata *stored) { + for (int i = 0; i < METADATA_TAG_COUNT; ++i) { + const optiga_metadata_item *expected_item = + (void *)((char *)expected + METADATA_OFFSET_TAG_MAP[i].offset); + if (expected_item->ptr == NULL) { + // Ignore undefined items. + continue; + } + + const optiga_metadata_item *stored_item = + (void *)((char *)stored + METADATA_OFFSET_TAG_MAP[i].offset); + if (stored_item->ptr == NULL) { + if (METADATA_OFFSET_TAG_MAP[i].default_value == NULL) { + return false; + } + stored_item = METADATA_OFFSET_TAG_MAP[i].default_value; + } + + if (stored_item->len != expected_item->len || + memcmp(stored_item->ptr, expected_item->ptr, expected_item->len) != 0) { + return false; + } + } + return true; +} + /* * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#openapplication */ optiga_result optiga_open_application(void) { static const uint8_t OPEN_APP[] = { - 0x70, 0x00, 0x00, 0x10, 0xD2, 0x76, 0x00, 0x00, 0x04, 0x47, + 0xF0, 0x00, 0x00, 0x10, 0xD2, 0x76, 0x00, 0x00, 0x04, 0x47, 0x65, 0x6E, 0x41, 0x75, 0x74, 0x68, 0x41, 0x70, 0x70, 0x6C, }; - optiga_result ret = - optiga_execute_command(false, OPEN_APP, sizeof(OPEN_APP), tx_buffer, - sizeof(tx_buffer), &tx_size); + optiga_result ret = optiga_execute_command( + OPEN_APP, sizeof(OPEN_APP), tx_buffer, sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -205,18 +260,21 @@ optiga_result optiga_open_application(void) { } optiga_result optiga_get_error_code(uint8_t *error_code) { - size_t data_size = 0; - optiga_result ret = - optiga_get_data_object(0xf1c2, false, error_code, 1, &data_size); + tx_size = 6; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x01; // command code + *(ptr++) = 0x00; // get data + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, OPTIGA_OID_ERROR_CODE); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } - if (data_size != 1) { - return OPTIGA_ERR_SIZE; - } - - return OPTIGA_SUCCESS; + return process_output_fixedlen(error_code, 1); } /* @@ -225,16 +283,16 @@ optiga_result optiga_get_error_code(uint8_t *error_code) { optiga_result optiga_get_data_object(uint16_t oid, bool get_metadata, uint8_t *data, size_t max_data_size, size_t *data_size) { - uint8_t get_data[6] = {0x01, 0x00, 0x00, 0x02}; - if (get_metadata) { - get_data[1] = 0x01; - } - get_data[4] = oid >> 8; - get_data[5] = oid & 0xff; + tx_size = 6; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x81; // command code + *(ptr++) = get_metadata ? 0x01 : 0x00; + write_uint16(&ptr, tx_size - 4); - optiga_result ret = - optiga_execute_command(false, get_data, sizeof(get_data), tx_buffer, - sizeof(tx_buffer), &tx_size); + write_uint16(&ptr, oid); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -247,26 +305,25 @@ optiga_result optiga_get_data_object(uint16_t oid, bool get_metadata, */ optiga_result optiga_set_data_object(uint16_t oid, bool set_metadata, const uint8_t *data, size_t data_size) { - if (data_size + 8 > sizeof(tx_buffer)) { + tx_size = data_size + 8; + if (tx_size > sizeof(tx_buffer)) { return OPTIGA_ERR_PARAM; } - tx_size = data_size + 8; - tx_buffer[0] = 0x02; - tx_buffer[1] = set_metadata ? 0x01 : 0x40; - tx_buffer[2] = (tx_size - 4) >> 8; - tx_buffer[3] = (tx_size - 4) & 0xff; - tx_buffer[4] = oid >> 8; - tx_buffer[5] = oid & 0xff; - tx_buffer[6] = 0; - tx_buffer[7] = 0; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x82; // command code + *(ptr++) = set_metadata ? 0x01 : 0x40; + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, oid); + write_uint16(&ptr, 0); // offset if (data_size != 0) { - memcpy(tx_buffer + 8, data, data_size); + memcpy(ptr, data, data_size); } - optiga_result ret = optiga_execute_command( - false, tx_buffer, data_size + 8, tx_buffer, sizeof(tx_buffer), &tx_size); + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { memzero(tx_buffer + 8, data_size); return ret; @@ -281,17 +338,21 @@ optiga_result optiga_set_data_object(uint16_t oid, bool set_metadata, * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#getrandom */ optiga_result optiga_get_random(uint8_t *random, size_t random_size) { - if (random_size < 8 || random_size > 256) { + if (random_size < OPTIGA_RANDOM_MIN_SIZE || + random_size > OPTIGA_RANDOM_MAX_SIZE) { return OPTIGA_ERR_SIZE; } - uint8_t get_random[6] = {0x0C, 0x00, 0x00, 0x02}; - get_random[4] = random_size >> 8; - get_random[5] = random_size & 0xff; + tx_size = 6; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x8C; // command code + *(ptr++) = 0x00; // random number from TRNG + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, random_size); - optiga_result ret = - optiga_execute_command(false, get_random, sizeof(get_random), tx_buffer, - sizeof(tx_buffer), &tx_size); + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -301,6 +362,7 @@ optiga_result optiga_get_random(uint8_t *random, size_t random_size) { /* * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#encryptsym + * Returns 0x61, mac_size (2 bytes), mac. */ optiga_result optiga_encrypt_sym(optiga_sym_mode mode, uint16_t oid, const uint8_t *input, size_t input_size, @@ -311,19 +373,18 @@ optiga_result optiga_encrypt_sym(optiga_sym_mode mode, uint16_t oid, } tx_size = 9 + input_size; - tx_buffer[0] = 0x14; - tx_buffer[1] = mode; - tx_buffer[2] = (tx_size - 4) >> 8; - tx_buffer[3] = (tx_size - 4) & 0xff; - tx_buffer[4] = oid >> 8; - tx_buffer[5] = oid & 0xff; - tx_buffer[6] = 0x01; - tx_buffer[7] = input_size >> 8; - tx_buffer[8] = input_size & 0xff; - memcpy(tx_buffer + 9, input, input_size); + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x94; // command code + *(ptr++) = mode; + write_uint16(&ptr, tx_size - 4); - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + write_uint16(&ptr, oid); + + *(ptr++) = 0x01; // start and final data block + write_prefixed_data(&ptr, input, input_size); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret == OPTIGA_SUCCESS) { ret = process_output_varlen(output, max_output_size, output_size); } @@ -336,43 +397,49 @@ optiga_result optiga_encrypt_sym(optiga_sym_mode mode, uint16_t oid, * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#decryptsym */ optiga_result optiga_set_auto_state(uint16_t nonce_oid, uint16_t key_oid, - const uint8_t key[32]) { + const uint8_t *key, size_t key_size) { uint8_t nonce[16] = {0}; - uint8_t get_random[] = { - 0x0C, 0x00, 0x00, 0x07, 0x00, sizeof(nonce), 0x00, 0x00, 0x41, 0x00, 0x00, - }; - get_random[6] = nonce_oid >> 8; - get_random[7] = nonce_oid & 0xff; - optiga_result ret = - optiga_execute_command(false, get_random, sizeof(get_random), tx_buffer, - sizeof(tx_buffer), &tx_size); + tx_size = 11; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x8C; // command code + *(ptr++) = 0x00; // random number from TRNG + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, sizeof(nonce)); + write_uint16(&ptr, nonce_oid); + + *(ptr++) = 0x41; // pre-pending optional data tag + write_uint16(&ptr, 0); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); ret = process_output_fixedlen(nonce, sizeof(nonce)); if (ret != OPTIGA_SUCCESS) { return ret; } - tx_size = 11 + sizeof(nonce) + 3 + 32; - tx_buffer[0] = 0x15; - tx_buffer[1] = 0x20; - tx_buffer[2] = 0x00; - tx_buffer[3] = tx_size - 4; - tx_buffer[4] = key_oid >> 8; - tx_buffer[5] = key_oid & 0xff; - tx_buffer[6] = 0x01; - tx_buffer[7] = 0x00; - tx_buffer[8] = 2 + sizeof(nonce); - tx_buffer[9] = nonce_oid >> 8; - tx_buffer[10] = nonce_oid & 0xff; - memcpy(&tx_buffer[11], nonce, sizeof(nonce)); - tx_buffer[11 + sizeof(nonce)] = 0x43; - tx_buffer[12 + sizeof(nonce)] = 0x00; - tx_buffer[13 + sizeof(nonce)] = 0x20; - hmac_sha256(key, 32, nonce, sizeof(nonce), &tx_buffer[14 + sizeof(nonce)]); - - ret = optiga_execute_command(false, tx_buffer, tx_size, tx_buffer, - sizeof(tx_buffer), &tx_size); + tx_size = 11 + sizeof(nonce) + 3 + SHA256_DIGEST_LENGTH; + ptr = tx_buffer; + *(ptr++) = 0x95; // command code + *(ptr++) = 0x20; // HMAC-SHA256 + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, key_oid); + + *(ptr++) = 0x01; // start and final data block + write_uint16(&ptr, 2 + sizeof(nonce)); // data length + write_uint16(&ptr, nonce_oid); + memcpy(ptr, nonce, sizeof(nonce)); + ptr += sizeof(nonce); + + *(ptr++) = 0x43; // verification value tag + write_uint16(&ptr, SHA256_DIGEST_LENGTH); + hmac_sha256(key, key_size, nonce, sizeof(nonce), ptr); + + ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), + &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -381,15 +448,22 @@ optiga_result optiga_set_auto_state(uint16_t nonce_oid, uint16_t key_oid, } optiga_result optiga_clear_auto_state(uint16_t key_oid) { - uint8_t decrypt_sym[] = { - 0x15, 0x20, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x43, 0x00, 0x00, - }; - decrypt_sym[4] = key_oid >> 8; - decrypt_sym[5] = key_oid & 0xff; + tx_size = 12; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0x95; // command code + *(ptr++) = 0x20; // HMAC-SHA256 + write_uint16(&ptr, tx_size - 4); + + write_uint16(&ptr, key_oid); + + *(ptr++) = 0x01; // start and final data block + write_uint16(&ptr, 0); // data length - optiga_result ret = - optiga_execute_command(false, decrypt_sym, sizeof(decrypt_sym), tx_buffer, - sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x43; // verification value tag + write_uint16(&ptr, 0); // verification value length + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -405,31 +479,30 @@ optiga_result optiga_clear_auto_state(uint16_t key_oid) { /* * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#calcsign + * Returns a signature pair (r,s) encoded as two DER INTEGERs. */ optiga_result optiga_calc_sign(uint16_t oid, const uint8_t *digest, size_t digest_size, uint8_t *signature, size_t max_sig_size, size_t *sig_size) { - if (digest_size + 12 > sizeof(tx_buffer)) { + tx_size = digest_size + 12; + if (tx_size > sizeof(tx_buffer)) { return OPTIGA_ERR_PARAM; } - tx_size = digest_size + 12; - tx_buffer[0] = 0x31; - tx_buffer[1] = 0x11; - tx_buffer[2] = (tx_size - 4) >> 8; - tx_buffer[3] = (tx_size - 4) & 0xff; - tx_buffer[4] = 0x01; - tx_buffer[5] = digest_size >> 8; - tx_buffer[6] = digest_size & 0xff; - memcpy(tx_buffer + 7, digest, digest_size); - tx_buffer[7 + digest_size] = 0x03; - tx_buffer[8 + digest_size] = 0x00; - tx_buffer[9 + digest_size] = 0x02; - tx_buffer[10 + digest_size] = oid >> 8; - tx_buffer[11 + digest_size] = oid & 0xff; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB1; // command code + *(ptr++) = 0x11; // ECDSA signature scheme + write_uint16(&ptr, tx_size - 4); - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x01; // digest tag + write_prefixed_data(&ptr, digest, digest_size); + + *(ptr++) = 0x03; // signature key OID tag + write_uint16(&ptr, 2); + write_uint16(&ptr, oid); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -437,30 +510,72 @@ optiga_result optiga_calc_sign(uint16_t oid, const uint8_t *digest, return process_output_varlen(signature, max_sig_size, sig_size); } +/* + * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#verifysign + * The public_key is encoded as a DER BIT STRING. + * The signature pair (r,s) is encoded as two DER INTEGERs. + */ +optiga_result optiga_verify_sign(optiga_curve curve, const uint8_t *public_key, + size_t public_key_size, const uint8_t *digest, + size_t digest_size, const uint8_t *signature, + size_t sig_size) { + tx_size = 17 + digest_size + sig_size + public_key_size; + if (tx_size > sizeof(tx_buffer)) { + return OPTIGA_ERR_PARAM; + } + + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB2; // command code + *(ptr++) = 0x11; // ECDSA signature scheme + write_uint16(&ptr, tx_size - 4); + + *(ptr++) = 0x01; // digest tag + write_prefixed_data(&ptr, digest, digest_size); + + *(ptr++) = 0x02; // signature tag + write_prefixed_data(&ptr, signature, sig_size); + + *(ptr++) = 0x05; // curve tag + write_uint16(&ptr, 1); + *(ptr++) = curve; + + *(ptr++) = 0x06; // public key tag + write_prefixed_data(&ptr, public_key, public_key_size); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); + if (ret != OPTIGA_SUCCESS) { + return ret; + } + + return process_output_fixedlen(NULL, 0); +} + /* * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#genkeypair + * Returns 0x02, public_key_size (2 bytes), public_key. + * The public_key is encoded as a DER BIT STRING. */ optiga_result optiga_gen_key_pair(optiga_curve curve, optiga_key_usage usage, uint16_t oid, uint8_t *public_key, size_t max_public_key_size, size_t *public_key_size) { tx_size = 13; - tx_buffer[0] = 0x38; - tx_buffer[1] = curve; - tx_buffer[2] = 0x00; - tx_buffer[3] = 0x09; - tx_buffer[4] = 0x01; - tx_buffer[5] = 0x00; - tx_buffer[6] = 0x02; - tx_buffer[7] = oid >> 8; - tx_buffer[8] = oid & 0xff; - tx_buffer[9] = 0x02; - tx_buffer[10] = 0x00; - tx_buffer[11] = 0x01; - tx_buffer[12] = usage; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB8; // command code + *(ptr++) = curve; + write_uint16(&ptr, tx_size - 4); - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x01; // private key OID tag + write_uint16(&ptr, 2); + write_uint16(&ptr, oid); + + *(ptr++) = 0x02; // key usage tag + write_uint16(&ptr, 1); + *(ptr++) = usage; + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -475,22 +590,21 @@ optiga_result optiga_gen_key_pair(optiga_curve curve, optiga_key_usage usage, optiga_result optiga_gen_sym_key(optiga_aes algorithm, optiga_key_usage usage, uint16_t oid) { tx_size = 13; - tx_buffer[0] = 0x39; - tx_buffer[1] = algorithm; - tx_buffer[2] = 0x00; - tx_buffer[3] = 0x09; - tx_buffer[4] = 0x01; - tx_buffer[5] = 0x00; - tx_buffer[6] = 0x02; - tx_buffer[7] = oid >> 8; - tx_buffer[8] = oid & 0xff; - tx_buffer[9] = 0x02; - tx_buffer[10] = 0x00; - tx_buffer[11] = 0x01; - tx_buffer[12] = usage; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB9; // command code + *(ptr++) = algorithm; + write_uint16(&ptr, tx_size - 4); - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x01; // key OID tag + write_uint16(&ptr, 2); + write_uint16(&ptr, oid); + + *(ptr++) = 0x02; // key usage tag + write_uint16(&ptr, 1); + *(ptr++) = usage; + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -500,12 +614,13 @@ optiga_result optiga_gen_sym_key(optiga_aes algorithm, optiga_key_usage usage, /* * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#calcssec + * The public_key is encoded as a DER BIT STRING. */ optiga_result optiga_calc_ssec(optiga_curve curve, uint16_t oid, const uint8_t *public_key, size_t public_key_size, uint8_t *secret, size_t max_secret_size, size_t *secret_size) { - // Size of a P521 public key encode as a DER BIT STRING. + // Size of a P521 public key encoded as a DER BIT STRING. static const size_t MAX_PUBKEY_SIZE = 5 + 2 * 66; if (public_key_size > MAX_PUBKEY_SIZE) { @@ -513,29 +628,27 @@ optiga_result optiga_calc_ssec(optiga_curve curve, uint16_t oid, } tx_size = 16 + public_key_size + 3; - tx_buffer[0] = 0x33; - tx_buffer[1] = 0x01; - tx_buffer[2] = 0x00; - tx_buffer[3] = tx_size - 4; - tx_buffer[4] = 0x01; - tx_buffer[5] = 0x00; - tx_buffer[6] = 0x02; - tx_buffer[7] = oid >> 8; - tx_buffer[8] = oid & 0xff; - tx_buffer[9] = 0x05; - tx_buffer[10] = 0x00; - tx_buffer[11] = 0x01; - tx_buffer[12] = curve; - tx_buffer[13] = 0x06; - tx_buffer[14] = 0x00; - tx_buffer[15] = public_key_size; - memcpy(&tx_buffer[16], public_key, public_key_size); - tx_buffer[16 + public_key_size] = 0x07; - tx_buffer[17 + public_key_size] = 0x00; - tx_buffer[18 + public_key_size] = 0x00; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB3; // command code + *(ptr++) = 0x01; // ECDH key agreement + write_uint16(&ptr, tx_size - 4); - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x01; // private key OID tag + write_uint16(&ptr, 2); + write_uint16(&ptr, oid); + + *(ptr++) = 0x05; // curve tag + write_uint16(&ptr, 1); + *(ptr++) = curve; + + *(ptr++) = 0x06; // public key tag + write_prefixed_data(&ptr, public_key, public_key_size); + + *(ptr++) = 0x07; // export tag + write_uint16(&ptr, 0); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { return ret; } @@ -563,45 +676,32 @@ optiga_result optiga_derive_key(optiga_key_derivation deriv, uint16_t oid, } tx_size = is_hkdf ? 23 + salt_size + info_size : 20 + salt_size; - tx_buffer[0] = 0x34; - tx_buffer[1] = deriv; - tx_buffer[2] = (tx_size - 4) >> 8; - tx_buffer[3] = (tx_size - 4) & 0xff; - tx_buffer[4] = 0x01; - tx_buffer[5] = 0x00; - tx_buffer[6] = 0x02; - tx_buffer[7] = oid >> 8; - tx_buffer[8] = oid & 0xff; - tx_buffer[9] = 0x02; - tx_buffer[10] = salt_size >> 8; - tx_buffer[11] = salt_size & 0xff; - if (salt_size != 0) { - memcpy(&tx_buffer[12], salt, salt_size); - } - tx_buffer[12 + salt_size] = 0x03; - tx_buffer[13 + salt_size] = 0x00; - tx_buffer[14 + salt_size] = 0x02; - tx_buffer[15 + salt_size] = key_size >> 8; - tx_buffer[16 + salt_size] = key_size & 0xff; + uint8_t *ptr = tx_buffer; + *(ptr++) = 0xB4; // command code + *(ptr++) = deriv; + write_uint16(&ptr, tx_size - 4); + + *(ptr++) = 0x01; // PRESSEC OID tag + write_uint16(&ptr, 2); + write_uint16(&ptr, oid); + + *(ptr++) = 0x02; // derivation salt tag + write_prefixed_data(&ptr, salt, salt_size); + + *(ptr++) = 0x03; // key size tag + write_uint16(&ptr, 2); + write_uint16(&ptr, key_size); if (is_hkdf) { - tx_buffer[17 + salt_size] = 0x04; - tx_buffer[18 + salt_size] = info_size >> 8; - tx_buffer[19 + salt_size] = info_size & 0xff; - if (info_size != 0) { - memcpy(&tx_buffer[20 + salt_size], info, info_size); - } - tx_buffer[20 + salt_size + info_size] = 0x07; - tx_buffer[21 + salt_size + info_size] = 0x00; - tx_buffer[22 + salt_size + info_size] = 0x00; - } else { - tx_buffer[17 + salt_size] = 0x07; - tx_buffer[18 + salt_size] = 0x00; - tx_buffer[19 + salt_size] = 0x00; + *(ptr++) = 0x04; // info tag + write_prefixed_data(&ptr, info, info_size); } - optiga_result ret = optiga_execute_command( - false, tx_buffer, tx_size, tx_buffer, sizeof(tx_buffer), &tx_size); + *(ptr++) = 0x07; // export tag + write_uint16(&ptr, 0); + + optiga_result ret = optiga_execute_command(tx_buffer, tx_size, tx_buffer, + sizeof(tx_buffer), &tx_size); if (ret == OPTIGA_SUCCESS) { ret = process_output_fixedlen(key, key_size); } @@ -684,7 +784,7 @@ optiga_result optiga_set_priv_key(uint16_t oid, const uint8_t priv_key[32]) { // First part of the SetObjectProtected command containing the manifest. uint8_t sop_cmd1[145] = { - 0x03, 0x01, 0x00, 0x8d, 0x30, 0x00, 0x8a, 0x84, 0x43, 0xA1, 0x01, 0x26, + 0x83, 0x01, 0x00, 0x8d, 0x30, 0x00, 0x8a, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0xE0, 0xE8, 0x58, 0x3C, 0x86, 0x01, 0xF6, 0xF6, 0x84, 0x22, 0x18, 0x23, 0x03, 0x82, 0x03, 0x10, 0x82, 0x82, 0x20, 0x58, 0x25, 0x82, 0x18, 0x29, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -696,7 +796,7 @@ optiga_result optiga_set_priv_key(uint16_t oid, const uint8_t priv_key[32]) { // Second part of the SetObjectProtected command containing the fragment // with the private key. uint8_t sop_cmd2[42] = { - 0x03, 0x01, 0x00, 0x26, 0x31, 0x00, 0x23, 0x01, 0x00, 0x20, + 0x83, 0x01, 0x00, 0x26, 0x31, 0x00, 0x23, 0x01, 0x00, 0x20, }; memcpy(&sop_cmd2[10], &priv_key[0], 32); @@ -726,7 +826,7 @@ optiga_result optiga_set_priv_key(uint16_t oid, const uint8_t priv_key[32]) { return OPTIGA_ERR_PROCESS; } - ret = optiga_execute_command(false, sop_cmd1, sizeof(sop_cmd1), tx_buffer, + ret = optiga_execute_command(sop_cmd1, sizeof(sop_cmd1), tx_buffer, sizeof(tx_buffer), &tx_size); if (ret != OPTIGA_SUCCESS) { memzero(sop_cmd2, sizeof(sop_cmd2)); @@ -739,7 +839,7 @@ optiga_result optiga_set_priv_key(uint16_t oid, const uint8_t priv_key[32]) { return ret; } - ret = optiga_execute_command(false, sop_cmd2, sizeof(sop_cmd2), tx_buffer, + ret = optiga_execute_command(sop_cmd2, sizeof(sop_cmd2), tx_buffer, sizeof(tx_buffer), &tx_size); memzero(sop_cmd2, sizeof(sop_cmd2)); if (ret != OPTIGA_SUCCESS) { diff --git a/core/embed/trezorhal/optiga/optiga_transport.c b/core/embed/trezorhal/optiga/optiga_transport.c index aa49d0994..9a724f6ec 100644 --- a/core/embed/trezorhal/optiga/optiga_transport.c +++ b/core/embed/trezorhal/optiga/optiga_transport.c @@ -24,9 +24,13 @@ #include "optiga_transport.h" #include +#include "aes/aesccm.h" #include "common.h" #include "i2c.h" +#include "memzero.h" #include "optiga_hal.h" +#include "tls_prf.h" + #include TREZOR_BOARD // Maximum possible packet size that can be transmitted. @@ -92,11 +96,44 @@ enum { PCTR_CHAIN_MASK = 0x07, // Mask of chain field. }; +// Security control byte. +enum { + SCTR_HELLO = 0x00, // Handshake hello message. + SCTR_FINISHED = 0x08, // Handshake finished message. + SCTR_PROTECTED = 0x23, // Record exchange message. Fully protected. +}; + static uint8_t frame_num_out = 0xff; static uint8_t frame_num_in = 0xff; static uint8_t frame_buffer[1 + OPTIGA_DATA_REG_LEN]; static size_t frame_size = 0; // Set by optiga_read(). +// Secure channel constants. +#define SEC_CHAN_SCTR_SIZE 1 +#define SEC_CHAN_RND_SIZE 32 +#define SEC_CHAN_SEQ_SIZE 4 +#define SEC_CHAN_TAG_SIZE 8 +#define SEC_CHAN_PROTOCOL 1 +#define SEC_CHAN_HANDSHAKE_SIZE (SEC_CHAN_RND_SIZE + SEC_CHAN_SEQ_SIZE) +#define SEC_CHAN_CIPHERTEXT_OFFSET (SEC_CHAN_SCTR_SIZE + SEC_CHAN_SEQ_SIZE) +#define SEC_CHAN_OVERHEAD_SIZE \ + (SEC_CHAN_SCTR_SIZE + SEC_CHAN_SEQ_SIZE + SEC_CHAN_TAG_SIZE) +#define SEC_CHAN_SEQ_OFFSET SEC_CHAN_SCTR_SIZE + +// Secure channel status. +static bool sec_chan_established = false; +static aes_encrypt_ctx sec_chan_encr_ctx = {0}; +static aes_encrypt_ctx sec_chan_decr_ctx = {0}; +static uint8_t sec_chan_encr_nonce[8] = {0}; +static uint8_t sec_chan_decr_nonce[8] = {0}; +static uint8_t *const sec_chan_mseq = &sec_chan_encr_nonce[4]; +static uint8_t *const sec_chan_sseq = &sec_chan_decr_nonce[4]; + +// Static buffer for encrypted commands and responses. +static uint8_t sec_chan_buffer[OPTIGA_MAX_APDU_SIZE + SEC_CHAN_OVERHEAD_SIZE] = + {0}; +static size_t sec_chan_size = 0; + #ifdef NDEBUG #define OPTIGA_LOG(prefix, data, data_size) #else @@ -406,8 +443,8 @@ static optiga_result optiga_receive_packet(uint8_t *packet_control_byte, return OPTIGA_SUCCESS; } -optiga_result optiga_execute_command( - bool presentation_layer, const uint8_t *command_data, size_t command_size, +static optiga_result optiga_transceive( + bool presentation_layer, const uint8_t *request_data, size_t request_size, uint8_t *response_data, size_t max_response_size, size_t *response_size) { *response_size = 0; optiga_result ret = optiga_ensure_ready(); @@ -426,7 +463,7 @@ optiga_result optiga_execute_command( size_t packet_data_size = 0; // The first byte of each packet is the packet control byte pctr, so each // packet contains at most OPTIGA_MAX_PACKET_SIZE - 1 bytes of data. - if (command_size > OPTIGA_MAX_PACKET_SIZE - 1) { + if (request_size > OPTIGA_MAX_PACKET_SIZE - 1) { packet_data_size = OPTIGA_MAX_PACKET_SIZE - 1; if (chain == PCTR_CHAIN_NONE) { chain = PCTR_CHAIN_FIRST; @@ -434,7 +471,7 @@ optiga_result optiga_execute_command( chain = PCTR_CHAIN_MIDDLE; } } else { - packet_data_size = command_size; + packet_data_size = request_size; if (chain != PCTR_CHAIN_NONE) { chain = PCTR_CHAIN_LAST; } @@ -442,13 +479,13 @@ optiga_result optiga_execute_command( frame_num_out += 1; - ret = optiga_send_packet(pctr | chain, command_data, packet_data_size); + ret = optiga_send_packet(pctr | chain, request_data, packet_data_size); if (ret != OPTIGA_SUCCESS) { return ret; } - command_data += packet_data_size; - command_size -= packet_data_size; + request_data += packet_data_size; + request_size -= packet_data_size; ret = optiga_read(); if (ret != OPTIGA_SUCCESS) { @@ -466,7 +503,7 @@ optiga_result optiga_execute_command( if (ret != OPTIGA_SUCCESS) { return ret; } - } while (command_size != 0); + } while (request_size != 0); // Receive response packets from OPTIGA. do { @@ -502,5 +539,187 @@ optiga_result optiga_execute_command( pctr &= PCTR_CHAIN_MASK; } while (pctr == PCTR_CHAIN_FIRST || pctr == PCTR_CHAIN_MIDDLE); - return command_size == 0 ? OPTIGA_SUCCESS : OPTIGA_ERR_CMD; + return request_size == 0 ? OPTIGA_SUCCESS : OPTIGA_ERR_CMD; +} + +static void increment_seq(uint8_t seq[SEC_CHAN_SEQ_SIZE]) { + for (int i = 3; i >= 0; --i) { + seq[i]++; + if (seq[i] != 0x00) { + return; + } + } + + sec_chan_established = false; + memzero(&sec_chan_encr_ctx, sizeof(sec_chan_encr_ctx)); + memzero(&sec_chan_decr_ctx, sizeof(sec_chan_decr_ctx)); + memzero(sec_chan_encr_nonce, sizeof(sec_chan_encr_nonce)); + memzero(sec_chan_decr_nonce, sizeof(sec_chan_decr_nonce)); +} + +optiga_result optiga_execute_command(const uint8_t *command_data, + size_t command_size, + uint8_t *response_data, + size_t max_response_size, + size_t *response_size) { + if (!sec_chan_established) { + return optiga_transceive(false, command_data, command_size, response_data, + max_response_size, response_size); + } + sec_chan_size = command_size + SEC_CHAN_OVERHEAD_SIZE; + if (sec_chan_size > sizeof(sec_chan_buffer)) { + return OPTIGA_ERR_SIZE; + } + + increment_seq(sec_chan_mseq); + + // Encrypt command. + sec_chan_buffer[0] = SCTR_PROTECTED; + memcpy(&sec_chan_buffer[SEC_CHAN_SEQ_OFFSET], sec_chan_mseq, + SEC_CHAN_SEQ_SIZE); + uint8_t *ciphertext = &sec_chan_buffer[SEC_CHAN_CIPHERTEXT_OFFSET]; + uint8_t associated_data[8] = {SCTR_PROTECTED, 0, 0, 0, 0, SEC_CHAN_PROTOCOL}; + memcpy(&associated_data[SEC_CHAN_SEQ_OFFSET], sec_chan_mseq, + SEC_CHAN_SEQ_SIZE); + associated_data[6] = command_size >> 8; + associated_data[7] = command_size & 0xff; + if (EXIT_SUCCESS != aes_ccm_encrypt(&sec_chan_encr_ctx, sec_chan_encr_nonce, + sizeof(sec_chan_encr_nonce), + associated_data, sizeof(associated_data), + command_data, command_size, + SEC_CHAN_TAG_SIZE, ciphertext)) { + return OPTIGA_ERR_PROCESS; + } + + // Transmit encrypted command and receive response. + optiga_result ret = + optiga_transceive(true, sec_chan_buffer, sec_chan_size, sec_chan_buffer, + sizeof(sec_chan_buffer), &sec_chan_size); + if (ret != OPTIGA_SUCCESS) { + return ret; + } + + increment_seq(sec_chan_sseq); + + if (sec_chan_size < SEC_CHAN_OVERHEAD_SIZE || + sec_chan_buffer[0] != SCTR_PROTECTED || + memcmp(&sec_chan_buffer[SEC_CHAN_SEQ_OFFSET], sec_chan_sseq, + SEC_CHAN_SEQ_SIZE) != 0) { + return OPTIGA_ERR_UNEXPECTED; + } + + *response_size = sec_chan_size - SEC_CHAN_OVERHEAD_SIZE; + if (*response_size > max_response_size) { + *response_size = 0; + return OPTIGA_ERR_SIZE; + } + + // Decrypt response. + memcpy(&associated_data[SEC_CHAN_SEQ_OFFSET], sec_chan_sseq, + SEC_CHAN_SEQ_SIZE); + associated_data[6] = *response_size >> 8; + associated_data[7] = *response_size & 0xff; + if (EXIT_SUCCESS != aes_ccm_decrypt(&sec_chan_decr_ctx, sec_chan_decr_nonce, + sizeof(sec_chan_decr_nonce), + associated_data, sizeof(associated_data), + ciphertext, + *response_size + SEC_CHAN_TAG_SIZE, + SEC_CHAN_TAG_SIZE, response_data)) { + return OPTIGA_ERR_PROCESS; + } + + return OPTIGA_SUCCESS; +} + +optiga_result optiga_sec_chan_handshake(const uint8_t *secret, + size_t secret_size) { + static const uint8_t HANDSHAKE_HELLO[] = {SCTR_HELLO, SEC_CHAN_PROTOCOL}; + + // Send Handshake Hello. + optiga_result ret = optiga_transceive( + true, HANDSHAKE_HELLO, sizeof(HANDSHAKE_HELLO), sec_chan_buffer, + sizeof(sec_chan_buffer), &sec_chan_size); + if (ret != OPTIGA_SUCCESS) { + return ret; + } + + // Process Handshake Hello response (sctr[1], pver[1], rnd[32], sseq[4]). + if (sec_chan_size != 2 + SEC_CHAN_RND_SIZE + SEC_CHAN_SEQ_SIZE || + sec_chan_buffer[0] != SCTR_HELLO || + sec_chan_buffer[1] != SEC_CHAN_PROTOCOL) { + return OPTIGA_ERR_UNEXPECTED; + } + + uint8_t payload[SEC_CHAN_HANDSHAKE_SIZE] = {0}; + memcpy(payload, &sec_chan_buffer[2], sizeof(payload)); + uint8_t *rnd = &payload[0]; + uint8_t *sseq = &payload[SEC_CHAN_RND_SIZE]; + + // Compute encryption and decryption keys. + uint8_t encryption_keys[40] = {0}; + tls_prf_sha256(secret, secret_size, (const uint8_t *)"Platform Binding", 16, + rnd, SEC_CHAN_RND_SIZE, encryption_keys, + sizeof(encryption_keys)); + aes_encrypt_key128(&encryption_keys[0], &sec_chan_encr_ctx); + aes_encrypt_key128(&encryption_keys[16], &sec_chan_decr_ctx); + memcpy(&sec_chan_encr_nonce[0], &encryption_keys[32], 4); + memcpy(&sec_chan_decr_nonce[0], &encryption_keys[36], 4); + memzero(encryption_keys, sizeof(encryption_keys)); + + // Prepare Handshake Finished message (sctr[1], sseq[4], ciphertext[44]). + uint8_t handshake_finished[SEC_CHAN_HANDSHAKE_SIZE + SEC_CHAN_OVERHEAD_SIZE] = + {SCTR_FINISHED}; + memcpy(&handshake_finished[SEC_CHAN_SEQ_OFFSET], sseq, SEC_CHAN_SEQ_SIZE); + uint8_t *ciphertext = &handshake_finished[SEC_CHAN_CIPHERTEXT_OFFSET]; + uint8_t associated_data[8] = { + SCTR_FINISHED, 0, 0, 0, 0, SEC_CHAN_PROTOCOL, 0, SEC_CHAN_HANDSHAKE_SIZE}; + memcpy(&associated_data[SEC_CHAN_SEQ_OFFSET], sseq, SEC_CHAN_SEQ_SIZE); + memcpy(sec_chan_mseq, sseq, SEC_CHAN_SEQ_SIZE); + if (EXIT_SUCCESS != aes_ccm_encrypt(&sec_chan_encr_ctx, sec_chan_encr_nonce, + sizeof(sec_chan_encr_nonce), + associated_data, sizeof(associated_data), + payload, SEC_CHAN_HANDSHAKE_SIZE, + SEC_CHAN_TAG_SIZE, ciphertext)) { + return OPTIGA_ERR_PROCESS; + } + + // Send Handshake Finished message. + ret = optiga_transceive(true, handshake_finished, sizeof(handshake_finished), + sec_chan_buffer, sizeof(sec_chan_buffer), + &sec_chan_size); + if (ret != OPTIGA_SUCCESS) { + return ret; + } + + // Process response (sctr[1], mseq[4], ciphertext[44]). + if (sec_chan_size != SEC_CHAN_HANDSHAKE_SIZE + SEC_CHAN_OVERHEAD_SIZE || + sec_chan_buffer[0] != SCTR_FINISHED) { + return OPTIGA_ERR_UNEXPECTED; + } + uint8_t *mseq = &sec_chan_buffer[SEC_CHAN_SEQ_OFFSET]; + ciphertext = &sec_chan_buffer[SEC_CHAN_CIPHERTEXT_OFFSET]; + + // Verify payload. + memcpy(sec_chan_sseq, mseq, SEC_CHAN_SEQ_SIZE); + memcpy(&associated_data[SEC_CHAN_SEQ_OFFSET], mseq, SEC_CHAN_SEQ_SIZE); + uint8_t response_payload[SEC_CHAN_HANDSHAKE_SIZE] = {0}; + if (EXIT_SUCCESS != + aes_ccm_decrypt(&sec_chan_decr_ctx, sec_chan_decr_nonce, + sizeof(sec_chan_decr_nonce), associated_data, + sizeof(associated_data), ciphertext, + SEC_CHAN_HANDSHAKE_SIZE + SEC_CHAN_TAG_SIZE, + SEC_CHAN_TAG_SIZE, response_payload)) { + return OPTIGA_ERR_UNEXPECTED; + } + + if (memcmp(response_payload, rnd, SEC_CHAN_RND_SIZE) != 0 || + memcmp(response_payload + SEC_CHAN_RND_SIZE, mseq, SEC_CHAN_SEQ_SIZE) != + 0) { + return OPTIGA_ERR_UNEXPECTED; + } + + memcpy(sec_chan_mseq, mseq, SEC_CHAN_SEQ_SIZE); + memcpy(sec_chan_sseq, sseq, SEC_CHAN_SEQ_SIZE); + sec_chan_established = true; + return OPTIGA_SUCCESS; } diff --git a/core/embed/trezorhal/optiga_commands.h b/core/embed/trezorhal/optiga_commands.h index 82ff328de..df4f8169a 100644 --- a/core/embed/trezorhal/optiga_commands.h +++ b/core/embed/trezorhal/optiga_commands.h @@ -25,6 +25,19 @@ #include #include "optiga_common.h" +// Data object identifiers. +typedef enum { + OPTIGA_OID_COPROC_UID = 0xE0C2, // Coprocessor UID. + OPTIGA_OID_CERT = 0xE0E0, // Public key certificates [1-4]. + OPTIGA_OID_CA_CERT = 0xE0E8, // Root CA public key certificates [1-2]. + OPTIGA_OID_COUNTER = 0xE120, // Monotonic counters [1-4]. + OPTIGA_OID_ECC_KEY = 0xE0F0, // Private ECC keys [1-4]. + OPTIGA_OID_PTFBIND_SECRET = 0xE140, // Shared platform binding secret. + OPTIGA_OID_ERROR_CODE = 0xF1C2, // Command error code. + OPTIGA_OID_DATA = 0xF1D0, // Arbitrary 140 B data objects [1-12]. + OPTIGA_OID_BIG_DATA = 0xF1E0, // Arbitrary 1500 B data objects [1-2]. +} optiga_oid; + // ECC curve identifiers. typedef enum { OPTIGA_CURVE_P256 = 0x03, // NIST P256 ECC key. @@ -79,6 +92,16 @@ typedef enum { OPTIGA_DATA_TYPE_AUTOREF = 0x31, // Secret for verifying external entity. } optiga_data_type; +// Access conditions. +typedef enum { + OPTIGA_ACCESS_COND_ALW = 0x00, // Always. + OPTIGA_ACCESS_COND_CONF = 0x20, // Confidentiality protection required. + OPTIGA_ACCESS_COND_INT = 0x21, // Integrity protection required. + OPTIGA_ACCESS_COND_AUTO = 0x23, // Authorization required. + OPTIGA_ACCESS_COND_LUC = 0x40, // Usage limited by counter. + OPTIGA_ACCESS_COND_NEV = 0xFF, // Never. +} optiga_access_cond; + typedef struct { const uint8_t *ptr; uint16_t len; @@ -99,6 +122,19 @@ typedef struct { optiga_metadata_item reset_type; // F0 - Factory reset type. } optiga_metadata; +#define OPTIGA_ECC_KEY_COUNT 4 +#define OPTIGA_CERT_COUNT 4 +#define OPTIGA_MAX_METADATA_SIZE 44 +#define OPTIGA_RANDOM_MIN_SIZE 8 +#define OPTIGA_RANDOM_MAX_SIZE 256 + +#define OPTIGA_ACCESS_CONDITION(ac_id, oid) \ + { (const uint8_t[]){ac_id, oid >> 8, oid & 0xff}, 3 } + +extern const optiga_metadata_item OPTIGA_LCS_OPERATIONAL; +extern const optiga_metadata_item OPTIGA_ACCESS_ALWAYS; +extern const optiga_metadata_item OPTIGA_ACCESS_NEVER; + optiga_result optiga_parse_metadata(const uint8_t *serialized, size_t serialized_size, optiga_metadata *metadata); @@ -106,6 +142,8 @@ optiga_result optiga_serialize_metadata(const optiga_metadata *metadata, uint8_t *serialized, size_t max_serialized, size_t *serialized_size); +bool optiga_compare_metadata(const optiga_metadata *expected, + const optiga_metadata *stored); optiga_result optiga_open_application(void); optiga_result optiga_get_error_code(uint8_t *error_code); @@ -120,11 +158,15 @@ optiga_result optiga_encrypt_sym(optiga_sym_mode mode, uint16_t oid, uint8_t *output, size_t max_output_size, size_t *output_size); optiga_result optiga_set_auto_state(uint16_t nonce_oid, uint16_t key_oid, - const uint8_t key[32]); + const uint8_t *key, size_t key_size); optiga_result optiga_clear_auto_state(uint16_t key_oid); optiga_result optiga_calc_sign(uint16_t oid, const uint8_t *digest, size_t digest_size, uint8_t *signature, size_t max_sig_size, size_t *sig_size); +optiga_result optiga_verify_sign(optiga_curve curve, const uint8_t *public_key, + size_t public_key_size, const uint8_t *digest, + size_t digest_size, const uint8_t *signature, + size_t sig_size); optiga_result optiga_gen_key_pair(optiga_curve curve, optiga_key_usage usage, uint16_t oid, uint8_t *public_key, size_t max_public_key_size, diff --git a/core/embed/trezorhal/optiga_transport.h b/core/embed/trezorhal/optiga_transport.h index 2f3ab4eb1..4275199eb 100644 --- a/core/embed/trezorhal/optiga_transport.h +++ b/core/embed/trezorhal/optiga_transport.h @@ -28,10 +28,17 @@ // Maximum data register length supported by OPTIGA. #define OPTIGA_DATA_REG_LEN 277 +// Maximum command and response APDU size supported by OPTIGA. +#define OPTIGA_MAX_APDU_SIZE 1557 + optiga_result optiga_init(void); -optiga_result optiga_execute_command( - bool presentation_layer, const uint8_t *command_data, size_t command_size, - uint8_t *response_data, size_t max_response_size, size_t *response_size); +optiga_result optiga_sec_chan_handshake(const uint8_t *secret, + size_t secret_size); +optiga_result optiga_execute_command(const uint8_t *command_data, + size_t command_size, + uint8_t *response_data, + size_t max_response_size, + size_t *response_size); optiga_result optiga_resync(void); optiga_result optiga_soft_reset(void); diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h index a5a8be8ef..336680147 100644 --- a/core/embed/trezorhal/secret.h +++ b/core/embed/trezorhal/secret.h @@ -7,6 +7,8 @@ #define SECRET_OPTIGA_KEY_OFFSET 16 #define SECRET_OPTIGA_KEY_LEN 32 +secbool secret_bootloader_locked(void); + void secret_write(uint8_t* data, uint32_t offset, uint32_t len); secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len); diff --git a/core/embed/trezorhal/stm32f4/dma.c b/core/embed/trezorhal/stm32f4/dma.c deleted file mode 100644 index 46e10f31a..000000000 --- a/core/embed/trezorhal/stm32f4/dma.c +++ /dev/null @@ -1,305 +0,0 @@ -// clang-format off - -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015-2019 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include - -#include "dma.h" -#include "irq.h" -#include "systick.h" -#include "supervise.h" - -#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0) -#define DMA_SYSTICK_LOG2 (3) -#define DMA_SYSTICK_MASK ((1 << DMA_SYSTICK_LOG2) - 1) -#define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec -#define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0) - -typedef enum { - dma_id_not_defined=-1, - dma_id_0, - dma_id_1, - dma_id_2, - dma_id_3, - dma_id_4, - dma_id_5, - dma_id_6, - dma_id_7, - dma_id_8, - dma_id_9, - dma_id_10, - dma_id_11, - dma_id_12, - dma_id_13, - dma_id_14, - dma_id_15, -} dma_id_t; - -typedef union { - uint16_t enabled; // Used to test if both counters are == 0 - uint8_t counter[2]; -} dma_idle_count_t; - -struct _dma_descr_t { - DMA_Stream_TypeDef *instance; - uint32_t sub_instance; - dma_id_t id; - const DMA_InitTypeDef *init; -}; - -// Parameters to dma_init() for SDIO tx and rx. -static const DMA_InitTypeDef dma_init_struct_sdio = { - .Channel = 0, - .Direction = 0, - .PeriphInc = DMA_PINC_DISABLE, - .MemInc = DMA_MINC_ENABLE, - .PeriphDataAlignment = DMA_PDATAALIGN_WORD, - .MemDataAlignment = DMA_MDATAALIGN_WORD, - .Mode = DMA_PFCTRL, - .Priority = DMA_PRIORITY_VERY_HIGH, - .FIFOMode = DMA_FIFOMODE_ENABLE, - .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, - .MemBurst = DMA_MBURST_INC4, - .PeriphBurst = DMA_PBURST_INC4, -}; - -#define NCONTROLLERS (2) -#define NSTREAMS_PER_CONTROLLER (8) -#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) - -#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 25) - -#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1 -#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2 - -const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio }; - -static const uint8_t dma_irqn[NSTREAM] = { - DMA1_Stream0_IRQn, - DMA1_Stream1_IRQn, - DMA1_Stream2_IRQn, - DMA1_Stream3_IRQn, - DMA1_Stream4_IRQn, - DMA1_Stream5_IRQn, - DMA1_Stream6_IRQn, - DMA1_Stream7_IRQn, - DMA2_Stream0_IRQn, - DMA2_Stream1_IRQn, - DMA2_Stream2_IRQn, - DMA2_Stream3_IRQn, - DMA2_Stream4_IRQn, - DMA2_Stream5_IRQn, - DMA2_Stream6_IRQn, - DMA2_Stream7_IRQn, -}; - -static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL}; -static uint8_t dma_last_sub_instance[NSTREAM]; -static volatile uint32_t dma_enable_mask = 0; -volatile dma_idle_count_t dma_idle; - -#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid - -#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) -#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) - -void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } -void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } -void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Stream2_IRQn); } -void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Stream3_IRQn); } -void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Stream4_IRQn); } -void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Stream5_IRQn); } -void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Stream6_IRQn); } -void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA1_Stream7_IRQn); } -void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Stream0_IRQn); } -void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Stream1_IRQn); } -void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]); } IRQ_EXIT(DMA2_Stream2_IRQn); } -void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]); } IRQ_EXIT(DMA2_Stream3_IRQn); } -void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]); } IRQ_EXIT(DMA2_Stream4_IRQn); } -void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]); } IRQ_EXIT(DMA2_Stream5_IRQn); } -void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); } -void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); } - -static void dma_idle_handler(uint32_t tick); - -// Resets the idle counter for the DMA controller associated with dma_id. -static void dma_tickle(dma_id_t dma_id) { - dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1; - systick_enable_dispatch(SYSTICK_DISPATCH_DMA, dma_idle_handler); -} - -static void dma_enable_clock(dma_id_t dma_id) { - // We don't want dma_tick_handler() to turn off the clock right after we - // enable it, so we need to mark the channel in use in an atomic fashion. - uint32_t irq_state = disable_irq(); - uint32_t old_enable_mask = dma_enable_mask; - dma_enable_mask |= (1 << dma_id); - enable_irq(irq_state); - - if (dma_id < NSTREAMS_PER_CONTROLLER) { - if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { - __HAL_RCC_DMA1_CLK_ENABLE(); - - // We just turned on the clock. This means that anything stored - // in dma_last_channel (for DMA1) needs to be invalidated. - - for (int channel = 0; channel < NSTREAMS_PER_CONTROLLER; channel++) { - dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; - } - } - } - #if defined(DMA2) - else { - if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { - __HAL_RCC_DMA2_CLK_ENABLE(); - - // We just turned on the clock. This means that anything stored - // in dma_last_channel (for DMA2) needs to be invalidated. - - for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) { - dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; - } - } - } - #endif -} - -static void dma_disable_clock(dma_id_t dma_id) { - // We just mark the clock as disabled here, but we don't actually disable it. - // We wait for the timer to expire first, which means that back-to-back - // transfers don't have to initialize as much. - dma_tickle(dma_id); - dma_enable_mask &= ~(1 << dma_id); -} - -void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data) { - // initialise parameters - dma->Instance = dma_descr->instance; - dma->Init = *dma_descr->init; - dma->Init.Direction = dir; - dma->Init.Channel = dma_descr->sub_instance; - // half of __HAL_LINKDMA(data, xxx, *dma) - // caller must implement other half by doing: data->xxx = dma - dma->Parent = data; -} - -void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data){ - // Some drivers allocate the DMA_HandleTypeDef from the stack - // (i.e. dac, i2c, spi) and for those cases we need to clear the - // structure so we don't get random values from the stack) - memset(dma, 0, sizeof(*dma)); - - if (dma_descr != NULL) { - dma_id_t dma_id = dma_descr->id; - - dma_init_handle(dma, dma_descr, dir, data); - // set global pointer for IRQ handler - dma_handle[dma_id] = dma; - - dma_enable_clock(dma_id); - - // if this stream was previously configured for this channel/request and direction then we - // can skip most of the initialisation - uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) | (dir == DMA_PERIPH_TO_MEMORY) << 7; - if (dma_last_sub_instance[dma_id] != sub_inst) { - dma_last_sub_instance[dma_id] = sub_inst; - - // reset and configure DMA peripheral - // (dma->State is set to HAL_DMA_STATE_RESET by memset above) - HAL_DMA_DeInit(dma); - HAL_DMA_Init(dma); - svc_setpriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); - } else { - // only necessary initialization - dma->State = HAL_DMA_STATE_READY; - // calculate DMA base address and bitshift to be used in IRQ handler - extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma); - DMA_CalcBaseAndBitshift(dma); - } - - svc_enableIRQ(dma_irqn[dma_id]); - } -} - -void dma_deinit(const dma_descr_t *dma_descr) { - if (dma_descr != NULL) { - svc_disableIRQ(dma_irqn[dma_descr->id]); - dma_handle[dma_descr->id] = NULL; - - dma_disable_clock(dma_descr->id); - } -} - -void dma_invalidate_channel(const dma_descr_t *dma_descr) { - if (dma_descr != NULL) { - dma_id_t dma_id = dma_descr->id; - // Only compare the sub-instance, not the direction bit (MSB) - if ((dma_last_sub_instance[dma_id] & 0x7f) == DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) ) { - dma_last_sub_instance[dma_id] = DMA_INVALID_CHANNEL; - } - } -} -// Called from the SysTick handler -// We use LSB of tick to select which controller to process -static void dma_idle_handler(uint32_t tick) { - if (!DMA_IDLE_ENABLED() || !DMA_IDLE_TICK(tick)) { - return; - } - - static const uint32_t controller_mask[] = { - DMA1_ENABLE_MASK, - #if defined(DMA2) - DMA2_ENABLE_MASK, - #endif - }; - { - int controller = (tick >> DMA_SYSTICK_LOG2) & 1; - if (dma_idle.counter[controller] == 0) { - return; - } - if (++dma_idle.counter[controller] > DMA_IDLE_TICK_MAX) { - if ((dma_enable_mask & controller_mask[controller]) == 0) { - // Nothing is active and we've reached our idle timeout, - // Now we'll really disable the clock. - dma_idle.counter[controller] = 0; - if (controller == 0) { - __HAL_RCC_DMA1_CLK_DISABLE(); - } - #if defined(DMA2) - else { - __HAL_RCC_DMA2_CLK_DISABLE(); - } - #endif - } else { - // Something is still active, but the counter never got - // reset, so we'll reset the counter here. - dma_idle.counter[controller] = 1; - } - } - } -} diff --git a/core/embed/trezorhal/stm32f4/dma.h b/core/embed/trezorhal/stm32f4/dma.h deleted file mode 100644 index a1a5883c4..000000000 --- a/core/embed/trezorhal/stm32f4/dma.h +++ /dev/null @@ -1,46 +0,0 @@ -// clang-format off - -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef MICROPY_INCLUDED_STM32_DMA_H -#define MICROPY_INCLUDED_STM32_DMA_H - -#include STM32_HAL_H - -typedef struct _dma_descr_t dma_descr_t; - -extern const dma_descr_t dma_SDIO_0; - -void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); -void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); -void dma_deinit(const dma_descr_t *dma_descr); -void dma_invalidate_channel(const dma_descr_t *dma_descr); - -void dma_nohal_init(const dma_descr_t *descr, uint32_t config); -void dma_nohal_deinit(const dma_descr_t *descr); -void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len); - -#endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/core/embed/trezorhal/stm32f4/limited_util.s b/core/embed/trezorhal/stm32f4/limited_util.s new file mode 100644 index 000000000..0c2f72f8c --- /dev/null +++ b/core/embed/trezorhal/stm32f4/limited_util.s @@ -0,0 +1,104 @@ + .syntax unified + + .text + + .global memset_reg + .type memset_reg, STT_FUNC +memset_reg: + // call with the following (note that the arguments are not validated prior to use): + // r0 - address of first word to write (inclusive) + // r1 - address of first word following the address in r0 to NOT write (exclusive) + // r2 - word value to be written + // both addresses in r0 and r1 needs to be divisible by 4! + .L_loop_begin: + str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed + cmp r0, r1 + bne .L_loop_begin + bx lr + + .global jump_to + .type jump_to, STT_FUNC +jump_to: + mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save) + // this subroutine re-points the exception handlers before the C code + // that comprises them has been given a good environment to run. + // therefore, this code needs to disable interrupts before the VTOR + // update. then, the reset_handler of the next stage needs to re-enable interrupts. + // the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI). + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8: + // "there is no requirement to insert memory barrier instructions after CPSID". + cpsid f + // wipe memory at the end of the current stage of code + bl clear_otg_hs_memory + ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM + ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM + ldr r2, =0 // r2 - the word-sized value to be written + bl memset_reg + ldr r0, =sram_start // r0 - point to beginning of SRAM + ldr r1, =sram_end // r1 - point to byte after the end of SRAM + ldr r2, =0 // r2 - the word-sized value to be written + bl memset_reg + mov lr, r4 + // clear out the general purpose registers before the next stage's code can run (even the NMI exception handler) + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + // give the next stage a fresh main stack pointer + ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table + msr msp, r0 // give the next stage its main stack pointer + // point to the next stage's exception handlers + // AN321, section 4.11: "a memory barrier is not required after a VTOR update" + .set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3 + ldr r0, =SCB_VTOR + str lr, [r0] + mov r0, r1 // zero out r0 + // go on to the next stage + ldr lr, [lr, 4] // set lr to the next stage's reset_handler + bx lr + + .global shutdown_privileged + .type shutdown_privileged, STT_FUNC + // The function must be called from the privileged mode +shutdown_privileged: + cpsid f // disable all exceptions (except for NMI), the instruction is ignored in unprivileged mode + // if the exceptions weren't disabled, an exception handler (for example systick handler) + // could be called after the memory is erased, which would lead to another exception + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + ldr lr, =0xffffffff + ldr r0, =ccmram_start + ldr r1, =ccmram_end + // set to value in r2 + bl memset_reg + ldr r0, =sram_start + ldr r1, =sram_end + // set to value in r2 + bl memset_reg + bl clear_otg_hs_memory + ldr r0, =1 + msr control, r0 // jump to unprivileged mode + ldr r0, =0 + b . // loop forever + + .end diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index c7c2676fa..483eb780c 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -125,13 +125,12 @@ void mpu_config_firmware(void) { MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk; - // Secret + Storage#2 (0x08100000 - 0x0811FFFF, 16 Kib + 64 KiB, read-write, - // execute never) + // Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never) MPU->RNR = MPU_REGION_NUMBER2; MPU->RBAR = FLASH_BASE + 0x110000; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | - LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_FULL_ACCESS | - MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0x0E); + LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk; // Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at // start = 768 KiB, read-only) @@ -194,3 +193,98 @@ void mpu_config_firmware(void) { __asm__ volatile("dsb"); __asm__ volatile("isb"); } + +void mpu_config_prodtest(void) { + // Disable MPU + HAL_MPU_Disable(); + + // Note: later entries overwrite previous ones + + // // Boardloader (0x08000000 - 0x0800BFFF, 48 KiB, read-only, execute never) + // MPU->RNR = MPU_REGION_NUMBER0; + // MPU->RBAR = FLASH_BASE; + // MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + // LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | + // MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); + + // Secret area (0x08100000 - 0x08103FFF, 16 KiB, read-write, execute never) + // MPU->RNR = MPU_REGION_NUMBER0; + // MPU->RBAR = FLASH_BASE + 0x100000; + // MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + // LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_FULL_ACCESS | + // MPU_RASR_XN_Msk; + + // Bootloader (0x08020000 - 0x0803FFFF, 64 KiB, read-only) + MPU->RNR = MPU_REGION_NUMBER1; + MPU->RBAR = FLASH_BASE + 0x20000; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO; + + // Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at + // start = 768 KiB, read-only) + MPU->RNR = MPU_REGION_NUMBER2; + MPU->RBAR = FLASH_BASE; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS | + MPU_SUBREGION_DISABLE(0x03); + + // Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8 + // at start = 896 KiB, read-only) + MPU->RNR = MPU_REGION_NUMBER3; + MPU->RBAR = FLASH_BASE + 0x100000; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS | + MPU_SUBREGION_DISABLE(0x01); + + // SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, + // read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER4; + MPU->RBAR = SRAM_BASE; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | + LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); + +#ifdef USE_SDRAM + // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) + // SDRAM (0xC0000000 - 0xDFFFFFFF, read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER5; + MPU->RBAR = 0; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | + LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xBB); +#else + // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) + // External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER5; + MPU->RBAR = PERIPH_BASE; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | + LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk; +#endif + +#if defined STM32F427xx || defined STM32F429xx + // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER6; + MPU->RBAR = CCMDATARAM_BASE; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | + LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk; +#elif STM32F405xx + // no CCMRAM +#else +#error Unsupported MCU +#endif + + // OTP (0x1FFF7800 - 0x1FFF7C00, read-write, execute never) + MPU->RNR = MPU_REGION_NUMBER7; + MPU->RBAR = FLASH_OTP_BASE; + MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | + LL_MPU_REGION_SIZE_1KB | LL_MPU_REGION_FULL_ACCESS | + MPU_RASR_XN_Msk; + + // Enable MPU + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +} diff --git a/core/embed/trezorhal/stm32f4/optiga_hal.c b/core/embed/trezorhal/stm32f4/optiga_hal.c index 4cf15524a..2f3164402 100644 --- a/core/embed/trezorhal/stm32f4/optiga_hal.c +++ b/core/embed/trezorhal/stm32f4/optiga_hal.c @@ -12,11 +12,14 @@ void optiga_hal_init(void) { GPIO_InitStructure.Pin = GPIO_PIN_9; HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_SET); - hal_delay(1); + // warm reset startup time min 15ms + hal_delay(20); } void optiga_reset(void) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_RESET); hal_delay(10); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_SET); + // warm reset startup time min 15ms + hal_delay(20); } diff --git a/core/embed/trezorhal/stm32f4/sdcard.c b/core/embed/trezorhal/stm32f4/sdcard.c index 6b298f7b6..a3a242b4d 100644 --- a/core/embed/trezorhal/stm32f4/sdcard.c +++ b/core/embed/trezorhal/stm32f4/sdcard.c @@ -47,7 +47,6 @@ #include -#include "dma.h" #include "irq.h" #include "sdcard-set_clr_card_detect.h" #include "sdcard.h" @@ -56,9 +55,17 @@ #define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE() #define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE() #define SDMMC_IRQn SDMMC1_IRQn -#define SDMMC_DMA dma_SDIO_0 -static SD_HandleTypeDef sd_handle; +static SD_HandleTypeDef sd_handle = {0}; +static DMA_HandleTypeDef sd_dma = {0}; + +void DMA2_Stream3_IRQHandler(void) { + IRQ_ENTER(DMA2_Stream3_IRQn); + + HAL_DMA_IRQHandler(&sd_dma); + + IRQ_EXIT(DMA2_Stream3_IRQn); +} static inline void sdcard_default_pin_state(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // SD_ON/PC0 @@ -114,7 +121,10 @@ static inline void sdcard_active_pin_state(void) { HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); } -void sdcard_init(void) { sdcard_default_pin_state(); } +void sdcard_init(void) { + sdcard_default_pin_state(); + __HAL_RCC_DMA2_CLK_ENABLE(); +} void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { if (hsd->Instance == sd_handle.Instance) { @@ -283,8 +293,23 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - DMA_HandleTypeDef sd_dma; - dma_init(&sd_dma, &SDMMC_DMA, DMA_PERIPH_TO_MEMORY, &sd_handle); + sd_dma.Instance = DMA2_Stream3; + sd_dma.State = HAL_DMA_STATE_RESET; + sd_dma.Init.Channel = DMA_CHANNEL_4; + sd_dma.Init.Direction = DMA_PERIPH_TO_MEMORY; + sd_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + sd_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + sd_dma.Init.MemBurst = DMA_MBURST_INC4; + sd_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + sd_dma.Init.MemInc = DMA_MINC_ENABLE; + sd_dma.Init.Mode = DMA_PFCTRL; + sd_dma.Init.PeriphBurst = DMA_PBURST_INC4; + sd_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + sd_dma.Init.PeriphInc = DMA_PINC_DISABLE; + sd_dma.Init.Priority = DMA_PRIORITY_VERY_HIGH; + sd_dma.Parent = &sd_handle; + HAL_DMA_Init(&sd_dma); + sd_handle.hdmarx = &sd_dma; // we need to assign hdmatx even though it's unused @@ -295,6 +320,8 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, memset(&dummy_dma, 0, sizeof(dummy_dma)); sd_handle.hdmatx = &dummy_dma; + svc_enableIRQ(DMA2_Stream3_IRQn); + sdcard_reset_periph(); err = HAL_SD_ReadBlocks_DMA(&sd_handle, (uint8_t *)dest, block_num, num_blocks); @@ -302,7 +329,8 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, err = sdcard_wait_finished(&sd_handle, 5000); } - dma_deinit(&SDMMC_DMA); + svc_disableIRQ(DMA2_Stream3_IRQn); + HAL_DMA_DeInit(&sd_dma); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); @@ -327,8 +355,23 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - DMA_HandleTypeDef sd_dma; - dma_init(&sd_dma, &SDMMC_DMA, DMA_MEMORY_TO_PERIPH, &sd_handle); + sd_dma.Instance = DMA2_Stream3; + sd_dma.State = HAL_DMA_STATE_RESET; + sd_dma.Init.Channel = DMA_CHANNEL_4; + sd_dma.Init.Direction = DMA_MEMORY_TO_PERIPH; + sd_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + sd_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + sd_dma.Init.MemBurst = DMA_MBURST_INC4; + sd_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + sd_dma.Init.MemInc = DMA_MINC_ENABLE; + sd_dma.Init.Mode = DMA_PFCTRL; + sd_dma.Init.PeriphBurst = DMA_PBURST_INC4; + sd_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + sd_dma.Init.PeriphInc = DMA_PINC_DISABLE; + sd_dma.Init.Priority = DMA_PRIORITY_VERY_HIGH; + sd_dma.Parent = &sd_handle; + HAL_DMA_Init(&sd_dma); + sd_handle.hdmatx = &sd_dma; // we need to assign hdmarx even though it's unused @@ -339,6 +382,8 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, memset(&dummy_dma, 0, sizeof(dummy_dma)); sd_handle.hdmarx = &dummy_dma; + svc_enableIRQ(DMA2_Stream3_IRQn); + sdcard_reset_periph(); err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t *)src, block_num, num_blocks); @@ -346,7 +391,8 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, err = sdcard_wait_finished(&sd_handle, 5000); } - dma_deinit(&SDMMC_DMA); + svc_disableIRQ(DMA2_Stream3_IRQn); + HAL_DMA_DeInit(&sd_dma); sd_handle.hdmatx = NULL; restore_irq_pri(basepri); diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index d8d032dec..2232f889a 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -4,13 +4,28 @@ #include "flash.h" #include "model.h" +static secbool bootloader_locked_set = secfalse; +static secbool bootloader_locked = secfalse; + static secbool verify_header(void) { uint8_t header[SECRET_HEADER_LEN] = {0}; memcpy(header, flash_area_get_address(&SECRET_AREA, 0, SECRET_HEADER_LEN), SECRET_HEADER_LEN); - return memcmp(header, SECRET_HEADER_MAGIC, 4) == 0 ? sectrue : secfalse; + bootloader_locked = + memcmp(header, SECRET_HEADER_MAGIC, 4) == 0 ? sectrue : secfalse; + bootloader_locked_set = sectrue; + return bootloader_locked; +} + +secbool secret_bootloader_locked(void) { + if (bootloader_locked_set != sectrue) { + // Set bootloader_locked. + verify_header(); + } + + return bootloader_locked; } void secret_write_header(void) { diff --git a/core/embed/trezorhal/stm32f4/supervise.h b/core/embed/trezorhal/stm32f4/supervise.h index 93769b012..7d51530d6 100644 --- a/core/embed/trezorhal/stm32f4/supervise.h +++ b/core/embed/trezorhal/stm32f4/supervise.h @@ -5,10 +5,17 @@ #define SVC_SET_PRIORITY 2 #define SVC_SHUTDOWN 4 #define SVC_REBOOT_TO_BOOTLOADER 5 +#define SVC_REBOOT_COPY_IMAGE_HEADER 6 + +#include +#include "common.h" +#include "image.h" // from util.s extern void shutdown_privileged(void); extern void reboot_to_bootloader(void); +extern void copy_image_header_for_bootloader(const uint8_t *image_header); +extern void ensure_compatible_settings(void); static inline uint32_t is_mode_unprivileged(void) { uint32_t r0; @@ -58,10 +65,25 @@ static inline void svc_shutdown(void) { shutdown_privileged(); } } + static inline void svc_reboot_to_bootloader(void) { + explicit_bzero(&firmware_header_start, IMAGE_HEADER_SIZE); if (is_mode_unprivileged() && !is_mode_handler()) { __asm__ __volatile__("svc %0" ::"i"(SVC_REBOOT_TO_BOOTLOADER) : "memory"); } else { + ensure_compatible_settings(); + reboot_to_bootloader(); + } +} + +static inline void svc_reboot_copy_image_header(const uint8_t *image_address) { + if (is_mode_unprivileged() && !is_mode_handler()) { + register const uint8_t *r0 __asm__("r0") = image_address; + __asm__ __volatile__("svc %0" ::"i"(SVC_REBOOT_COPY_IMAGE_HEADER), "r"(r0) + : "memory"); + } else { + copy_image_header_for_bootloader(image_address); + ensure_compatible_settings(); reboot_to_bootloader(); } } diff --git a/core/embed/trezorhal/stm32f4/systick.c b/core/embed/trezorhal/stm32f4/systick.c index f4d56c62c..5afa8a5bf 100644 --- a/core/embed/trezorhal/stm32f4/systick.c +++ b/core/embed/trezorhal/stm32f4/systick.c @@ -56,8 +56,6 @@ extern __IO uint32_t uwTick; -systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS]; - void SysTick_Handler(void) { SEGGER_SYSVIEW_RecordEnterISR(); // this is a millisecond tick counter that wraps after approximately @@ -67,9 +65,6 @@ void SysTick_Handler(void) { #ifdef RDI rdi_handler(uw_tick); #endif - systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)]; - if (f != NULL) { - f(uw_tick); - } + SEGGER_SYSVIEW_RecordExitISR(); } diff --git a/core/embed/trezorhal/stm32f4/systick.h b/core/embed/trezorhal/stm32f4/systick.h index 99421ff21..7c94a91a3 100644 --- a/core/embed/trezorhal/stm32f4/systick.h +++ b/core/embed/trezorhal/stm32f4/systick.h @@ -34,23 +34,4 @@ // Works for x between 0 and 16 inclusive #define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1) -enum { - SYSTICK_DISPATCH_DMA = 0, - SYSTICK_DISPATCH_MAX -}; - -#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX) - -typedef void (*systick_dispatch_t)(uint32_t); - -extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS]; - -static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) { - systick_dispatch_table[slot] = f; -} - -static inline void systick_disable_dispatch(size_t slot) { - systick_dispatch_table[slot] = NULL; -} - #endif // MICROPY_INCLUDED_STM32_SYSTICK_H diff --git a/core/embed/trezorhal/stm32f4/util.s b/core/embed/trezorhal/stm32f4/util.s index 74b0ca4c0..1e39846d0 100644 --- a/core/embed/trezorhal/stm32f4/util.s +++ b/core/embed/trezorhal/stm32f4/util.s @@ -43,7 +43,7 @@ jump_to_with_flag: // wipe memory at the end of the current stage of code bl clear_otg_hs_memory ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM - ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM + ldr r1, =firmware_header_start // r1 - point to byte after the end of CCMRAM ldr r2, =0 // r2 - the word-sized value to be written bl memset_reg ldr r0, =sram_start // r0 - point to beginning of SRAM diff --git a/core/embed/trezorhal/unix/optiga.c b/core/embed/trezorhal/unix/optiga.c new file mode 100644 index 000000000..91889965c --- /dev/null +++ b/core/embed/trezorhal/unix/optiga.c @@ -0,0 +1,153 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "optiga.h" +#include +#include "ecdsa.h" +#include "nist256p1.h" +#include "optiga_common.h" +#include "rand.h" + +static const uint8_t DEVICE_CERT_CHAIN[] = { + 0x30, 0x82, 0x01, 0x90, 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x04, 0x4e, 0xe2, 0xa5, 0x0f, 0x30, 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x4f, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x5a, 0x31, 0x1e, + 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x15, 0x54, 0x72, 0x65, + 0x7a, 0x6f, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, + 0x73, 0x2e, 0x72, 0x2e, 0x6f, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x17, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, + 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x69, 0x6e, + 0x67, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x34, + 0x33, 0x30, 0x31, 0x34, 0x31, 0x36, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x34, + 0x32, 0x30, 0x34, 0x33, 0x30, 0x31, 0x34, 0x31, 0x36, 0x30, 0x31, 0x5a, + 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x04, 0x54, 0x32, 0x42, 0x31, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x9b, 0xbf, 0x06, 0xda, + 0xd9, 0xab, 0x59, 0x05, 0xe0, 0x54, 0x71, 0xce, 0x16, 0xd5, 0x22, 0x2c, + 0x89, 0xc2, 0xca, 0xa3, 0x9f, 0x26, 0x26, 0x7a, 0xc0, 0x74, 0x71, 0x29, + 0x88, 0x5f, 0xbd, 0x44, 0x1b, 0xcc, 0x7f, 0xa8, 0x4d, 0xe1, 0x20, 0xa3, + 0x67, 0x55, 0xda, 0xf3, 0x0a, 0x6f, 0x47, 0xe8, 0xc0, 0xd4, 0xbd, 0xdc, + 0x15, 0x03, 0x6e, 0xd2, 0xa3, 0x44, 0x7d, 0xfa, 0x7a, 0x1d, 0x3e, 0x88, + 0xa3, 0x41, 0x30, 0x3f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0x80, 0x30, 0x0c, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x0a, + 0x80, 0xa4, 0x22, 0xc1, 0x6e, 0x36, 0x94, 0x24, 0xd3, 0xb8, 0x12, 0x67, + 0xb5, 0xaa, 0xe6, 0x46, 0x74, 0x74, 0xc8, 0x30, 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, + 0x02, 0x20, 0x2f, 0xba, 0xc7, 0xe7, 0x99, 0x5b, 0x0e, 0x00, 0xc2, 0xc2, + 0xa7, 0xcb, 0xd8, 0xdd, 0x1d, 0x4e, 0xce, 0xf5, 0x58, 0x75, 0xa2, 0x65, + 0xc6, 0x86, 0xd4, 0xa8, 0xd2, 0x80, 0x68, 0x63, 0x5b, 0xf8, 0x02, 0x20, + 0x1e, 0xee, 0x62, 0x10, 0x0d, 0x0c, 0x97, 0x5a, 0x96, 0x34, 0x6f, 0x14, + 0xef, 0xe2, 0x6b, 0xc9, 0x3b, 0x00, 0xba, 0x30, 0x28, 0x9c, 0xe3, 0x7c, + 0xef, 0x17, 0x89, 0xbc, 0xc0, 0x68, 0xba, 0xb9, 0x30, 0x82, 0x01, 0xe0, + 0x30, 0x82, 0x01, 0x85, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x00, + 0x94, 0x4e, 0x25, 0x7c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x02, 0x30, 0x54, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x5a, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x15, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x73, 0x2e, 0x72, + 0x2e, 0x6f, 0x2e, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x1c, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x4d, 0x61, 0x6e, + 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x33, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, + 0x0f, 0x32, 0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x5a, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x15, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x73, 0x2e, 0x72, + 0x2e, 0x6f, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x17, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x4d, 0x61, 0x6e, + 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x43, + 0x41, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x9b, 0xf0, 0x76, 0x0c, 0xd7, 0x55, 0x5e, 0xfc, + 0x5b, 0x01, 0xe6, 0x4c, 0xe9, 0x46, 0x06, 0xcd, 0xee, 0xb4, 0x8a, 0x4f, + 0x91, 0x96, 0xf4, 0x54, 0xbc, 0x2a, 0x01, 0x41, 0xb3, 0x31, 0x88, 0x2d, + 0x06, 0x8b, 0x4b, 0x6e, 0x63, 0x79, 0x13, 0xdd, 0x22, 0x06, 0x54, 0xe2, + 0x8f, 0xde, 0x3c, 0x44, 0x21, 0x41, 0xf9, 0x53, 0xb3, 0xe3, 0x6a, 0xd9, + 0xa5, 0x75, 0x19, 0x00, 0x71, 0x19, 0xd9, 0xc9, 0xa3, 0x47, 0x30, 0x45, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x02, 0x04, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0x28, 0xb2, 0x02, 0xf8, 0xf9, 0xc7, 0x8a, 0x74, 0xe8, 0xc1, 0x52, + 0xbb, 0xfb, 0x43, 0x3d, 0x99, 0xd0, 0xca, 0x03, 0xef, 0x30, 0x0a, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, + 0x30, 0x46, 0x02, 0x21, 0x00, 0x9b, 0x60, 0xfb, 0x5f, 0xc7, 0xee, 0x07, + 0x00, 0x31, 0x2d, 0x40, 0x2d, 0xcb, 0xe0, 0x77, 0xe4, 0x81, 0x82, 0xbb, + 0x94, 0x4b, 0xb1, 0xb3, 0x30, 0x79, 0xdd, 0xa0, 0xb6, 0xca, 0x9a, 0xb5, + 0xb7, 0x02, 0x21, 0x00, 0x81, 0x5d, 0xd9, 0x76, 0xab, 0xec, 0xb9, 0xb3, + 0xa8, 0x0f, 0x5b, 0x86, 0xb4, 0x49, 0x4f, 0xef, 0x94, 0xf2, 0xe0, 0xc1, + 0xf2, 0xc4, 0x5d, 0xe6, 0xec, 0x5f, 0x89, 0x5c, 0xa5, 0x6f, 0x04, 0x8b}; + +int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size, + uint8_t *signature, size_t max_sig_size, size_t *sig_size) { + const uint8_t DEVICE_PRIV_KEY[32] = {1}; + + if (index != OPTIGA_DEVICE_ECC_KEY_INDEX) { + return false; + } + + if (max_sig_size < 72) { + return OPTIGA_ERR_SIZE; + } + + uint8_t raw_signature[64] = {0}; + int ret = ecdsa_sign_digest(&nist256p1, DEVICE_PRIV_KEY, digest, + raw_signature, NULL, NULL); + if (ret != 0) { + return OPTIGA_ERR_CMD; + } + + *sig_size = ecdsa_sig_to_der(raw_signature, signature); + return OPTIGA_SUCCESS; +} + +bool optiga_cert_size(uint8_t index, size_t *cert_size) { + if (index != OPTIGA_DEVICE_CERT_INDEX) { + return false; + } + + *cert_size = sizeof(DEVICE_CERT_CHAIN); + return true; +} + +bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, + size_t *cert_size) { + if (index != OPTIGA_DEVICE_CERT_INDEX) { + return false; + } + + if (max_cert_size < sizeof(DEVICE_CERT_CHAIN)) { + return false; + } + + memcpy(cert, DEVICE_CERT_CHAIN, sizeof(DEVICE_CERT_CHAIN)); + *cert_size = sizeof(DEVICE_CERT_CHAIN); + return true; +} + +bool optiga_random_buffer(uint8_t *dest, size_t size) { + random_buffer(dest, size); + return true; +} diff --git a/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.json b/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 000000000..7bdc03ecc --- /dev/null +++ b/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,20 @@ +{ + "header_len": 4608, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "D001", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": false, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.toif b/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.toif new file mode 120000 index 000000000..1fc944393 --- /dev/null +++ b/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.toif @@ -0,0 +1 @@ +./vendor_unsafe.toif \ No newline at end of file diff --git a/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 000000000..dc01833e6 Binary files /dev/null and b/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_unsigned.bin new file mode 100644 index 000000000..2fee42f97 Binary files /dev/null and b/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json b/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.json similarity index 93% rename from core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json rename to core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.json index 325e759e8..1d75f08d8 100644 --- a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json +++ b/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.json @@ -1,6 +1,6 @@ { "header_len": 4608, - "text": "QA ONLY, DO NOT USE!", + "text": "DEV ONLY, DO NOT USE!", "hw_model": "T2B1", "expiry": 0, "version": [0, 0], diff --git a/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.toif new file mode 120000 index 000000000..3dc5d9734 --- /dev/null +++ b/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.toif @@ -0,0 +1 @@ +./vendor_satoshilabs.toif \ No newline at end of file diff --git a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.toif b/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.toif deleted file mode 120000 index 32ec8b259..000000000 --- a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.toif +++ /dev/null @@ -1 +0,0 @@ -vendor_satoshilabs.toif \ No newline at end of file diff --git a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 97% rename from core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin rename to core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin index 59bce50df..dc7ce39c0 100644 Binary files a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin and b/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 98% rename from core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin rename to core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin index 8440523af..95bc9788c 100644 Binary files a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin and b/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json b/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.json similarity index 93% rename from core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json rename to core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.json index 6fab49ebb..d22bff3da 100644 --- a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json +++ b/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.json @@ -1,6 +1,6 @@ { "header_len": 4608, - "text": "QA ONLY, DO NOT USE!", + "text": "DEV ONLY, DO NOT USE!", "hw_model": null, "expiry": 0, "version": [0, 0], diff --git a/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.toif new file mode 120000 index 000000000..3dc5d9734 --- /dev/null +++ b/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.toif @@ -0,0 +1 @@ +./vendor_satoshilabs.toif \ No newline at end of file diff --git a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.toif b/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.toif deleted file mode 120000 index 32ec8b259..000000000 --- a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.toif +++ /dev/null @@ -1 +0,0 @@ -vendor_satoshilabs.toif \ No newline at end of file diff --git a/core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 96% rename from core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin rename to core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin index bcfc1226e..574ef8b28 100644 Binary files a/core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin and b/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 98% rename from core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin rename to core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin index ba6872ce1..a4dacb6cd 100644 Binary files a/core/embed/vendorheader/T2T1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin and b/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/generate.sh b/core/embed/vendorheader/generate.sh index fd0a19c30..7dc1a264f 100755 --- a/core/embed/vendorheader/generate.sh +++ b/core/embed/vendorheader/generate.sh @@ -20,6 +20,7 @@ MODELS=(T2T1 T2B1 D001) for MODEL in ${MODELS[@]}; do cd $MODEL + echo "Generating vendor headers for $MODEL" # construct all vendor headers for fn in *.json; do name=$(echo $fn | sed 's/vendor_\(.*\)\.json/\1/') @@ -29,7 +30,7 @@ for MODEL in ${MODELS[@]}; do TMPDIR=$(mktemp -d) trap "rm -rf $TMPDIR" EXIT # sign dev and QA vendor header - for name in unsafe qa_DO_NOT_SIGN; do + for name in unsafe dev_DO_NOT_SIGN; do SRC_NAME="vendorheader_${name}_unsigned.bin" DEST_NAME="vendorheader_${name}_signed_dev.bin" if [ ! -f "$SRC_NAME" ]; then diff --git a/core/mocks/generated/trezorcrypto/optiga.pyi b/core/mocks/generated/trezorcrypto/optiga.pyi new file mode 100644 index 000000000..25af0f16c --- /dev/null +++ b/core/mocks/generated/trezorcrypto/optiga.pyi @@ -0,0 +1,33 @@ +from typing import * + + +# extmod/modtrezorcrypto/modtrezorcrypto-optiga.h +class OptigaError(Exception): + """Error returned by the Optiga chip.""" + + +# extmod/modtrezorcrypto/modtrezorcrypto-optiga.h +class SigningInaccessible(OptigaError): + """The signing key is inaccessible. + Typically, this will happen after the bootloader has been unlocked. + """ + + +# extmod/modtrezorcrypto/modtrezorcrypto-optiga.h +def get_certificate(cert_index: int) -> bytes: + """ + Return the certificate stored at the given index. + """ + + +# extmod/modtrezorcrypto/modtrezorcrypto-optiga.h +def sign( + key_index: int, + digest: bytes, +) -> bytes: + """ + Uses the private key at key_index to produce a DER-encoded signature of + the digest. + """ +DEVICE_CERT_INDEX: int +DEVICE_ECC_KEY_INDEX: int diff --git a/core/mocks/generated/trezorcrypto/random.pyi b/core/mocks/generated/trezorcrypto/random.pyi index 78fc9c58b..bd3260580 100644 --- a/core/mocks/generated/trezorcrypto/random.pyi +++ b/core/mocks/generated/trezorcrypto/random.pyi @@ -10,9 +10,10 @@ import builtins # extmod/modtrezorcrypto/modtrezorcrypto-random.h -def bytes(len: int) -> builtins.bytes: +def bytes(len: int, strong: bool = False) -> builtins.bytes: """ - Generate random bytes sequence of length len. + Generate random bytes sequence of length len. If `strong` is set then + maximum sources of entropy are used. """ diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index b7a7ce0ec..fbd9789f1 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -50,6 +50,7 @@ def confirm_address( data: str, description: str | None, # unused on TR extra: str | None, # unused on TR + chunkify: bool = False, ) -> object: """Confirm address.""" @@ -125,15 +126,23 @@ def confirm_modify_output( # rust/src/ui/model_tr/layout.rs -def confirm_output( +def confirm_output_address( *, address: str, address_label: str, - amount: str, address_title: str, + chunkify: bool = False, +) -> object: + """Confirm output address.""" + + +# rust/src/ui/model_tr/layout.rs +def confirm_output_amount( + *, + amount: str, amount_title: str, ) -> object: - """Confirm output.""" + """Confirm output amount.""" # rust/src/ui/model_tr/layout.rs @@ -149,6 +158,17 @@ def confirm_total( """Confirm summary of a transaction.""" +# rust/src/ui/model_tr/layout.rs +def confirm_ethereum_tx( + *, + recipient: str, + total_amount: str, + maximum_fee: str, + items: Iterable[Tuple[str, str]], +) -> object: + """Confirm details about Ethereum transaction.""" + + # rust/src/ui/model_tr/layout.rs def tutorial() -> object: """Show user how to interact with the device.""" @@ -215,7 +235,7 @@ def show_passphrase() -> object: # rust/src/ui/model_tr/layout.rs -def show_mismatch() -> object: +def show_mismatch(*, title: str) -> object: """Warning modal, receiving address mismatch.""" @@ -223,14 +243,26 @@ def show_mismatch() -> object: def confirm_with_info( *, title: str, - button: str, # unused on TR + button: str, info_button: str, # unused on TR items: Iterable[Tuple[int, str]], + verb_cancel: str | None = None, ) -> object: """Confirm given items but with third button. Always single page without scrolling.""" +# rust/src/ui/model_tr/layout.rs +def confirm_more( + *, + title: str, + button: str, + items: Iterable[tuple[int, str]], +) -> object: + """Confirm long content with the possibility to go back from any page. + Meant to be used with confirm_with_info.""" + + # rust/src/ui/model_tr/layout.rs def confirm_coinjoin( *, @@ -473,6 +505,7 @@ def confirm_address( data: str | bytes, description: str | None, extra: str | None, + chunkify: bool = False, ) -> object: """Confirm address. Similar to `confirm_blob` but has corner info button and allows left swipe which does the same thing as the button.""" @@ -501,8 +534,10 @@ def confirm_reset_device( # rust/src/ui/model_tt/layout.rs def show_address_details( *, + qr_title: str, address: str, case_sensitive: bool, + details_title: str, account: str | None, path: str | None, xpubs: list[tuple[str, str]], @@ -511,12 +546,10 @@ def show_address_details( # rust/src/ui/model_tt/layout.rs -def show_spending_details( +def show_info_with_cancel( *, - title: str = "INFORMATION", - account: str | None, - fee_rate: str | None, - fee_rate_title: str = "Fee rate:", + title: str, + items: Iterable[Tuple[str, str]], ) -> object: """Show metadata when for outgoing transaction.""" @@ -532,6 +565,7 @@ def confirm_value( verb_cancel: str | None = None, info_button: bool = False, hold: bool = False, + chunkify: bool = False, ) -> object: """Confirm value. Merge of confirm_total and confirm_output.""" @@ -542,6 +576,7 @@ def confirm_total( title: str, items: list[tuple[str, str]], info_button: bool = False, + cancel_arrow: bool = False, ) -> object: """Transaction summary. Always hold to confirm.""" @@ -599,6 +634,7 @@ def show_warning( *, title: str, button: str = "CONTINUE", + value: str = "", description: str = "", allow_cancel: bool = False, time_ms: int = 0, @@ -631,7 +667,7 @@ def show_info( # rust/src/ui/model_tt/layout.rs -def show_mismatch() -> object: +def show_mismatch(*, title: str) -> object: """Warning modal, receiving address mismatch.""" diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi index 913d95841..9fa4ab13b 100644 --- a/core/mocks/generated/trezorutils.pyi +++ b/core/mocks/generated/trezorutils.pyi @@ -79,12 +79,21 @@ def reboot_to_bootloader() -> None: """ Reboots to bootloader. """ + + +# extmod/modtrezorutils/modtrezorutils.c +def bootloader_locked() -> bool | None: + """ + Returns True/False if the the bootloader is locked/unlocked and None if + the feature is not supported. + """ SCM_REVISION: bytes VERSION_MAJOR: int VERSION_MINOR: int VERSION_PATCH: int USE_SD_CARD: bool USE_BACKLIGHT: bool +USE_OPTIGA: bool MODEL: str INTERNAL_MODEL: str EMULATOR: bool diff --git a/core/site_scons/boards/stm32f4_common.py b/core/site_scons/boards/stm32f4_common.py index 2b4d951b7..329de344c 100644 --- a/core/site_scons/boards/stm32f4_common.py +++ b/core/site_scons/boards/stm32f4_common.py @@ -45,10 +45,21 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/trezorhal/stm32f4/systick.c", "embed/trezorhal/stm32f4/random_delays.c", "embed/trezorhal/stm32f4/rng.c", - "embed/trezorhal/stm32f4/util.s", "embed/trezorhal/stm32f4/vectortable.s", ] + # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks + # this helps to prevent making a bug in boardloader which may be hard to fix since it's locked with write-protect + env_constraints = env.get("CONSTRAINTS") + if env_constraints and "limited_util_s" in env_constraints: + sources += [ + "embed/trezorhal/stm32f4/limited_util.s", + ] + else: + sources += [ + "embed/trezorhal/stm32f4/util.s", + ] + env.get("ENV")["RUST_INCLUDES"] = ( "-I../trezorhal/stm32f4;" "-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc;" diff --git a/core/site_scons/boards/trezor_r_v10.py b/core/site_scons/boards/trezor_r_v10.py index fa704d94b..03f4a152f 100644 --- a/core/site_scons/boards/trezor_r_v10.py +++ b/core/site_scons/boards/trezor_r_v10.py @@ -33,6 +33,7 @@ def configure( defines += [f'TREZOR_BOARD=\\"boards/{board}\\"'] defines += [f"HW_MODEL={hw_model}"] defines += [f"HW_REVISION={hw_revision}"] + defines += ["USE_OPTIGA=1"] sources += [ "embed/models/model_T2B1_layout.c", ] @@ -53,8 +54,6 @@ def configure( sources += [ "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c" ] - sources += ["embed/trezorhal/stm32f4/dma.c"] - if "usb" in features_wanted: sources += [ "embed/trezorhal/stm32f4/usb.c", @@ -68,9 +67,11 @@ def configure( if "optiga" in features_wanted: sources += ["embed/trezorhal/stm32f4/optiga_hal.c"] + sources += ["embed/trezorhal/optiga/optiga.c"] sources += ["embed/trezorhal/optiga/optiga_commands.c"] sources += ["embed/trezorhal/optiga/optiga_transport.c"] sources += ["embed/trezorhal/stm32f4/secret.c"] + features_available.append("optiga") env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu diff --git a/core/site_scons/boards/trezor_t.py b/core/site_scons/boards/trezor_t.py index 2de5975f3..1bf39befb 100644 --- a/core/site_scons/boards/trezor_t.py +++ b/core/site_scons/boards/trezor_t.py @@ -67,7 +67,6 @@ def configure( sources += [ "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c" ] - sources += ["embed/trezorhal/stm32f4/dma.c"] features_available.append("sd_card") if "sbu" in features_wanted: diff --git a/core/site_scons/site_tools/micropython/__init__.py b/core/site_scons/site_tools/micropython/__init__.py index 00355e45a..d2fdd97fa 100644 --- a/core/site_scons/site_tools/micropython/__init__.py +++ b/core/site_scons/site_tools/micropython/__init__.py @@ -36,12 +36,16 @@ def generate(env): # replace "utils.BITCOIN_ONLY" with literal constant (True/False) # so the compiler can optimize out the things we don't want btc_only = env["bitcoin_only"] == "1" + is_t2b1 = env["TREZOR_MODEL"] == "R" backlight = env["backlight"] + optiga = env["optiga"] interim = f"{target[:-4]}.i" # replace .mpy with .i sed_scripts = " ".join( [ + rf"-e 's/utils\.MODEL_IS_T2B1/{is_t2b1}/g'", rf"-e 's/utils\.BITCOIN_ONLY/{btc_only}/g'", rf"-e 's/utils\.USE_BACKLIGHT/{backlight}/g'", + rf"-e 's/utils\.USE_OPTIGA/{optiga}/g'", r"-e 's/if TYPE_CHECKING/if False/'", r"-e 's/import typing/# \0/'", r"-e '/from typing import (/,/^\s*)/ {s/^/# /}'", diff --git a/core/src/all_modules.py b/core/src/all_modules.py index 60ac66b01..e66de0e36 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -313,6 +313,8 @@ apps.management.apply_flags import apps.management.apply_flags apps.management.apply_settings import apps.management.apply_settings +apps.management.authenticate_device +import apps.management.authenticate_device apps.management.backup_device import apps.management.backup_device apps.management.backup_types diff --git a/core/src/apps/base.py b/core/src/apps/base.py index ef513d613..32d3b917f 100644 --- a/core/src/apps/base.py +++ b/core/src/apps/base.py @@ -66,6 +66,7 @@ def get_features() -> Features: homescreen_height=HEIGHT, unit_color=utils.unit_color(), unit_btconly=utils.unit_btconly(), + bootloader_locked=utils.bootloader_locked(), ) if utils.INTERNAL_MODEL in ("T1B1", "T2B1"): @@ -87,10 +88,8 @@ def get_features() -> Features: Capability.Binance, Capability.Cardano, Capability.Crypto, - Capability.EOS, Capability.Ethereum, Capability.Monero, - Capability.NEM, Capability.Ripple, Capability.Stellar, Capability.Tezos, @@ -100,6 +99,15 @@ def get_features() -> Features: Capability.PassphraseEntry, ] + # We do not support some currencies on T2B1 + if not utils.MODEL_IS_T2B1: + f.capabilities.extend( + [ + Capability.NEM, + Capability.EOS, + ] + ) + # Only some models are capable of SD card if utils.USE_SD_CARD: from trezor import sdcard diff --git a/core/src/apps/binance/get_address.py b/core/src/apps/binance/get_address.py index 5f9ad6254..2cbe0dca9 100644 --- a/core/src/apps/binance/get_address.py +++ b/core/src/apps/binance/get_address.py @@ -26,6 +26,8 @@ async def get_address(msg: BinanceGetAddress, keychain: Keychain) -> BinanceAddr pubkey = node.public_key() address = address_from_public_key(pubkey, HRP) if msg.show_display: - await show_address(address, path=paths.address_n_to_str(address_n)) + await show_address( + address, path=paths.address_n_to_str(address_n), chunkify=bool(msg.chunkify) + ) return BinanceAddress(address=address) diff --git a/core/src/apps/binance/get_public_key.py b/core/src/apps/binance/get_public_key.py index 272731d51..fba66761a 100644 --- a/core/src/apps/binance/get_public_key.py +++ b/core/src/apps/binance/get_public_key.py @@ -24,6 +24,7 @@ async def get_public_key( pubkey = node.public_key() if msg.show_display: - await show_pubkey(hexlify(pubkey).decode()) + path = paths.address_n_to_str(msg.address_n) + await show_pubkey(hexlify(pubkey).decode(), path=path) return BinancePublicKey(public_key=pubkey) diff --git a/core/src/apps/binance/layout.py b/core/src/apps/binance/layout.py index 95eea31cf..115f59eeb 100644 --- a/core/src/apps/binance/layout.py +++ b/core/src/apps/binance/layout.py @@ -34,21 +34,18 @@ async def require_confirm_transfer(msg: BinanceTransferMsg) -> None: for txoutput in msg.outputs: make_input_output_pages(txoutput, "Confirm output") - await _confirm_transfer(items) + await _confirm_transfer(items, chunkify=bool(msg.chunkify)) -async def _confirm_transfer(inputs_outputs: Sequence[tuple[str, str, str]]) -> None: +async def _confirm_transfer( + inputs_outputs: Sequence[tuple[str, str, str]], chunkify: bool +) -> None: from trezor.ui.layouts import confirm_output for index, (title, amount, address) in enumerate(inputs_outputs): # Having hold=True on the last item hold = index == len(inputs_outputs) - 1 - await confirm_output( - address, - amount, - title, - hold=hold, - ) + await confirm_output(address, amount, title, hold=hold, chunkify=chunkify) async def require_confirm_cancel(msg: BinanceCancelMsg) -> None: diff --git a/core/src/apps/bitcoin/get_address.py b/core/src/apps/bitcoin/get_address.py index 4dd302433..408b6c0d0 100644 --- a/core/src/apps/bitcoin/get_address.py +++ b/core/src/apps/bitcoin/get_address.py @@ -33,7 +33,7 @@ def _get_xpubs( async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Address: from trezor.enums import InputScriptType from trezor.messages import Address - from trezor.ui.layouts import show_address + from trezor.ui.layouts import show_address, show_warning from apps.common.address_mac import get_address_mac from apps.common.paths import address_n_to_str, validate_path @@ -100,6 +100,12 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad pubnodes = [hd.node for hd in multisig.pubkeys] multisig_index = multisig_pubkey_index(multisig, node.public_key()) + await show_warning( + "warning_multisig", + "Receiving to a multisig address.", + "Continue anyway?", + ) + await show_address( address_short, case_sensitive=address_case_sensitive, @@ -107,6 +113,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad multisig_index=multisig_index, xpubs=_get_xpubs(coin, multisig_xpub_magic, pubnodes), account=f"Multisig {multisig.m} of {len(pubnodes)}", + chunkify=bool(msg.chunkify), ) else: account_name = address_n_to_name(coin, address_n, script_type) @@ -122,6 +129,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad case_sensitive=address_case_sensitive, path=path, account=account, + chunkify=bool(msg.chunkify), ) return Address(address=address, mac=mac) diff --git a/core/src/apps/bitcoin/get_public_key.py b/core/src/apps/bitcoin/get_public_key.py index f5c778960..83c08c34a 100644 --- a/core/src/apps/bitcoin/get_public_key.py +++ b/core/src/apps/bitcoin/get_public_key.py @@ -79,9 +79,31 @@ async def get_public_key( ) if msg.show_display: - from trezor.ui.layouts import show_xpub + from trezor.ui.layouts import confirm_path_warning, show_pubkey - await show_xpub(node_xpub, "XPUB") + from apps.common.paths import address_n_to_str + + from .keychain import address_n_to_name + + path = address_n_to_str(address_n) + account_name = address_n_to_name( + coin, address_n, script_type, account_level=True + ) + if account_name is None: + account = None + await confirm_path_warning(path) + elif account_name == "": + account = coin.coin_shortcut + else: + account = f"{coin.coin_shortcut} {account_name}" + await show_pubkey( + node_xpub, + "XPUB", + account=account, + path=path, + mismatch_title="XPUB mismatch?", + br_type="show_xpub", + ) return PublicKey( node=node_type, diff --git a/core/src/apps/bitcoin/keychain.py b/core/src/apps/bitcoin/keychain.py index 4e07ea6a3..d6a99fd36 100644 --- a/core/src/apps/bitcoin/keychain.py +++ b/core/src/apps/bitcoin/keychain.py @@ -7,7 +7,7 @@ from trezor.messages import AuthorizeCoinJoin, SignMessage from apps.common.paths import PATTERN_BIP44, PATTERN_CASA, PathSchema, unharden from . import authorization -from .common import BITCOIN_NAMES +from .common import BIP32_WALLET_DEPTH, BITCOIN_NAMES if TYPE_CHECKING: from typing import Awaitable, Callable, Iterable, TypeVar @@ -341,6 +341,7 @@ class AccountType: require_segwit: bool, require_bech32: bool, require_taproot: bool, + account_level: bool = False, ): self.account_name = account_name self.pattern = pattern @@ -348,16 +349,24 @@ class AccountType: self.require_segwit = require_segwit self.require_bech32 = require_bech32 self.require_taproot = require_taproot + self.account_level = account_level def get_name( self, coin: coininfo.CoinInfo, address_n: Bip32Path, script_type: InputScriptType | None, + show_account_str: bool, ) -> str | None: + pattern = self.pattern + if self.account_level: + # Discard the last two parts of the pattern. For bitcoin these generally are `change` + # and `address_index`. The result can be used to match XPUB paths. + pattern = "/".join(pattern.split("/")[:-BIP32_WALLET_DEPTH]) + if ( (script_type is not None and script_type != self.script_type) - or not PathSchema.parse(self.pattern, coin.slip44).match(address_n) + or not PathSchema.parse(pattern, coin.slip44).match(address_n) or (not coin.segwit and self.require_segwit) or (not coin.bech32_prefix and self.require_bech32) or (not coin.taproot and self.require_taproot) @@ -365,9 +374,11 @@ class AccountType: return None name = self.account_name - account_pos = self.pattern.find("/account'") + if show_account_str: + name = f"{self.account_name} account" + account_pos = pattern.find("/account'") if account_pos >= 0: - i = self.pattern.count("/", 0, account_pos) + i = pattern.count("/", 0, account_pos) account_number = unharden(address_n[i]) + 1 name += f" #{account_number}" @@ -378,6 +389,8 @@ def address_n_to_name( coin: coininfo.CoinInfo, address_n: Bip32Path, script_type: InputScriptType | None = None, + account_level: bool = False, + show_account_str: bool = False, ) -> str | None: ACCOUNT_TYPES = ( AccountType( @@ -387,6 +400,7 @@ def address_n_to_name( require_segwit=True, require_bech32=False, require_taproot=False, + account_level=account_level, ), AccountType( "", @@ -395,6 +409,7 @@ def address_n_to_name( require_segwit=False, require_bech32=False, require_taproot=False, + account_level=account_level, ), AccountType( "L. SegWit", @@ -403,6 +418,7 @@ def address_n_to_name( require_segwit=True, require_bech32=False, require_taproot=False, + account_level=account_level, ), AccountType( "SegWit", @@ -411,6 +427,7 @@ def address_n_to_name( require_segwit=True, require_bech32=True, require_taproot=False, + account_level=account_level, ), AccountType( "Taproot", @@ -419,6 +436,7 @@ def address_n_to_name( require_segwit=False, require_bech32=True, require_taproot=True, + account_level=account_level, ), AccountType( "Coinjoin", @@ -427,11 +445,12 @@ def address_n_to_name( require_segwit=False, require_bech32=True, require_taproot=True, + account_level=account_level, ), ) for account in ACCOUNT_TYPES: - name = account.get_name(coin, address_n, script_type) + name = account.get_name(coin, address_n, script_type, show_account_str) if name: return name diff --git a/core/src/apps/bitcoin/sign_tx/__init__.py b/core/src/apps/bitcoin/sign_tx/__init__.py index e6bd380e4..ac8c8803d 100644 --- a/core/src/apps/bitcoin/sign_tx/__init__.py +++ b/core/src/apps/bitcoin/sign_tx/__init__.py @@ -4,11 +4,6 @@ from trezor import utils from ..keychain import with_keychain -if not utils.BITCOIN_ONLY: - from apps.zcash.signer import Zcash - - from . import bitcoinlike, decred, zcash_v4 - if TYPE_CHECKING: from typing import Protocol @@ -74,13 +69,21 @@ async def sign_tx( signer_class: type[SignerClass] = bitcoin.Bitcoin else: if coin.decred: + from . import decred + signer_class = decred.Decred elif coin.overwintered: if msg.version == 5: + from apps.zcash.signer import Zcash + signer_class = Zcash else: + from . import zcash_v4 + signer_class = zcash_v4.ZcashV4 else: + from . import bitcoinlike + signer_class = bitcoinlike.Bitcoinlike signer = signer_class(msg, keychain, coin, approver).signer() diff --git a/core/src/apps/bitcoin/sign_tx/approvers.py b/core/src/apps/bitcoin/sign_tx/approvers.py index 840d1a31b..27ac1cebc 100644 --- a/core/src/apps/bitcoin/sign_tx/approvers.py +++ b/core/src/apps/bitcoin/sign_tx/approvers.py @@ -144,6 +144,7 @@ class BasicApprover(Approver): super().__init__(tx, coin) self.change_count = 0 # the number of change-outputs self.foreign_address_confirmed = False + self.chunkify = bool(tx.chunkify) async def add_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None: if not validate_path_against_script_type(self.coin, txi): @@ -224,7 +225,11 @@ class BasicApprover(Approver): # Ask user to confirm output, unless it is part of a payment # request, which gets confirmed separately. await helpers.confirm_output( - txo, self.coin, self.amount_unit, self.external_output_index + txo, + self.coin, + self.amount_unit, + self.external_output_index, + self.chunkify, ) self.external_output_index += 1 @@ -274,6 +279,9 @@ class BasicApprover(Approver): if self.has_unverified_external_input: await helpers.confirm_unverified_external_input() + if tx_info.wallet_path.get_path() is None: + await helpers.confirm_multiple_accounts() + fee = self.total_in - self.total_out # some coins require negative fees for reward TX diff --git a/core/src/apps/bitcoin/sign_tx/helpers.py b/core/src/apps/bitcoin/sign_tx/helpers.py index d8d37fda0..5ee9cdee2 100644 --- a/core/src/apps/bitcoin/sign_tx/helpers.py +++ b/core/src/apps/bitcoin/sign_tx/helpers.py @@ -44,11 +44,13 @@ class UiConfirmOutput(UiConfirm): coin: CoinInfo, amount_unit: AmountUnit, output_index: int, + chunkify: bool, ): self.output = output self.coin = coin self.amount_unit = amount_unit self.output_index = output_index + self.chunkify = chunkify def confirm_dialog(self) -> Awaitable[Any]: return layout.confirm_output( @@ -56,6 +58,7 @@ class UiConfirmOutput(UiConfirm): self.coin, self.amount_unit, self.output_index, + self.chunkify, ) @@ -233,8 +236,13 @@ class UiConfirmNonDefaultLocktime(UiConfirm): ) -def confirm_output(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit, output_index: int) -> Awaitable[None]: # type: ignore [awaitable-is-generator] - return (yield UiConfirmOutput(output, coin, amount_unit, output_index)) +class UiConfirmMultipleAccounts(UiConfirm): + def confirm_dialog(self) -> Awaitable[Any]: + return layout.confirm_multiple_accounts() + + +def confirm_output(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit, output_index: int, chunkify: bool) -> Awaitable[None]: # type: ignore [awaitable-is-generator] + return (yield UiConfirmOutput(output, coin, amount_unit, output_index, chunkify)) def confirm_decred_sstx_submission(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore [awaitable-is-generator] @@ -289,6 +297,10 @@ def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> Awa return (yield UiConfirmNonDefaultLocktime(lock_time, lock_time_disabled)) +def confirm_multiple_accounts() -> Awaitable[Any]: # type: ignore [awaitable-is-generator] + return (yield UiConfirmMultipleAccounts()) + + def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevTx]: # type: ignore [awaitable-is-generator] from trezor.messages import TxAckPrevMeta diff --git a/core/src/apps/bitcoin/sign_tx/layout.py b/core/src/apps/bitcoin/sign_tx/layout.py index 7e656f74e..4323cc410 100644 --- a/core/src/apps/bitcoin/sign_tx/layout.py +++ b/core/src/apps/bitcoin/sign_tx/layout.py @@ -62,6 +62,7 @@ async def confirm_output( coin: CoinInfo, amount_unit: AmountUnit, output_index: int, + chunkify: bool, ) -> None: from trezor.enums import OutputScriptType @@ -97,9 +98,18 @@ async def confirm_output( address_label = None if output.address_n and not output.multisig: + from trezor import utils + + # Showing the account string only for T2B1 model + show_account_str = utils.INTERNAL_MODEL == "T2B1" script_type = CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[output.script_type] address_label = ( - address_n_to_name(coin, output.address_n, script_type) + address_n_to_name( + coin, + output.address_n, + script_type, + show_account_str=show_account_str, + ) or f"address path {address_n_to_str(output.address_n)}" ) @@ -109,6 +119,7 @@ async def confirm_output( title=title, address_label=address_label, output_index=output_index, + chunkify=chunkify, ) await layout @@ -147,7 +158,7 @@ async def confirm_payment_request( ) -> Any: from trezor import wire - memo_texts = [] + memo_texts: list[str] = [] for m in msg.memos: if m.text_memo is not None: memo_texts.append(m.text_memo.text) @@ -270,6 +281,16 @@ async def confirm_unverified_external_input() -> None: ) +async def confirm_multiple_accounts() -> None: + await layouts.show_warning( + "sending_from_multiple_accounts", + "Sending from multiple accounts.", + "Continue anyway?", + button="Continue", + br_code=ButtonRequestType.SignTx, + ) + + async def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> None: from trezor.strings import format_timestamp diff --git a/core/src/apps/cardano/get_address.py b/core/src/apps/cardano/get_address.py index c5a627dca..e1685aff0 100644 --- a/core/src/apps/cardano/get_address.py +++ b/core/src/apps/cardano/get_address.py @@ -39,6 +39,8 @@ async def get_address( Credential.payment_credential(address_parameters), Credential.stake_credential(address_parameters), ) - await show_cardano_address(address_parameters, address, msg.protocol_magic) + await show_cardano_address( + address_parameters, address, msg.protocol_magic, chunkify=bool(msg.chunkify) + ) return CardanoAddress(address=address) diff --git a/core/src/apps/cardano/get_public_key.py b/core/src/apps/cardano/get_public_key.py index 87d9d0eb4..5d637fe78 100644 --- a/core/src/apps/cardano/get_public_key.py +++ b/core/src/apps/cardano/get_public_key.py @@ -35,7 +35,10 @@ async def get_public_key( raise wire.ProcessError("Deriving public key failed") if msg.show_display: - await show_pubkey(hexlify(key.node.public_key).decode()) + from apps.common.paths import address_n_to_str + + path = address_n_to_str(address_n) + await show_pubkey(key.xpub, "Public key", path=path) return key diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py index b93710b98..aa95efa8e 100644 --- a/core/src/apps/cardano/layout.py +++ b/core/src/apps/cardano/layout.py @@ -210,6 +210,7 @@ async def confirm_sending( to: str, output_type: Literal["address", "change", "collateral-return"], network_id: int, + chunkify: bool, ) -> None: if output_type == "address": title = "Sending" @@ -225,6 +226,7 @@ async def confirm_sending( format_coin_amount(ada_amount, network_id), title, br_code=ButtonRequestType.Other, + chunkify=chunkify, ) @@ -898,6 +900,7 @@ async def show_cardano_address( address_parameters: messages.CardanoAddressParametersType, address: str, protocol_magic: int, + chunkify: bool, ) -> None: CAT = CardanoAddressType # local_cache_global @@ -925,4 +928,5 @@ async def show_cardano_address( path=path, account=account, network=network_name, + chunkify=chunkify, ) diff --git a/core/src/apps/cardano/sign_tx/signer.py b/core/src/apps/cardano/sign_tx/signer.py index f8b22bc34..9627c8736 100644 --- a/core/src/apps/cardano/sign_tx/signer.py +++ b/core/src/apps/cardano/sign_tx/signer.py @@ -366,6 +366,7 @@ class Signer: address, "change" if self._is_change_output(output) else "address", self.msg.network_id, + chunkify=bool(self.msg.chunkify), ) async def _show_output_credentials( @@ -1043,6 +1044,7 @@ class Signer: address, "collateral-return", self.msg.network_id, + chunkify=bool(self.msg.chunkify), ) def _should_show_collateral_return_init(self, output: CardanoTxOutput) -> bool: diff --git a/core/src/apps/common/coininfo.py b/core/src/apps/common/coininfo.py index 8c47c4db2..8fa146f6b 100644 --- a/core/src/apps/common/coininfo.py +++ b/core/src/apps/common/coininfo.py @@ -94,142 +94,26 @@ class CoinInfo: # fmt: off def by_name(name: str) -> CoinInfo: - if name == "Bitcoin": - return CoinInfo( - name, # coin_name - "BTC", # coin_shortcut - 8, # decimals - 0, # address_type - 5, # address_type_p2sh - 2000000, # maxfee_kb - "Bitcoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0295b43f, # xpub_magic_multisig_segwit_p2sh - 0x02aa7ed3, # xpub_magic_multisig_segwit_native - "bc", # bech32_prefix - None, # cashaddr_prefix - 0, # slip44 - True, # segwit - True, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Regtest": - return CoinInfo( - name, # coin_name - "REGTEST", # coin_shortcut - 8, # decimals - 111, # address_type - 196, # address_type_p2sh - 10000000, # maxfee_kb - "Bitcoin Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x024289ef, # xpub_magic_multisig_segwit_p2sh - 0x02575483, # xpub_magic_multisig_segwit_native - "bcrt", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - True, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Testnet": - return CoinInfo( - name, # coin_name - "TEST", # coin_shortcut - 8, # decimals - 111, # address_type - 196, # address_type_p2sh - 10000000, # maxfee_kb - "Bitcoin Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x024289ef, # xpub_magic_multisig_segwit_p2sh - 0x02575483, # xpub_magic_multisig_segwit_native - "tb", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - True, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if not utils.BITCOIN_ONLY: - if name == "Actinium": + if utils.MODEL_IS_T2B1: + if name == "Bitcoin": return CoinInfo( name, # coin_name - "ACM", # coin_shortcut + "BTC", # coin_shortcut 8, # decimals - 53, # address_type - 55, # address_type_p2sh - 320000000000, # maxfee_kb - "Actinium Signed Message:\n", # signed_message_header + 0, # address_type + 5, # address_type_p2sh + 2000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header 0x0488b21e, # xpub_magic 0x049d7cb2, # xpub_magic_segwit_p2sh 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "acm", # bech32_prefix + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "bc", # bech32_prefix None, # cashaddr_prefix - 228, # slip44 + 0, # slip44 True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Axe": - return CoinInfo( - name, # coin_name - "AXE", # coin_shortcut - 8, # decimals - 55, # address_type - 16, # address_type_p2sh - 21000000000, # maxfee_kb - "DarkCoin Signed Message:\n", # signed_message_header - 0x02fe52cc, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 4242, # slip44 - False, # segwit - False, # taproot + True, # taproot None, # fork_id False, # force_bip143 False, # decred @@ -240,228 +124,25 @@ def by_name(name: str) -> CoinInfo: False, # overwintered None, # confidential_assets ) - if name == "Bcash": - return CoinInfo( - name, # coin_name - "BCH", # coin_shortcut - 8, # decimals - 0, # address_type - 5, # address_type_p2sh - 14000000, # maxfee_kb - "Bitcoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - "bitcoincash", # cashaddr_prefix - 145, # slip44 - False, # segwit - False, # taproot - 0, # fork_id - True, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Bcash Testnet": + if name == "Regtest": return CoinInfo( name, # coin_name - "TBCH", # coin_shortcut + "REGTEST", # coin_shortcut 8, # decimals 111, # address_type 196, # address_type_p2sh 10000000, # maxfee_kb "Bitcoin Signed Message:\n", # signed_message_header 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - "bchtest", # cashaddr_prefix - 1, # slip44 - False, # segwit - False, # taproot - 0, # fork_id - True, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Bgold": - return CoinInfo( - name, # coin_name - "BTG", # coin_shortcut - 8, # decimals - 38, # address_type - 23, # address_type_p2sh - 380000000, # maxfee_kb - "Bitcoin Gold Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "btg", # bech32_prefix - None, # cashaddr_prefix - 156, # slip44 - True, # segwit - False, # taproot - 79, # fork_id - True, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Bgold Testnet": - return CoinInfo( - name, # coin_name - "TBTG", # coin_shortcut - 8, # decimals - 111, # address_type - 196, # address_type_p2sh - 500000, # maxfee_kb - "Bitcoin Gold Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic 0x044a5262, # xpub_magic_segwit_p2sh 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "tbtg", # bech32_prefix + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "bcrt", # bech32_prefix None, # cashaddr_prefix 1, # slip44 True, # segwit - False, # taproot - 79, # fork_id - True, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Bprivate": - return CoinInfo( - name, # coin_name - "BTCP", # coin_shortcut - 8, # decimals - 4901, # address_type - 5039, # address_type_p2sh - 32000000000, # maxfee_kb - "BitcoinPrivate Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 183, # slip44 - False, # segwit - False, # taproot - 42, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Bitcore": - return CoinInfo( - name, # coin_name - "BTX", # coin_shortcut - 8, # decimals - 3, # address_type - 125, # address_type_p2sh - 14000000000, # maxfee_kb - "BitCore Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "btx", # bech32_prefix - None, # cashaddr_prefix - 160, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "CPUchain": - return CoinInfo( - name, # coin_name - "CPU", # coin_shortcut - 8, # decimals - 28, # address_type - 30, # address_type_p2sh - 8700000000000, # maxfee_kb - "CPUchain Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "cpu", # bech32_prefix - None, # cashaddr_prefix - 363, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Crown": - return CoinInfo( - name, # coin_name - "CRW", # coin_shortcut - 8, # decimals - 95495, # address_type - 95473, # address_type_p2sh - 52000000000, # maxfee_kb - "Crown Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 72, # slip44 - False, # segwit - False, # taproot + True, # taproot None, # fork_id False, # force_bip143 False, # decred @@ -472,170 +153,1275 @@ def by_name(name: str) -> CoinInfo: False, # overwintered None, # confidential_assets ) - if name == "Dash": - return CoinInfo( - name, # coin_name - "DASH", # coin_shortcut - 8, # decimals - 76, # address_type - 16, # address_type_p2sh - 45000000, # maxfee_kb - "DarkCoin Signed Message:\n", # signed_message_header - 0x02fe52cc, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 5, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Dash Testnet": + if name == "Testnet": return CoinInfo( name, # coin_name - "tDASH", # coin_shortcut + "TEST", # coin_shortcut 8, # decimals - 140, # address_type - 19, # address_type_p2sh - 100000, # maxfee_kb - "DarkCoin Signed Message:\n", # signed_message_header + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "tb", # bech32_prefix None, # cashaddr_prefix 1, # slip44 - False, # segwit - False, # taproot + True, # segwit + True, # taproot None, # fork_id False, # force_bip143 False, # decred False, # negative_fee 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Decred": - return CoinInfo( - name, # coin_name - "DCR", # coin_shortcut - 8, # decimals - 1855, # address_type - 1818, # address_type_p2sh - 220000000, # maxfee_kb - "Decred Signed Message:\n", # signed_message_header - 0x02fda926, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 42, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - True, # decred - False, # negative_fee - 'secp256k1-decred', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Decred Testnet": - return CoinInfo( - name, # coin_name - "TDCR", # coin_shortcut - 8, # decimals - 3873, # address_type - 3836, # address_type_p2sh - 10000000, # maxfee_kb - "Decred Signed Message:\n", # signed_message_header - 0x043587d1, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - True, # decred - False, # negative_fee - 'secp256k1-decred', # curve_name False, # extra_data False, # timestamp False, # overwintered None, # confidential_assets ) - if name == "DigiByte": + if not utils.BITCOIN_ONLY: + if name == "Actinium": + return CoinInfo( + name, # coin_name + "ACM", # coin_shortcut + 8, # decimals + 53, # address_type + 55, # address_type_p2sh + 320000000000, # maxfee_kb + "Actinium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "acm", # bech32_prefix + None, # cashaddr_prefix + 228, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Axe": + return CoinInfo( + name, # coin_name + "AXE", # coin_shortcut + 8, # decimals + 55, # address_type + 16, # address_type_p2sh + 21000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x02fe52cc, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 4242, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash": + return CoinInfo( + name, # coin_name + "BCH", # coin_shortcut + 8, # decimals + 0, # address_type + 5, # address_type_p2sh + 14000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bitcoincash", # cashaddr_prefix + 145, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash Testnet": + return CoinInfo( + name, # coin_name + "TBCH", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bchtest", # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bprivate": + return CoinInfo( + name, # coin_name + "BTCP", # coin_shortcut + 8, # decimals + 4901, # address_type + 5039, # address_type_p2sh + 32000000000, # maxfee_kb + "BitcoinPrivate Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 183, # slip44 + False, # segwit + False, # taproot + 42, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bitcore": + return CoinInfo( + name, # coin_name + "BTX", # coin_shortcut + 8, # decimals + 3, # address_type + 125, # address_type_p2sh + 14000000000, # maxfee_kb + "BitCore Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "btx", # bech32_prefix + None, # cashaddr_prefix + 160, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "CPUchain": + return CoinInfo( + name, # coin_name + "CPU", # coin_shortcut + 8, # decimals + 28, # address_type + 30, # address_type_p2sh + 8700000000000, # maxfee_kb + "CPUchain Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "cpu", # bech32_prefix + None, # cashaddr_prefix + 363, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Crown": + return CoinInfo( + name, # coin_name + "CRW", # coin_shortcut + 8, # decimals + 95495, # address_type + 95473, # address_type_p2sh + 52000000000, # maxfee_kb + "Crown Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 72, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Dogecoin": + return CoinInfo( + name, # coin_name + "DOGE", # coin_shortcut + 8, # decimals + 30, # address_type + 22, # address_type_p2sh + 1200000000000, # maxfee_kb + "Dogecoin Signed Message:\n", # signed_message_header + 0x02facafd, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 3, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Elements": + return CoinInfo( + name, # coin_name + "ELEMENTS", # coin_shortcut + 8, # decimals + 235, # address_type + 75, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "ert", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + {'address_prefix': 4, 'blech32_prefix': 'el'}, # confidential_assets + ) + if name == "Feathercoin": + return CoinInfo( + name, # coin_name + "FTC", # coin_shortcut + 8, # decimals + 14, # address_type + 5, # address_type_p2sh + 390000000000, # maxfee_kb + "Feathercoin Signed Message:\n", # signed_message_header + 0x0488bc26, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488bc26, # xpub_magic_multisig_segwit_p2sh + 0x0488bc26, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 8, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo": + return CoinInfo( + name, # coin_name + "FIRO", # coin_shortcut + 8, # decimals + 82, # address_type + 7, # address_type_p2sh + 640000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 136, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo Testnet": + return CoinInfo( + name, # coin_name + "tFIRO", # coin_shortcut + 8, # decimals + 65, # address_type + 178, # address_type_p2sh + 1000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Florincoin": + return CoinInfo( + name, # coin_name + "FLO", # coin_shortcut + 8, # decimals + 35, # address_type + 94, # address_type_p2sh + 78000000000, # maxfee_kb + "Florincoin Signed Message:\n", # signed_message_header + 0x00174921, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x00174921, # xpub_magic_multisig_segwit_p2sh + 0x00174921, # xpub_magic_multisig_segwit_native + "flo", # bech32_prefix + None, # cashaddr_prefix + 216, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Fujicoin": + return CoinInfo( + name, # coin_name + "FJC", # coin_shortcut + 8, # decimals + 36, # address_type + 16, # address_type_p2sh + 35000000000000, # maxfee_kb + "FujiCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 75, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin": + return CoinInfo( + name, # coin_name + "GRS", # coin_shortcut + 8, # decimals + 36, # address_type + 5, # address_type_p2sh + 16000000000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "grs", # bech32_prefix + None, # cashaddr_prefix + 17, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin Testnet": + return CoinInfo( + name, # coin_name + "tGRS", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 100000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tgrs", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Komodo": + return CoinInfo( + name, # coin_name + "KMD", # coin_shortcut + 8, # decimals + 60, # address_type + 85, # address_type_p2sh + 4800000000, # maxfee_kb + "Komodo Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 141, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + True, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Koto": + return CoinInfo( + name, # coin_name + "KOTO", # coin_shortcut + 8, # decimals + 6198, # address_type + 6203, # address_type_p2sh + 1000000, # maxfee_kb + "Koto Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 510, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Litecoin": + return CoinInfo( + name, # coin_name + "LTC", # coin_shortcut + 8, # decimals + 48, # address_type + 50, # address_type_p2sh + 67000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x019da462, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x019da462, # xpub_magic_multisig_segwit_p2sh + 0x019da462, # xpub_magic_multisig_segwit_native + "ltc", # bech32_prefix + None, # cashaddr_prefix + 2, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Litecoin Testnet": + return CoinInfo( + name, # coin_name + "tLTC", # coin_shortcut + 8, # decimals + 111, # address_type + 58, # address_type_p2sh + 40000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tltc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Monacoin": + return CoinInfo( + name, # coin_name + "MONA", # coin_shortcut + 8, # decimals + 50, # address_type + 55, # address_type_p2sh + 2100000000, # maxfee_kb + "Monacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "mona", # bech32_prefix + None, # cashaddr_prefix + 22, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin": + return CoinInfo( + name, # coin_name + "PPC", # coin_shortcut + 6, # decimals + 55, # address_type + 117, # address_type_p2sh + 13000000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "pc", # bech32_prefix + None, # cashaddr_prefix + 6, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin Testnet": + return CoinInfo( + name, # coin_name + "tPPC", # coin_shortcut + 6, # decimals + 111, # address_type + 196, # address_type_p2sh + 2000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tpc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Primecoin": + return CoinInfo( + name, # coin_name + "XPM", # coin_shortcut + 8, # decimals + 23, # address_type + 83, # address_type_p2sh + 89000000000, # maxfee_kb + "Primecoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 24, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum": + return CoinInfo( + name, # coin_name + "QTUM", # coin_shortcut + 8, # decimals + 58, # address_type + 50, # address_type_p2sh + 1000000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "qc", # bech32_prefix + None, # cashaddr_prefix + 2301, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum Testnet": + return CoinInfo( + name, # coin_name + "tQTUM", # coin_shortcut + 8, # decimals + 120, # address_type + 110, # address_type_p2sh + 40000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tq", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin": + return CoinInfo( + name, # coin_name + "RVN", # coin_shortcut + 8, # decimals + 60, # address_type + 122, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 175, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin Testnet": + return CoinInfo( + name, # coin_name + "tRVN", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ritocoin": + return CoinInfo( + name, # coin_name + "RITO", # coin_shortcut + 8, # decimals + 25, # address_type + 105, # address_type_p2sh + 39000000000000, # maxfee_kb + "Rito Signed Message:\n", # signed_message_header + 0x0534e7ca, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 19169, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash": + return CoinInfo( + name, # coin_name + "SMART", # coin_shortcut + 8, # decimals + 63, # address_type + 18, # address_type_p2sh + 780000000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 224, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash Testnet": + return CoinInfo( + name, # coin_name + "tSMART", # coin_shortcut + 8, # decimals + 65, # address_type + 21, # address_type_p2sh + 1000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Stakenet": + return CoinInfo( + name, # coin_name + "XSN", # coin_shortcut + 8, # decimals + 76, # address_type + 16, # address_type_p2sh + 11000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "xc", # bech32_prefix + None, # cashaddr_prefix + 199, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Syscoin": + return CoinInfo( + name, # coin_name + "SYS", # coin_shortcut + 8, # decimals + 63, # address_type + 5, # address_type_p2sh + 42000000000, # maxfee_kb + "Syscoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "sys", # bech32_prefix + None, # cashaddr_prefix + 57, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Unobtanium": + return CoinInfo( + name, # coin_name + "UNO", # coin_shortcut + 8, # decimals + 130, # address_type + 30, # address_type_p2sh + 53000000, # maxfee_kb + "Unobtanium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 92, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "VIPSTARCOIN": + return CoinInfo( + name, # coin_name + "VIPS", # coin_shortcut + 8, # decimals + 70, # address_type + 50, # address_type_p2sh + 140000000000000, # maxfee_kb + "VIPSTARCOIN Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "vips", # bech32_prefix + None, # cashaddr_prefix + 1919, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Verge": + return CoinInfo( + name, # coin_name + "XVG", # coin_shortcut + 6, # decimals + 30, # address_type + 33, # address_type_p2sh + 550000000000, # maxfee_kb + "Name: Dogecoin Dark\n", # signed_message_header + 0x022d2533, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 77, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Viacoin": + return CoinInfo( + name, # coin_name + "VIA", # coin_shortcut + 8, # decimals + 71, # address_type + 33, # address_type_p2sh + 14000000000, # maxfee_kb + "Viacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "via", # bech32_prefix + None, # cashaddr_prefix + 14, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "ZCore": + return CoinInfo( + name, # coin_name + "ZCR", # coin_shortcut + 8, # decimals + 142, # address_type + 145, # address_type_p2sh + 170000000000, # maxfee_kb + "DarkNet Signed Message:\n", # signed_message_header + 0x04b24746, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 428, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Zcash": + return CoinInfo( + name, # coin_name + "ZEC", # coin_shortcut + 8, # decimals + 7352, # address_type + 7357, # address_type_p2sh + 51000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 133, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Zcash Testnet": + return CoinInfo( + name, # coin_name + "TAZ", # coin_shortcut + 8, # decimals + 7461, # address_type + 7354, # address_type_p2sh + 10000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Brhodium": + return CoinInfo( + name, # coin_name + "XRC", # coin_shortcut + 8, # decimals + 61, # address_type + 123, # address_type_p2sh + 1000000000, # maxfee_kb + "BitCoin Rhodium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 10291, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + raise ValueError # Unknown coin name + else: + if name == "Bitcoin": return CoinInfo( name, # coin_name - "DGB", # coin_shortcut + "BTC", # coin_shortcut 8, # decimals - 30, # address_type - 63, # address_type_p2sh - 130000000000, # maxfee_kb - "DigiByte Signed Message:\n", # signed_message_header + 0, # address_type + 5, # address_type_p2sh + 2000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header 0x0488b21e, # xpub_magic 0x049d7cb2, # xpub_magic_segwit_p2sh 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "dgb", # bech32_prefix + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "bc", # bech32_prefix None, # cashaddr_prefix - 20, # slip44 + 0, # slip44 True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Dogecoin": - return CoinInfo( - name, # coin_name - "DOGE", # coin_shortcut - 8, # decimals - 30, # address_type - 22, # address_type_p2sh - 1200000000000, # maxfee_kb - "Dogecoin Signed Message:\n", # signed_message_header - 0x02facafd, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 3, # slip44 - False, # segwit - False, # taproot + True, # taproot None, # fork_id False, # force_bip143 False, # decred @@ -646,54 +1432,25 @@ def by_name(name: str) -> CoinInfo: False, # overwintered None, # confidential_assets ) - if name == "Elements": + if name == "Regtest": return CoinInfo( name, # coin_name - "ELEMENTS", # coin_shortcut + "REGTEST", # coin_shortcut 8, # decimals - 235, # address_type - 75, # address_type_p2sh + 111, # address_type + 196, # address_type_p2sh 10000000, # maxfee_kb "Bitcoin Signed Message:\n", # signed_message_header 0x043587cf, # xpub_magic 0x044a5262, # xpub_magic_segwit_p2sh 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "ert", # bech32_prefix + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "bcrt", # bech32_prefix None, # cashaddr_prefix 1, # slip44 True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - {'address_prefix': 4, 'blech32_prefix': 'el'}, # confidential_assets - ) - if name == "Feathercoin": - return CoinInfo( - name, # coin_name - "FTC", # coin_shortcut - 8, # decimals - 14, # address_type - 5, # address_type_p2sh - 390000000000, # maxfee_kb - "Feathercoin Signed Message:\n", # signed_message_header - 0x0488bc26, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488bc26, # xpub_magic_multisig_segwit_p2sh - 0x0488bc26, # xpub_magic_multisig_segwit_native - "fc", # bech32_prefix - None, # cashaddr_prefix - 8, # slip44 - True, # segwit - False, # taproot + True, # taproot None, # fork_id False, # force_bip143 False, # decred @@ -704,961 +1461,1513 @@ def by_name(name: str) -> CoinInfo: False, # overwintered None, # confidential_assets ) - if name == "Firo": - return CoinInfo( - name, # coin_name - "FIRO", # coin_shortcut - 8, # decimals - 82, # address_type - 7, # address_type_p2sh - 640000000, # maxfee_kb - "Zcoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 136, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Firo Testnet": + if name == "Testnet": return CoinInfo( name, # coin_name - "tFIRO", # coin_shortcut + "TEST", # coin_shortcut 8, # decimals - 65, # address_type - 178, # address_type_p2sh - 1000000, # maxfee_kb - "Zcoin Signed Message:\n", # signed_message_header + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "tb", # bech32_prefix None, # cashaddr_prefix 1, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Florincoin": - return CoinInfo( - name, # coin_name - "FLO", # coin_shortcut - 8, # decimals - 35, # address_type - 94, # address_type_p2sh - 78000000000, # maxfee_kb - "Florincoin Signed Message:\n", # signed_message_header - 0x00174921, # xpub_magic - 0x01b26ef6, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x00174921, # xpub_magic_multisig_segwit_p2sh - 0x00174921, # xpub_magic_multisig_segwit_native - "flo", # bech32_prefix - None, # cashaddr_prefix - 216, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Fujicoin": - return CoinInfo( - name, # coin_name - "FJC", # coin_shortcut - 8, # decimals - 36, # address_type - 16, # address_type_p2sh - 35000000000000, # maxfee_kb - "FujiCoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0295b43f, # xpub_magic_multisig_segwit_p2sh - 0x02aa7ed3, # xpub_magic_multisig_segwit_native - "fc", # bech32_prefix - None, # cashaddr_prefix - 75, # slip44 - True, # segwit - True, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Groestlcoin": - return CoinInfo( - name, # coin_name - "GRS", # coin_shortcut - 8, # decimals - 36, # address_type - 5, # address_type_p2sh - 16000000000, # maxfee_kb - "GroestlCoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "grs", # bech32_prefix - None, # cashaddr_prefix - 17, # slip44 True, # segwit True, # taproot None, # fork_id False, # force_bip143 False, # decred False, # negative_fee - 'secp256k1-groestl', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Groestlcoin Testnet": - return CoinInfo( - name, # coin_name - "tGRS", # coin_shortcut - 8, # decimals - 111, # address_type - 196, # address_type_p2sh - 100000, # maxfee_kb - "GroestlCoin Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "tgrs", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - True, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1-groestl', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Komodo": - return CoinInfo( - name, # coin_name - "KMD", # coin_shortcut - 8, # decimals - 60, # address_type - 85, # address_type_p2sh - 4800000000, # maxfee_kb - "Komodo Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 141, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - True, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - True, # overwintered - None, # confidential_assets - ) - if name == "Koto": - return CoinInfo( - name, # coin_name - "KOTO", # coin_shortcut - 8, # decimals - 6198, # address_type - 6203, # address_type_p2sh - 1000000, # maxfee_kb - "Koto Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 510, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - True, # overwintered - None, # confidential_assets - ) - if name == "Litecoin": - return CoinInfo( - name, # coin_name - "LTC", # coin_shortcut - 8, # decimals - 48, # address_type - 50, # address_type_p2sh - 67000000, # maxfee_kb - "Litecoin Signed Message:\n", # signed_message_header - 0x019da462, # xpub_magic - 0x01b26ef6, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x019da462, # xpub_magic_multisig_segwit_p2sh - 0x019da462, # xpub_magic_multisig_segwit_native - "ltc", # bech32_prefix - None, # cashaddr_prefix - 2, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Litecoin Testnet": - return CoinInfo( - name, # coin_name - "tLTC", # coin_shortcut - 8, # decimals - 111, # address_type - 58, # address_type_p2sh - 40000000, # maxfee_kb - "Litecoin Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "tltc", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Monacoin": - return CoinInfo( - name, # coin_name - "MONA", # coin_shortcut - 8, # decimals - 50, # address_type - 55, # address_type_p2sh - 2100000000, # maxfee_kb - "Monacoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "mona", # bech32_prefix - None, # cashaddr_prefix - 22, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Namecoin": - return CoinInfo( - name, # coin_name - "NMC", # coin_shortcut - 8, # decimals - 52, # address_type - 5, # address_type_p2sh - 8700000000, # maxfee_kb - "Namecoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 7, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Peercoin": - return CoinInfo( - name, # coin_name - "PPC", # coin_shortcut - 6, # decimals - 55, # address_type - 117, # address_type_p2sh - 13000000000, # maxfee_kb - "Peercoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "pc", # bech32_prefix - None, # cashaddr_prefix - 6, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - True, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Peercoin Testnet": - return CoinInfo( - name, # coin_name - "tPPC", # coin_shortcut - 6, # decimals - 111, # address_type - 196, # address_type_p2sh - 2000000, # maxfee_kb - "Peercoin Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "tpc", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - True, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Primecoin": - return CoinInfo( - name, # coin_name - "XPM", # coin_shortcut - 8, # decimals - 23, # address_type - 83, # address_type_p2sh - 89000000000, # maxfee_kb - "Primecoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 24, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Qtum": - return CoinInfo( - name, # coin_name - "QTUM", # coin_shortcut - 8, # decimals - 58, # address_type - 50, # address_type_p2sh - 1000000000, # maxfee_kb - "Qtum Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "qc", # bech32_prefix - None, # cashaddr_prefix - 2301, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Qtum Testnet": - return CoinInfo( - name, # coin_name - "tQTUM", # coin_shortcut - 8, # decimals - 120, # address_type - 110, # address_type_p2sh - 40000000, # maxfee_kb - "Qtum Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - 0x044a5262, # xpub_magic_segwit_p2sh - 0x045f1cf6, # xpub_magic_segwit_native - 0x043587cf, # xpub_magic_multisig_segwit_p2sh - 0x043587cf, # xpub_magic_multisig_segwit_native - "tq", # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Ravencoin": - return CoinInfo( - name, # coin_name - "RVN", # coin_shortcut - 8, # decimals - 60, # address_type - 122, # address_type_p2sh - 170000000000, # maxfee_kb - "Raven Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 175, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Ravencoin Testnet": - return CoinInfo( - name, # coin_name - "tRVN", # coin_shortcut - 8, # decimals - 111, # address_type - 196, # address_type_p2sh - 170000000000, # maxfee_kb - "Raven Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Ritocoin": - return CoinInfo( - name, # coin_name - "RITO", # coin_shortcut - 8, # decimals - 25, # address_type - 105, # address_type_p2sh - 39000000000000, # maxfee_kb - "Rito Signed Message:\n", # signed_message_header - 0x0534e7ca, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 19169, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "SmartCash": - return CoinInfo( - name, # coin_name - "SMART", # coin_shortcut - 8, # decimals - 63, # address_type - 18, # address_type_p2sh - 780000000000, # maxfee_kb - "SmartCash Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 224, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1-smart', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "SmartCash Testnet": - return CoinInfo( - name, # coin_name - "tSMART", # coin_shortcut - 8, # decimals - 65, # address_type - 21, # address_type_p2sh - 1000000, # maxfee_kb - "SmartCash Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1-smart', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Stakenet": - return CoinInfo( - name, # coin_name - "XSN", # coin_shortcut - 8, # decimals - 76, # address_type - 16, # address_type_p2sh - 11000000000, # maxfee_kb - "DarkCoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "xc", # bech32_prefix - None, # cashaddr_prefix - 199, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Syscoin": - return CoinInfo( - name, # coin_name - "SYS", # coin_shortcut - 8, # decimals - 63, # address_type - 5, # address_type_p2sh - 42000000000, # maxfee_kb - "Syscoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "sys", # bech32_prefix - None, # cashaddr_prefix - 57, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Unobtanium": - return CoinInfo( - name, # coin_name - "UNO", # coin_shortcut - 8, # decimals - 130, # address_type - 30, # address_type_p2sh - 53000000, # maxfee_kb - "Unobtanium Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 92, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "VIPSTARCOIN": - return CoinInfo( - name, # coin_name - "VIPS", # coin_shortcut - 8, # decimals - 70, # address_type - 50, # address_type_p2sh - 140000000000000, # maxfee_kb - "VIPSTARCOIN Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "vips", # bech32_prefix - None, # cashaddr_prefix - 1919, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Verge": - return CoinInfo( - name, # coin_name - "XVG", # coin_shortcut - 6, # decimals - 30, # address_type - 33, # address_type_p2sh - 550000000000, # maxfee_kb - "Name: Dogecoin Dark\n", # signed_message_header - 0x022d2533, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 77, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - True, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Vertcoin": - return CoinInfo( - name, # coin_name - "VTC", # coin_shortcut - 8, # decimals - 71, # address_type - 5, # address_type_p2sh - 13000000000, # maxfee_kb - "Vertcoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "vtc", # bech32_prefix - None, # cashaddr_prefix - 28, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Viacoin": - return CoinInfo( - name, # coin_name - "VIA", # coin_shortcut - 8, # decimals - 71, # address_type - 33, # address_type_p2sh - 14000000000, # maxfee_kb - "Viacoin Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - 0x049d7cb2, # xpub_magic_segwit_p2sh - 0x04b24746, # xpub_magic_segwit_native - 0x0488b21e, # xpub_magic_multisig_segwit_p2sh - 0x0488b21e, # xpub_magic_multisig_segwit_native - "via", # bech32_prefix - None, # cashaddr_prefix - 14, # slip44 - True, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "ZCore": - return CoinInfo( - name, # coin_name - "ZCR", # coin_shortcut - 8, # decimals - 142, # address_type - 145, # address_type_p2sh - 170000000000, # maxfee_kb - "DarkNet Signed Message:\n", # signed_message_header - 0x04b24746, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 428, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - False, # extra_data - False, # timestamp - False, # overwintered - None, # confidential_assets - ) - if name == "Zcash": - return CoinInfo( - name, # coin_name - "ZEC", # coin_shortcut - 8, # decimals - 7352, # address_type - 7357, # address_type_p2sh - 51000000, # maxfee_kb - "Zcash Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 133, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - True, # overwintered - None, # confidential_assets - ) - if name == "Zcash Testnet": - return CoinInfo( - name, # coin_name - "TAZ", # coin_shortcut - 8, # decimals - 7461, # address_type - 7354, # address_type_p2sh - 10000000, # maxfee_kb - "Zcash Signed Message:\n", # signed_message_header - 0x043587cf, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 1, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee - 'secp256k1', # curve_name - True, # extra_data - False, # timestamp - True, # overwintered - None, # confidential_assets - ) - if name == "Brhodium": - return CoinInfo( - name, # coin_name - "XRC", # coin_shortcut - 8, # decimals - 61, # address_type - 123, # address_type_p2sh - 1000000000, # maxfee_kb - "BitCoin Rhodium Signed Message:\n", # signed_message_header - 0x0488b21e, # xpub_magic - None, # xpub_magic_segwit_p2sh - None, # xpub_magic_segwit_native - None, # xpub_magic_multisig_segwit_p2sh - None, # xpub_magic_multisig_segwit_native - None, # bech32_prefix - None, # cashaddr_prefix - 10291, # slip44 - False, # segwit - False, # taproot - None, # fork_id - False, # force_bip143 - False, # decred - False, # negative_fee 'secp256k1', # curve_name False, # extra_data False, # timestamp False, # overwintered None, # confidential_assets ) - raise ValueError # Unknown coin name + if not utils.BITCOIN_ONLY: + if name == "Actinium": + return CoinInfo( + name, # coin_name + "ACM", # coin_shortcut + 8, # decimals + 53, # address_type + 55, # address_type_p2sh + 320000000000, # maxfee_kb + "Actinium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "acm", # bech32_prefix + None, # cashaddr_prefix + 228, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Axe": + return CoinInfo( + name, # coin_name + "AXE", # coin_shortcut + 8, # decimals + 55, # address_type + 16, # address_type_p2sh + 21000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x02fe52cc, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 4242, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash": + return CoinInfo( + name, # coin_name + "BCH", # coin_shortcut + 8, # decimals + 0, # address_type + 5, # address_type_p2sh + 14000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bitcoincash", # cashaddr_prefix + 145, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash Testnet": + return CoinInfo( + name, # coin_name + "TBCH", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bchtest", # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bgold": + return CoinInfo( + name, # coin_name + "BTG", # coin_shortcut + 8, # decimals + 38, # address_type + 23, # address_type_p2sh + 380000000, # maxfee_kb + "Bitcoin Gold Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "btg", # bech32_prefix + None, # cashaddr_prefix + 156, # slip44 + True, # segwit + False, # taproot + 79, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bgold Testnet": + return CoinInfo( + name, # coin_name + "TBTG", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 500000, # maxfee_kb + "Bitcoin Gold Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tbtg", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + 79, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bprivate": + return CoinInfo( + name, # coin_name + "BTCP", # coin_shortcut + 8, # decimals + 4901, # address_type + 5039, # address_type_p2sh + 32000000000, # maxfee_kb + "BitcoinPrivate Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 183, # slip44 + False, # segwit + False, # taproot + 42, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bitcore": + return CoinInfo( + name, # coin_name + "BTX", # coin_shortcut + 8, # decimals + 3, # address_type + 125, # address_type_p2sh + 14000000000, # maxfee_kb + "BitCore Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "btx", # bech32_prefix + None, # cashaddr_prefix + 160, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "CPUchain": + return CoinInfo( + name, # coin_name + "CPU", # coin_shortcut + 8, # decimals + 28, # address_type + 30, # address_type_p2sh + 8700000000000, # maxfee_kb + "CPUchain Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "cpu", # bech32_prefix + None, # cashaddr_prefix + 363, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Crown": + return CoinInfo( + name, # coin_name + "CRW", # coin_shortcut + 8, # decimals + 95495, # address_type + 95473, # address_type_p2sh + 52000000000, # maxfee_kb + "Crown Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 72, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Dash": + return CoinInfo( + name, # coin_name + "DASH", # coin_shortcut + 8, # decimals + 76, # address_type + 16, # address_type_p2sh + 45000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x02fe52cc, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 5, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Dash Testnet": + return CoinInfo( + name, # coin_name + "tDASH", # coin_shortcut + 8, # decimals + 140, # address_type + 19, # address_type_p2sh + 100000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Decred": + return CoinInfo( + name, # coin_name + "DCR", # coin_shortcut + 8, # decimals + 1855, # address_type + 1818, # address_type_p2sh + 220000000, # maxfee_kb + "Decred Signed Message:\n", # signed_message_header + 0x02fda926, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 42, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + True, # decred + False, # negative_fee + 'secp256k1-decred', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Decred Testnet": + return CoinInfo( + name, # coin_name + "TDCR", # coin_shortcut + 8, # decimals + 3873, # address_type + 3836, # address_type_p2sh + 10000000, # maxfee_kb + "Decred Signed Message:\n", # signed_message_header + 0x043587d1, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + True, # decred + False, # negative_fee + 'secp256k1-decred', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "DigiByte": + return CoinInfo( + name, # coin_name + "DGB", # coin_shortcut + 8, # decimals + 30, # address_type + 63, # address_type_p2sh + 130000000000, # maxfee_kb + "DigiByte Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "dgb", # bech32_prefix + None, # cashaddr_prefix + 20, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Dogecoin": + return CoinInfo( + name, # coin_name + "DOGE", # coin_shortcut + 8, # decimals + 30, # address_type + 22, # address_type_p2sh + 1200000000000, # maxfee_kb + "Dogecoin Signed Message:\n", # signed_message_header + 0x02facafd, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 3, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Elements": + return CoinInfo( + name, # coin_name + "ELEMENTS", # coin_shortcut + 8, # decimals + 235, # address_type + 75, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "ert", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + {'address_prefix': 4, 'blech32_prefix': 'el'}, # confidential_assets + ) + if name == "Feathercoin": + return CoinInfo( + name, # coin_name + "FTC", # coin_shortcut + 8, # decimals + 14, # address_type + 5, # address_type_p2sh + 390000000000, # maxfee_kb + "Feathercoin Signed Message:\n", # signed_message_header + 0x0488bc26, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488bc26, # xpub_magic_multisig_segwit_p2sh + 0x0488bc26, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 8, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo": + return CoinInfo( + name, # coin_name + "FIRO", # coin_shortcut + 8, # decimals + 82, # address_type + 7, # address_type_p2sh + 640000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 136, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo Testnet": + return CoinInfo( + name, # coin_name + "tFIRO", # coin_shortcut + 8, # decimals + 65, # address_type + 178, # address_type_p2sh + 1000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Florincoin": + return CoinInfo( + name, # coin_name + "FLO", # coin_shortcut + 8, # decimals + 35, # address_type + 94, # address_type_p2sh + 78000000000, # maxfee_kb + "Florincoin Signed Message:\n", # signed_message_header + 0x00174921, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x00174921, # xpub_magic_multisig_segwit_p2sh + 0x00174921, # xpub_magic_multisig_segwit_native + "flo", # bech32_prefix + None, # cashaddr_prefix + 216, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Fujicoin": + return CoinInfo( + name, # coin_name + "FJC", # coin_shortcut + 8, # decimals + 36, # address_type + 16, # address_type_p2sh + 35000000000000, # maxfee_kb + "FujiCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 75, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin": + return CoinInfo( + name, # coin_name + "GRS", # coin_shortcut + 8, # decimals + 36, # address_type + 5, # address_type_p2sh + 16000000000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "grs", # bech32_prefix + None, # cashaddr_prefix + 17, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin Testnet": + return CoinInfo( + name, # coin_name + "tGRS", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 100000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tgrs", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Komodo": + return CoinInfo( + name, # coin_name + "KMD", # coin_shortcut + 8, # decimals + 60, # address_type + 85, # address_type_p2sh + 4800000000, # maxfee_kb + "Komodo Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 141, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + True, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Koto": + return CoinInfo( + name, # coin_name + "KOTO", # coin_shortcut + 8, # decimals + 6198, # address_type + 6203, # address_type_p2sh + 1000000, # maxfee_kb + "Koto Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 510, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Litecoin": + return CoinInfo( + name, # coin_name + "LTC", # coin_shortcut + 8, # decimals + 48, # address_type + 50, # address_type_p2sh + 67000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x019da462, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x019da462, # xpub_magic_multisig_segwit_p2sh + 0x019da462, # xpub_magic_multisig_segwit_native + "ltc", # bech32_prefix + None, # cashaddr_prefix + 2, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Litecoin Testnet": + return CoinInfo( + name, # coin_name + "tLTC", # coin_shortcut + 8, # decimals + 111, # address_type + 58, # address_type_p2sh + 40000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tltc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Monacoin": + return CoinInfo( + name, # coin_name + "MONA", # coin_shortcut + 8, # decimals + 50, # address_type + 55, # address_type_p2sh + 2100000000, # maxfee_kb + "Monacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "mona", # bech32_prefix + None, # cashaddr_prefix + 22, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Namecoin": + return CoinInfo( + name, # coin_name + "NMC", # coin_shortcut + 8, # decimals + 52, # address_type + 5, # address_type_p2sh + 8700000000, # maxfee_kb + "Namecoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 7, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin": + return CoinInfo( + name, # coin_name + "PPC", # coin_shortcut + 6, # decimals + 55, # address_type + 117, # address_type_p2sh + 13000000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "pc", # bech32_prefix + None, # cashaddr_prefix + 6, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin Testnet": + return CoinInfo( + name, # coin_name + "tPPC", # coin_shortcut + 6, # decimals + 111, # address_type + 196, # address_type_p2sh + 2000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tpc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Primecoin": + return CoinInfo( + name, # coin_name + "XPM", # coin_shortcut + 8, # decimals + 23, # address_type + 83, # address_type_p2sh + 89000000000, # maxfee_kb + "Primecoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 24, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum": + return CoinInfo( + name, # coin_name + "QTUM", # coin_shortcut + 8, # decimals + 58, # address_type + 50, # address_type_p2sh + 1000000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "qc", # bech32_prefix + None, # cashaddr_prefix + 2301, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum Testnet": + return CoinInfo( + name, # coin_name + "tQTUM", # coin_shortcut + 8, # decimals + 120, # address_type + 110, # address_type_p2sh + 40000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tq", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin": + return CoinInfo( + name, # coin_name + "RVN", # coin_shortcut + 8, # decimals + 60, # address_type + 122, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 175, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin Testnet": + return CoinInfo( + name, # coin_name + "tRVN", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ritocoin": + return CoinInfo( + name, # coin_name + "RITO", # coin_shortcut + 8, # decimals + 25, # address_type + 105, # address_type_p2sh + 39000000000000, # maxfee_kb + "Rito Signed Message:\n", # signed_message_header + 0x0534e7ca, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 19169, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash": + return CoinInfo( + name, # coin_name + "SMART", # coin_shortcut + 8, # decimals + 63, # address_type + 18, # address_type_p2sh + 780000000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 224, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash Testnet": + return CoinInfo( + name, # coin_name + "tSMART", # coin_shortcut + 8, # decimals + 65, # address_type + 21, # address_type_p2sh + 1000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Stakenet": + return CoinInfo( + name, # coin_name + "XSN", # coin_shortcut + 8, # decimals + 76, # address_type + 16, # address_type_p2sh + 11000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "xc", # bech32_prefix + None, # cashaddr_prefix + 199, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Syscoin": + return CoinInfo( + name, # coin_name + "SYS", # coin_shortcut + 8, # decimals + 63, # address_type + 5, # address_type_p2sh + 42000000000, # maxfee_kb + "Syscoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "sys", # bech32_prefix + None, # cashaddr_prefix + 57, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Unobtanium": + return CoinInfo( + name, # coin_name + "UNO", # coin_shortcut + 8, # decimals + 130, # address_type + 30, # address_type_p2sh + 53000000, # maxfee_kb + "Unobtanium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 92, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "VIPSTARCOIN": + return CoinInfo( + name, # coin_name + "VIPS", # coin_shortcut + 8, # decimals + 70, # address_type + 50, # address_type_p2sh + 140000000000000, # maxfee_kb + "VIPSTARCOIN Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "vips", # bech32_prefix + None, # cashaddr_prefix + 1919, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Verge": + return CoinInfo( + name, # coin_name + "XVG", # coin_shortcut + 6, # decimals + 30, # address_type + 33, # address_type_p2sh + 550000000000, # maxfee_kb + "Name: Dogecoin Dark\n", # signed_message_header + 0x022d2533, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 77, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Vertcoin": + return CoinInfo( + name, # coin_name + "VTC", # coin_shortcut + 8, # decimals + 71, # address_type + 5, # address_type_p2sh + 13000000000, # maxfee_kb + "Vertcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "vtc", # bech32_prefix + None, # cashaddr_prefix + 28, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Viacoin": + return CoinInfo( + name, # coin_name + "VIA", # coin_shortcut + 8, # decimals + 71, # address_type + 33, # address_type_p2sh + 14000000000, # maxfee_kb + "Viacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "via", # bech32_prefix + None, # cashaddr_prefix + 14, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "ZCore": + return CoinInfo( + name, # coin_name + "ZCR", # coin_shortcut + 8, # decimals + 142, # address_type + 145, # address_type_p2sh + 170000000000, # maxfee_kb + "DarkNet Signed Message:\n", # signed_message_header + 0x04b24746, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 428, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Zcash": + return CoinInfo( + name, # coin_name + "ZEC", # coin_shortcut + 8, # decimals + 7352, # address_type + 7357, # address_type_p2sh + 51000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 133, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Zcash Testnet": + return CoinInfo( + name, # coin_name + "TAZ", # coin_shortcut + 8, # decimals + 7461, # address_type + 7354, # address_type_p2sh + 10000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Brhodium": + return CoinInfo( + name, # coin_name + "XRC", # coin_shortcut + 8, # decimals + 61, # address_type + 123, # address_type_p2sh + 1000000000, # maxfee_kb + "BitCoin Rhodium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 10291, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + raise ValueError # Unknown coin name diff --git a/core/src/apps/common/coininfo.py.mako b/core/src/apps/common/coininfo.py.mako index fba7ef0ac..38e3716bb 100644 --- a/core/src/apps/common/coininfo.py.mako +++ b/core/src/apps/common/coininfo.py.mako @@ -136,21 +136,37 @@ ATTRIBUTES = ( btc_names = ["Bitcoin", "Testnet", "Regtest"] -coins_btc = [c for c in supported_on("trezor2", bitcoin) if c.name in btc_names] -coins_alt = [c for c in supported_on("trezor2", bitcoin) if c.name not in btc_names] +# TODO: make this easily extendable for more models + +coins_btc_t2t1 = [c for c in supported_on("T2T1", bitcoin) if c.name in btc_names] +coins_alt_t2t1 = [c for c in supported_on("T2T1", bitcoin) if c.name not in btc_names] + +coins_btc_t2b1 = [c for c in supported_on("T2B1", bitcoin) if c.name in btc_names] +coins_alt_t2b1 = [c for c in supported_on("T2B1", bitcoin) if c.name not in btc_names] %>\ def by_name(name: str) -> CoinInfo: -% for coin in coins_btc: - if name == ${black_repr(coin["coin_name"])}: - return CoinInfo( - % for attr, func in ATTRIBUTES: - ${func(coin[attr])}, # ${attr} - % endfor - ) + if utils.MODEL_IS_T2B1: +% for coin in coins_btc_t2b1: + if name == ${black_repr(coin["coin_name"])}: + return CoinInfo( + % for attr, func in ATTRIBUTES: + ${func(coin[attr])}, # ${attr} + % endfor + ) +% endfor + if not utils.BITCOIN_ONLY: +% for coin in coins_alt_t2b1: + if name == ${black_repr(coin["coin_name"])}: + return CoinInfo( + % for attr, func in ATTRIBUTES: + ${func(coin[attr])}, # ${attr} + % endfor + ) % endfor - if not utils.BITCOIN_ONLY: -% for coin in coins_alt: + raise ValueError # Unknown coin name + else: +% for coin in coins_btc_t2t1: if name == ${black_repr(coin["coin_name"])}: return CoinInfo( % for attr, func in ATTRIBUTES: @@ -158,4 +174,13 @@ def by_name(name: str) -> CoinInfo: % endfor ) % endfor - raise ValueError # Unknown coin name + if not utils.BITCOIN_ONLY: +% for coin in coins_alt_t2t1: + if name == ${black_repr(coin["coin_name"])}: + return CoinInfo( + % for attr, func in ATTRIBUTES: + ${func(coin[attr])}, # ${attr} + % endfor + ) +% endfor + raise ValueError # Unknown coin name diff --git a/core/src/apps/common/request_pin.py b/core/src/apps/common/request_pin.py index be2b3b4ab..fb9ab1519 100644 --- a/core/src/apps/common/request_pin.py +++ b/core/src/apps/common/request_pin.py @@ -3,6 +3,7 @@ from typing import Any, NoReturn import storage.cache as storage_cache from trezor import config, utils, wire +from trezor.ui.layouts import show_error_and_raise async def _request_sd_salt( @@ -125,8 +126,6 @@ async def verify_user_pin( async def error_pin_invalid() -> NoReturn: - from trezor.ui.layouts import show_error_and_raise - await show_error_and_raise( "warning_wrong_pin", "The PIN you have entered is not valid.", @@ -137,8 +136,6 @@ async def error_pin_invalid() -> NoReturn: async def error_pin_matches_wipe_code() -> NoReturn: - from trezor.ui.layouts import show_error_and_raise - await show_error_and_raise( "warning_invalid_new_pin", "The new PIN must be different from your wipe code.", diff --git a/core/src/apps/eos/get_public_key.py b/core/src/apps/eos/get_public_key.py index e6eb93aa9..55a9bbbd4 100644 --- a/core/src/apps/eos/get_public_key.py +++ b/core/src/apps/eos/get_public_key.py @@ -26,5 +26,6 @@ async def get_public_key(msg: EosGetPublicKey, keychain: Keychain) -> EosPublicK wif = public_key_to_wif(public_key) if msg.show_display: - await require_get_public_key(wif) + path = paths.address_n_to_str(msg.address_n) + await require_get_public_key(wif, path) return EosPublicKey(wif_public_key=wif, raw_public_key=public_key) diff --git a/core/src/apps/eos/layout.py b/core/src/apps/eos/layout.py index 9433bb3be..5c99f5e05 100644 --- a/core/src/apps/eos/layout.py +++ b/core/src/apps/eos/layout.py @@ -1,7 +1,7 @@ -async def require_get_public_key(public_key: str) -> None: +async def require_get_public_key(public_key: str, path: str) -> None: from trezor.ui.layouts import show_pubkey - await show_pubkey(public_key) + await show_pubkey(public_key, path=path) async def require_sign_tx(num_actions: int) -> None: diff --git a/core/src/apps/ethereum/get_address.py b/core/src/apps/ethereum/get_address.py index 6a8c12e2c..33de65fa3 100644 --- a/core/src/apps/ethereum/get_address.py +++ b/core/src/apps/ethereum/get_address.py @@ -32,6 +32,8 @@ async def get_address( address = address_from_bytes(node.ethereum_pubkeyhash(), defs.network) if msg.show_display: - await show_address(address, path=paths.address_n_to_str(address_n)) + await show_address( + address, path=paths.address_n_to_str(address_n), chunkify=bool(msg.chunkify) + ) return EthereumAddress(address=address) diff --git a/core/src/apps/ethereum/layout.py b/core/src/apps/ethereum/layout.py index cf470eac0..2d3632bd3 100644 --- a/core/src/apps/ethereum/layout.py +++ b/core/src/apps/ethereum/layout.py @@ -4,14 +4,13 @@ from trezor import ui from trezor.enums import ButtonRequestType from trezor.strings import format_plural from trezor.ui.layouts import ( - confirm_amount, confirm_blob, + confirm_ethereum_tx, confirm_text, - confirm_total, should_show_more, ) -from .helpers import decode_typed_data +from .helpers import address_from_bytes, decode_typed_data if TYPE_CHECKING: from typing import Awaitable, Iterable @@ -24,72 +23,61 @@ if TYPE_CHECKING: ) -def require_confirm_tx( +async def require_confirm_tx( to_bytes: bytes, value: int, + gas_price: int, + gas_limit: int, network: EthereumNetworkInfo, token: EthereumTokenInfo | None, -) -> Awaitable[None]: - from trezor.ui.layouts import confirm_output - - from .helpers import address_from_bytes - +) -> None: if to_bytes: to_str = address_from_bytes(to_bytes, network) else: to_str = "new contract?" - return confirm_output( - to_str, - format_ethereum_amount(value, token, network), - br_code=ButtonRequestType.SignTx, - ) + total_amount = format_ethereum_amount(value, token, network) + maximum_fee = format_ethereum_amount(gas_price * gas_limit, None, network) + gas_limit_str = f"{gas_limit} units" + gas_price_str = format_ethereum_amount(gas_price, None, network) -async def require_confirm_fee( - spending: int, - gas_price: int, - gas_limit: int, - network: EthereumNetworkInfo, - token: EthereumTokenInfo | None, -) -> None: - await confirm_amount( - title="Confirm fee", - description="Gas price:", - amount=format_ethereum_amount(gas_price, None, network), - ) - await confirm_total( - total_amount=format_ethereum_amount(spending, token, network), - fee_amount=format_ethereum_amount(gas_price * gas_limit, None, network), - total_label="Amount sent:", - fee_label="Maximum fee:", + items = ( + ("Gas limit:", gas_limit_str), + ("Gas price:", gas_price_str), ) + await confirm_ethereum_tx(to_str, total_amount, maximum_fee, items) -async def require_confirm_eip1559_fee( - spending: int, - max_priority_fee: int, + +async def require_confirm_tx_eip1559( + to_bytes: bytes, + value: int, max_gas_fee: int, + max_priority_fee: int, gas_limit: int, network: EthereumNetworkInfo, token: EthereumTokenInfo | None, ) -> None: - await confirm_amount( - "Confirm fee", - format_ethereum_amount(max_gas_fee, None, network), - "Maximum fee per gas", - ) - await confirm_amount( - "Confirm fee", - format_ethereum_amount(max_priority_fee, None, network), - "Priority fee per gas", - ) - await confirm_total( - format_ethereum_amount(spending, token, network), - format_ethereum_amount(max_gas_fee * gas_limit, None, network), - total_label="Amount sent:", - fee_label="Maximum fee:", + + if to_bytes: + to_str = address_from_bytes(to_bytes, network) + else: + to_str = "new contract?" + + total_amount = format_ethereum_amount(value, token, network) + maximum_fee = format_ethereum_amount(max_gas_fee * gas_limit, None, network) + gas_limit_str = f"{gas_limit} units" + max_gas_fee_str = format_ethereum_amount(max_gas_fee, None, network) + max_priority_fee_str = format_ethereum_amount(max_priority_fee, None, network) + + items = ( + ("Gas limit:", gas_limit_str), + ("Max gas price:", max_gas_fee_str), + ("Priority fee:", max_priority_fee_str), ) + await confirm_ethereum_tx(to_str, total_amount, maximum_fee, items) + def require_confirm_unknown_token(address_bytes: bytes) -> Awaitable[None]: from ubinascii import hexlify diff --git a/core/src/apps/ethereum/networks.py b/core/src/apps/ethereum/networks.py index b68f0f848..12a742026 100644 --- a/core/src/apps/ethereum/networks.py +++ b/core/src/apps/ethereum/networks.py @@ -7,6 +7,7 @@ from typing import TYPE_CHECKING +from trezor import utils from trezor.messages import EthereumNetworkInfo if TYPE_CHECKING: @@ -58,45 +59,89 @@ def by_slip44(slip44: int) -> EthereumNetworkInfo: # fmt: off def _networks_iterator() -> Iterator[NetworkInfoTuple]: - yield ( - 1, # chain_id - 60, # slip44 - "ETH", # symbol - "Ethereum", # name - ) - yield ( - 3, # chain_id - 1, # slip44 - "tETH", # symbol - "Ropsten", # name - ) - yield ( - 4, # chain_id - 1, # slip44 - "tETH", # symbol - "Rinkeby", # name - ) - yield ( - 5, # chain_id - 1, # slip44 - "tETH", # symbol - "Görli", # name - ) - yield ( - 56, # chain_id - 714, # slip44 - "BNB", # symbol - "Binance Smart Chain", # name - ) - yield ( - 61, # chain_id - 61, # slip44 - "ETC", # symbol - "Ethereum Classic", # name - ) - yield ( - 137, # chain_id - 966, # slip44 - "MATIC", # symbol - "Polygon", # name - ) + if utils.MODEL_IS_T2B1: + yield ( + 1, # chain_id + 60, # slip44 + "ETH", # symbol + "Ethereum", # name + ) + yield ( + 3, # chain_id + 1, # slip44 + "tETH", # symbol + "Ropsten", # name + ) + yield ( + 4, # chain_id + 1, # slip44 + "tETH", # symbol + "Rinkeby", # name + ) + yield ( + 5, # chain_id + 1, # slip44 + "tETH", # symbol + "Görli", # name + ) + yield ( + 56, # chain_id + 714, # slip44 + "BNB", # symbol + "Binance Smart Chain", # name + ) + yield ( + 61, # chain_id + 61, # slip44 + "ETC", # symbol + "Ethereum Classic", # name + ) + yield ( + 137, # chain_id + 966, # slip44 + "MATIC", # symbol + "Polygon", # name + ) + else: + yield ( + 1, # chain_id + 60, # slip44 + "ETH", # symbol + "Ethereum", # name + ) + yield ( + 3, # chain_id + 1, # slip44 + "tETH", # symbol + "Ropsten", # name + ) + yield ( + 4, # chain_id + 1, # slip44 + "tETH", # symbol + "Rinkeby", # name + ) + yield ( + 5, # chain_id + 1, # slip44 + "tETH", # symbol + "Görli", # name + ) + yield ( + 56, # chain_id + 714, # slip44 + "BNB", # symbol + "Binance Smart Chain", # name + ) + yield ( + 61, # chain_id + 61, # slip44 + "ETC", # symbol + "Ethereum Classic", # name + ) + yield ( + 137, # chain_id + 966, # slip44 + "MATIC", # symbol + "Polygon", # name + ) diff --git a/core/src/apps/ethereum/networks.py.mako b/core/src/apps/ethereum/networks.py.mako index 81a53fa16..e310600cf 100644 --- a/core/src/apps/ethereum/networks.py.mako +++ b/core/src/apps/ethereum/networks.py.mako @@ -7,6 +7,7 @@ from typing import TYPE_CHECKING +from trezor import utils from trezor.messages import EthereumNetworkInfo if TYPE_CHECKING: @@ -58,11 +59,21 @@ def by_slip44(slip44: int) -> EthereumNetworkInfo: # fmt: off def _networks_iterator() -> Iterator[NetworkInfoTuple]: -% for n in sorted(supported_on("trezor2", eth), key=lambda network: (int(network.chain_id), network.name)): - yield ( - ${n.chain_id}, # chain_id - ${n.slip44}, # slip44 - "${n.shortcut}", # symbol - "${n.name}", # name - ) + if utils.MODEL_IS_T2B1: +% for n in sorted(supported_on("T2B1", eth), key=lambda network: (int(network.chain_id), network.name)): + yield ( + ${n.chain_id}, # chain_id + ${n.slip44}, # slip44 + "${n.shortcut}", # symbol + "${n.name}", # name + ) +% endfor + else: +% for n in sorted(supported_on("T2T1", eth), key=lambda network: (int(network.chain_id), network.name)): + yield ( + ${n.chain_id}, # chain_id + ${n.slip44}, # slip44 + "${n.shortcut}", # symbol + "${n.name}", # name + ) % endfor diff --git a/core/src/apps/ethereum/sign_tx.py b/core/src/apps/ethereum/sign_tx.py index bd10054b3..7dec659ab 100644 --- a/core/src/apps/ethereum/sign_tx.py +++ b/core/src/apps/ethereum/sign_tx.py @@ -33,7 +33,7 @@ async def sign_tx( from apps.common import paths - from .layout import require_confirm_data, require_confirm_fee, require_confirm_tx + from .layout import require_confirm_data, require_confirm_tx # check if msg.tx_type not in [1, 6, None]: @@ -47,13 +47,13 @@ async def sign_tx( # Handle ERC20s token, address_bytes, recipient, value = await handle_erc20(msg, defs) - data_total = msg.data_length + data_total = msg.data_length # local_cache_attribute - await require_confirm_tx(recipient, value, defs.network, token) - if token is None and msg.data_length > 0: + if token is None and data_total > 0: await require_confirm_data(msg.data_initial_chunk, data_total) - await require_confirm_fee( + await require_confirm_tx( + recipient, value, int.from_bytes(msg.gas_price, "big"), int.from_bytes(msg.gas_limit, "big"), diff --git a/core/src/apps/ethereum/sign_tx_eip1559.py b/core/src/apps/ethereum/sign_tx_eip1559.py index 466b63e93..13bbff111 100644 --- a/core/src/apps/ethereum/sign_tx_eip1559.py +++ b/core/src/apps/ethereum/sign_tx_eip1559.py @@ -42,14 +42,11 @@ async def sign_tx_eip1559( from apps.common import paths - from .layout import ( - require_confirm_data, - require_confirm_eip1559_fee, - require_confirm_tx, - ) + from .layout import require_confirm_data, require_confirm_tx_eip1559 from .sign_tx import check_common_fields, handle_erc20, send_request_chunk gas_limit = msg.gas_limit # local_cache_attribute + data_total = msg.data_length # local_cache_attribute # check if len(msg.max_gas_fee) + len(gas_limit) > 30: @@ -63,16 +60,14 @@ async def sign_tx_eip1559( # Handle ERC20s token, address_bytes, recipient, value = await handle_erc20(msg, defs) - data_total = msg.data_length - - await require_confirm_tx(recipient, value, defs.network, token) - if token is None and msg.data_length > 0: + if token is None and data_total > 0: await require_confirm_data(msg.data_initial_chunk, data_total) - await require_confirm_eip1559_fee( + await require_confirm_tx_eip1559( + recipient, value, - int.from_bytes(msg.max_priority_fee, "big"), int.from_bytes(msg.max_gas_fee, "big"), + int.from_bytes(msg.max_priority_fee, "big"), int.from_bytes(gas_limit, "big"), defs.network, token, diff --git a/core/src/apps/ethereum/tokens.py b/core/src/apps/ethereum/tokens.py index e010f6f9f..eeb61cf86 100644 --- a/core/src/apps/ethereum/tokens.py +++ b/core/src/apps/ethereum/tokens.py @@ -16,6 +16,7 @@ from typing import Iterator +from trezor import utils from trezor.messages import EthereumTokenInfo UNKNOWN_TOKEN = EthereumTokenInfo( @@ -41,150 +42,299 @@ def token_by_chain_address(chain_id: int, address: bytes) -> EthereumTokenInfo | def _token_iterator(chain_id: int) -> Iterator[tuple[bytes, str, int, str]]: - if chain_id == 1: # eth - yield ( # address, symbol, decimals, name - b"\x7f\xc6\x65\x00\xc8\x4a\x76\xad\x7e\x9c\x93\x43\x7b\xfc\x5a\xc3\x3e\x2d\xda\xe9", - "AAVE", - 18, - "Aave", - ) - yield ( # address, symbol, decimals, name - b"\x4d\x22\x44\x52\x80\x1a\xce\xd8\xb2\xf0\xae\xbe\x15\x53\x79\xbb\x5d\x59\x43\x81", - "APE", - 18, - "ApeCoin", - ) - yield ( # address, symbol, decimals, name - b"\xbb\x0e\x17\xef\x65\xf8\x2a\xb0\x18\xd8\xed\xd7\x76\xe8\xdd\x94\x03\x27\xb2\x8b", - "AXS", - 18, - "Axie Infinity", - ) - yield ( # address, symbol, decimals, name - b"\x4f\xab\xb1\x45\xd6\x46\x52\xa9\x48\xd7\x25\x33\x02\x3f\x6e\x7a\x62\x3c\x7c\x53", - "BUSD", - 18, - "Binance USD", - ) - yield ( # address, symbol, decimals, name - b"\x35\x06\x42\x4f\x91\xfd\x33\x08\x44\x66\xf4\x02\xd5\xd9\x7f\x05\xf8\xe3\xb4\xaf", - "CHZ", - 18, - "Chiliz", - ) - yield ( # address, symbol, decimals, name - b"\xa0\xb7\x3e\x1f\xf0\xb8\x09\x14\xab\x6f\xe0\x44\x4e\x65\x84\x8c\x4c\x34\x45\x0b", - "CRO", - 8, - "Cronos", - ) - yield ( # address, symbol, decimals, name - b"\x6b\x17\x54\x74\xe8\x90\x94\xc4\x4d\xa9\x8b\x95\x4e\xed\xea\xc4\x95\x27\x1d\x0f", - "DAI", - 18, - "Dai", - ) - yield ( # address, symbol, decimals, name - b"\x85\x3d\x95\x5a\xce\xf8\x22\xdb\x05\x8e\xb8\x50\x59\x11\xed\x77\xf1\x75\xb9\x9e", - "FRAX", - 18, - "Frax", - ) - yield ( # address, symbol, decimals, name - b"\x2a\xf5\xd2\xad\x76\x74\x11\x91\xd1\x5d\xfe\x7b\xf6\xac\x92\xd4\xbd\x91\x2c\xa3", - "LEO", - 18, - "LEO Token", - ) - yield ( # address, symbol, decimals, name - b"\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", - "LINK", - 18, - "Chainlink", - ) - yield ( # address, symbol, decimals, name - b"\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", - "MANA", - 18, - "Decentraland", - ) - yield ( # address, symbol, decimals, name - b"\x7d\x1a\xfa\x7b\x71\x8f\xb8\x93\xdb\x30\xa3\xab\xc0\xcf\xc6\x08\xaa\xcf\xeb\xb0", - "MATIC", - 18, - "Polygon", - ) - yield ( # address, symbol, decimals, name - b"\x75\x23\x1f\x58\xb4\x32\x40\xc9\x71\x8d\xd5\x8b\x49\x67\xc5\x11\x43\x42\xa8\x6c", - "OKB", - 18, - "OKB", - ) - yield ( # address, symbol, decimals, name - b"\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", - "QNT", - 18, - "Quant", - ) - yield ( # address, symbol, decimals, name - b"\x38\x45\xba\xda\xde\x8e\x6d\xff\x04\x98\x20\x68\x0d\x1f\x14\xbd\x39\x03\xa5\xd0", - "SAND", - 18, - "The Sandbox", - ) - yield ( # address, symbol, decimals, name - b"\x95\xad\x61\xb0\xa1\x50\xd7\x92\x19\xdc\xf6\x4e\x1e\x6c\xc0\x1f\x0b\x64\xc4\xce", - "SHIB", - 18, - "Shiba Inu", - ) - yield ( # address, symbol, decimals, name - b"\xae\x7a\xb9\x65\x20\xde\x3a\x18\xe5\xe1\x11\xb5\xea\xab\x09\x53\x12\xd7\xfe\x84", - "STETH", - 18, - "Lido Staked Ether", - ) - yield ( # address, symbol, decimals, name - b"\x1f\x98\x40\xa8\x5d\x5a\xf5\xbf\x1d\x17\x62\xf9\x25\xbd\xad\xdc\x42\x01\xf9\x84", - "UNI", - 18, - "Uniswap", - ) - yield ( # address, symbol, decimals, name - b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48", - "USDC", - 6, - "USD Coin", - ) - yield ( # address, symbol, decimals, name - b"\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", - "USDT", - 6, - "Tether", - ) - yield ( # address, symbol, decimals, name - b"\x22\x60\xfa\xc5\xe5\x54\x2a\x77\x3a\xa4\x4f\xbc\xfe\xdf\x7c\x19\x3b\xc2\xc5\x99", - "WBTC", - 8, - "Wrapped Bitcoin", - ) - yield ( # address, symbol, decimals, name - b"\xa2\xcd\x3d\x43\xc7\x75\x97\x8a\x96\xbd\xbf\x12\xd7\x33\xd5\xa1\xed\x94\xfb\x18", - "XCN", - 18, - "Chain", - ) - if chain_id == 56: # bnb - yield ( # address, symbol, decimals, name - b"\x0e\xb3\xa7\x05\xfc\x54\x72\x50\x37\xcc\x9e\x00\x8b\xde\xde\x69\x7f\x62\xf3\x35", - "ATOM", - 18, - "Cosmos Hub", - ) - if chain_id == 137: # matic - yield ( # address, symbol, decimals, name - b"\x2c\x89\xbb\xc9\x2b\xd8\x6f\x80\x75\xd1\xde\xcc\x58\xc7\xf4\xe0\x10\x7f\x28\x6b", - "WAVAX", - 18, - "Wrapped AVAX", - ) + if utils.MODEL_IS_T2B1: + if chain_id == 1: # eth + yield ( # address, symbol, decimals, name + b"\x7f\xc6\x65\x00\xc8\x4a\x76\xad\x7e\x9c\x93\x43\x7b\xfc\x5a\xc3\x3e\x2d\xda\xe9", + "AAVE", + 18, + "Aave", + ) + yield ( # address, symbol, decimals, name + b"\x4d\x22\x44\x52\x80\x1a\xce\xd8\xb2\xf0\xae\xbe\x15\x53\x79\xbb\x5d\x59\x43\x81", + "APE", + 18, + "ApeCoin", + ) + yield ( # address, symbol, decimals, name + b"\xbb\x0e\x17\xef\x65\xf8\x2a\xb0\x18\xd8\xed\xd7\x76\xe8\xdd\x94\x03\x27\xb2\x8b", + "AXS", + 18, + "Axie Infinity", + ) + yield ( # address, symbol, decimals, name + b"\x4f\xab\xb1\x45\xd6\x46\x52\xa9\x48\xd7\x25\x33\x02\x3f\x6e\x7a\x62\x3c\x7c\x53", + "BUSD", + 18, + "Binance USD", + ) + yield ( # address, symbol, decimals, name + b"\x35\x06\x42\x4f\x91\xfd\x33\x08\x44\x66\xf4\x02\xd5\xd9\x7f\x05\xf8\xe3\xb4\xaf", + "CHZ", + 18, + "Chiliz", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb7\x3e\x1f\xf0\xb8\x09\x14\xab\x6f\xe0\x44\x4e\x65\x84\x8c\x4c\x34\x45\x0b", + "CRO", + 8, + "Cronos", + ) + yield ( # address, symbol, decimals, name + b"\x6b\x17\x54\x74\xe8\x90\x94\xc4\x4d\xa9\x8b\x95\x4e\xed\xea\xc4\x95\x27\x1d\x0f", + "DAI", + 18, + "Dai", + ) + yield ( # address, symbol, decimals, name + b"\x85\x3d\x95\x5a\xce\xf8\x22\xdb\x05\x8e\xb8\x50\x59\x11\xed\x77\xf1\x75\xb9\x9e", + "FRAX", + 18, + "Frax", + ) + yield ( # address, symbol, decimals, name + b"\x2a\xf5\xd2\xad\x76\x74\x11\x91\xd1\x5d\xfe\x7b\xf6\xac\x92\xd4\xbd\x91\x2c\xa3", + "LEO", + 18, + "LEO Token", + ) + yield ( # address, symbol, decimals, name + b"\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", + "LINK", + 18, + "Chainlink", + ) + yield ( # address, symbol, decimals, name + b"\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", + "MANA", + 18, + "Decentraland", + ) + yield ( # address, symbol, decimals, name + b"\x7d\x1a\xfa\x7b\x71\x8f\xb8\x93\xdb\x30\xa3\xab\xc0\xcf\xc6\x08\xaa\xcf\xeb\xb0", + "MATIC", + 18, + "Polygon", + ) + yield ( # address, symbol, decimals, name + b"\x75\x23\x1f\x58\xb4\x32\x40\xc9\x71\x8d\xd5\x8b\x49\x67\xc5\x11\x43\x42\xa8\x6c", + "OKB", + 18, + "OKB", + ) + yield ( # address, symbol, decimals, name + b"\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", + "QNT", + 18, + "Quant", + ) + yield ( # address, symbol, decimals, name + b"\x38\x45\xba\xda\xde\x8e\x6d\xff\x04\x98\x20\x68\x0d\x1f\x14\xbd\x39\x03\xa5\xd0", + "SAND", + 18, + "The Sandbox", + ) + yield ( # address, symbol, decimals, name + b"\x95\xad\x61\xb0\xa1\x50\xd7\x92\x19\xdc\xf6\x4e\x1e\x6c\xc0\x1f\x0b\x64\xc4\xce", + "SHIB", + 18, + "Shiba Inu", + ) + yield ( # address, symbol, decimals, name + b"\xae\x7a\xb9\x65\x20\xde\x3a\x18\xe5\xe1\x11\xb5\xea\xab\x09\x53\x12\xd7\xfe\x84", + "STETH", + 18, + "Lido Staked Ether", + ) + yield ( # address, symbol, decimals, name + b"\x1f\x98\x40\xa8\x5d\x5a\xf5\xbf\x1d\x17\x62\xf9\x25\xbd\xad\xdc\x42\x01\xf9\x84", + "UNI", + 18, + "Uniswap", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48", + "USDC", + 6, + "USD Coin", + ) + yield ( # address, symbol, decimals, name + b"\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", + "USDT", + 6, + "Tether", + ) + yield ( # address, symbol, decimals, name + b"\x22\x60\xfa\xc5\xe5\x54\x2a\x77\x3a\xa4\x4f\xbc\xfe\xdf\x7c\x19\x3b\xc2\xc5\x99", + "WBTC", + 8, + "Wrapped Bitcoin", + ) + yield ( # address, symbol, decimals, name + b"\xa2\xcd\x3d\x43\xc7\x75\x97\x8a\x96\xbd\xbf\x12\xd7\x33\xd5\xa1\xed\x94\xfb\x18", + "XCN", + 18, + "Chain", + ) + if chain_id == 56: # bnb + yield ( # address, symbol, decimals, name + b"\x0e\xb3\xa7\x05\xfc\x54\x72\x50\x37\xcc\x9e\x00\x8b\xde\xde\x69\x7f\x62\xf3\x35", + "ATOM", + 18, + "Cosmos Hub", + ) + if chain_id == 137: # matic + yield ( # address, symbol, decimals, name + b"\x2c\x89\xbb\xc9\x2b\xd8\x6f\x80\x75\xd1\xde\xcc\x58\xc7\xf4\xe0\x10\x7f\x28\x6b", + "WAVAX", + 18, + "Wrapped AVAX", + ) + else: + if chain_id == 1: # eth + yield ( # address, symbol, decimals, name + b"\x7f\xc6\x65\x00\xc8\x4a\x76\xad\x7e\x9c\x93\x43\x7b\xfc\x5a\xc3\x3e\x2d\xda\xe9", + "AAVE", + 18, + "Aave", + ) + yield ( # address, symbol, decimals, name + b"\x4d\x22\x44\x52\x80\x1a\xce\xd8\xb2\xf0\xae\xbe\x15\x53\x79\xbb\x5d\x59\x43\x81", + "APE", + 18, + "ApeCoin", + ) + yield ( # address, symbol, decimals, name + b"\xbb\x0e\x17\xef\x65\xf8\x2a\xb0\x18\xd8\xed\xd7\x76\xe8\xdd\x94\x03\x27\xb2\x8b", + "AXS", + 18, + "Axie Infinity", + ) + yield ( # address, symbol, decimals, name + b"\x4f\xab\xb1\x45\xd6\x46\x52\xa9\x48\xd7\x25\x33\x02\x3f\x6e\x7a\x62\x3c\x7c\x53", + "BUSD", + 18, + "Binance USD", + ) + yield ( # address, symbol, decimals, name + b"\x35\x06\x42\x4f\x91\xfd\x33\x08\x44\x66\xf4\x02\xd5\xd9\x7f\x05\xf8\xe3\xb4\xaf", + "CHZ", + 18, + "Chiliz", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb7\x3e\x1f\xf0\xb8\x09\x14\xab\x6f\xe0\x44\x4e\x65\x84\x8c\x4c\x34\x45\x0b", + "CRO", + 8, + "Cronos", + ) + yield ( # address, symbol, decimals, name + b"\x6b\x17\x54\x74\xe8\x90\x94\xc4\x4d\xa9\x8b\x95\x4e\xed\xea\xc4\x95\x27\x1d\x0f", + "DAI", + 18, + "Dai", + ) + yield ( # address, symbol, decimals, name + b"\x85\x3d\x95\x5a\xce\xf8\x22\xdb\x05\x8e\xb8\x50\x59\x11\xed\x77\xf1\x75\xb9\x9e", + "FRAX", + 18, + "Frax", + ) + yield ( # address, symbol, decimals, name + b"\x2a\xf5\xd2\xad\x76\x74\x11\x91\xd1\x5d\xfe\x7b\xf6\xac\x92\xd4\xbd\x91\x2c\xa3", + "LEO", + 18, + "LEO Token", + ) + yield ( # address, symbol, decimals, name + b"\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", + "LINK", + 18, + "Chainlink", + ) + yield ( # address, symbol, decimals, name + b"\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", + "MANA", + 18, + "Decentraland", + ) + yield ( # address, symbol, decimals, name + b"\x7d\x1a\xfa\x7b\x71\x8f\xb8\x93\xdb\x30\xa3\xab\xc0\xcf\xc6\x08\xaa\xcf\xeb\xb0", + "MATIC", + 18, + "Polygon", + ) + yield ( # address, symbol, decimals, name + b"\x75\x23\x1f\x58\xb4\x32\x40\xc9\x71\x8d\xd5\x8b\x49\x67\xc5\x11\x43\x42\xa8\x6c", + "OKB", + 18, + "OKB", + ) + yield ( # address, symbol, decimals, name + b"\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", + "QNT", + 18, + "Quant", + ) + yield ( # address, symbol, decimals, name + b"\x38\x45\xba\xda\xde\x8e\x6d\xff\x04\x98\x20\x68\x0d\x1f\x14\xbd\x39\x03\xa5\xd0", + "SAND", + 18, + "The Sandbox", + ) + yield ( # address, symbol, decimals, name + b"\x95\xad\x61\xb0\xa1\x50\xd7\x92\x19\xdc\xf6\x4e\x1e\x6c\xc0\x1f\x0b\x64\xc4\xce", + "SHIB", + 18, + "Shiba Inu", + ) + yield ( # address, symbol, decimals, name + b"\xae\x7a\xb9\x65\x20\xde\x3a\x18\xe5\xe1\x11\xb5\xea\xab\x09\x53\x12\xd7\xfe\x84", + "STETH", + 18, + "Lido Staked Ether", + ) + yield ( # address, symbol, decimals, name + b"\x1f\x98\x40\xa8\x5d\x5a\xf5\xbf\x1d\x17\x62\xf9\x25\xbd\xad\xdc\x42\x01\xf9\x84", + "UNI", + 18, + "Uniswap", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48", + "USDC", + 6, + "USD Coin", + ) + yield ( # address, symbol, decimals, name + b"\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", + "USDT", + 6, + "Tether", + ) + yield ( # address, symbol, decimals, name + b"\x22\x60\xfa\xc5\xe5\x54\x2a\x77\x3a\xa4\x4f\xbc\xfe\xdf\x7c\x19\x3b\xc2\xc5\x99", + "WBTC", + 8, + "Wrapped Bitcoin", + ) + yield ( # address, symbol, decimals, name + b"\xa2\xcd\x3d\x43\xc7\x75\x97\x8a\x96\xbd\xbf\x12\xd7\x33\xd5\xa1\xed\x94\xfb\x18", + "XCN", + 18, + "Chain", + ) + if chain_id == 56: # bnb + yield ( # address, symbol, decimals, name + b"\x0e\xb3\xa7\x05\xfc\x54\x72\x50\x37\xcc\x9e\x00\x8b\xde\xde\x69\x7f\x62\xf3\x35", + "ATOM", + 18, + "Cosmos Hub", + ) + if chain_id == 137: # matic + yield ( # address, symbol, decimals, name + b"\x2c\x89\xbb\xc9\x2b\xd8\x6f\x80\x75\xd1\xde\xcc\x58\xc7\xf4\xe0\x10\x7f\x28\x6b", + "WAVAX", + 18, + "Wrapped AVAX", + ) diff --git a/core/src/apps/ethereum/tokens.py.mako b/core/src/apps/ethereum/tokens.py.mako index 7ec886965..afb60851d 100644 --- a/core/src/apps/ethereum/tokens.py.mako +++ b/core/src/apps/ethereum/tokens.py.mako @@ -16,6 +16,7 @@ from typing import Iterator +from trezor import utils from trezor.messages import EthereumTokenInfo <% from collections import defaultdict @@ -50,14 +51,27 @@ def token_by_chain_address(chain_id: int, address: bytes) -> EthereumTokenInfo | def _token_iterator(chain_id: int) -> Iterator[tuple[bytes, str, int, str]]: -% for token_chain_id, tokens in group_tokens(supported_on("trezor2", erc20)).items(): - if chain_id == ${token_chain_id}: # ${tokens[0].chain} - % for t in tokens: - yield ( # address, symbol, decimals, name - ${black_repr(t.address_bytes)}, - ${black_repr(t.symbol)}, - ${t.decimals}, - ${black_repr(t.name.strip())}, - ) - % endfor + if utils.MODEL_IS_T2B1: +% for token_chain_id, tokens in group_tokens(supported_on("T2B1", erc20)).items(): + if chain_id == ${token_chain_id}: # ${tokens[0].chain} + % for t in tokens: + yield ( # address, symbol, decimals, name + ${black_repr(t.address_bytes)}, + ${black_repr(t.symbol)}, + ${t.decimals}, + ${black_repr(t.name.strip())}, + ) + % endfor +% endfor + else: +% for token_chain_id, tokens in group_tokens(supported_on("T2T1", erc20)).items(): + if chain_id == ${token_chain_id}: # ${tokens[0].chain} + % for t in tokens: + yield ( # address, symbol, decimals, name + ${black_repr(t.address_bytes)}, + ${black_repr(t.symbol)}, + ${t.decimals}, + ${black_repr(t.name.strip())}, + ) + % endfor % endfor diff --git a/core/src/apps/management/authenticate_device.py b/core/src/apps/management/authenticate_device.py new file mode 100644 index 000000000..32bac8ec7 --- /dev/null +++ b/core/src/apps/management/authenticate_device.py @@ -0,0 +1,53 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from trezor.messages import AuthenticateDevice, AuthenticityProof + + +async def authenticate_device(msg: AuthenticateDevice) -> AuthenticityProof: + from trezor import utils, wire + from trezor.crypto import optiga + from trezor.crypto.der import read_length + from trezor.crypto.hashlib import sha256 + from trezor.messages import AuthenticityProof + from trezor.ui.layouts import confirm_action + from trezor.utils import BufferReader, bootloader_locked + + from apps.common.writers import write_compact_size + + if not bootloader_locked(): + raise wire.ProcessError("Cannot authenticate since bootloader is unlocked.") + + await confirm_action( + "authenticate_device", + "Authenticate device", + description="Do you wish to verify the authenticity of your device?", + ) + + header = b"AuthenticateDevice:" + h = utils.HashWriter(sha256()) + write_compact_size(h, len(header)) + h.extend(header) + write_compact_size(h, len(msg.challenge)) + h.extend(msg.challenge) + + try: + signature = optiga.sign(optiga.DEVICE_ECC_KEY_INDEX, h.get_digest()) + except optiga.SigningInaccessible: + raise wire.ProcessError("Signing inaccessible.") + + certificates = [] + r = BufferReader(optiga.get_certificate(optiga.DEVICE_CERT_INDEX)) + while r.remaining_count() > 0: + cert_begin = r.offset + if r.get() != 0x30: + wire.FirmwareError("Device certificate is corrupted.") + n = read_length(r) + cert_len = r.offset - cert_begin + n + r.seek(cert_begin) + certificates.append(r.read_memoryview(cert_len)) + + return AuthenticityProof( + certificates=certificates, + signature=signature, + ) diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 0c24fef3f..7a58f9554 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -56,7 +56,7 @@ async def reset_device(msg: ResetDevice) -> Success: raise ProcessError("Failed to set PIN") # generate and display internal entropy - int_entropy = random.bytes(32) + int_entropy = random.bytes(32, True) if __debug__: storage.debug.reset_internal_entropy = int_entropy if msg.display_random: diff --git a/core/src/apps/misc/get_entropy.py b/core/src/apps/misc/get_entropy.py index 75b56e7e9..ae4c41bea 100644 --- a/core/src/apps/misc/get_entropy.py +++ b/core/src/apps/misc/get_entropy.py @@ -19,6 +19,6 @@ async def get_entropy(msg: GetEntropy) -> Entropy: ) size = min(msg.size, 1024) - entropy = random.bytes(size) + entropy = random.bytes(size, True) return Entropy(entropy=entropy) diff --git a/core/src/apps/monero/get_address.py b/core/src/apps/monero/get_address.py index be7970f5a..49ab3f28d 100644 --- a/core/src/apps/monero/get_address.py +++ b/core/src/apps/monero/get_address.py @@ -69,6 +69,7 @@ async def get_address(msg: MoneroGetAddress, keychain: Keychain) -> MoneroAddres addr, address_qr="monero:" + addr, path=paths.address_n_to_str(msg.address_n), + chunkify=bool(msg.chunkify), ) return MoneroAddress(address=addr.encode()) diff --git a/core/src/apps/monero/layout.py b/core/src/apps/monero/layout.py index 31d0c20ff..a0c2e01e7 100644 --- a/core/src/apps/monero/layout.py +++ b/core/src/apps/monero/layout.py @@ -126,7 +126,9 @@ async def require_confirm_transaction( cur_payment = payment_id else: cur_payment = None - await _require_confirm_output(dst, network_type, cur_payment) + await _require_confirm_output( + dst, network_type, cur_payment, chunkify=bool(tsx_data.chunkify) + ) if ( payment_id @@ -143,6 +145,7 @@ async def _require_confirm_output( dst: MoneroTransactionDestinationEntry, network_type: MoneroNetworkType, payment_id: bytes | None, + chunkify: bool, ) -> None: """ Single transaction destination confirmation @@ -161,6 +164,7 @@ async def _require_confirm_output( addr, _format_amount(dst.amount), br_code=BRT_SignTx, + chunkify=chunkify, ) diff --git a/core/src/apps/nem/get_address.py b/core/src/apps/nem/get_address.py index 4686cbd6c..d0c9061ff 100644 --- a/core/src/apps/nem/get_address.py +++ b/core/src/apps/nem/get_address.py @@ -35,6 +35,7 @@ async def get_address(msg: NEMGetAddress, keychain: Keychain) -> NEMAddress: case_sensitive=False, path=address_n_to_str(address_n), network=get_network_str(network), + chunkify=bool(msg.chunkify), ) return NEMAddress(address=address) diff --git a/core/src/apps/nem/mosaic/nem_mosaics.py.mako b/core/src/apps/nem/mosaic/nem_mosaics.py.mako index e97520310..ed87beaa4 100644 --- a/core/src/apps/nem/mosaic/nem_mosaics.py.mako +++ b/core/src/apps/nem/mosaic/nem_mosaics.py.mako @@ -45,7 +45,7 @@ class Mosaic: def mosaics_iterator() -> Iterator[Mosaic]: -% for m in supported_on("trezor2", nem): +% for m in supported_on("T2T1", nem): yield Mosaic( "${m.name}", # name " ${m.ticker}", # ticker diff --git a/core/src/apps/nem/sign_tx.py b/core/src/apps/nem/sign_tx.py index 4cb76c13b..a4216af36 100644 --- a/core/src/apps/nem/sign_tx.py +++ b/core/src/apps/nem/sign_tx.py @@ -46,7 +46,9 @@ async def sign_tx(msg: NEMSignTx, keychain: Keychain) -> NEMSignedTx: common = transaction if msg.transfer: - tx = await transfer.transfer(public_key, common, msg.transfer, node) + tx = await transfer.transfer( + public_key, common, msg.transfer, node, chunkify=bool(msg.chunkify) + ) elif msg.provision_namespace: tx = await namespace.namespace(public_key, common, msg.provision_namespace) elif msg.mosaic_creation: diff --git a/core/src/apps/nem/transfer/__init__.py b/core/src/apps/nem/transfer/__init__.py index 2e576fce5..c6a95d39a 100644 --- a/core/src/apps/nem/transfer/__init__.py +++ b/core/src/apps/nem/transfer/__init__.py @@ -12,11 +12,12 @@ async def transfer( common: NEMTransactionCommon, transfer: NEMTransfer, node: bip32.HDNode, + chunkify: bool, ) -> bytes: transfer.mosaics = serialize.canonicalize_mosaics(transfer.mosaics) payload, encrypted = serialize.get_transfer_payload(transfer, node) - await layout.ask_transfer(common, transfer, encrypted) + await layout.ask_transfer(common, transfer, encrypted, chunkify) w = serialize.serialize_transfer(common, transfer, public_key, payload, encrypted) for mosaic in transfer.mosaics: diff --git a/core/src/apps/nem/transfer/layout.py b/core/src/apps/nem/transfer/layout.py index 5828e8cb3..d615c4426 100644 --- a/core/src/apps/nem/transfer/layout.py +++ b/core/src/apps/nem/transfer/layout.py @@ -20,6 +20,7 @@ async def ask_transfer( common: NEMTransactionCommon, transfer: NEMTransfer, encrypted: bool, + chunkify: bool, ) -> None: from trezor.ui.layouts import confirm_output, confirm_text @@ -42,6 +43,7 @@ async def ask_transfer( await confirm_output( transfer.recipient, f"{format_amount(_get_xem_amount(transfer), NEM_MAX_DIVISIBILITY)} XEM", + chunkify=chunkify, ) await require_confirm_final(common.fee) diff --git a/core/src/apps/ripple/get_address.py b/core/src/apps/ripple/get_address.py index c0c96d1cd..b21d9659f 100644 --- a/core/src/apps/ripple/get_address.py +++ b/core/src/apps/ripple/get_address.py @@ -25,6 +25,10 @@ async def get_address(msg: RippleGetAddress, keychain: Keychain) -> RippleAddres address = address_from_public_key(pubkey) if msg.show_display: - await show_address(address, path=paths.address_n_to_str(msg.address_n)) + await show_address( + address, + path=paths.address_n_to_str(msg.address_n), + chunkify=bool(msg.chunkify), + ) return RippleAddress(address=address) diff --git a/core/src/apps/ripple/layout.py b/core/src/apps/ripple/layout.py index b9f2ebc6d..f91934d2a 100644 --- a/core/src/apps/ripple/layout.py +++ b/core/src/apps/ripple/layout.py @@ -22,7 +22,7 @@ async def require_confirm_destination_tag(tag: int) -> None: ) -async def require_confirm_tx(to: str, value: int) -> None: +async def require_confirm_tx(to: str, value: int, chunkify: bool = False) -> None: from trezor.ui.layouts import confirm_output - await confirm_output(to, format_amount(value, DECIMALS) + " XRP") + await confirm_output(to, format_amount(value, DECIMALS) + " XRP", chunkify=chunkify) diff --git a/core/src/apps/ripple/sign_tx.py b/core/src/apps/ripple/sign_tx.py index f9de3eb8a..c8957bec4 100644 --- a/core/src/apps/ripple/sign_tx.py +++ b/core/src/apps/ripple/sign_tx.py @@ -47,7 +47,9 @@ async def sign_tx(msg: RippleSignTx, keychain: Keychain) -> RippleSignedTx: if payment.destination_tag is not None: await layout.require_confirm_destination_tag(payment.destination_tag) - await layout.require_confirm_tx(payment.destination, payment.amount) + await layout.require_confirm_tx( + payment.destination, payment.amount, chunkify=bool(msg.chunkify) + ) await layout.require_confirm_total(payment.amount + msg.fee, msg.fee) # Signs and encodes signature into DER format diff --git a/core/src/apps/stellar/get_address.py b/core/src/apps/stellar/get_address.py index cc9fea05d..6d48b2310 100644 --- a/core/src/apps/stellar/get_address.py +++ b/core/src/apps/stellar/get_address.py @@ -25,6 +25,8 @@ async def get_address(msg: StellarGetAddress, keychain: Keychain) -> StellarAddr if msg.show_display: path = paths.address_n_to_str(msg.address_n) - await show_address(address, case_sensitive=False, path=path) + await show_address( + address, case_sensitive=False, path=path, chunkify=bool(msg.chunkify) + ) return StellarAddress(address=address) diff --git a/core/src/apps/tezos/get_address.py b/core/src/apps/tezos/get_address.py index 1ab640787..d7fd52d27 100644 --- a/core/src/apps/tezos/get_address.py +++ b/core/src/apps/tezos/get_address.py @@ -29,6 +29,10 @@ async def get_address(msg: TezosGetAddress, keychain: Keychain) -> TezosAddress: address = helpers.base58_encode_check(pkh, helpers.TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: - await show_address(address, path=paths.address_n_to_str(msg.address_n)) + await show_address( + address, + path=paths.address_n_to_str(msg.address_n), + chunkify=bool(msg.chunkify), + ) return TezosAddress(address=address) diff --git a/core/src/apps/tezos/layout.py b/core/src/apps/tezos/layout.py index 1589581c9..78f7e2aee 100644 --- a/core/src/apps/tezos/layout.py +++ b/core/src/apps/tezos/layout.py @@ -4,13 +4,14 @@ from trezor.ui.layouts import confirm_address, confirm_metadata, confirm_propert BR_SIGN_TX = ButtonRequestType.SignTx # global_import_cache -async def require_confirm_tx(to: str, value: int) -> None: +async def require_confirm_tx(to: str, value: int, chunkify: bool = False) -> None: from trezor.ui.layouts import confirm_output await confirm_output( to, format_tezos_amount(value), br_code=BR_SIGN_TX, + chunkify=chunkify, ) diff --git a/core/src/apps/tezos/sign_tx.py b/core/src/apps/tezos/sign_tx.py index c0d172c62..124402161 100644 --- a/core/src/apps/tezos/sign_tx.py +++ b/core/src/apps/tezos/sign_tx.py @@ -71,12 +71,16 @@ async def sign_tx(msg: TezosSignTx, keychain: Keychain) -> TezosSignedTx: # operation to transfer tokens from a smart contract to an implicit account or a smart contract elif transfer is not None: to = _get_address_from_contract(transfer.destination) - await layout.require_confirm_tx(to, transfer.amount) + await layout.require_confirm_tx( + to, transfer.amount, chunkify=bool(msg.chunkify) + ) await layout.require_confirm_fee(transfer.amount, fee) else: # transactions from an implicit account to = _get_address_from_contract(transaction.destination) - await layout.require_confirm_tx(to, transaction.amount) + await layout.require_confirm_tx( + to, transaction.amount, chunkify=bool(msg.chunkify) + ) await layout.require_confirm_fee(transaction.amount, fee) elif origination is not None: diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index a4951409f..fd184be6e 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -59,6 +59,9 @@ def _find_message_handler_module(msg_type: int) -> str: if utils.USE_SD_CARD and msg_type == MessageType.SdProtect: return "apps.management.sd_protect" + if utils.USE_OPTIGA and msg_type == MessageType.AuthenticateDevice: + return "apps.management.authenticate_device" + # bitcoin if msg_type == MessageType.AuthorizeCoinJoin: return "apps.bitcoin.authorize_coinjoin" diff --git a/core/src/trezor/crypto/__init__.py b/core/src/trezor/crypto/__init__.py index ad1d409c7..b7bc22345 100644 --- a/core/src/trezor/crypto/__init__.py +++ b/core/src/trezor/crypto/__init__.py @@ -13,3 +13,6 @@ from trezor import utils if not utils.BITCOIN_ONLY: from trezorcrypto import cardano, monero, nem # noqa: F401 + +if utils.USE_OPTIGA: + from trezorcrypto import optiga # noqa: F401 diff --git a/core/src/trezor/crypto/slip39.py b/core/src/trezor/crypto/slip39.py index baa5bce1e..304f4bdee 100644 --- a/core/src/trezor/crypto/slip39.py +++ b/core/src/trezor/crypto/slip39.py @@ -443,9 +443,11 @@ def _split_secret( random_share_count = threshold - 2 - shares = [(i, random.bytes(len(shared_secret))) for i in range(random_share_count)] + shares = [ + (i, random.bytes(len(shared_secret), True)) for i in range(random_share_count) + ] - random_part = random.bytes(len(shared_secret) - _DIGEST_LENGTH_BYTES) + random_part = random.bytes(len(shared_secret) - _DIGEST_LENGTH_BYTES, True) digest = _create_digest(random_part, shared_secret) base_shares = shares + [ diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 205e64875..e010a34b1 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -48,6 +48,8 @@ UnlockPath = 93 UnlockedPathRequest = 94 ShowDeviceTutorial = 95 UnlockBootloader = 96 +AuthenticateDevice = 97 +AuthenticityProof = 98 FirmwareErase = 6 FirmwareUpload = 7 FirmwareRequest = 8 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index b2b3981f7..d2c31237c 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -65,6 +65,8 @@ if TYPE_CHECKING: UnlockedPathRequest = 94 ShowDeviceTutorial = 95 UnlockBootloader = 96 + AuthenticateDevice = 97 + AuthenticityProof = 98 SetU2FCounter = 63 GetNextU2FCounter = 80 NextU2FCounter = 81 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 095c04e94..efe61ba80 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -65,12 +65,14 @@ if TYPE_CHECKING: class BinanceGetAddress(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -130,6 +132,7 @@ if TYPE_CHECKING: memo: "str | None" sequence: "int" source: "int" + chunkify: "bool | None" def __init__( self, @@ -141,6 +144,7 @@ if TYPE_CHECKING: address_n: "list[int] | None" = None, chain_id: "str | None" = None, memo: "str | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -157,12 +161,14 @@ if TYPE_CHECKING: class BinanceTransferMsg(protobuf.MessageType): inputs: "list[BinanceInputOutput]" outputs: "list[BinanceInputOutput]" + chunkify: "bool | None" def __init__( self, *, inputs: "list[BinanceInputOutput] | None" = None, outputs: "list[BinanceInputOutput] | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -461,6 +467,7 @@ if TYPE_CHECKING: multisig: "MultisigRedeemScriptType | None" script_type: "InputScriptType" ignore_xpub_magic: "bool | None" + chunkify: "bool | None" def __init__( self, @@ -471,6 +478,7 @@ if TYPE_CHECKING: multisig: "MultisigRedeemScriptType | None" = None, script_type: "InputScriptType | None" = None, ignore_xpub_magic: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -600,6 +608,7 @@ if TYPE_CHECKING: decred_staking_ticket: "bool" serialize: "bool" coinjoin_request: "CoinJoinRequest | None" + chunkify: "bool | None" def __init__( self, @@ -617,6 +626,7 @@ if TYPE_CHECKING: decred_staking_ticket: "bool | None" = None, serialize: "bool | None" = None, coinjoin_request: "CoinJoinRequest | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -1286,6 +1296,7 @@ if TYPE_CHECKING: network_id: "int" address_parameters: "CardanoAddressParametersType" derivation_type: "CardanoDerivationType" + chunkify: "bool | None" def __init__( self, @@ -1295,6 +1306,7 @@ if TYPE_CHECKING: address_parameters: "CardanoAddressParametersType", derivation_type: "CardanoDerivationType", show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -1372,6 +1384,7 @@ if TYPE_CHECKING: has_collateral_return: "bool" total_collateral: "int | None" reference_inputs_count: "int" + chunkify: "bool | None" def __init__( self, @@ -1397,6 +1410,7 @@ if TYPE_CHECKING: has_collateral_return: "bool | None" = None, total_collateral: "int | None" = None, reference_inputs_count: "int | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -2114,6 +2128,7 @@ if TYPE_CHECKING: unit_btconly: "bool | None" homescreen_width: "int | None" homescreen_height: "int | None" + bootloader_locked: "bool | None" def __init__( self, @@ -2163,6 +2178,7 @@ if TYPE_CHECKING: unit_btconly: "bool | None" = None, homescreen_width: "int | None" = None, homescreen_height: "int | None" = None, + bootloader_locked: "bool | None" = None, ) -> None: pass @@ -2362,6 +2378,36 @@ if TYPE_CHECKING: def is_type_of(cls, msg: Any) -> TypeGuard["FirmwareHash"]: return isinstance(msg, cls) + class AuthenticateDevice(protobuf.MessageType): + challenge: "bytes" + + def __init__( + self, + *, + challenge: "bytes", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["AuthenticateDevice"]: + return isinstance(msg, cls) + + class AuthenticityProof(protobuf.MessageType): + certificates: "list[bytes]" + signature: "bytes" + + def __init__( + self, + *, + signature: "bytes", + certificates: "list[bytes] | None" = None, + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["AuthenticityProof"]: + return isinstance(msg, cls) + class WipeDevice(protobuf.MessageType): @classmethod @@ -2885,12 +2931,14 @@ if TYPE_CHECKING: class EosGetPublicKey(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -2919,6 +2967,7 @@ if TYPE_CHECKING: chain_id: "bytes" header: "EosTxHeader" num_actions: "int" + chunkify: "bool | None" def __init__( self, @@ -2927,6 +2976,7 @@ if TYPE_CHECKING: header: "EosTxHeader", num_actions: "int", address_n: "list[int] | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -3612,6 +3662,7 @@ if TYPE_CHECKING: address_n: "list[int]" show_display: "bool | None" encoded_network: "bytes | None" + chunkify: "bool | None" def __init__( self, @@ -3619,6 +3670,7 @@ if TYPE_CHECKING: address_n: "list[int] | None" = None, show_display: "bool | None" = None, encoded_network: "bytes | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -3652,6 +3704,7 @@ if TYPE_CHECKING: chain_id: "int" tx_type: "int | None" definitions: "EthereumDefinitions | None" + chunkify: "bool | None" def __init__( self, @@ -3667,6 +3720,7 @@ if TYPE_CHECKING: data_length: "int | None" = None, tx_type: "int | None" = None, definitions: "EthereumDefinitions | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -3687,6 +3741,7 @@ if TYPE_CHECKING: chain_id: "int" access_list: "list[EthereumAccessList]" definitions: "EthereumDefinitions | None" + chunkify: "bool | None" def __init__( self, @@ -3703,6 +3758,7 @@ if TYPE_CHECKING: to: "str | None" = None, data_initial_chunk: "bytes | None" = None, definitions: "EthereumDefinitions | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -3935,6 +3991,7 @@ if TYPE_CHECKING: account: "int | None" minor: "int | None" payment_id: "bytes | None" + chunkify: "bool | None" def __init__( self, @@ -3945,6 +4002,7 @@ if TYPE_CHECKING: account: "int | None" = None, minor: "int | None" = None, payment_id: "bytes | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -4596,6 +4654,7 @@ if TYPE_CHECKING: client_version: "int | None" hard_fork: "int | None" monero_version: "bytes | None" + chunkify: "bool | None" def __init__( self, @@ -4615,6 +4674,7 @@ if TYPE_CHECKING: client_version: "int | None" = None, hard_fork: "int | None" = None, monero_version: "bytes | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -4700,6 +4760,7 @@ if TYPE_CHECKING: address_n: "list[int]" network: "int" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, @@ -4707,6 +4768,7 @@ if TYPE_CHECKING: address_n: "list[int] | None" = None, network: "int | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -4738,6 +4800,7 @@ if TYPE_CHECKING: supply_change: "NEMMosaicSupplyChange | None" aggregate_modification: "NEMAggregateModification | None" importance_transfer: "NEMImportanceTransfer | None" + chunkify: "bool | None" def __init__( self, @@ -4751,6 +4814,7 @@ if TYPE_CHECKING: supply_change: "NEMMosaicSupplyChange | None" = None, aggregate_modification: "NEMAggregateModification | None" = None, importance_transfer: "NEMImportanceTransfer | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5023,12 +5087,14 @@ if TYPE_CHECKING: class RippleGetAddress(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5057,6 +5123,7 @@ if TYPE_CHECKING: sequence: "int" last_ledger_sequence: "int | None" payment: "RipplePayment" + chunkify: "bool | None" def __init__( self, @@ -5067,6 +5134,7 @@ if TYPE_CHECKING: address_n: "list[int] | None" = None, flags: "int | None" = None, last_ledger_sequence: "int | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5129,12 +5197,14 @@ if TYPE_CHECKING: class StellarGetAddress(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5509,12 +5579,14 @@ if TYPE_CHECKING: class TezosGetAddress(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5539,12 +5611,14 @@ if TYPE_CHECKING: class TezosGetPublicKey(protobuf.MessageType): address_n: "list[int]" show_display: "bool | None" + chunkify: "bool | None" def __init__( self, *, address_n: "list[int] | None" = None, show_display: "bool | None" = None, + chunkify: "bool | None" = None, ) -> None: pass @@ -5575,6 +5649,7 @@ if TYPE_CHECKING: delegation: "TezosDelegationOp | None" proposal: "TezosProposalOp | None" ballot: "TezosBallotOp | None" + chunkify: "bool | None" def __init__( self, @@ -5587,6 +5662,7 @@ if TYPE_CHECKING: delegation: "TezosDelegationOp | None" = None, proposal: "TezosProposalOp | None" = None, ballot: "TezosBallotOp | None" = None, + chunkify: "bool | None" = None, ) -> None: pass diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 59dc992f5..f7e445cb5 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -452,31 +452,10 @@ async def confirm_homescreen( ) -def _show_xpub(xpub: str, title: str, cancel: str | None) -> ui.Layout: - return RustLayout( - trezorui2.confirm_blob( - title=title.upper(), - data=xpub, - verb_cancel=cancel, - description=None, - extra=None, - ) - ) - - -async def show_xpub(xpub: str, title: str) -> None: - await raise_if_not_confirmed( - interact( - _show_xpub(xpub, title, None), - "show_xpub", - ButtonRequestType.PublicKey, - ) - ) - - async def show_address( address: str, *, + title: str | None = None, address_qr: str | None = None, case_sensitive: bool = True, path: str | None = None, @@ -484,14 +463,19 @@ async def show_address( network: str | None = None, multisig_index: int | None = None, xpubs: Sequence[str] = (), + mismatch_title: str = "ADDRESS MISMATCH?", + br_type: str = "show_address", + br_code: ButtonRequestType = ButtonRequestType.Address, + chunkify: bool = False, ) -> None: send_button_request = True - # Will be a marquee in case of multisig - title = ( - "RECEIVE ADDRESS (MULTISIG)" - if multisig_index is not None - else "RECEIVE ADDRESS" - ) + if title is None: + # Will be a marquee in case of multisig + title = ( + "RECEIVE ADDRESS (MULTISIG)" + if multisig_index is not None + else "RECEIVE ADDRESS" + ) while True: layout = RustLayout( trezorui2.confirm_address( @@ -499,13 +483,14 @@ async def show_address( data=address, description="", # unused on TR extra=None, # unused on TR + chunkify=chunkify, ) ) if send_button_request: send_button_request = False await button_request( - "show_address", - ButtonRequestType.Address, + br_type, + br_code, pages=layout.page_count(), ) result = await ctx_wait(layout) @@ -526,8 +511,10 @@ async def show_address( result = await ctx_wait( RustLayout( trezorui2.show_address_details( + qr_title="", # unused on this model address=address if address_qr is None else address_qr, case_sensitive=case_sensitive, + details_title="", # unused on this model account=account, path=path, xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)], @@ -539,19 +526,33 @@ async def show_address( # User pressed left cancel button, show mismatch dialogue. else: - result = await ctx_wait(RustLayout(trezorui2.show_mismatch())) + result = await ctx_wait( + RustLayout(trezorui2.show_mismatch(title=mismatch_title.upper())) + ) assert result in (CONFIRMED, CANCELLED) # Right button aborts action, left goes back to showing address. if result is CONFIRMED: raise ActionCancelled -def show_pubkey(pubkey: str, title: str = "Confirm public key") -> Awaitable[None]: - return confirm_blob( - "show_pubkey", - title.upper(), - pubkey, +def show_pubkey( + pubkey: str, + title: str = "Public key", + *, + account: str | None = None, + path: str | None = None, + mismatch_title: str = "KEY MISMATCH?", + br_type="show_pubkey", +) -> Awaitable[None]: + return show_address( + address=pubkey, + title=title.upper(), + account=account, + path=path, + br_type=br_type, br_code=ButtonRequestType.PublicKey, + mismatch_title=mismatch_title, + chunkify=False, ) @@ -580,21 +581,16 @@ async def _show_modal( async def show_error_and_raise( br_type: str, content: str, - header: str = "Error", subheader: str | None = None, - button: str = "Close", - red: bool = False, # unused on TR + button: str = "TRY AGAIN", exc: ExceptionType = ActionCancelled, ) -> NoReturn: - await _show_modal( + await show_warning( br_type, - header, - subheader, + subheader or "", content, - button_confirm=None, - button_cancel=button, + button=button, br_code=BR_TYPE_OTHER, - exc=exc, ) raise exc @@ -659,19 +655,32 @@ async def confirm_output( br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput, address_label: str | None = None, output_index: int | None = None, + chunkify: bool = False, ) -> None: address_title = ( "RECIPIENT" if output_index is None else f"RECIPIENT #{output_index + 1}" ) amount_title = "AMOUNT" if output_index is None else f"AMOUNT #{output_index + 1}" - await raise_if_not_confirmed( - interact( + while True: + result = await interact( RustLayout( - trezorui2.confirm_output( + trezorui2.confirm_output_address( address=address, address_label=address_label or "", address_title=address_title, + chunkify=chunkify, + ) + ), + "confirm_output", + br_code, + ) + if result is not CONFIRMED: + raise ActionCancelled + + result = await interact( + RustLayout( + trezorui2.confirm_output_amount( amount_title=amount_title, amount=amount, ) @@ -679,7 +688,8 @@ async def confirm_output( "confirm_output", br_code, ) - ) + if result is CONFIRMED: + return async def tutorial( @@ -716,6 +726,7 @@ async def should_show_more( br_type: str = "should_show_more", br_code: ButtonRequestType = BR_TYPE_OTHER, confirm: str | bytes | None = None, + verb_cancel: str | None = None, ) -> bool: """Return True if the user wants to show more (they click a special button) and False when the user wants to continue without showing details. @@ -731,7 +742,8 @@ async def should_show_more( title=title.upper(), items=para, button=confirm.upper(), - info_button=button_text.upper(), + verb_cancel=verb_cancel, # type: ignore [No parameter named "verb_cancel"] + info_button=button_text.upper(), # unused on TR ) ), br_type, @@ -752,6 +764,8 @@ async def confirm_blob( title: str, data: bytes | str, description: str | None = None, + verb: str = "CONFIRM", + verb_cancel: str | None = "", # icon hold: bool = False, br_code: ButtonRequestType = BR_TYPE_OTHER, ask_pagination: bool = False, @@ -764,18 +778,67 @@ async def confirm_blob( description=description, data=data, extra=None, - verb_cancel="", # to show the cancel icon + verb=verb, + verb_cancel=verb_cancel, hold=hold, ) ) - await raise_if_not_confirmed( - interact( - layout, - br_type, - br_code, + if ask_pagination and layout.page_count() > 1: + assert not hold + await _confirm_ask_pagination( + br_type, title, data, description, verb_cancel, br_code ) - ) + + else: + await raise_if_not_confirmed( + interact( + layout, + br_type, + br_code, + ) + ) + + +async def _confirm_ask_pagination( + br_type: str, + title: str, + data: bytes | str, + description: str, + verb_cancel: str | None, + br_code: ButtonRequestType, +) -> None: + paginated: ui.Layout | None = None + # TODO: make should_show_more/confirm_more accept bytes directly + if isinstance(data, bytes): + from ubinascii import hexlify + + data = hexlify(data).decode() + while True: + if not await should_show_more( + title, + para=[(ui.NORMAL, description), (ui.MONO, data)], + verb_cancel=verb_cancel, + br_type=br_type, + br_code=br_code, + ): + return + + if paginated is None: + paginated = RustLayout( + trezorui2.confirm_more( + title=title, + button="GO BACK", + items=[(ui.BOLD, f"Size: {len(data)} bytes"), (ui.MONO, data)], + ) + ) + else: + paginated.request_complete_repaint() + + result = await interact(paginated, br_type, br_code) + assert result in (CONFIRMED, CANCELLED) + + assert False async def confirm_address( @@ -924,8 +987,31 @@ async def confirm_total( ) -async def confirm_joint_total(spending_amount: str, total_amount: str) -> None: +async def confirm_ethereum_tx( + recipient: str, + total_amount: str, + maximum_fee: str, + items: Iterable[tuple[str, str]], + br_type: str = "confirm_ethereum_tx", + br_code: ButtonRequestType = ButtonRequestType.SignTx, +) -> None: + await raise_if_not_confirmed( + interact( + RustLayout( + trezorui2.confirm_ethereum_tx( + recipient=recipient, + total_amount=total_amount, + maximum_fee=maximum_fee, + items=items, + ) + ), + br_type, + br_code, + ) + ) + +async def confirm_joint_total(spending_amount: str, total_amount: str) -> None: await raise_if_not_confirmed( interact( RustLayout( @@ -1049,29 +1135,31 @@ async def confirm_sign_identity( async def confirm_signverify( coin: str, message: str, address: str, verify: bool ) -> None: - if verify: - header = f"Verify {coin} message" - br_type = "verify_message" - else: - header = f"Sign {coin} message" - br_type = "sign_message" + br_type = "verify_message" if verify else "sign_message" - await confirm_blob( - br_type, - header.upper(), - address, - "Confirm address:", - br_code=BR_TYPE_OTHER, - ) + # Allowing to go back from the second screen + while True: + await confirm_blob( + br_type, + "SIGNING ADDRESS", + address, + verb="CONTINUE", + br_code=BR_TYPE_OTHER, + ) - await confirm_value( - header.upper(), - message, - "Confirm message:", - br_type, - BR_TYPE_OTHER, - verb="CONFIRM", - ) + try: + await confirm_blob( + br_type, + "CONFIRM MESSAGE", + message, + verb_cancel="^", + br_code=BR_TYPE_OTHER, + ask_pagination=True, + ) + except ActionCancelled: + continue + else: + break async def show_error_popup( diff --git a/core/src/trezor/ui/layouts/tt_v2/__init__.py b/core/src/trezor/ui/layouts/tt_v2/__init__.py index 562442d51..acdfa987d 100644 --- a/core/src/trezor/ui/layouts/tt_v2/__init__.py +++ b/core/src/trezor/ui/layouts/tt_v2/__init__.py @@ -365,12 +365,24 @@ async def confirm_path_warning( path: str, path_type: str | None = None, ) -> None: - title = "Unknown path" if not path_type else f"Unknown {path_type.lower()}" - await show_warning( - "path_warning", - title, - path, - br_code=ButtonRequestType.UnknownDerivationPath, + title = ( + "Wrong derivation path for selected account." + if not path_type + else f"Unknown {path_type.lower()}." + ) + await raise_if_not_confirmed( + interact( + RustLayout( + trezorui2.show_warning( + title=title, + value=path, + description="Continue anyway?", + button="CONTINUE", + ) + ), + "path_warning", + br_code=ButtonRequestType.UnknownDerivationPath, + ) ) @@ -391,28 +403,10 @@ async def confirm_homescreen( ) -async def show_xpub(xpub: str, title: str) -> None: - await raise_if_not_confirmed( - interact( - RustLayout( - trezorui2.confirm_blob( - title=title, - data=xpub, - verb="CONFIRM", - verb_cancel=None, - extra=None, - description=None, - ) - ), - "show_xpub", - ButtonRequestType.PublicKey, - ) - ) - - async def show_address( address: str, *, + title: str | None = None, address_qr: str | None = None, case_sensitive: bool = True, path: str | None = None, @@ -420,13 +414,21 @@ async def show_address( network: str | None = None, multisig_index: int | None = None, xpubs: Sequence[str] = (), + mismatch_title: str = "Address mismatch?", + br_type: str = "show_address", + br_code: ButtonRequestType = ButtonRequestType.Address, + chunkify: bool = False, ) -> None: send_button_request = True - title = ( - "RECEIVE ADDRESS\n(MULTISIG)" - if multisig_index is not None - else "RECEIVE ADDRESS" - ) + if title is None: + title = ( + "RECEIVE ADDRESS\n(MULTISIG)" + if multisig_index is not None + else "RECEIVE ADDRESS" + ) + details_title = "RECEIVING TO" + else: + details_title = title while True: layout = RustLayout( trezorui2.confirm_address( @@ -434,13 +436,14 @@ async def show_address( data=address, description=network or "", extra=None, + chunkify=chunkify, ) ) if send_button_request: send_button_request = False await button_request( - "show_address", - ButtonRequestType.Address, + br_type, + br_code, pages=layout.page_count(), ) result = await ctx_wait(layout) @@ -460,8 +463,10 @@ async def show_address( result = await ctx_wait( RustLayout( trezorui2.show_address_details( + qr_title=title, address=address if address_qr is None else address_qr, case_sensitive=case_sensitive, + details_title=details_title, account=account, path=path, xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)], @@ -471,19 +476,33 @@ async def show_address( assert result is CANCELLED else: - result = await ctx_wait(RustLayout(trezorui2.show_mismatch())) + result = await ctx_wait( + RustLayout(trezorui2.show_mismatch(title=mismatch_title)) + ) assert result in (CONFIRMED, CANCELLED) # Right button aborts action, left goes back to showing address. if result is CONFIRMED: raise ActionCancelled -def show_pubkey(pubkey: str, title: str = "Confirm public key") -> Awaitable[None]: - return confirm_blob( - "show_pubkey", - title, - pubkey, +def show_pubkey( + pubkey: str, + title: str = "Public key", + *, + account: str | None = None, + path: str | None = None, + mismatch_title: str = "Key mismatch?", + br_type="show_pubkey", +) -> Awaitable[None]: + return show_address( + address=pubkey, + title=title.upper(), + account=account, + path=path, + br_type=br_type, br_code=ButtonRequestType.PublicKey, + mismatch_title=mismatch_title, + chunkify=False, ) @@ -491,7 +510,7 @@ async def show_error_and_raise( br_type: str, content: str, subheader: str | None = None, - button: str = "CLOSE", + button: str = "TRY AGAIN", exc: ExceptionType = ActionCancelled, ) -> NoReturn: await interact( @@ -561,6 +580,7 @@ async def confirm_output( br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput, address_label: str | None = None, output_index: int | None = None, + chunkify: bool = False, ) -> None: if title is not None: if title.upper().startswith("CONFIRM "): @@ -585,6 +605,7 @@ async def confirm_output( verb="CONTINUE", hold=False, info_button=False, + chunkify=chunkify, ) ), "confirm_output", @@ -725,6 +746,7 @@ async def confirm_blob( data: bytes | str, description: str | None = None, verb: str = "CONFIRM", + verb_cancel: str | None = None, hold: bool = False, br_code: ButtonRequestType = BR_TYPE_OTHER, ask_pagination: bool = False, @@ -739,6 +761,7 @@ async def confirm_blob( extra=None, hold=hold, verb=verb, + verb_cancel=verb_cancel, ) ) @@ -892,15 +915,63 @@ async def confirm_total( info_button=bool(account_label or fee_rate_amount), ) ) + items: list[tuple[str, str]] = [] + if account_label: + items.append(("Sending from account:", account_label)) + if fee_rate_amount: + items.append(("Fee rate:", fee_rate_amount)) info_layout = RustLayout( - trezorui2.show_spending_details( - account=account_label or "", - fee_rate=fee_rate_amount or "", + trezorui2.show_info_with_cancel( + title="INFORMATION", + items=items, ) ) await with_info(total_layout, info_layout, br_type, br_code) +async def confirm_ethereum_tx( + recipient: str, + total_amount: str, + maximum_fee: str, + items: Iterable[tuple[str, str]], + br_type: str = "confirm_ethereum_tx", + br_code: ButtonRequestType = ButtonRequestType.SignTx, +) -> None: + total_layout = RustLayout( + trezorui2.confirm_total( + title="SUMMARY", + items=[ + ("Amount:", total_amount), + ("Maximum fee:", maximum_fee), + ], + info_button=True, + cancel_arrow=True, + ) + ) + info_layout = RustLayout( + trezorui2.show_info_with_cancel( + title="FEE INFORMATION", + items=items, + ) + ) + + while True: + # Allowing going back and forth between recipient and summary/details + await confirm_blob( + br_type, + "RECIPIENT", + recipient, + verb="CONTINUE", + ) + + try: + total_layout.request_complete_repaint() + await with_info(total_layout, info_layout, br_type, br_code) + break + except ActionCancelled: + continue + + async def confirm_joint_total(spending_amount: str, total_amount: str) -> None: await raise_if_not_confirmed( interact( @@ -1039,12 +1110,13 @@ async def confirm_modify_fee( fee_rate_amount=fee_rate_amount, ) ) + items: list[tuple[str, str]] = [] + if fee_rate_amount: + items.append(("New fee rate:", fee_rate_amount)) info_layout = RustLayout( - trezorui2.show_spending_details( - account=None, + trezorui2.show_info_with_cancel( title="FEE INFORMATION", - fee_rate=fee_rate_amount, - fee_rate_title="New fee rate:", + items=items, ) ) await with_info(fee_layout, info_layout, "modify_fee", ButtonRequestType.SignTx) diff --git a/core/src/trezor/ui/layouts/tt_v2/recovery.py b/core/src/trezor/ui/layouts/tt_v2/recovery.py index 60affed78..731b66326 100644 --- a/core/src/trezor/ui/layouts/tt_v2/recovery.py +++ b/core/src/trezor/ui/layouts/tt_v2/recovery.py @@ -20,6 +20,7 @@ async def _is_confirmed_info( if result is trezorui2.INFO: await info_func() + dialog.request_complete_repaint() else: return result is CONFIRMED diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index 74de2e722..63ca9e6db 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -7,10 +7,12 @@ from trezorutils import ( # noqa: F401 MODEL, SCM_REVISION, USE_BACKLIGHT, + USE_OPTIGA, USE_SD_CARD, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, + bootloader_locked, consteq, firmware_hash, firmware_vendor, @@ -22,6 +24,10 @@ from trezorutils import ( # noqa: F401 ) from typing import TYPE_CHECKING +# Will get replaced by "True" / "False" in the build process +# However, needs to stay as an exported symbol for the unit tests +MODEL_IS_T2B1: bool = INTERNAL_MODEL == "T2B1" + DISABLE_ANIMATION = 0 if __debug__: diff --git a/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh.py b/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh.py index 92a05fbdc..bcce720cd 100644 --- a/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh.py +++ b/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh.py @@ -95,13 +95,13 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out2)), - helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1), + helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1, False), True, helpers.UiConfirmTotal(12300000, 11000, fee_rate, coin, AmountUnit.BITCOIN, inp1.address_n[:3]), @@ -229,7 +229,7 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), diff --git a/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh_grs.py b/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh_grs.py index ab1055069..9765132cf 100644 --- a/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh_grs.py +++ b/core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh_grs.py @@ -93,13 +93,13 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out2)), - helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1), + helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1, False), True, helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False), @@ -227,7 +227,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), diff --git a/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh.py b/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh.py index e65bbcfc5..934e64308 100644 --- a/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh.py +++ b/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh.py @@ -92,13 +92,13 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out2)), - helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1), + helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1, False), True, helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN, inp1.address_n[:3]), @@ -223,7 +223,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase): TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), @@ -371,7 +371,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), diff --git a/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh_grs.py b/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh_grs.py index 64079fc84..cae18a447 100644 --- a/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh_grs.py +++ b/core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh_grs.py @@ -93,13 +93,13 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out2)), - helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1), + helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1, False), True, helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False), @@ -226,7 +226,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase): TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), diff --git a/core/tests/test_apps.bitcoin.signtx.fee_threshold.py b/core/tests/test_apps.bitcoin.signtx.fee_threshold.py index 57e8d898f..893aef17c 100644 --- a/core/tests/test_apps.bitcoin.signtx.fee_threshold.py +++ b/core/tests/test_apps.bitcoin.signtx.fee_threshold.py @@ -85,7 +85,7 @@ class TestSignTxFeeThreshold(unittest.TestCase): TxAckPrevOutput(tx=TxAckPrevOutputWrapper(output=pout1)), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=None), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0, False), True, helpers.UiConfirmFeeOverThreshold(100000, coin_bitcoin), True, @@ -146,7 +146,9 @@ class TestSignTxFeeThreshold(unittest.TestCase): True, TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0, False), + True, + helpers.UiConfirmMultipleAccounts(), True, helpers.UiConfirmTotal(300000 + 90000, 90000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN, None), True, diff --git a/core/tests/test_apps.bitcoin.signtx.py b/core/tests/test_apps.bitcoin.signtx.py index 0f0d04d0a..6d0ee620f 100644 --- a/core/tests/test_apps.bitcoin.signtx.py +++ b/core/tests/test_apps.bitcoin.signtx.py @@ -111,7 +111,7 @@ class TestSignTx(unittest.TestCase): serialized=EMPTY_SERIALIZED, ), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0, False), True, helpers.UiConfirmTotal(3_801_747, 50_000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN, inp1.address_n[:3]), True, diff --git a/core/tests/test_apps.bitcoin.signtx_decred.py b/core/tests/test_apps.bitcoin.signtx_decred.py index adda5656b..ef615a567 100644 --- a/core/tests/test_apps.bitcoin.signtx_decred.py +++ b/core/tests/test_apps.bitcoin.signtx_decred.py @@ -109,7 +109,7 @@ class TestSignTxDecred(unittest.TestCase): ), ), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN, 0, False), True, helpers.UiConfirmTotal( 200_000_000, 100_000, fee_rate, coin_decred, AmountUnit.BITCOIN, inp1.address_n[:3] diff --git a/core/tests/test_apps.bitcoin.signtx_grs.py b/core/tests/test_apps.bitcoin.signtx_grs.py index f7a12d90f..55abd9551 100644 --- a/core/tests/test_apps.bitcoin.signtx_grs.py +++ b/core/tests/test_apps.bitcoin.signtx_grs.py @@ -70,7 +70,7 @@ class TestSignTx_GRS(unittest.TestCase): TxAckInput(tx=TxAckInputWrapper(input=inp1)), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxAckOutput(tx=TxAckOutputWrapper(output=out1)), - helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0), + helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0, False), True, helpers.UiConfirmTotal(210016, 192, fee_rate, coin, AmountUnit.BITCOIN, inp1.address_n[:3]), True, diff --git a/crypto/Makefile b/crypto/Makefile index 7a5d7e35b..1d83619de 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -83,6 +83,7 @@ CFLAGS += -DUSE_MONERO=1 CFLAGS += -DUSE_NEM=1 CFLAGS += -DUSE_CARDANO=1 CFLAGS += -DUSE_INSECURE_PRNG=1 +CFLAGS += -DAES_128 CFLAGS += $(shell pkg-config --cflags openssl) # disable certain optimizations and features when small footprint is required @@ -97,7 +98,7 @@ SRCS += ripemd160.c SRCS += sha2.c SRCS += sha3.c SRCS += hasher.c -SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c +SRCS += aes/aesccm.c aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c @@ -122,6 +123,7 @@ SRCS += zkp_context.c SRCS += zkp_ecdsa.c SRCS += zkp_bip340.c SRCS += cardano.c +SRCS += tls_prf.c OBJS = $(SRCS:.c=.o) OBJS += secp256k1-zkp.o diff --git a/crypto/aes/aesccm.c b/crypto/aes/aesccm.c new file mode 100644 index 000000000..a18279fe3 --- /dev/null +++ b/crypto/aes/aesccm.c @@ -0,0 +1,330 @@ +/** + * Copyright (c) 2023 Andrew Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * For a specification of AES-CCM see one of the following: + * https://datatracker.ietf.org/doc/html/rfc3610 + * https://doi.org/10.6028/NIST.SP.800-38C + */ + +#include + +#include "aesccm.h" +#include "memzero.h" + +typedef struct { + const aes_encrypt_ctx *encrypt_ctx; + union { + // Ensure 32-bit alignment. + uint8_t state[AES_BLOCK_SIZE]; + uint32_t state32[AES_BLOCK_SIZE / 4]; + }; + // Next position in the state where data will be added. + // Valid values are 0 to 15. + uint8_t pos; +} cbc_mac_context; + +// WARNING: Caller must ensure that encrypt_ctx remains valid for the lifetime +// of ctx. +static void cbc_mac_init(cbc_mac_context *ctx, + const aes_encrypt_ctx *encrypt_ctx) { + memzero(ctx, sizeof(cbc_mac_context)); + ctx->encrypt_ctx = encrypt_ctx; +} + +static AES_RETURN cbc_mac_update(cbc_mac_context *ctx, const uint8_t *data, + size_t size) { + if (ctx->pos != 0) { + while (size > 0 && ctx->pos < AES_BLOCK_SIZE) { + ctx->state[ctx->pos] ^= *data; + ctx->pos++; + data++; + size--; + } + + if (ctx->pos != AES_BLOCK_SIZE) { + return EXIT_SUCCESS; + } + + if (aes_encrypt(ctx->state, ctx->state, ctx->encrypt_ctx) != EXIT_SUCCESS) { + memzero(ctx, sizeof(*ctx)); + return EXIT_FAILURE; + } + ctx->pos = 0; + } + + size_t block_count = size >> AES_BLOCK_SIZE_P2; + size %= AES_BLOCK_SIZE; + + if (!ALIGN_OFFSET(data, 4)) { + while (block_count != 0) { + ctx->state32[0] ^= ((uint32_t *)data)[0]; + ctx->state32[1] ^= ((uint32_t *)data)[1]; + ctx->state32[2] ^= ((uint32_t *)data)[2]; + ctx->state32[3] ^= ((uint32_t *)data)[3]; + if (aes_encrypt(ctx->state, ctx->state, ctx->encrypt_ctx) != + EXIT_SUCCESS) { + memzero(ctx, sizeof(*ctx)); + return EXIT_FAILURE; + } + data += AES_BLOCK_SIZE; + block_count--; + } + } else { + while (block_count != 0) { + ctx->state[0] ^= data[0]; + ctx->state[1] ^= data[1]; + ctx->state[2] ^= data[2]; + ctx->state[3] ^= data[3]; + ctx->state[4] ^= data[4]; + ctx->state[5] ^= data[5]; + ctx->state[6] ^= data[6]; + ctx->state[7] ^= data[7]; + ctx->state[8] ^= data[8]; + ctx->state[9] ^= data[9]; + ctx->state[10] ^= data[10]; + ctx->state[11] ^= data[11]; + ctx->state[12] ^= data[12]; + ctx->state[13] ^= data[13]; + ctx->state[14] ^= data[14]; + ctx->state[15] ^= data[15]; + if (aes_encrypt(ctx->state, ctx->state, ctx->encrypt_ctx) != + EXIT_SUCCESS) { + memzero(ctx, sizeof(*ctx)); + return EXIT_FAILURE; + } + data += AES_BLOCK_SIZE; + block_count--; + } + } + + while (size > 0) { + ctx->state[ctx->pos] ^= *data; + ctx->pos++; + data++; + size--; + } + + return EXIT_SUCCESS; +} + +static AES_RETURN cbc_mac_update_zero_padding(cbc_mac_context *ctx) { + if (ctx->pos != 0) { + if (aes_encrypt(ctx->state, ctx->state, ctx->encrypt_ctx) != EXIT_SUCCESS) { + memzero(ctx, sizeof(*ctx)); + return EXIT_FAILURE; + } + ctx->pos = 0; + } + return EXIT_SUCCESS; +} + +static AES_RETURN cbc_mac_final(cbc_mac_context *ctx, uint8_t *mac, + size_t mac_len) { + if (ctx->pos != 0 || mac_len > AES_BLOCK_SIZE) { + memzero(ctx, sizeof(*ctx)); + return EXIT_FAILURE; + } + memcpy(mac, ctx->state, mac_len); + memzero(ctx, sizeof(*ctx)); + return EXIT_SUCCESS; +} + +static AES_RETURN aes_ccm_init(aes_encrypt_ctx *encrypt_ctx, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *adata, size_t adata_len, + size_t plaintext_len, size_t mac_len, + cbc_mac_context *cbc_ctx, uint8_t *ctr_block) { + if (mac_len < 4 || mac_len > AES_BLOCK_SIZE || mac_len % 2 != 0) { + return EXIT_FAILURE; + } + + if (nonce_len < 7 || nonce_len > 13) { + return EXIT_FAILURE; + } + + // Length of the binary representation of plaintext_len. + const size_t q = 15 - nonce_len; + + uint8_t flags = (adata_len != 0) << 6; + flags |= ((mac_len - 2) / 2) << 3; + flags |= q - 1; + + // Encode the first block. + uint8_t block[AES_BLOCK_SIZE] = {0}; + block[0] = flags; + memcpy(&block[1], nonce, nonce_len); + size_t shifted_len = plaintext_len; + for (size_t i = 0; i < q; ++i) { + block[15 - i] = shifted_len & 0xff; + shifted_len >>= 8; + } + if (shifted_len != 0) { + // plaintext_len does not fit into q octets. + return EXIT_FAILURE; + } + + aes_mode_reset(encrypt_ctx); + cbc_mac_init(cbc_ctx, encrypt_ctx); + if (cbc_mac_update(cbc_ctx, block, sizeof(block)) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + // Format the associated data length. + if (adata_len != 0) { + size_t block_size = 0; + if (adata_len < 65536 - 256) { + block[0] = adata_len >> 8; + block[1] = adata_len & 0xff; + block_size = 2; + } else { + shifted_len = adata_len; + block[5] = shifted_len & 0xff; + shifted_len >>= 8; + block[4] = shifted_len & 0xff; + shifted_len >>= 8; + block[3] = shifted_len & 0xff; + shifted_len >>= 8; + block[2] = shifted_len & 0xff; + block[1] = 0xfe; + block[0] = 0xff; + block_size = 6; + if ((shifted_len >> 8) != 0) { + // Associated data over 4 GB not supported. + return EXIT_FAILURE; + } + } + + if (cbc_mac_update(cbc_ctx, block, block_size) != EXIT_SUCCESS || + cbc_mac_update(cbc_ctx, adata, adata_len) != EXIT_SUCCESS || + cbc_mac_update_zero_padding(cbc_ctx) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + } + + // Initialize counter. + memzero(ctr_block, AES_BLOCK_SIZE); + ctr_block[0] = q - 1; + memcpy(&ctr_block[1], nonce, nonce_len); + + return EXIT_SUCCESS; +} + +// The length of data written to the ciphertext array is plaintext_len + +// mac_len. +AES_RETURN aes_ccm_encrypt(aes_encrypt_ctx *encrypt_ctx, const uint8_t *nonce, + size_t nonce_len, const uint8_t *adata, + size_t adata_len, const uint8_t *plaintext, + size_t plaintext_len, size_t mac_len, + uint8_t *ciphertext) { + cbc_mac_context cbc_ctx = {0}; + uint8_t ctr_block[AES_BLOCK_SIZE] = {0}; + if (aes_ccm_init(encrypt_ctx, nonce, nonce_len, adata, adata_len, + plaintext_len, mac_len, &cbc_ctx, + ctr_block) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + if (cbc_mac_update(&cbc_ctx, plaintext, plaintext_len) != EXIT_SUCCESS || + cbc_mac_update_zero_padding(&cbc_ctx) != EXIT_SUCCESS || + cbc_mac_final(&cbc_ctx, &ciphertext[plaintext_len], mac_len) != + EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + uint8_t s0[AES_BLOCK_SIZE] = {0}; + if (aes_ecb_encrypt(ctr_block, s0, AES_BLOCK_SIZE, encrypt_ctx) != + EXIT_SUCCESS) { + memzero(s0, sizeof(s0)); + return EXIT_FAILURE; + } + + for (size_t i = 0; i < mac_len; ++i) { + ciphertext[plaintext_len + i] ^= s0[i]; + } + memzero(s0, sizeof(s0)); + + ctr_block[AES_BLOCK_SIZE - 1] = 1; + if (aes_ctr_crypt(plaintext, ciphertext, plaintext_len, ctr_block, + aes_ctr_cbuf_inc, encrypt_ctx) != EXIT_SUCCESS) { + memzero(ciphertext, plaintext_len + mac_len); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +// The length of data written to the plaintext array is ciphertext_len - +// mac_len. +AES_RETURN aes_ccm_decrypt(aes_encrypt_ctx *encrypt_ctx, const uint8_t *nonce, + size_t nonce_len, const uint8_t *adata, + size_t adata_len, const uint8_t *ciphertext, + size_t ciphertext_len, size_t mac_len, + uint8_t *plaintext) { + cbc_mac_context cbc_ctx = {0}; + uint8_t ctr_block[AES_BLOCK_SIZE] = {0}; + size_t plaintext_len = ciphertext_len - mac_len; + if (ciphertext_len < mac_len || + aes_ccm_init(encrypt_ctx, nonce, nonce_len, adata, adata_len, + plaintext_len, mac_len, &cbc_ctx, + ctr_block) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + uint8_t s0[AES_BLOCK_SIZE] = {0}; + if (aes_ecb_encrypt(ctr_block, s0, AES_BLOCK_SIZE, encrypt_ctx) != + EXIT_SUCCESS) { + memzero(&cbc_ctx, sizeof(cbc_ctx)); + return EXIT_FAILURE; + } + + ctr_block[AES_BLOCK_SIZE - 1] = 1; + if (aes_ctr_crypt(ciphertext, plaintext, plaintext_len, ctr_block, + aes_ctr_cbuf_inc, encrypt_ctx) != EXIT_SUCCESS) { + memzero(&cbc_ctx, sizeof(cbc_ctx)); + memzero(s0, sizeof(s0)); + memzero(plaintext, plaintext_len); + return EXIT_FAILURE; + } + + uint8_t cbc_mac[AES_BLOCK_SIZE] = {0}; + if (cbc_mac_update(&cbc_ctx, plaintext, plaintext_len) != EXIT_SUCCESS || + cbc_mac_update_zero_padding(&cbc_ctx) != EXIT_SUCCESS || + cbc_mac_final(&cbc_ctx, cbc_mac, mac_len) != EXIT_SUCCESS) { + memzero(s0, sizeof(s0)); + memzero(plaintext, plaintext_len); + return EXIT_FAILURE; + } + + uint8_t diff = 0; + for (size_t i = 0; i < mac_len; ++i) { + diff |= ciphertext[plaintext_len + i] ^ s0[i] ^ cbc_mac[i]; + } + memzero(cbc_mac, sizeof(cbc_mac)); + memzero(s0, sizeof(s0)); + + if (diff != 0) { + memzero(plaintext, plaintext_len); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/crypto/aes/aesccm.h b/crypto/aes/aesccm.h new file mode 100644 index 000000000..d03cf8738 --- /dev/null +++ b/crypto/aes/aesccm.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2023 Andrew Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __AESCCM_H__ +#define __AESCCM_H__ + +#include +#include + +#include "aes/aes.h" + +AES_RETURN aes_ccm_encrypt(aes_encrypt_ctx *encrypt_ctx, const uint8_t *nonce, + size_t nonce_len, const uint8_t *adata, + size_t adata_len, const uint8_t *plaintext, + size_t plaintext_len, size_t mac_len, + uint8_t *ciphertext); + +AES_RETURN aes_ccm_decrypt(aes_encrypt_ctx *encrypt_ctx, const uint8_t *nonce, + size_t nonce_len, const uint8_t *adata, + size_t adata_len, const uint8_t *ciphertext, + size_t ciphertext_len, size_t mac_len, + uint8_t *plaintext); + +#endif diff --git a/crypto/sha2.c b/crypto/sha2.c index 42c7efb10..5d9c18817 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -273,6 +273,18 @@ const sha2_word64 sha512_initial_hash_value[8] = { 0x5be0cd19137e2179ULL }; +/* Initial hash value H for SHA-384 */ +const sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + /* * Constant used by SHA256/384/512_End() functions for converting the * digest to a readable hexadecimal character string: @@ -984,7 +996,7 @@ char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_S } -/*** SHA-512: *********************************************************/ +/*** SHA-512 and SHA-384: *********************************************/ void sha512_Init(SHA512_CTX* context) { if (context == (SHA512_CTX*)0) { return; @@ -994,6 +1006,15 @@ void sha512_Init(SHA512_CTX* context) { context->bitcount[0] = context->bitcount[1] = 0; } +static void sha384_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); + memzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ @@ -1284,6 +1305,16 @@ void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_ sha512_Final(&context, digest); } +void sha384_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA384_DIGEST_LENGTH]) { + uint8_t full_digest[SHA512_DIGEST_LENGTH] = {0}; + SHA512_CTX context = {0}; + sha384_Init(&context); + sha512_Update(&context, data, len); + sha512_Final(&context, full_digest); + memcpy(digest, full_digest, SHA384_DIGEST_LENGTH); + memzero(full_digest, sizeof(full_digest)); +} + char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { SHA512_CTX context = {0}; diff --git a/crypto/sha2.h b/crypto/sha2.h index d310120f4..5149b8dae 100644 --- a/crypto/sha2.h +++ b/crypto/sha2.h @@ -41,6 +41,7 @@ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_DIGEST_LENGTH 48 #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) @@ -81,6 +82,8 @@ char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); +void sha384_Raw(const uint8_t*, size_t, uint8_t[SHA384_DIGEST_LENGTH]); + void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); void sha512_Init(SHA512_CTX*); void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 58e959d1b..128667af5 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -41,6 +41,7 @@ #include "address.h" #include "aes/aes.h" +#include "aes/aesccm.h" #include "base32.h" #include "base58.h" #include "bignum.h" @@ -73,6 +74,7 @@ #include "shamir.h" #include "slip39.h" #include "slip39_wordlist.h" +#include "tls_prf.h" #include "zkp_bip340.h" #include "zkp_context.h" #include "zkp_ecdsa.h" @@ -4108,6 +4110,299 @@ START_TEST(test_aes) { } END_TEST +// test vectors from +// https://datatracker.ietf.org/doc/html/rfc3610 +// https://doi.org/10.6028/NIST.SP.800-38C +START_TEST(test_aesccm) { + struct { + char *key; + char *nonce; + char *aad; + char *plaintext; + int mac_len; + char *ciphertext; + } vectors[] = { + { + // RFC 3610 Packet Vector #1 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000003020100A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E", + 8, + "588C979A61C663D2F066D0C2C0F989806D5F6B61DAC38417E8D12CFDF926E0", + }, + { + // RFC 3610 Packet Vector #2 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000004030201A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + 8, + "72C91A36E135F8CF291CA894085C87E3CC15C439C9E43A3BA091D56E10400916", + }, + { + // RFC 3610 Packet Vector #3 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000005040302A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", + 8, + "51B1E5F44A197D1DA46B0F8E2D282AE871E838BB64DA8596574ADAA76FBD9FB0C5", + }, + { + // RFC 3610 Packet Vector #4 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000006050403A0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E", + 8, + "A28C6865939A9A79FAAA5C4C2A9D4A91CDAC8C96C861B9C9E61EF1", + }, + { + // RFC 3610 Packet Vector #5 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000007060504A0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E1F", + 8, + "DCF1FB7B5D9E23FB9D4E131253658AD86EBDCA3E51E83F077D9C2D93", + }, + { + // RFC 3610 Packet Vector #6 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000008070605A0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E1F20", + 8, + "6FC1B011F006568B5171A42D953D469B2570A4BD87405A0443AC91CB94", + }, + { + // RFC 3610 Packet Vector #7 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "00000009080706A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E", + 10, + "0135D1B2C95F41D5D1D4FEC185D166B8094E999DFED96C048C56602C97ACBB7490", + }, + { + // RFC 3610 Packet Vector #8 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000A090807A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + 10, + "7B75399AC0831DD2F0BBD75879A2FD8F6CAE6B6CD9B7DB24C17B4433F434963F34B" + "4", + }, + { + // RFC 3610 Packet Vector #9 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000B0A0908A0A1A2A3A4A5", + "0001020304050607", + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20", + 10, + "82531A60CC24945A4B8279181AB5C84DF21CE7F9B73F42E197EA9C07E56B5EB17E5F" + "4E", + }, + { + // RFC 3610 Packet Vector #10 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000C0B0A09A0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E", + 10, + "07342594157785152B074098330ABB141B947B566AA9406B4D999988DD", + }, + { + // RFC 3610 Packet Vector #11 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000D0C0B0AA0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E1F", + 10, + "676BB20380B0E301E8AB79590A396DA78B834934F53AA2E9107A8B6C022C", + }, + { + // RFC 3610 Packet Vector #12 + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF", + "0000000E0D0C0BA0A1A2A3A4A5", + "000102030405060708090A0B", + "0C0D0E0F101112131415161718191A1B1C1D1E1F20", + 10, + "C0FFA0D6F05BDB67F24D43A4338D2AA4BED7B20E43CD1AA31662E7AD65D6DB", + }, + { + // RFC 3610 Packet Vector #13 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00412B4EA9CDBE3C9696766CFA", + "0BE1A88BACE018B1", + "08E8CF97D820EA258460E96AD9CF5289054D895CEAC47C", + 8, + "4CB97F86A2A4689A877947AB8091EF5386A6FFBDD080F8E78CF7CB0CDDD7B3", + }, + { + // RFC 3610 Packet Vector #14 + "D7828D13B2B0BDC325A76236DF93CC6B", + "0033568EF7B2633C9696766CFA", + "63018F76DC8A1BCB", + "9020EA6F91BDD85AFA0039BA4BAFF9BFB79C7028949CD0EC", + 8, + "4CCB1E7CA981BEFAA0726C55D378061298C85C92814ABC33C52EE81D7D77C08A", + }, + { + // RFC 3610 Packet Vector #15 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00103FE41336713C9696766CFA", + "AA6CFA36CAE86B40", + "B916E0EACC1C00D7DCEC68EC0B3BBB1A02DE8A2D1AA346132E", + 8, + "B1D23A2220DDC0AC900D9AA03C61FCF4A559A4417767089708A776796EDB723506", + }, + { + // RFC 3610 Packet Vector #16 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00764C63B8058E3C9696766CFA", + "D0D0735C531E1BECF049C244", + "12DAAC5630EFA5396F770CE1A66B21F7B2101C", + 8, + "14D253C3967B70609B7CBB7C499160283245269A6F49975BCADEAF", + }, + { + // RFC 3610 Packet Vector #17 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00F8B678094E3B3C9696766CFA", + "77B60F011C03E1525899BCAE", + "E88B6A46C78D63E52EB8C546EFB5DE6F75E9CC0D", + 8, + "5545FF1A085EE2EFBF52B2E04BEE1E2336C73E3F762C0C7744FE7E3C", + }, + { + // RFC 3610 Packet Vector #18 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00D560912D3F703C9696766CFA", + "CD9044D2B71FDB8120EA60C0", + "6435ACBAFB11A82E2F071D7CA4A5EBD93A803BA87F", + 8, + "009769ECABDF48625594C59251E6035722675E04C847099E5AE0704551", + }, + { + // RFC 3610 Packet Vector #19 + "D7828D13B2B0BDC325A76236DF93CC6B", + "0042FFF8F1951C3C9696766CFA", + "D85BC7E69F944FB8", + "8A19B950BCF71A018E5E6701C91787659809D67DBEDD18", + 10, + "BC218DAA947427B6DB386A99AC1AEF23ADE0B52939CB6A637CF9BEC2408897C6BA", + }, + { + // RFC 3610 Packet Vector #20 + "D7828D13B2B0BDC325A76236DF93CC6B", + "00920F40E56CDC3C9696766CFA", + "74A0EBC9069F5B37", + "1761433C37C5A35FC1F39F406302EB907C6163BE38C98437", + 10, + "5810E6FD25874022E80361A478E3E9CF484AB04F447EFFF6F0A477CC2FC9BF54894" + "4", + }, + { + // RFC 3610 Packet Vector #21 + "D7828D13B2B0BDC325A76236DF93CC6B", + "0027CA0C7120BC3C9696766CFA", + "44A3AA3AAE6475CA", + "A434A8E58500C6E41530538862D686EA9E81301B5AE4226BFA", + 10, + "F2BEED7BC5098E83FEB5B31608F8E29C38819A89C8E776F1544D4151A4ED3A8B87B9" + "CE", + }, + { + // RFC 3610 Packet Vector #22 + "D7828D13B2B0BDC325A76236DF93CC6B", + "005B8CCBCD9AF83C9696766CFA", + "EC46BB63B02520C33C49FD70", + "B96B49E21D621741632875DB7F6C9243D2D7C2", + 10, + "31D750A09DA3ED7FDDD49A2032AABF17EC8EBF7D22C8088C666BE5C197", + }, + { + // RFC 3610 Packet Vector #23 + "D7828D13B2B0BDC325A76236DF93CC6B", + "003EBE94044B9A3C9696766CFA", + "47A65AC78B3D594227E85E71", + "E2FCFBB880442C731BF95167C8FFD7895E337076", + 10, + "E882F1DBD38CE3EDA7C23F04DD65071EB41342ACDF7E00DCCEC7AE52987D", + }, + { + // RFC 3610 Packet Vector #24 + "D7828D13B2B0BDC325A76236DF93CC6B", + "008D493B30AE8B3C9696766CFA", + "6E37A6EF546D955D34AB6059", + "ABF21C0B02FEB88F856DF4A37381BCE3CC128517D4", + 10, + "F32905B88A641B04B9C9FFB58CC390900F3DA12AB16DCE9E82EFA16DA62059", + }, + { + // NIST.SP.800-38C Example 1 + "404142434445464748494a4b4c4d4e4f", + "10111213141516", + "0001020304050607", + "20212223", + 4, + "7162015b4dac255d", + }, + { + // NIST.SP.800-38C Example 2 + "404142434445464748494a4b4c4d4e4f", + "1011121314151617", + "000102030405060708090a0b0c0d0e0f", + "202122232425262728292a2b2c2d2e2f", + 6, + "d2a1f0e051ea5f62081a7792073d593d1fc64fbfaccd", + }, + { + // NIST.SP.800-38C Example 3 + "404142434445464748494a4b4c4d4e4f", + "101112131415161718191a1b", + "000102030405060708090a0b0c0d0e0f10111213", + "202122232425262728292a2b2c2d2e2f3031323334353637", + 8, + "e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5484392fbc1b09951", + }}; + + uint8_t nonce[13] = {0}; + uint8_t aad[20] = {0}; + uint8_t plaintext[30] = {0}; + uint8_t ciphertext[40] = {0}; + for (size_t i = 0; i < sizeof(vectors) / sizeof(vectors[0]); ++i) { + aes_encrypt_ctx ctx; + aes_encrypt_key128(fromhex(vectors[i].key), &ctx); + size_t nonce_len = strlen(vectors[i].nonce) / 2; + memcpy(nonce, fromhex(vectors[i].nonce), nonce_len); + size_t aad_len = strlen(vectors[i].aad) / 2; + memcpy(aad, fromhex(vectors[i].aad), aad_len); + size_t plaintext_len = strlen(vectors[i].plaintext) / 2; + memcpy(plaintext, fromhex(vectors[i].plaintext), plaintext_len); + size_t ciphertext_len = strlen(vectors[i].ciphertext) / 2; + + // Test encryption. + AES_RETURN ret = + aes_ccm_encrypt(&ctx, nonce, nonce_len, aad, aad_len, plaintext, + plaintext_len, vectors[i].mac_len, ciphertext); + ck_assert_int_eq(ret, EXIT_SUCCESS); + ck_assert_mem_eq(ciphertext, fromhex(vectors[i].ciphertext), + ciphertext_len); + + // Test decryption. + aes_encrypt_key128(fromhex(vectors[i].key), &ctx); + ret = aes_ccm_decrypt(&ctx, nonce, nonce_len, aad, aad_len, ciphertext, + ciphertext_len, vectors[i].mac_len, plaintext); + ck_assert_int_eq(ret, EXIT_SUCCESS); + ck_assert_mem_eq(plaintext, fromhex(vectors[i].plaintext), plaintext_len); + } +} +END_TEST + #define TEST1 "abc" #define TEST2_1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" #define TEST2_2a "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" @@ -4281,6 +4576,97 @@ START_TEST(test_sha256) { } END_TEST +#define TEST7_384 "\x8b\xc5\x00\xc7\x7c\xee\xd9\x87\x9d\xa9\x89\x10\x7c\xe0\xaa" +#define TEST8_384 \ + "\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1\x0a\x7f\x4e\x08\x59\x17\x39" +#define TEST9_384 \ + "\x68\xf5\x01\x79\x2d\xea\x97\x96\x76\x70\x22\xd9\x3d\xa7\x16\x79" \ + "\x30\x99\x20\xfa\x10\x12\xae\xa3\x57\xb2\xb1\x33\x1d\x40\xa1\xd0" \ + "\x3c\x41\xc2\x40\xb3\xc9\xa7\x5b\x48\x92\xf4\xc0\x72\x4b\x68\xc8" \ + "\x75\x32\x1a\xb8\xcf\xe5\x02\x3b\xd3\x75\xbc\x0f\x94\xbd\x89\xfe" \ + "\x04\xf2\x97\x10\x5d\x7b\x82\xff\xc0\x02\x1a\xeb\x1c\xcb\x67\x4f" \ + "\x52\x44\xea\x34\x97\xde\x26\xa4\x19\x1c\x5f\x62\xe5\xe9\xa2\xd8" \ + "\x08\x2f\x05\x51\xf4\xa5\x30\x68\x26\xe9\x1c\xc0\x06\xce\x1b\xf6" \ + "\x0f\xf7\x19\xd4\x2f\xa5\x21\xc8\x71\xcd\x23\x94\xd9\x6e\xf4\x46" \ + "\x8f\x21\x96\x6b\x41\xf2\xba\x80\xc2\x6e\x83\xa9" +#define TEST10_384 \ + "\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb\x69\x12\xec\x10\xff\xcf" \ + "\x74\x79\x03\x49\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21\xdb\x0f" \ + "\x3e\x7d\xc8\x7f\x82\x32\x64\xbb\xe4\x0d\x18\x11\xc9\xea\x20\x61" \ + "\xe1\xc8\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02\xfc\x3f\x50\x42" \ + "\xe6\xbf\x58\xcb\xa8\xa2\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71" \ + "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86\x5f\x25\xcc\x22\xb5\xe8" \ + "\x77\x84\xa1\x2f\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a\x2c\xe6" \ + "\x56\x5c\xbd\xf1\x3d\xca\x40\x38\x32\xcf\xcb\x0e\x8b\x72\x11\xe8" \ + "\x3a\xf3\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5\x1c\xc0\x27\xaa" \ + "\xed\xef\xf8\x5a\xad\x7c\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a" \ + "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15\x1c\xb9\xbc\x51\x25\xa4" \ + "\x22\xe9\x41\xde\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd\xd0\x96" \ + "\x76\x71\x1c\xf3\xdb\x0a\x34\x40\x72\x0e\x16\x15\xc1\xf2\x2f\xbc" \ + "\x3c\x72\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77\x40\x86\x42\x14" \ + "\x7e\xd0\x96" + +// test vectors from rfc-4634 +START_TEST(test_sha384) { + struct { + const char *test; + int length; + int repeatcount; + int extrabits; + int numberExtrabits; + const char *result; + } tests[] = {/* 1 */ {TEST1, length(TEST1), 1, 0, 0, + "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED163" + "1A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7"}, + /* 2 */ + {TEST2_2, length(TEST2_2), 1, 0, 0, + "09330C33F71147E83D192FC782CD1B4753111B173B3B05D2" + "2FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039"}, + /* 3 */ + {TEST3, length(TEST3), 1000000, 0, 0, + "9D0E1809716474CB086E834E310A4A1CED149E9C00F24852" + "7972CEC5704C2A5B07B8B3DC38ECC4EBAE97DDD87F3D8985"}, + /* 4 */ + {TEST4, length(TEST4), 10, 0, 0, + "2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A70" + "BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A0D79FB4596"}, + /* 5 */ + {"", 0, 0, 0x10, 5, + "8D17BE79E32B6718E07D8A603EB84BA0478F7FCFD1BB9399" + "5F7D1149E09143AC1FFCFC56820E469F3878D957A15A3FE4"}, + /* 6 */ + {"\xb9", 1, 1, 0, 0, + "BC8089A19007C0B14195F4ECC74094FEC64F01F90929282C" + "2FB392881578208AD466828B1C6C283D2722CF0AD1AB6938"}, + /* 7 */ + {TEST7_384, length(TEST7_384), 1, 0xA0, 3, + "D8C43B38E12E7C42A7C9B810299FD6A770BEF30920F17532" + "A898DE62C7A07E4293449C0B5FA70109F0783211CFC4BCE3"}, + /* 8 */ + {TEST8_384, length(TEST8_384), 1, 0, 0, + "C9A68443A005812256B8EC76B00516F0DBB74FAB26D66591" + "3F194B6FFB0E91EA9967566B58109CBC675CC208E4C823F7"}, + /* 9 */ + {TEST9_384, length(TEST9_384), 1, 0xE0, 3, + "5860E8DE91C21578BB4174D227898A98E0B45C4C760F0095" + "49495614DAEDC0775D92D11D9F8CE9B064EEAC8DAFC3A297"}, + /* 10 */ + {TEST10_384, length(TEST10_384), 1, 0, 0, + "4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4AAF" + "38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD20CFF1288C0"}}; + + for (int i = 0; i < 10; i++) { + uint8_t digest[SHA384_DIGEST_LENGTH]; + /* extra bits are not supported */ + if (tests[i].numberExtrabits) continue; + /* repeat count not supported */ + if (tests[i].repeatcount != 1) continue; + sha384_Raw((const uint8_t *)tests[i].test, tests[i].length, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].result), sizeof(digest)); + } +} +END_TEST + #define TEST7_512 "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" #define TEST8_512 \ "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" @@ -5159,6 +5545,56 @@ START_TEST(test_pbkdf2_hmac_sha512) { } END_TEST +START_TEST(test_tls_prf_sha256) { + static const struct { + const char *secret; + const char *label; + const char *seed; + const char *result; + } tests[] = { + { + // Test vector from + // https://github.com/Infineon/optiga-trust-m/tree/develop/pal + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "426162796c6f6e20505246204170704e6f7465", + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "bf88ebdefa7846a110559188d422f3f7fafef4a549bdaace3739c944657f2dd9bc30" + "831447d0ed1c89f65823b2ece052f3b795ede86cad59ca473b3a78986369446562c9" + "a40d6aac59a204fa0e44b7d7", + }, + { + // Test vector from + // www.ietf.org/mail-archive/web/tls/current/msg03416.html + "9bbe436ba940f017b17652849a71db35", + "74657374206c6162656c", + "a0ba9f936cda311827a6f796ffd5198c", + "e3f229ba727be17b8d122620557cd453c2aab21d07c3d495329b52d4e61edb5a6b30" + "1791e90d35c9c9a46b4e14baf9af0fa022f7077def17abfd3797c0564bab4fbc9166" + "6e9def9b97fce34f796789baa48082d122ee42c5a72e5a5110fff70187347b66", + }, + }; + + uint8_t secret[32] = {0}; + uint8_t label[20] = {0}; + uint8_t seed[32] = {0}; + uint8_t output[100] = {0}; + + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t secret_len = strlen(tests[i].secret) / 2; + size_t label_len = strlen(tests[i].label) / 2; + size_t seed_len = strlen(tests[i].seed) / 2; + size_t result_len = strlen(tests[i].result) / 2; + memcpy(secret, fromhex(tests[i].secret), secret_len); + memcpy(label, fromhex(tests[i].label), label_len); + memcpy(seed, fromhex(tests[i].seed), seed_len); + + tls_prf_sha256(secret, secret_len, label, label_len, seed, seed_len, output, + result_len); + ck_assert_mem_eq(output, fromhex(tests[i].result), result_len); + } +} +END_TEST + START_TEST(test_hmac_drbg) { char entropy[] = "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; @@ -9572,9 +10008,14 @@ Suite *test_suite(void) { tcase_add_test(tc, test_aes); suite_add_tcase(s, tc); + tc = tcase_create("aes_ccm"); + tcase_add_test(tc, test_aesccm); + suite_add_tcase(s, tc); + tc = tcase_create("sha2"); tcase_add_test(tc, test_sha1); tcase_add_test(tc, test_sha256); + tcase_add_test(tc, test_sha384); tcase_add_test(tc, test_sha512); suite_add_tcase(s, tc); @@ -9603,6 +10044,10 @@ Suite *test_suite(void) { tcase_add_test(tc, test_pbkdf2_hmac_sha512); suite_add_tcase(s, tc); + tc = tcase_create("tls_prf"); + tcase_add_test(tc, test_tls_prf_sha256); + suite_add_tcase(s, tc); + tc = tcase_create("hmac_drbg"); tcase_add_test(tc, test_hmac_drbg); suite_add_tcase(s, tc); diff --git a/crypto/tls_prf.c b/crypto/tls_prf.c new file mode 100644 index 000000000..32b58b613 --- /dev/null +++ b/crypto/tls_prf.c @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2023 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * For a specification of TLS-PRF see + * https://datatracker.ietf.org/doc/html/rfc5246#section-5 + */ + +#include + +#include "hmac.h" +#include "memzero.h" +#include "sha2.h" + +void tls_prf_sha256(const uint8_t *secret, size_t secret_len, + const uint8_t *label, size_t label_len, const uint8_t *seed, + size_t seed_len, uint8_t *output, size_t out_len) { + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)] = {0}; + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)] = {0}; + uint8_t a[SHA256_DIGEST_LENGTH] = {0}; + uint8_t result[SHA256_DIGEST_LENGTH] = {0}; + SHA256_CTX ctx = {0}; + + // Prepare inner and outer digest. + hmac_sha256_prepare(secret, secret_len, odig, idig); + + // a = HMAC(secret, label + seed) + sha256_Init_ex(&ctx, idig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, label, label_len); + sha256_Update(&ctx, seed, seed_len); + sha256_Final(&ctx, a); + sha256_Init_ex(&ctx, odig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, a, SHA256_DIGEST_LENGTH); + sha256_Final(&ctx, a); + + while (1) { + // result = HMAC(secret, a + label + seed) + sha256_Init_ex(&ctx, idig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, a, SHA256_DIGEST_LENGTH); + sha256_Update(&ctx, label, label_len); + sha256_Update(&ctx, seed, seed_len); + sha256_Final(&ctx, result); + sha256_Init_ex(&ctx, odig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, result, SHA256_DIGEST_LENGTH); + sha256_Final(&ctx, result); + + if (out_len <= SHA256_DIGEST_LENGTH) { + break; + } + + memcpy(output, result, SHA256_DIGEST_LENGTH); + output += SHA256_DIGEST_LENGTH; + out_len -= SHA256_DIGEST_LENGTH; + + // a = HMAC(secret, a) + sha256_Init_ex(&ctx, idig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, a, SHA256_DIGEST_LENGTH); + sha256_Final(&ctx, a); + sha256_Init_ex(&ctx, odig, 8 * SHA256_BLOCK_LENGTH); + sha256_Update(&ctx, a, SHA256_DIGEST_LENGTH); + sha256_Final(&ctx, a); + } + + memcpy(output, result, out_len); + memzero(idig, sizeof(idig)); + memzero(odig, sizeof(odig)); + memzero(a, sizeof(a)); + memzero(result, sizeof(result)); +} diff --git a/crypto/tls_prf.h b/crypto/tls_prf.h new file mode 100644 index 000000000..d97b8fb58 --- /dev/null +++ b/crypto/tls_prf.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2023 Andrew R. Kozlik + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __TLS_PRF_H__ +#define __TLS_PRF_H__ + +#include +#include "hmac.h" + +void tls_prf_sha256(const uint8_t *secret, size_t secret_len, + const uint8_t *label, size_t label_len, const uint8_t *seed, + size_t seed_len, uint8_t *output, size_t out_len); + +#endif diff --git a/docs/ci/jobs.md b/docs/ci/jobs.md index 0dd6e0c66..e654ae7c2 100644 --- a/docs/ci/jobs.md +++ b/docs/ci/jobs.md @@ -83,60 +83,60 @@ present which get interpreted. ### [core unix regular asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L208) -### [core unix frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L227) +### [core unix frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L229) Build of Core into UNIX emulator. Something you can run on your laptop. Frozen version. That means you do not need any other files to run it, it is just a single binary file that you can execute directly. -### [core unix frozen btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L244) +### [core unix frozen btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L248) Build of Core into UNIX emulator. Something you can run on your laptop. Frozen version. That means you do not need any other files to run it, it is just a single binary file that you can execute directly. See [Emulator](../core/emulator/index.md) for more info. Debug mode enabled, Bitcoin-only version. -### [core unix frozen btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L260) +### [core unix frozen btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L264) -### [core unix frozen debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L283) +### [core unix frozen debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L287) Build of Core into UNIX emulator. Something you can run on your laptop. Frozen version. That means you do not need any other files to run it, it is just a single binary file that you can execute directly. **Are you looking for a Trezor T emulator? This is most likely it.** -### [core unix frozen R debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L296) +### [core unix frozen R debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L300) -### [core unix frozen R debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L310) +### [core unix frozen R debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L315) -### [core unix frozen debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L328) +### [core unix frozen debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L333) -### [core unix frozen debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L344) +### [core unix frozen debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L349) -### [core macos frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L366) +### [core macos frozen regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L371) -### [crypto build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L391) +### [crypto build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L396) Build of our cryptographic library, which is then incorporated into the other builds. -### [legacy fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L421) +### [legacy fw regular build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L426) -### [legacy fw regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L437) +### [legacy fw regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L442) -### [legacy fw btconly build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L454) +### [legacy fw btconly build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L459) -### [legacy fw btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L473) +### [legacy fw btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L478) -### [legacy emu regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L494) +### [legacy emu regular debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L499) Regular version (not only Bitcoin) of above. **Are you looking for a Trezor One emulator? This is most likely it.** -### [legacy emu regular debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L509) +### [legacy emu regular debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L514) -### [legacy emu regular debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L527) +### [legacy emu regular debug build arm](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L532) -### [legacy emu btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L553) +### [legacy emu btconly debug build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L558) Build of Legacy into UNIX emulator. Use keyboard arrows to emulate button presses. Bitcoin-only version. -### [legacy emu btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L570) +### [legacy emu btconly debug asan build](https://github.com/trezor/trezor-firmware/blob/master/ci/build.yml#L575) --- ## TEST stage - [test.yml](https://github.com/trezor/trezor-firmware/blob/master/ci/test.yml) diff --git a/legacy/firmware/coin_info.c.mako b/legacy/firmware/coin_info.c.mako index 705da2161..5c3d87883 100644 --- a/legacy/firmware/coin_info.c.mako +++ b/legacy/firmware/coin_info.c.mako @@ -23,7 +23,7 @@ def hex(x): #include "secp256k1.h" const CoinInfo coins[COINS_COUNT] = { -% for c in supported_on("trezor1", bitcoin): +% for c in supported_on("T1B1", bitcoin): { .coin_name = ${c_str(c.coin_name)}, .coin_shortcut = ${c_str(c.coin_shortcut)}, diff --git a/legacy/firmware/coin_info.h.mako b/legacy/firmware/coin_info.h.mako index bcd16120b..a71816ae1 100644 --- a/legacy/firmware/coin_info.h.mako +++ b/legacy/firmware/coin_info.h.mako @@ -6,7 +6,7 @@ #include "coins.h" -<% coins_list = list(supported_on("trezor1", bitcoin)) %>\ +<% coins_list = list(supported_on("T1B1", bitcoin)) %>\ #define COINS_COUNT (${len(coins_list)}) extern const CoinInfo coins[COINS_COUNT]; diff --git a/legacy/firmware/ethereum_networks.c.mako b/legacy/firmware/ethereum_networks.c.mako index 92e10420d..a3b863e0d 100644 --- a/legacy/firmware/ethereum_networks.c.mako +++ b/legacy/firmware/ethereum_networks.c.mako @@ -1,4 +1,4 @@ -<% networks = list(supported_on("trezor1", eth)) %>\ +<% networks = list(supported_on("T1B1", eth)) %>\ // This file is automatically generated from ethereum_networks.c.mako // DO NOT EDIT diff --git a/legacy/firmware/ethereum_tokens.c.mako b/legacy/firmware/ethereum_tokens.c.mako index 462dc7085..79bad82b3 100644 --- a/legacy/firmware/ethereum_tokens.c.mako +++ b/legacy/firmware/ethereum_tokens.c.mako @@ -5,7 +5,7 @@ #include "ethereum.h" #include "ethereum_tokens.h" -<% erc20_list = list(supported_on("trezor1", erc20)) %>\ +<% erc20_list = list(supported_on("T1B1", erc20)) %>\ #define TOKENS_COUNT ${len(erc20_list)} static const EthereumTokenInfo tokens[TOKENS_COUNT] = { diff --git a/legacy/firmware/nem_mosaics.c.mako b/legacy/firmware/nem_mosaics.c.mako index 73f949790..83becf3a3 100644 --- a/legacy/firmware/nem_mosaics.c.mako +++ b/legacy/firmware/nem_mosaics.c.mako @@ -20,7 +20,7 @@ ATTRIBUTES_OPTIONAL = ( #include "nem_mosaics.h" const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = { -% for m in supported_on("trezor1", nem): +% for m in supported_on("T1B1", nem): { % for attr, func in ATTRIBUTES_REQUIRED: % if attr in m: diff --git a/legacy/firmware/nem_mosaics.h.mako b/legacy/firmware/nem_mosaics.h.mako index 5667713b9..faec6b87b 100644 --- a/legacy/firmware/nem_mosaics.h.mako +++ b/legacy/firmware/nem_mosaics.h.mako @@ -6,7 +6,7 @@ #include "messages-nem.pb.h" -<% nem_list = list(supported_on("trezor1", nem)) %>\ +<% nem_list = list(supported_on("T1B1", nem)) %>\ #define NEM_MOSAIC_DEFINITIONS_COUNT (${len(nem_list)}) extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 911296422..ae8d95fc0 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -8,7 +8,7 @@ SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdPro TxAckInput TxAckOutput TxAckPrev TxAckPaymentRequest \ EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \ EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial \ - UnlockBootloader + UnlockBootloader AuthenticateDevice AuthenticityProof ifeq ($(BITCOIN_ONLY), 1) SKIPPED_MESSAGES += Ethereum NEM Stellar diff --git a/python/.changelog.d/+06ca7357.fixed b/python/.changelog.d/+06ca7357.fixed new file mode 100644 index 000000000..d6be6a933 --- /dev/null +++ b/python/.changelog.d/+06ca7357.fixed @@ -0,0 +1 @@ +Corrected vendor header signing keys for Model R (T2B1). diff --git a/python/.changelog.d/+bdb3ea1b.changed b/python/.changelog.d/+bdb3ea1b.changed new file mode 100644 index 000000000..88def8e15 --- /dev/null +++ b/python/.changelog.d/+bdb3ea1b.changed @@ -0,0 +1 @@ +Trezor model detection will try to use the `internal_name` field. diff --git a/python/.changelog.d/3227.fixed b/python/.changelog.d/3227.fixed new file mode 100644 index 000000000..25a2040f2 --- /dev/null +++ b/python/.changelog.d/3227.fixed @@ -0,0 +1 @@ +Fixed printing Trezor model when validating firmware image diff --git a/python/.changelog.d/3237.added b/python/.changelog.d/3237.added new file mode 100644 index 000000000..08672d1dc --- /dev/null +++ b/python/.changelog.d/3237.added @@ -0,0 +1 @@ +Add support for address chunkification in Receive and Sign flow. diff --git a/python/.changelog.d/3255.added b/python/.changelog.d/3255.added new file mode 100644 index 000000000..b806f9349 --- /dev/null +++ b/python/.changelog.d/3255.added @@ -0,0 +1 @@ +Implement device authenticate command. diff --git a/python/src/trezorlib/binance.py b/python/src/trezorlib/binance.py index 0334f2e2e..d2e4b9791 100644 --- a/python/src/trezorlib/binance.py +++ b/python/src/trezorlib/binance.py @@ -28,10 +28,15 @@ if TYPE_CHECKING: @expect(messages.BinanceAddress, field="address", ret_type=str) def get_address( - client: "TrezorClient", address_n: "Address", show_display: bool = False + client: "TrezorClient", + address_n: "Address", + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.BinanceGetAddress(address_n=address_n, show_display=show_display) + messages.BinanceGetAddress( + address_n=address_n, show_display=show_display, chunkify=chunkify + ) ) @@ -46,12 +51,13 @@ def get_public_key( @session def sign_tx( - client: "TrezorClient", address_n: "Address", tx_json: dict + client: "TrezorClient", address_n: "Address", tx_json: dict, chunkify: bool = False ) -> messages.BinanceSignedTx: msg = tx_json["msgs"][0] tx_msg = tx_json.copy() tx_msg["msg_count"] = 1 tx_msg["address_n"] = address_n + tx_msg["chunkify"] = chunkify envelope = dict_to_proto(messages.BinanceSignTx, tx_msg) response = client.call(envelope) diff --git a/python/src/trezorlib/btc.py b/python/src/trezorlib/btc.py index af0b722a0..ec5e83307 100644 --- a/python/src/trezorlib/btc.py +++ b/python/src/trezorlib/btc.py @@ -152,6 +152,7 @@ def get_authenticated_address( ignore_xpub_magic: bool = False, unlock_path: Optional[List[int]] = None, unlock_path_mac: Optional[bytes] = None, + chunkify: bool = False, ) -> "MessageType": if unlock_path: res = client.call( @@ -168,6 +169,7 @@ def get_authenticated_address( multisig=multisig, script_type=script_type, ignore_xpub_magic=ignore_xpub_magic, + chunkify=chunkify, ) ) diff --git a/python/src/trezorlib/cardano.py b/python/src/trezorlib/cardano.py index 4ec36b5a3..2ff367cc1 100644 --- a/python/src/trezorlib/cardano.py +++ b/python/src/trezorlib/cardano.py @@ -781,6 +781,7 @@ def get_address( network_id: int = NETWORK_IDS["mainnet"], show_display: bool = False, derivation_type: messages.CardanoDerivationType = messages.CardanoDerivationType.ICARUS, + chunkify: bool = False, ) -> "MessageType": return client.call( messages.CardanoGetAddress( @@ -789,6 +790,7 @@ def get_address( network_id=network_id, show_display=show_display, derivation_type=derivation_type, + chunkify=chunkify, ) ) @@ -798,10 +800,13 @@ def get_public_key( client: "TrezorClient", address_n: List[int], derivation_type: messages.CardanoDerivationType = messages.CardanoDerivationType.ICARUS, + show_display: bool = False, ) -> "MessageType": return client.call( messages.CardanoGetPublicKey( - address_n=address_n, derivation_type=derivation_type + address_n=address_n, + derivation_type=derivation_type, + show_display=show_display, ) ) @@ -845,6 +850,7 @@ def sign_tx( additional_witness_requests: Sequence[Path] = (), derivation_type: messages.CardanoDerivationType = messages.CardanoDerivationType.ICARUS, include_network_id: bool = False, + chunkify: bool = False, ) -> Dict[str, Any]: UNEXPECTED_RESPONSE_ERROR = exceptions.TrezorException("Unexpected response") @@ -881,6 +887,7 @@ def sign_tx( witness_requests_count=len(witness_requests), derivation_type=derivation_type, include_network_id=include_network_id, + chunkify=chunkify, ) ) if not isinstance(response, messages.CardanoTxItemAck): diff --git a/python/src/trezorlib/cli/binance.py b/python/src/trezorlib/cli/binance.py index c9ba0752d..b954274dd 100644 --- a/python/src/trezorlib/cli/binance.py +++ b/python/src/trezorlib/cli/binance.py @@ -38,11 +38,14 @@ def cli() -> None: @cli.command() @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def get_address(client: "TrezorClient", address: str, show_display: bool) -> str: +def get_address( + client: "TrezorClient", address: str, show_display: bool, chunkify: bool +) -> str: """Get Binance address for specified path.""" address_n = tools.parse_path(address) - return binance.get_address(client, address_n, show_display) + return binance.get_address(client, address_n, show_display, chunkify) @cli.command() @@ -59,13 +62,14 @@ def get_public_key(client: "TrezorClient", address: str, show_display: bool) -> @click.argument("file", type=click.File("r")) @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-f", "--file", "_ignore", is_flag=True, hidden=True, expose_value=False) +@click.option("-C", "--chunkify", is_flag=True) @with_client def sign_tx( - client: "TrezorClient", address: str, file: TextIO + client: "TrezorClient", address: str, file: TextIO, chunkify: bool ) -> "messages.BinanceSignedTx": """Sign Binance transaction. Transaction must be provided as a JSON file. """ address_n = tools.parse_path(address) - return binance.sign_tx(client, address_n, json.load(file)) + return binance.sign_tx(client, address_n, json.load(file), chunkify=chunkify) diff --git a/python/src/trezorlib/cli/btc.py b/python/src/trezorlib/cli/btc.py index e3ddf4811..ad02a1f1b 100644 --- a/python/src/trezorlib/cli/btc.py +++ b/python/src/trezorlib/cli/btc.py @@ -167,6 +167,7 @@ def cli() -> None: type=int, default=2, ) +@click.option("-C", "--chunkify", is_flag=True) @with_client def get_address( client: "TrezorClient", @@ -177,6 +178,7 @@ def get_address( multisig_xpub: List[str], multisig_threshold: Optional[int], multisig_suffix_length: int, + chunkify: bool, ) -> str: """Get address for specified path. @@ -225,6 +227,7 @@ def get_address( script_type=script_type, multisig=multisig, unlock_path=get_unlock_path(address_n), + chunkify=chunkify, ) @@ -366,9 +369,10 @@ def get_descriptor( @cli.command() @click.option("-c", "--coin", is_flag=True, hidden=True, expose_value=False) +@click.option("-C", "--chunkify", is_flag=True) @click.argument("json_file", type=click.File()) @with_client -def sign_tx(client: "TrezorClient", json_file: TextIO) -> None: +def sign_tx(client: "TrezorClient", json_file: TextIO, chunkify: bool) -> None: """Sign transaction. Transaction data must be provided in a JSON file. See `transaction-format.md` for @@ -398,6 +402,7 @@ def sign_tx(client: "TrezorClient", json_file: TextIO) -> None: inputs, outputs, prev_txes=prev_txes, + chunkify=chunkify, **details, ) diff --git a/python/src/trezorlib/cli/cardano.py b/python/src/trezorlib/cli/cardano.py index 8e96aff04..b18ae5a11 100644 --- a/python/src/trezorlib/cli/cardano.py +++ b/python/src/trezorlib/cli/cardano.py @@ -60,6 +60,7 @@ def cli() -> None: default=messages.CardanoDerivationType.ICARUS, ) @click.option("-i", "--include-network-id", is_flag=True) +@click.option("-C", "chunkify", is_flag=True) @with_client def sign_tx( client: "TrezorClient", @@ -70,6 +71,7 @@ def sign_tx( testnet: str, derivation_type: messages.CardanoDerivationType, include_network_id: bool, + chunkify: bool, ) -> cardano.SignTxResponse: """Sign Cardano transaction.""" transaction = json.load(file) @@ -143,6 +145,7 @@ def sign_tx( additional_witness_requests, derivation_type=derivation_type, include_network_id=include_network_id, + chunkify=chunkify, ) sign_tx_response["tx_hash"] = sign_tx_response["tx_hash"].hex() @@ -200,6 +203,7 @@ def sign_tx( type=ChoiceType({m.name: m for m in messages.CardanoDerivationType}), default=messages.CardanoDerivationType.ICARUS, ) +@click.option("-C", "--chunkify", is_flag=True) @with_client def get_address( client: "TrezorClient", @@ -217,6 +221,7 @@ def get_address( show_display: bool, testnet: str, derivation_type: messages.CardanoDerivationType, + chunkify: bool, ) -> str: """ Get Cardano address. @@ -260,6 +265,7 @@ def get_address( network_id, show_display, derivation_type=derivation_type, + chunkify=chunkify, ) @@ -271,16 +277,20 @@ def get_address( type=ChoiceType({m.name: m for m in messages.CardanoDerivationType}), default=messages.CardanoDerivationType.ICARUS, ) +@click.option("-d", "--show-display", is_flag=True) @with_client def get_public_key( client: "TrezorClient", address: str, derivation_type: messages.CardanoDerivationType, + show_display: bool, ) -> messages.CardanoPublicKey: """Get Cardano public key.""" address_n = tools.parse_path(address) client.init_device(derive_cardano=True) - return cardano.get_public_key(client, address_n, derivation_type=derivation_type) + return cardano.get_public_key( + client, address_n, derivation_type=derivation_type, show_display=show_display + ) @cli.command() diff --git a/python/src/trezorlib/cli/device.py b/python/src/trezorlib/cli/device.py index f2dcb1ef5..6ca2e9b0d 100644 --- a/python/src/trezorlib/cli/device.py +++ b/python/src/trezorlib/cli/device.py @@ -14,6 +14,7 @@ # You should have received a copy of the License along with this library. # If not, see . +import secrets import sys from typing import TYPE_CHECKING, Optional, Sequence @@ -331,3 +332,19 @@ def set_busy( ) return device.set_busy(client, expiry * 1000) + + +@cli.command() +@click.argument("hex_challenge", required=False) +@with_client +def authenticate(client: "TrezorClient", hex_challenge: Optional[str]) -> None: + """Get information to verify the authenticity of the device.""" + if hex_challenge is None: + hex_challenge = secrets.token_hex(32) + click.echo(f"Challenge: {hex_challenge}") + challenge = bytes.fromhex(hex_challenge) + msg = device.authenticate(client, challenge) + click.echo(f"Signature of challenge: {msg.signature.hex()}") + click.echo(f"Device certificate: {msg.certificates[0].hex()}") + for cert in msg.certificates[1:]: + click.echo(f"CA certificate: {cert.hex()}") diff --git a/python/src/trezorlib/cli/eos.py b/python/src/trezorlib/cli/eos.py index 93800294a..c0b3657b9 100644 --- a/python/src/trezorlib/cli/eos.py +++ b/python/src/trezorlib/cli/eos.py @@ -49,12 +49,19 @@ def get_public_key(client: "TrezorClient", address: str, show_display: bool) -> @click.argument("file", type=click.File("r")) @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-f", "--file", "_ignore", is_flag=True, hidden=True, expose_value=False) +@click.option("-C", "--chunkify", is_flag=True) @with_client def sign_transaction( - client: "TrezorClient", address: str, file: TextIO + client: "TrezorClient", address: str, file: TextIO, chunkify: bool ) -> "messages.EosSignedTx": """Sign EOS transaction.""" tx_json = json.load(file) address_n = tools.parse_path(address) - return eos.sign_tx(client, address_n, tx_json["transaction"], tx_json["chain_id"]) + return eos.sign_tx( + client, + address_n, + tx_json["transaction"], + tx_json["chain_id"], + chunkify=chunkify, + ) diff --git a/python/src/trezorlib/cli/ethereum.py b/python/src/trezorlib/cli/ethereum.py index 4abe3adb4..31b53e7c0 100644 --- a/python/src/trezorlib/cli/ethereum.py +++ b/python/src/trezorlib/cli/ethereum.py @@ -273,12 +273,15 @@ def cli( @cli.command() @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def get_address(client: "TrezorClient", address: str, show_display: bool) -> str: +def get_address( + client: "TrezorClient", address: str, show_display: bool, chunkify: bool +) -> str: """Get Ethereum address in hex encoding.""" address_n = tools.parse_path(address) network = ethereum.network_from_address_n(address_n, DEFINITIONS_SOURCE) - return ethereum.get_address(client, address_n, show_display, network) + return ethereum.get_address(client, address_n, show_display, network, chunkify) @cli.command() @@ -344,6 +347,7 @@ def get_public_node(client: "TrezorClient", address: str, show_display: bool) -> callback=_list_units, expose_value=False, ) +@click.option("-C", "--chunkify", is_flag=True) @click.argument("to_address") @click.argument("amount", callback=_amount_to_int) @with_client @@ -364,6 +368,7 @@ def sign_tx( max_priority_fee: Optional[int], access_list: List[ethereum.messages.EthereumAccessList], eip2718_type: Optional[int], + chunkify: bool, ) -> str: """Sign (and optionally publish) Ethereum transaction. @@ -462,6 +467,7 @@ def sign_tx( max_priority_fee=max_priority_fee, access_list=access_list, definitions=defs, + chunkify=chunkify, ) else: if gas_price is None: @@ -479,6 +485,7 @@ def sign_tx( data=data_bytes, chain_id=chain_id, definitions=defs, + chunkify=chunkify, ) to = ethereum.decode_hex(to_address) diff --git a/python/src/trezorlib/cli/firmware.py b/python/src/trezorlib/cli/firmware.py index 7599dff8e..4035bd0c4 100644 --- a/python/src/trezorlib/cli/firmware.py +++ b/python/src/trezorlib/cli/firmware.py @@ -70,7 +70,7 @@ def print_firmware_version(fw: "firmware.FirmwareType") -> None: click.echo("Trezor One v2 firmware (1.8.0 or later)") _print_version(fw.header.version) elif isinstance(fw, firmware.VendorFirmware): - click.echo("Trezor T firmware image.") + click.echo(f"{fw.vendor_header.hw_model} firmware image.") vendor = fw.vendor_header.text vendor_version = "{}.{}".format(*fw.vendor_header.version) click.echo(f"Vendor header from {vendor}, version {vendor_version}") diff --git a/python/src/trezorlib/cli/monero.py b/python/src/trezorlib/cli/monero.py index d06fbc165..91311af6e 100644 --- a/python/src/trezorlib/cli/monero.py +++ b/python/src/trezorlib/cli/monero.py @@ -41,16 +41,18 @@ def cli() -> None: type=ChoiceType({m.name: m for m in messages.MoneroNetworkType}), default=messages.MoneroNetworkType.MAINNET, ) +@click.option("-C", "--chunkify", is_flag=True) @with_client def get_address( client: "TrezorClient", address: str, show_display: bool, network_type: messages.MoneroNetworkType, + chunkify: bool, ) -> bytes: """Get Monero address for specified path.""" address_n = tools.parse_path(address) - return monero.get_address(client, address_n, show_display, network_type) + return monero.get_address(client, address_n, show_display, network_type, chunkify) @cli.command() diff --git a/python/src/trezorlib/cli/nem.py b/python/src/trezorlib/cli/nem.py index 5facba725..9cf77a276 100644 --- a/python/src/trezorlib/cli/nem.py +++ b/python/src/trezorlib/cli/nem.py @@ -38,13 +38,18 @@ def cli() -> None: @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-N", "--network", type=int, default=0x68) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client def get_address( - client: "TrezorClient", address: str, network: int, show_display: bool + client: "TrezorClient", + address: str, + network: int, + show_display: bool, + chunkify: bool, ) -> str: """Get NEM address for specified path.""" address_n = tools.parse_path(address) - return nem.get_address(client, address_n, network, show_display) + return nem.get_address(client, address_n, network, show_display, chunkify) @cli.command() @@ -52,16 +57,21 @@ def get_address( @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-f", "--file", "_ignore", is_flag=True, hidden=True, expose_value=False) @click.option("-b", "--broadcast", help="NIS to announce transaction to") +@click.option("-C", "--chunkify", is_flag=True) @with_client def sign_tx( - client: "TrezorClient", address: str, file: TextIO, broadcast: Optional[str] + client: "TrezorClient", + address: str, + file: TextIO, + broadcast: Optional[str], + chunkify: bool, ) -> dict: """Sign (and optionally broadcast) NEM transaction. Transaction file is expected in the NIS (RequestPrepareAnnounce) format. """ address_n = tools.parse_path(address) - transaction = nem.sign_tx(client, address_n, json.load(file)) + transaction = nem.sign_tx(client, address_n, json.load(file), chunkify=chunkify) payload = {"data": transaction.data.hex(), "signature": transaction.signature.hex()} diff --git a/python/src/trezorlib/cli/ripple.py b/python/src/trezorlib/cli/ripple.py index 56206ae69..f710ac01c 100644 --- a/python/src/trezorlib/cli/ripple.py +++ b/python/src/trezorlib/cli/ripple.py @@ -36,24 +36,28 @@ def cli() -> None: @cli.command() @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def get_address(client: "TrezorClient", address: str, show_display: bool) -> str: +def get_address( + client: "TrezorClient", address: str, show_display: bool, chunkify: bool +) -> str: """Get Ripple address""" address_n = tools.parse_path(address) - return ripple.get_address(client, address_n, show_display) + return ripple.get_address(client, address_n, show_display, chunkify) @cli.command() @click.argument("file", type=click.File("r")) @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-f", "--file", "_ignore", is_flag=True, hidden=True, expose_value=False) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def sign_tx(client: "TrezorClient", address: str, file: TextIO) -> None: +def sign_tx(client: "TrezorClient", address: str, file: TextIO, chunkify: bool) -> None: """Sign Ripple transaction""" address_n = tools.parse_path(address) msg = ripple.create_sign_tx_msg(json.load(file)) - result = ripple.sign_tx(client, address_n, msg) + result = ripple.sign_tx(client, address_n, msg, chunkify=chunkify) click.echo("Signature:") click.echo(result.signature.hex()) click.echo() diff --git a/python/src/trezorlib/cli/stellar.py b/python/src/trezorlib/cli/stellar.py index f10454aed..1d56de2fb 100644 --- a/python/src/trezorlib/cli/stellar.py +++ b/python/src/trezorlib/cli/stellar.py @@ -51,11 +51,14 @@ def cli() -> None: default=stellar.DEFAULT_BIP32_PATH, ) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def get_address(client: "TrezorClient", address: str, show_display: bool) -> str: +def get_address( + client: "TrezorClient", address: str, show_display: bool, chunkify: bool +) -> str: """Get Stellar public address.""" address_n = tools.parse_path(address) - return stellar.get_address(client, address_n, show_display) + return stellar.get_address(client, address_n, show_display, chunkify) @cli.command() diff --git a/python/src/trezorlib/cli/tezos.py b/python/src/trezorlib/cli/tezos.py index 5e063c23a..45af6bafd 100644 --- a/python/src/trezorlib/cli/tezos.py +++ b/python/src/trezorlib/cli/tezos.py @@ -36,11 +36,14 @@ def cli() -> None: @cli.command() @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) @with_client -def get_address(client: "TrezorClient", address: str, show_display: bool) -> str: +def get_address( + client: "TrezorClient", address: str, show_display: bool, chunkify: bool +) -> str: """Get Tezos address for specified path.""" address_n = tools.parse_path(address) - return tezos.get_address(client, address_n, show_display) + return tezos.get_address(client, address_n, show_display, chunkify) @cli.command() @@ -57,11 +60,12 @@ def get_public_key(client: "TrezorClient", address: str, show_display: bool) -> @click.argument("file", type=click.File("r")) @click.option("-n", "--address", required=True, help=PATH_HELP) @click.option("-f", "--file", "_ignore", is_flag=True, hidden=True, expose_value=False) +@click.option("-C", "--chunkify", is_flag=True) @with_client def sign_tx( - client: "TrezorClient", address: str, file: TextIO + client: "TrezorClient", address: str, file: TextIO, chunkify: bool ) -> messages.TezosSignedTx: """Sign Tezos transaction.""" address_n = tools.parse_path(address) msg = protobuf.dict_to_proto(messages.TezosSignTx, json.load(file)) - return tezos.sign_tx(client, address_n, msg) + return tezos.sign_tx(client, address_n, msg, chunkify=chunkify) diff --git a/python/src/trezorlib/device.py b/python/src/trezorlib/device.py index 4ed5cbbfa..930b78ab3 100644 --- a/python/src/trezorlib/device.py +++ b/python/src/trezorlib/device.py @@ -265,3 +265,8 @@ def set_busy(client: "TrezorClient", expiry_ms: Optional[int]) -> "MessageType": ret = client.call(messages.SetBusy(expiry_ms=expiry_ms)) client.refresh_features() return ret + + +@expect(messages.AuthenticityProof) +def authenticate(client: "TrezorClient", challenge: bytes): + return client.call(messages.AuthenticateDevice(challenge=challenge)) diff --git a/python/src/trezorlib/eos.py b/python/src/trezorlib/eos.py index a56059087..1ffaafb4a 100644 --- a/python/src/trezorlib/eos.py +++ b/python/src/trezorlib/eos.py @@ -331,7 +331,11 @@ def get_public_key( @session def sign_tx( - client: "TrezorClient", address: "Address", transaction: dict, chain_id: str + client: "TrezorClient", + address: "Address", + transaction: dict, + chain_id: str, + chunkify: bool = False, ) -> messages.EosSignedTx: header, actions = parse_transaction_json(transaction) @@ -340,6 +344,7 @@ def sign_tx( chain_id=bytes.fromhex(chain_id), header=header, num_actions=len(actions), + chunkify=chunkify, ) response = client.call(msg) diff --git a/python/src/trezorlib/ethereum.py b/python/src/trezorlib/ethereum.py index adf4408ad..2dc9d9151 100644 --- a/python/src/trezorlib/ethereum.py +++ b/python/src/trezorlib/ethereum.py @@ -167,12 +167,14 @@ def get_address( n: "Address", show_display: bool = False, encoded_network: Optional[bytes] = None, + chunkify: bool = False, ) -> "MessageType": return client.call( messages.EthereumGetAddress( address_n=n, show_display=show_display, encoded_network=encoded_network, + chunkify=chunkify, ) ) @@ -199,6 +201,7 @@ def sign_tx( chain_id: Optional[int] = None, tx_type: Optional[int] = None, definitions: Optional[messages.EthereumDefinitions] = None, + chunkify: bool = False, ) -> Tuple[int, bytes, bytes]: if chain_id is None: raise exceptions.TrezorException("Chain ID cannot be undefined") @@ -213,6 +216,7 @@ def sign_tx( chain_id=chain_id, tx_type=tx_type, definitions=definitions, + chunkify=chunkify, ) if data is None: @@ -258,6 +262,7 @@ def sign_tx_eip1559( max_priority_fee: int, access_list: Optional[List[messages.EthereumAccessList]] = None, definitions: Optional[messages.EthereumDefinitions] = None, + chunkify: bool = False, ) -> Tuple[int, bytes, bytes]: length = len(data) data, chunk = data[1024:], data[:1024] @@ -274,6 +279,7 @@ def sign_tx_eip1559( data_length=length, data_initial_chunk=chunk, definitions=definitions, + chunkify=chunkify, ) response = client.call(msg) diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index e1b90f79a..adabfc2be 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -73,6 +73,8 @@ class MessageType(IntEnum): UnlockedPathRequest = 94 ShowDeviceTutorial = 95 UnlockBootloader = 96 + AuthenticateDevice = 97 + AuthenticityProof = 98 SetU2FCounter = 63 GetNextU2FCounter = 80 NextU2FCounter = 81 @@ -581,6 +583,7 @@ class BinanceGetAddress(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -588,9 +591,11 @@ class BinanceGetAddress(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class BinanceAddress(protobuf.MessageType): @@ -648,6 +653,7 @@ class BinanceSignTx(protobuf.MessageType): 5: protobuf.Field("memo", "string", repeated=False, required=False, default=None), 6: protobuf.Field("sequence", "sint64", repeated=False, required=True), 7: protobuf.Field("source", "sint64", repeated=False, required=True), + 8: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -660,6 +666,7 @@ class BinanceSignTx(protobuf.MessageType): address_n: Optional[Sequence["int"]] = None, chain_id: Optional["str"] = None, memo: Optional["str"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.msg_count = msg_count @@ -668,6 +675,7 @@ class BinanceSignTx(protobuf.MessageType): self.source = source self.chain_id = chain_id self.memo = memo + self.chunkify = chunkify class BinanceTxRequest(protobuf.MessageType): @@ -679,6 +687,7 @@ class BinanceTransferMsg(protobuf.MessageType): FIELDS = { 1: protobuf.Field("inputs", "BinanceInputOutput", repeated=True, required=False, default=None), 2: protobuf.Field("outputs", "BinanceInputOutput", repeated=True, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -686,9 +695,11 @@ class BinanceTransferMsg(protobuf.MessageType): *, inputs: Optional[Sequence["BinanceInputOutput"]] = None, outputs: Optional[Sequence["BinanceInputOutput"]] = None, + chunkify: Optional["bool"] = None, ) -> None: self.inputs: Sequence["BinanceInputOutput"] = inputs if inputs is not None else [] self.outputs: Sequence["BinanceInputOutput"] = outputs if outputs is not None else [] + self.chunkify = chunkify class BinanceOrderMsg(protobuf.MessageType): @@ -1042,6 +1053,7 @@ class GetAddress(protobuf.MessageType): 4: protobuf.Field("multisig", "MultisigRedeemScriptType", repeated=False, required=False, default=None), 5: protobuf.Field("script_type", "InputScriptType", repeated=False, required=False, default=InputScriptType.SPENDADDRESS), 6: protobuf.Field("ignore_xpub_magic", "bool", repeated=False, required=False, default=None), + 7: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -1053,6 +1065,7 @@ class GetAddress(protobuf.MessageType): multisig: Optional["MultisigRedeemScriptType"] = None, script_type: Optional["InputScriptType"] = InputScriptType.SPENDADDRESS, ignore_xpub_magic: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.coin_name = coin_name @@ -1060,6 +1073,7 @@ class GetAddress(protobuf.MessageType): self.multisig = multisig self.script_type = script_type self.ignore_xpub_magic = ignore_xpub_magic + self.chunkify = chunkify class Address(protobuf.MessageType): @@ -1199,6 +1213,7 @@ class SignTx(protobuf.MessageType): 12: protobuf.Field("decred_staking_ticket", "bool", repeated=False, required=False, default=False), 13: protobuf.Field("serialize", "bool", repeated=False, required=False, default=True), 14: protobuf.Field("coinjoin_request", "CoinJoinRequest", repeated=False, required=False, default=None), + 15: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -1218,6 +1233,7 @@ class SignTx(protobuf.MessageType): decred_staking_ticket: Optional["bool"] = False, serialize: Optional["bool"] = True, coinjoin_request: Optional["CoinJoinRequest"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.outputs_count = outputs_count self.inputs_count = inputs_count @@ -1233,6 +1249,7 @@ class SignTx(protobuf.MessageType): self.decred_staking_ticket = decred_staking_ticket self.serialize = serialize self.coinjoin_request = coinjoin_request + self.chunkify = chunkify class TxRequest(protobuf.MessageType): @@ -2238,6 +2255,7 @@ class CardanoGetAddress(protobuf.MessageType): 4: protobuf.Field("network_id", "uint32", repeated=False, required=True), 5: protobuf.Field("address_parameters", "CardanoAddressParametersType", repeated=False, required=True), 6: protobuf.Field("derivation_type", "CardanoDerivationType", repeated=False, required=True), + 7: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -2248,12 +2266,14 @@ class CardanoGetAddress(protobuf.MessageType): address_parameters: "CardanoAddressParametersType", derivation_type: "CardanoDerivationType", show_display: Optional["bool"] = False, + chunkify: Optional["bool"] = None, ) -> None: self.protocol_magic = protocol_magic self.network_id = network_id self.address_parameters = address_parameters self.derivation_type = derivation_type self.show_display = show_display + self.chunkify = chunkify class CardanoAddress(protobuf.MessageType): @@ -2331,6 +2351,7 @@ class CardanoSignTxInit(protobuf.MessageType): 19: protobuf.Field("has_collateral_return", "bool", repeated=False, required=False, default=False), 20: protobuf.Field("total_collateral", "uint64", repeated=False, required=False, default=None), 21: protobuf.Field("reference_inputs_count", "uint32", repeated=False, required=False, default=0), + 22: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -2357,6 +2378,7 @@ class CardanoSignTxInit(protobuf.MessageType): has_collateral_return: Optional["bool"] = False, total_collateral: Optional["int"] = None, reference_inputs_count: Optional["int"] = 0, + chunkify: Optional["bool"] = None, ) -> None: self.signing_mode = signing_mode self.protocol_magic = protocol_magic @@ -2379,6 +2401,7 @@ class CardanoSignTxInit(protobuf.MessageType): self.has_collateral_return = has_collateral_return self.total_collateral = total_collateral self.reference_inputs_count = reference_inputs_count + self.chunkify = chunkify class CardanoTxInput(protobuf.MessageType): @@ -3167,6 +3190,7 @@ class Features(protobuf.MessageType): 46: protobuf.Field("unit_btconly", "bool", repeated=False, required=False, default=None), 47: protobuf.Field("homescreen_width", "uint32", repeated=False, required=False, default=None), 48: protobuf.Field("homescreen_height", "uint32", repeated=False, required=False, default=None), + 49: protobuf.Field("bootloader_locked", "bool", repeated=False, required=False, default=None), } def __init__( @@ -3218,6 +3242,7 @@ class Features(protobuf.MessageType): unit_btconly: Optional["bool"] = None, homescreen_width: Optional["int"] = None, homescreen_height: Optional["int"] = None, + bootloader_locked: Optional["bool"] = None, ) -> None: self.capabilities: Sequence["Capability"] = capabilities if capabilities is not None else [] self.major_version = major_version @@ -3265,6 +3290,7 @@ class Features(protobuf.MessageType): self.unit_btconly = unit_btconly self.homescreen_width = homescreen_width self.homescreen_height = homescreen_height + self.bootloader_locked = bootloader_locked class LockDevice(protobuf.MessageType): @@ -3466,6 +3492,37 @@ class FirmwareHash(protobuf.MessageType): self.hash = hash +class AuthenticateDevice(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 97 + FIELDS = { + 1: protobuf.Field("challenge", "bytes", repeated=False, required=True), + } + + def __init__( + self, + *, + challenge: "bytes", + ) -> None: + self.challenge = challenge + + +class AuthenticityProof(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 98 + FIELDS = { + 1: protobuf.Field("certificates", "bytes", repeated=True, required=False, default=None), + 2: protobuf.Field("signature", "bytes", repeated=False, required=True), + } + + def __init__( + self, + *, + signature: "bytes", + certificates: Optional[Sequence["bytes"]] = None, + ) -> None: + self.certificates: Sequence["bytes"] = certificates if certificates is not None else [] + self.signature = signature + + class WipeDevice(protobuf.MessageType): MESSAGE_WIRE_TYPE = 5 @@ -4018,6 +4075,7 @@ class EosGetPublicKey(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -4025,9 +4083,11 @@ class EosGetPublicKey(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class EosPublicKey(protobuf.MessageType): @@ -4054,6 +4114,7 @@ class EosSignTx(protobuf.MessageType): 2: protobuf.Field("chain_id", "bytes", repeated=False, required=True), 3: protobuf.Field("header", "EosTxHeader", repeated=False, required=True), 4: protobuf.Field("num_actions", "uint32", repeated=False, required=True), + 5: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -4063,11 +4124,13 @@ class EosSignTx(protobuf.MessageType): header: "EosTxHeader", num_actions: "int", address_n: Optional[Sequence["int"]] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.chain_id = chain_id self.header = header self.num_actions = num_actions + self.chunkify = chunkify class EosTxActionRequest(protobuf.MessageType): @@ -4828,6 +4891,7 @@ class EthereumGetAddress(protobuf.MessageType): 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), 3: protobuf.Field("encoded_network", "bytes", repeated=False, required=False, default=None), + 4: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -4836,10 +4900,12 @@ class EthereumGetAddress(protobuf.MessageType): address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, encoded_network: Optional["bytes"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display self.encoded_network = encoded_network + self.chunkify = chunkify class EthereumAddress(protobuf.MessageType): @@ -4873,6 +4939,7 @@ class EthereumSignTx(protobuf.MessageType): 9: protobuf.Field("chain_id", "uint64", repeated=False, required=True), 10: protobuf.Field("tx_type", "uint32", repeated=False, required=False, default=None), 12: protobuf.Field("definitions", "EthereumDefinitions", repeated=False, required=False, default=None), + 13: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -4889,6 +4956,7 @@ class EthereumSignTx(protobuf.MessageType): data_length: Optional["int"] = 0, tx_type: Optional["int"] = None, definitions: Optional["EthereumDefinitions"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.gas_price = gas_price @@ -4901,6 +4969,7 @@ class EthereumSignTx(protobuf.MessageType): self.data_length = data_length self.tx_type = tx_type self.definitions = definitions + self.chunkify = chunkify class EthereumSignTxEIP1559(protobuf.MessageType): @@ -4918,6 +4987,7 @@ class EthereumSignTxEIP1559(protobuf.MessageType): 10: protobuf.Field("chain_id", "uint64", repeated=False, required=True), 11: protobuf.Field("access_list", "EthereumAccessList", repeated=True, required=False, default=None), 12: protobuf.Field("definitions", "EthereumDefinitions", repeated=False, required=False, default=None), + 13: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -4935,6 +5005,7 @@ class EthereumSignTxEIP1559(protobuf.MessageType): to: Optional["str"] = '', data_initial_chunk: Optional["bytes"] = b'', definitions: Optional["EthereumDefinitions"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.access_list: Sequence["EthereumAccessList"] = access_list if access_list is not None else [] @@ -4948,6 +5019,7 @@ class EthereumSignTxEIP1559(protobuf.MessageType): self.to = to self.data_initial_chunk = data_initial_chunk self.definitions = definitions + self.chunkify = chunkify class EthereumTxRequest(protobuf.MessageType): @@ -5209,6 +5281,7 @@ class MoneroGetAddress(protobuf.MessageType): 4: protobuf.Field("account", "uint32", repeated=False, required=False, default=None), 5: protobuf.Field("minor", "uint32", repeated=False, required=False, default=None), 6: protobuf.Field("payment_id", "bytes", repeated=False, required=False, default=None), + 7: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -5220,6 +5293,7 @@ class MoneroGetAddress(protobuf.MessageType): account: Optional["int"] = None, minor: Optional["int"] = None, payment_id: Optional["bytes"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display @@ -5227,6 +5301,7 @@ class MoneroGetAddress(protobuf.MessageType): self.account = account self.minor = minor self.payment_id = payment_id + self.chunkify = chunkify class MoneroAddress(protobuf.MessageType): @@ -5932,6 +6007,7 @@ class MoneroTransactionData(protobuf.MessageType): 13: protobuf.Field("client_version", "uint32", repeated=False, required=False, default=None), 14: protobuf.Field("hard_fork", "uint32", repeated=False, required=False, default=None), 15: protobuf.Field("monero_version", "bytes", repeated=False, required=False, default=None), + 16: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -5952,6 +6028,7 @@ class MoneroTransactionData(protobuf.MessageType): client_version: Optional["int"] = None, hard_fork: Optional["int"] = None, monero_version: Optional["bytes"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.outputs: Sequence["MoneroTransactionDestinationEntry"] = outputs if outputs is not None else [] self.minor_indices: Sequence["int"] = minor_indices if minor_indices is not None else [] @@ -5968,6 +6045,7 @@ class MoneroTransactionData(protobuf.MessageType): self.client_version = client_version self.hard_fork = hard_fork self.monero_version = monero_version + self.chunkify = chunkify class MoneroRingCtSig(protobuf.MessageType): @@ -6059,6 +6137,7 @@ class NEMGetAddress(protobuf.MessageType): 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("network", "uint32", repeated=False, required=False, default=104), 3: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 4: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -6067,10 +6146,12 @@ class NEMGetAddress(protobuf.MessageType): address_n: Optional[Sequence["int"]] = None, network: Optional["int"] = 104, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.network = network self.show_display = show_display + self.chunkify = chunkify class NEMAddress(protobuf.MessageType): @@ -6099,6 +6180,7 @@ class NEMSignTx(protobuf.MessageType): 7: protobuf.Field("supply_change", "NEMMosaicSupplyChange", repeated=False, required=False, default=None), 8: protobuf.Field("aggregate_modification", "NEMAggregateModification", repeated=False, required=False, default=None), 9: protobuf.Field("importance_transfer", "NEMImportanceTransfer", repeated=False, required=False, default=None), + 10: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -6113,6 +6195,7 @@ class NEMSignTx(protobuf.MessageType): supply_change: Optional["NEMMosaicSupplyChange"] = None, aggregate_modification: Optional["NEMAggregateModification"] = None, importance_transfer: Optional["NEMImportanceTransfer"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.transaction = transaction self.multisig = multisig @@ -6123,6 +6206,7 @@ class NEMSignTx(protobuf.MessageType): self.supply_change = supply_change self.aggregate_modification = aggregate_modification self.importance_transfer = importance_transfer + self.chunkify = chunkify class NEMSignedTx(protobuf.MessageType): @@ -6432,6 +6516,7 @@ class RippleGetAddress(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -6439,9 +6524,11 @@ class RippleGetAddress(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class RippleAddress(protobuf.MessageType): @@ -6467,6 +6554,7 @@ class RippleSignTx(protobuf.MessageType): 4: protobuf.Field("sequence", "uint32", repeated=False, required=True), 5: protobuf.Field("last_ledger_sequence", "uint32", repeated=False, required=False, default=None), 6: protobuf.Field("payment", "RipplePayment", repeated=False, required=True), + 7: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -6478,6 +6566,7 @@ class RippleSignTx(protobuf.MessageType): address_n: Optional[Sequence["int"]] = None, flags: Optional["int"] = 0, last_ledger_sequence: Optional["int"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.fee = fee @@ -6485,6 +6574,7 @@ class RippleSignTx(protobuf.MessageType): self.payment = payment self.flags = flags self.last_ledger_sequence = last_ledger_sequence + self.chunkify = chunkify class RippleSignedTx(protobuf.MessageType): @@ -6549,6 +6639,7 @@ class StellarGetAddress(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -6556,9 +6647,11 @@ class StellarGetAddress(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class StellarAddress(protobuf.MessageType): @@ -6995,6 +7088,7 @@ class TezosGetAddress(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -7002,9 +7096,11 @@ class TezosGetAddress(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class TezosAddress(protobuf.MessageType): @@ -7026,6 +7122,7 @@ class TezosGetPublicKey(protobuf.MessageType): FIELDS = { 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -7033,9 +7130,11 @@ class TezosGetPublicKey(protobuf.MessageType): *, address_n: Optional[Sequence["int"]] = None, show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.show_display = show_display + self.chunkify = chunkify class TezosPublicKey(protobuf.MessageType): @@ -7063,6 +7162,7 @@ class TezosSignTx(protobuf.MessageType): 6: protobuf.Field("delegation", "TezosDelegationOp", repeated=False, required=False, default=None), 7: protobuf.Field("proposal", "TezosProposalOp", repeated=False, required=False, default=None), 8: protobuf.Field("ballot", "TezosBallotOp", repeated=False, required=False, default=None), + 9: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), } def __init__( @@ -7076,6 +7176,7 @@ class TezosSignTx(protobuf.MessageType): delegation: Optional["TezosDelegationOp"] = None, proposal: Optional["TezosProposalOp"] = None, ballot: Optional["TezosBallotOp"] = None, + chunkify: Optional["bool"] = None, ) -> None: self.address_n: Sequence["int"] = address_n if address_n is not None else [] self.branch = branch @@ -7085,6 +7186,7 @@ class TezosSignTx(protobuf.MessageType): self.delegation = delegation self.proposal = proposal self.ballot = ballot + self.chunkify = chunkify class TezosSignedTx(protobuf.MessageType): diff --git a/python/src/trezorlib/monero.py b/python/src/trezorlib/monero.py index dbb65aa20..5bce7574e 100644 --- a/python/src/trezorlib/monero.py +++ b/python/src/trezorlib/monero.py @@ -37,10 +37,14 @@ def get_address( n: "Address", show_display: bool = False, network_type: messages.MoneroNetworkType = messages.MoneroNetworkType.MAINNET, + chunkify: bool = False, ) -> "MessageType": return client.call( messages.MoneroGetAddress( - address_n=n, show_display=show_display, network_type=network_type + address_n=n, + show_display=show_display, + network_type=network_type, + chunkify=chunkify, ) ) diff --git a/python/src/trezorlib/nem.py b/python/src/trezorlib/nem.py index 9b948992d..3a67aec72 100644 --- a/python/src/trezorlib/nem.py +++ b/python/src/trezorlib/nem.py @@ -174,10 +174,11 @@ def fill_transaction_by_type(msg: messages.NEMSignTx, transaction: dict) -> None raise ValueError("Unknown transaction type") -def create_sign_tx(transaction: dict) -> messages.NEMSignTx: +def create_sign_tx(transaction: dict, chunkify: bool = False) -> messages.NEMSignTx: msg = messages.NEMSignTx( transaction=create_transaction_common(transaction), cosigning=transaction["type"] == TYPE_MULTISIG_SIGNATURE, + chunkify=chunkify, ) if transaction["type"] in (TYPE_MULTISIG_SIGNATURE, TYPE_MULTISIG): @@ -197,17 +198,25 @@ def create_sign_tx(transaction: dict) -> messages.NEMSignTx: @expect(messages.NEMAddress, field="address", ret_type=str) def get_address( - client: "TrezorClient", n: "Address", network: int, show_display: bool = False + client: "TrezorClient", + n: "Address", + network: int, + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.NEMGetAddress(address_n=n, network=network, show_display=show_display) + messages.NEMGetAddress( + address_n=n, network=network, show_display=show_display, chunkify=chunkify + ) ) @expect(messages.NEMSignedTx) -def sign_tx(client: "TrezorClient", n: "Address", transaction: dict) -> "MessageType": +def sign_tx( + client: "TrezorClient", n: "Address", transaction: dict, chunkify: bool = False +) -> "MessageType": try: - msg = create_sign_tx(transaction) + msg = create_sign_tx(transaction, chunkify=chunkify) except ValueError as e: raise exceptions.TrezorException("Failed to encode transaction") from e diff --git a/python/src/trezorlib/ripple.py b/python/src/trezorlib/ripple.py index 534d4c502..7a953b8fa 100644 --- a/python/src/trezorlib/ripple.py +++ b/python/src/trezorlib/ripple.py @@ -31,18 +31,27 @@ REQUIRED_PAYMENT_FIELDS = ("Amount", "Destination") @expect(messages.RippleAddress, field="address", ret_type=str) def get_address( - client: "TrezorClient", address_n: "Address", show_display: bool = False + client: "TrezorClient", + address_n: "Address", + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.RippleGetAddress(address_n=address_n, show_display=show_display) + messages.RippleGetAddress( + address_n=address_n, show_display=show_display, chunkify=chunkify + ) ) @expect(messages.RippleSignedTx) def sign_tx( - client: "TrezorClient", address_n: "Address", msg: messages.RippleSignTx + client: "TrezorClient", + address_n: "Address", + msg: messages.RippleSignTx, + chunkify: bool = False, ) -> "MessageType": msg.address_n = address_n + msg.chunkify = chunkify return client.call(msg) diff --git a/python/src/trezorlib/stellar.py b/python/src/trezorlib/stellar.py index 0670ac755..27b988dce 100644 --- a/python/src/trezorlib/stellar.py +++ b/python/src/trezorlib/stellar.py @@ -324,10 +324,15 @@ def _read_asset(asset: "Asset") -> messages.StellarAsset: @expect(messages.StellarAddress, field="address", ret_type=str) def get_address( - client: "TrezorClient", address_n: "Address", show_display: bool = False + client: "TrezorClient", + address_n: "Address", + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.StellarGetAddress(address_n=address_n, show_display=show_display) + messages.StellarGetAddress( + address_n=address_n, show_display=show_display, chunkify=chunkify + ) ) diff --git a/python/src/trezorlib/tezos.py b/python/src/trezorlib/tezos.py index 89b1b4fef..cff06ed6c 100644 --- a/python/src/trezorlib/tezos.py +++ b/python/src/trezorlib/tezos.py @@ -27,25 +27,39 @@ if TYPE_CHECKING: @expect(messages.TezosAddress, field="address", ret_type=str) def get_address( - client: "TrezorClient", address_n: "Address", show_display: bool = False + client: "TrezorClient", + address_n: "Address", + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.TezosGetAddress(address_n=address_n, show_display=show_display) + messages.TezosGetAddress( + address_n=address_n, show_display=show_display, chunkify=chunkify + ) ) @expect(messages.TezosPublicKey, field="public_key", ret_type=str) def get_public_key( - client: "TrezorClient", address_n: "Address", show_display: bool = False + client: "TrezorClient", + address_n: "Address", + show_display: bool = False, + chunkify: bool = False, ) -> "MessageType": return client.call( - messages.TezosGetPublicKey(address_n=address_n, show_display=show_display) + messages.TezosGetPublicKey( + address_n=address_n, show_display=show_display, chunkify=chunkify + ) ) @expect(messages.TezosSignedTx) def sign_tx( - client: "TrezorClient", address_n: "Address", sign_tx_msg: messages.TezosSignTx + client: "TrezorClient", + address_n: "Address", + sign_tx_msg: messages.TezosSignTx, + chunkify: bool = False, ) -> "MessageType": sign_tx_msg.address_n = address_n + sign_tx_msg.chunkify = chunkify return client.call(sign_tx_msg) diff --git a/tests/click_tests/common.py b/tests/click_tests/common.py index e34103c04..4765a8835 100644 --- a/tests/click_tests/common.py +++ b/tests/click_tests/common.py @@ -51,11 +51,16 @@ def go_next(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None: raise RuntimeError("Unknown model") -def go_back(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None: +def go_back( + debug: "DebugLink", wait: bool = False, r_middle: bool = False +) -> "LayoutContent" | None: if debug.model == "T": return debug.click(buttons.CANCEL, wait=wait) # type: ignore elif debug.model == "R": - return debug.press_left(wait=wait) # type: ignore + if r_middle: + return debug.press_middle(wait=wait) # type: ignore + else: + return debug.press_left(wait=wait) # type: ignore else: raise RuntimeError("Unknown model") diff --git a/tests/click_tests/test_pin.py b/tests/click_tests/test_pin.py index 2c048677c..ca6f99fa4 100644 --- a/tests/click_tests/test_pin.py +++ b/tests/click_tests/test_pin.py @@ -311,4 +311,4 @@ def test_pin_same_as_wipe_code(device_handler: "BackgroundDeviceHandler"): _enter_two_times(debug, "1", "1") with PIN_INVALID, prepare(device_handler, Situation.PIN_SETUP) as debug: _enter_two_times(debug, "1", "1") - go_back(debug) + go_back(debug, r_middle=True) diff --git a/tests/common.py b/tests/common.py index fb37e6973..4379aad56 100644 --- a/tests/common.py +++ b/tests/common.py @@ -263,3 +263,14 @@ def get_test_address(client: "Client") -> str: """Fetch a testnet address on a fixed path. Useful to make a pin/passphrase protected call, or to identify the root secret (seed+passphrase)""" return btc.get_address(client, "Testnet", TEST_ADDRESS_N) + + +def compact_size(n) -> bytes: + if n < 253: + return n.to_bytes(1, "little") + elif n < 0x1_0000: + return bytes([253]) + n.to_bytes(2, "little") + elif n < 0x1_0000_0000: + return bytes([254]) + n.to_bytes(4, "little") + else: + return bytes([255]) + n.to_bytes(8, "little") diff --git a/tests/device_tests/binance/test_get_address.py b/tests/device_tests/binance/test_get_address.py index 28aac5c81..612e50c53 100644 --- a/tests/device_tests/binance/test_get_address.py +++ b/tests/device_tests/binance/test_get_address.py @@ -32,9 +32,14 @@ BINANCE_ADDRESS_TEST_VECTORS = [ @pytest.mark.setup_client( mnemonic="offer caution gift cross surge pretty orange during eye soldier popular holiday mention east eight office fashion ill parrot vault rent devote earth cousin" ) +@pytest.mark.parametrize("chunkify", (True, False)) @pytest.mark.parametrize("path, expected_address", BINANCE_ADDRESS_TEST_VECTORS) -def test_binance_get_address(client: Client, path, expected_address): +def test_binance_get_address( + client: Client, chunkify: bool, path: str, expected_address: str +): # data from https://github.com/binance-chain/javascript-sdk/blob/master/__tests__/crypto.test.js#L50 - address = get_address(client, parse_path(path), show_display=True) + address = get_address( + client, parse_path(path), show_display=True, chunkify=chunkify + ) assert address == expected_address diff --git a/tests/device_tests/binance/test_get_public_key.py b/tests/device_tests/binance/test_get_public_key.py index 08e75f5da..add82eb6d 100644 --- a/tests/device_tests/binance/test_get_public_key.py +++ b/tests/device_tests/binance/test_get_public_key.py @@ -20,6 +20,8 @@ from trezorlib import binance from trezorlib.debuglink import TrezorClientDebugLink as Client from trezorlib.tools import parse_path +from ...input_flows import InputFlowShowXpubQRCode + BINANCE_PATH = parse_path("m/44h/714h/0h/0/0") @@ -30,8 +32,11 @@ BINANCE_PATH = parse_path("m/44h/714h/0h/0/0") mnemonic="offer caution gift cross surge pretty orange during eye soldier popular holiday mention east eight office fashion ill parrot vault rent devote earth cousin" ) def test_binance_get_public_key(client: Client): - sig = binance.get_public_key(client, BINANCE_PATH, show_display=True) - assert ( - sig.hex() - == "029729a52e4e3c2b4a4e52aa74033eedaf8ba1df5ab6d1f518fd69e67bbd309b0e" - ) + with client: + IF = InputFlowShowXpubQRCode(client) + client.set_input_flow(IF.get()) + sig = binance.get_public_key(client, BINANCE_PATH, show_display=True) + assert ( + sig.hex() + == "029729a52e4e3c2b4a4e52aa74033eedaf8ba1df5ab6d1f518fd69e67bbd309b0e" + ) diff --git a/tests/device_tests/binance/test_sign_tx.py b/tests/device_tests/binance/test_sign_tx.py index 25b0dff99..05dcacc4d 100644 --- a/tests/device_tests/binance/test_sign_tx.py +++ b/tests/device_tests/binance/test_sign_tx.py @@ -108,8 +108,13 @@ BINANCE_TEST_VECTORS = [ mnemonic="offer caution gift cross surge pretty orange during eye soldier popular holiday mention east eight office fashion ill parrot vault rent devote earth cousin" ) @pytest.mark.parametrize("message, expected_response", BINANCE_TEST_VECTORS) -def test_binance_sign_message(client: Client, message, expected_response): - response = binance.sign_tx(client, parse_path("m/44h/714h/0h/0/0"), message) +@pytest.mark.parametrize("chunkify", (True, False)) +def test_binance_sign_message( + client: Client, chunkify: bool, message: dict, expected_response: dict +): + response = binance.sign_tx( + client, parse_path("m/44h/714h/0h/0/0"), message, chunkify=chunkify + ) assert response.public_key.hex() == expected_response["public_key"] diff --git a/tests/device_tests/bitcoin/payment_req.py b/tests/device_tests/bitcoin/payment_req.py index 9ab2d4dad..5d987706d 100644 --- a/tests/device_tests/bitcoin/payment_req.py +++ b/tests/device_tests/bitcoin/payment_req.py @@ -5,6 +5,8 @@ from ecdsa import ECDH, SECP256k1, SigningKey from trezorlib import btc, messages +from ...common import compact_size + SLIP44 = 1 # Testnet TextMemo = namedtuple("TextMemo", "text") @@ -20,13 +22,7 @@ payment_req_signer = SigningKey.from_string( def hash_bytes_prefixed(hasher, data): - n = len(data) - if n < 253: - hasher.update(n.to_bytes(1, "little")) - elif n < 0x1_0000: - hasher.update(bytes([253])) - hasher.update(n.to_bytes(2, "little")) - + hasher.update(compact_size(len(data))) hasher.update(data) diff --git a/tests/device_tests/bitcoin/test_authorize_coinjoin.py b/tests/device_tests/bitcoin/test_authorize_coinjoin.py index 687c08025..e1cff4ec1 100644 --- a/tests/device_tests/bitcoin/test_authorize_coinjoin.py +++ b/tests/device_tests/bitcoin/test_authorize_coinjoin.py @@ -56,8 +56,9 @@ ROUND_ID_LEN = 32 SLIP25_PATH = parse_path("m/10025h") +@pytest.mark.parametrize("chunkify", (True, False)) @pytest.mark.setup_client(pin=PIN) -def test_sign_tx(client: Client): +def test_sign_tx(client: Client, chunkify: bool): # NOTE: FAKE input tx commitment_data = b"\x0fwww.example.com" + (1).to_bytes(ROUND_ID_LEN, "big") @@ -228,6 +229,7 @@ def test_sign_tx(client: Client): coinjoin_request=coinjoin_req, preauthorized=True, serialize=False, + chunkify=chunkify, ) assert serialized_tx == b"" @@ -247,6 +249,7 @@ def test_sign_tx(client: Client): prev_txes=TX_CACHE_TESTNET, coinjoin_request=coinjoin_req, preauthorized=True, + chunkify=chunkify, ) # Test for a third time, number of rounds should be exceeded. @@ -259,6 +262,7 @@ def test_sign_tx(client: Client): prev_txes=TX_CACHE_TESTNET, coinjoin_request=coinjoin_req, preauthorized=True, + chunkify=chunkify, ) @@ -449,7 +453,7 @@ def test_sign_tx_spend(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ messages.ButtonRequest(code=B.Other), @@ -458,7 +462,7 @@ def test_sign_tx_spend(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), @@ -524,7 +528,7 @@ def test_sign_tx_migration(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ messages.ButtonRequest(code=B.Other), @@ -533,7 +537,7 @@ def test_sign_tx_migration(client: Client): request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_2cc3c1), @@ -728,16 +732,18 @@ def test_get_address(client: Client): unlock_path_mac = device.unlock_path(client, SLIP25_PATH) # Ensure that the SLIP-0025 external chain is accessible after user confirmation. - resp = btc.get_address( - client, - "Testnet", - parse_path("m/10025h/1h/0h/1h/0/0"), - script_type=messages.InputScriptType.SPENDTAPROOT, - show_display=True, - unlock_path=SLIP25_PATH, - unlock_path_mac=unlock_path_mac, - ) - assert resp == "tb1pl3y9gf7xk2ryvmav5ar66ra0d2hk7lhh9mmusx3qvn0n09kmaghqh32ru7" + for chunkify in (True, False): + resp = btc.get_address( + client, + "Testnet", + parse_path("m/10025h/1h/0h/1h/0/0"), + script_type=messages.InputScriptType.SPENDTAPROOT, + show_display=True, + unlock_path=SLIP25_PATH, + unlock_path_mac=unlock_path_mac, + chunkify=chunkify, + ) + assert resp == "tb1pl3y9gf7xk2ryvmav5ar66ra0d2hk7lhh9mmusx3qvn0n09kmaghqh32ru7" resp = btc.get_address( client, diff --git a/tests/device_tests/bitcoin/test_bcash.py b/tests/device_tests/bitcoin/test_bcash.py index 08b74d2db..7f1fe78b5 100644 --- a/tests/device_tests/bitcoin/test_bcash.py +++ b/tests/device_tests/bitcoin/test_bcash.py @@ -72,14 +72,14 @@ def test_send_bch_change(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_bc37c2), @@ -125,14 +125,14 @@ def test_send_bch_nochange(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_502e85), @@ -184,14 +184,14 @@ def test_send_bch_oldaddr(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_502e85), @@ -255,7 +255,7 @@ def test_attack_change_input(client: Client): return msg with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses( [ @@ -263,7 +263,7 @@ def test_attack_change_input(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_bd32ff), @@ -331,13 +331,13 @@ def test_send_bch_multisig_wrongchange(client: Client): amount=23_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_062fbd), @@ -400,13 +400,13 @@ def test_send_bch_multisig_change(client: Client): amount=24_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -445,7 +445,7 @@ def test_send_bch_multisig_change(client: Client): request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -502,14 +502,14 @@ def test_send_bch_external_presigned(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_502e85), diff --git a/tests/device_tests/bitcoin/test_bgold.py b/tests/device_tests/bitcoin/test_bgold.py index f5aeb30b5..10bb18bb8 100644 --- a/tests/device_tests/bitcoin/test_bgold.py +++ b/tests/device_tests/bitcoin/test_bgold.py @@ -46,7 +46,7 @@ FAKE_TXHASH_a63dbe = bytes.fromhex( "a63dbedd8cd284bf0d3c468e84b9b0eeb14c3a08824eab8f80e7723a299f30db" ) -pytestmark = pytest.mark.altcoin +pytestmark = [pytest.mark.altcoin, pytest.mark.skip_tr] # All data taken from T1 @@ -71,14 +71,14 @@ def test_send_bitcoin_gold_change(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_6f0398), @@ -125,14 +125,14 @@ def test_send_bitcoin_gold_nochange(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_6f0398), @@ -195,7 +195,7 @@ def test_attack_change_input(client: Client): return msg with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses( [ @@ -203,7 +203,7 @@ def test_attack_change_input(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_6f0398), @@ -257,13 +257,13 @@ def test_send_btg_multisig_change(client: Client): amount=1_252_382_934 - 24_000 - 1_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -302,7 +302,7 @@ def test_send_btg_multisig_change(client: Client): request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -351,16 +351,16 @@ def test_send_p2sh(client: Client): amount=1_252_382_934 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_db7239), @@ -405,13 +405,13 @@ def test_send_p2sh_witness_change(client: Client): amount=1_252_382_934 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -466,13 +466,13 @@ def test_send_multisig_1(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_7f1f6b), @@ -495,7 +495,7 @@ def test_send_multisig_1(client: Client): request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_7f1f6b), @@ -584,14 +584,14 @@ def test_send_btg_external_presigned(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_6f0398), diff --git a/tests/device_tests/bitcoin/test_dash.py b/tests/device_tests/bitcoin/test_dash.py index 21fbc3ef9..1f6441d19 100644 --- a/tests/device_tests/bitcoin/test_dash.py +++ b/tests/device_tests/bitcoin/test_dash.py @@ -39,7 +39,7 @@ TXHASH_15575a = bytes.fromhex( "15575a1c874bd60a819884e116c42e6791c8283ce1fc3b79f0d18531a61bbb8a" ) -pytestmark = pytest.mark.altcoin +pytestmark = [pytest.mark.altcoin, pytest.mark.skip_tr] def test_send_dash(client: Client): @@ -57,13 +57,13 @@ def test_send_dash(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(inp1.prev_hash), @@ -105,14 +105,14 @@ def test_send_dash_dip2_input(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(inp1.prev_hash), diff --git a/tests/device_tests/bitcoin/test_decred.py b/tests/device_tests/bitcoin/test_decred.py index 8f6de14bb..b762498db 100644 --- a/tests/device_tests/bitcoin/test_decred.py +++ b/tests/device_tests/bitcoin/test_decred.py @@ -49,7 +49,7 @@ FAKE_TXHASH_51bc9c = bytes.fromhex( "51bc9c71f10a81eef3caedb5333062eb4b1f70998adf02916fe98fdc04c572e8" ) -pytestmark = [pytest.mark.altcoin, pytest.mark.decred] +pytestmark = [pytest.mark.altcoin, pytest.mark.decred, pytest.mark.skip_tr] def test_send_decred(client: Client): @@ -72,13 +72,13 @@ def test_send_decred(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.FeeOverThreshold), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -194,14 +194,14 @@ def test_spend_from_stake_generation_and_revocation_decred(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_f8e2f2), @@ -276,7 +276,7 @@ def test_send_decred_change(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), @@ -284,7 +284,7 @@ def test_send_decred_change(client: Client): request_input(2), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -383,7 +383,7 @@ def test_decred_multisig_change(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), @@ -391,7 +391,7 @@ def test_decred_multisig_change(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_9ac7d2), diff --git a/tests/device_tests/bitcoin/test_descriptors.py b/tests/device_tests/bitcoin/test_descriptors.py index 24a3dc27d..a89289b61 100644 --- a/tests/device_tests/bitcoin/test_descriptors.py +++ b/tests/device_tests/bitcoin/test_descriptors.py @@ -20,6 +20,8 @@ from trezorlib import messages from trezorlib.cli import btc from trezorlib.debuglink import TrezorClientDebugLink as Client +from ...input_flows import InputFlowShowXpubQRCode + VECTORS_DESCRIPTORS = ( # coin, account, script_type, descriptors ( "Bitcoin", @@ -154,7 +156,11 @@ VECTORS_DESCRIPTORS = ( # coin, account, script_type, descriptors "coin, account, purpose, script_type, descriptors", VECTORS_DESCRIPTORS ) def test_descriptors(client: Client, coin, account, purpose, script_type, descriptors): - res = btc._get_descriptor( - client, coin, account, purpose, script_type, show_display=True - ) - assert res == descriptors + with client: + if client.features.model != "1": + IF = InputFlowShowXpubQRCode(client) + client.set_input_flow(IF.get()) + res = btc._get_descriptor( + client, coin, account, purpose, script_type, show_display=True + ) + assert res == descriptors diff --git a/tests/device_tests/bitcoin/test_getaddress_segwit_native.py b/tests/device_tests/bitcoin/test_getaddress_segwit_native.py index ae6f3eda0..f14163005 100644 --- a/tests/device_tests/bitcoin/test_getaddress_segwit_native.py +++ b/tests/device_tests/bitcoin/test_getaddress_segwit_native.py @@ -140,7 +140,14 @@ BIP86_VECTORS = ( # path, address for "abandon ... abandon about" seed @pytest.mark.parametrize("show_display", (True, False)) @pytest.mark.parametrize("coin, path, script_type, address", VECTORS) -def test_show_segwit(client: Client, show_display, coin, path, script_type, address): +def test_show_segwit( + client: Client, + show_display: bool, + coin: str, + path: str, + script_type: messages.InputScriptType, + address: str, +): assert ( btc.get_address( client, @@ -159,7 +166,7 @@ def test_show_segwit(client: Client, show_display, coin, path, script_type, addr mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" ) @pytest.mark.parametrize("path, address", BIP86_VECTORS) -def test_bip86(client: Client, path, address): +def test_bip86(client: Client, path: str, address: str): assert ( btc.get_address( client, @@ -214,7 +221,7 @@ def test_show_multisig_3(client: Client): @pytest.mark.multisig @pytest.mark.parametrize("show_display", (True, False)) -def test_multisig_missing(client: Client, show_display): +def test_multisig_missing(client: Client, show_display: bool): # Multisig with global suffix specification. # Use account numbers 1, 2 and 3 to create a valid multisig, # but not containing the keys from account 0 used below. diff --git a/tests/device_tests/bitcoin/test_getaddress_show.py b/tests/device_tests/bitcoin/test_getaddress_show.py index c017298f5..8b251dd82 100644 --- a/tests/device_tests/bitcoin/test_getaddress_show.py +++ b/tests/device_tests/bitcoin/test_getaddress_show.py @@ -78,9 +78,14 @@ def test_show_t1( @pytest.mark.skip_t1 +@pytest.mark.parametrize("chunkify", (True, False)) @pytest.mark.parametrize("path, script_type, address", VECTORS) def test_show_tt( - client: Client, path: str, script_type: messages.InputScriptType, address: str + client: Client, + chunkify: bool, + path: str, + script_type: messages.InputScriptType, + address: str, ): with client: IF = InputFlowShowAddressQRCode(client) @@ -92,6 +97,7 @@ def test_show_tt( tools.parse_path(path), script_type=script_type, show_display=True, + chunkify=chunkify, ) == address ) diff --git a/tests/device_tests/bitcoin/test_getpublickey.py b/tests/device_tests/bitcoin/test_getpublickey.py index ad51307c8..199a20615 100644 --- a/tests/device_tests/bitcoin/test_getpublickey.py +++ b/tests/device_tests/bitcoin/test_getpublickey.py @@ -22,6 +22,7 @@ from trezorlib.exceptions import TrezorFailure from trezorlib.tools import parse_path from ... import bip32 +from ...input_flows import InputFlowShowXpubQRCode VECTORS_BITCOIN = ( # coin_name, xpub_magic, path, xpub ( @@ -115,6 +116,17 @@ def test_get_public_node(client: Client, coin_name, xpub_magic, path, xpub): assert bip32.serialize(res.node, xpub_magic) == xpub +@pytest.mark.skip_t1 +@pytest.mark.parametrize("coin_name, xpub_magic, path, xpub", VECTORS_BITCOIN) +def test_get_public_node_show(client: Client, coin_name, xpub_magic, path, xpub): + with client: + IF = InputFlowShowXpubQRCode(client) + client.set_input_flow(IF.get()) + res = btc.get_public_node(client, path, coin_name=coin_name, show_display=True) + assert res.xpub == xpub + assert bip32.serialize(res.node, xpub_magic) == xpub + + @pytest.mark.xfail(reason="Currently path validation on get_public_node is disabled.") @pytest.mark.parametrize("coin_name, path", VECTORS_INVALID) def test_invalid_path(client: Client, coin_name, path): diff --git a/tests/device_tests/bitcoin/test_komodo.py b/tests/device_tests/bitcoin/test_komodo.py index 26c1de6eb..dccfea95a 100644 --- a/tests/device_tests/bitcoin/test_komodo.py +++ b/tests/device_tests/bitcoin/test_komodo.py @@ -61,13 +61,13 @@ def test_one_one_fee_sapling(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -126,16 +126,16 @@ def test_one_one_rewards_claim(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), messages.ButtonRequest(code=B.SignTx), request_input(0), diff --git a/tests/device_tests/bitcoin/test_multisig.py b/tests/device_tests/bitcoin/test_multisig.py index b61f4d926..abfe61641 100644 --- a/tests/device_tests/bitcoin/test_multisig.py +++ b/tests/device_tests/bitcoin/test_multisig.py @@ -52,7 +52,8 @@ pytestmark = pytest.mark.multisig @pytest.mark.multisig -def test_2_of_3(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_2_of_3(client: Client, chunkify: bool): # input tx: 6b07c1321b52d9c85743f9695e13eb431b41708cdf4e1585258d51208e5b93fc nodes = [ @@ -82,12 +83,12 @@ def test_2_of_3(client: Client): ) # Expected responses are the same for both two signings - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_6b07c1), @@ -104,7 +105,12 @@ def test_2_of_3(client: Client): # Now we have first signature signatures1, _ = btc.sign_tx( - client, "Testnet", [inp1], [out1], prev_txes=TX_API_TESTNET + client, + "Testnet", + [inp1], + [out1], + prev_txes=TX_API_TESTNET, + chunkify=chunkify, ) assert ( diff --git a/tests/device_tests/bitcoin/test_multisig_change.py b/tests/device_tests/bitcoin/test_multisig_change.py index d2fcd0d35..6e155babb 100644 --- a/tests/device_tests/bitcoin/test_multisig_change.py +++ b/tests/device_tests/bitcoin/test_multisig_change.py @@ -145,7 +145,7 @@ def _responses( change: int = 0, foreign: bool = False, ): - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") resp = [ request_input(0), request_input(1), @@ -154,7 +154,7 @@ def _responses( if change != 1: resp.append(messages.ButtonRequest(code=B.ConfirmOutput)) - if tt: + if is_core: resp.append(messages.ButtonRequest(code=B.ConfirmOutput)) elif foreign: resp.append(messages.ButtonRequest(code=B.UnknownDerivationPath)) @@ -163,7 +163,7 @@ def _responses( if change != 2: resp.append(messages.ButtonRequest(code=B.ConfirmOutput)) - if tt: + if is_core: resp.append(messages.ButtonRequest(code=B.ConfirmOutput)) elif foreign: resp.append(messages.ButtonRequest(code=B.UnknownDerivationPath)) diff --git a/tests/device_tests/bitcoin/test_nonstandard_paths.py b/tests/device_tests/bitcoin/test_nonstandard_paths.py index 38ce879f4..8aa0e038c 100644 --- a/tests/device_tests/bitcoin/test_nonstandard_paths.py +++ b/tests/device_tests/bitcoin/test_nonstandard_paths.py @@ -93,7 +93,9 @@ VECTORS_MULTISIG = ( # paths, address_index # Has AlwaysMatchingSchema but let's make sure the nonstandard paths are # accepted in case we make this more restrictive in the future. @pytest.mark.parametrize("path, script_types", VECTORS) -def test_getpublicnode(client: Client, path, script_types): +def test_getpublicnode( + client: Client, path: str, script_types: list[messages.InputScriptType] +): for script_type in script_types: res = btc.get_public_node( client, parse_path(path), coin_name="Bitcoin", script_type=script_type @@ -102,8 +104,14 @@ def test_getpublicnode(client: Client, path, script_types): assert res.xpub +@pytest.mark.parametrize("chunkify", (True, False)) @pytest.mark.parametrize("path, script_types", VECTORS) -def test_getaddress(client: Client, path, script_types): +def test_getaddress( + client: Client, + chunkify: bool, + path: str, + script_types: list[messages.InputScriptType], +): for script_type in script_types: res = btc.get_address( client, @@ -111,13 +119,16 @@ def test_getaddress(client: Client, path, script_types): parse_path(path), show_display=True, script_type=script_type, + chunkify=chunkify, ) assert res @pytest.mark.parametrize("path, script_types", VECTORS) -def test_signmessage(client: Client, path, script_types): +def test_signmessage( + client: Client, path: str, script_types: list[messages.InputScriptType] +): for script_type in script_types: sig = btc.sign_message( client, @@ -131,7 +142,9 @@ def test_signmessage(client: Client, path, script_types): @pytest.mark.parametrize("path, script_types", VECTORS) -def test_signtx(client: Client, path, script_types): +def test_signtx( + client: Client, path: str, script_types: list[messages.InputScriptType] +): address_n = parse_path(path) for script_type in script_types: @@ -160,7 +173,9 @@ def test_signtx(client: Client, path, script_types): @pytest.mark.multisig @pytest.mark.parametrize("paths, address_index", VECTORS_MULTISIG) -def test_getaddress_multisig(client: Client, paths, address_index): +def test_getaddress_multisig( + client: Client, paths: list[str], address_index: list[int] +): pubs = [ messages.HDNodePathType( node=btc.get_public_node( @@ -186,7 +201,7 @@ def test_getaddress_multisig(client: Client, paths, address_index): @pytest.mark.multisig @pytest.mark.parametrize("paths, address_index", VECTORS_MULTISIG) -def test_signtx_multisig(client: Client, paths, address_index): +def test_signtx_multisig(client: Client, paths: list[str], address_index: list[int]): pubs = [ messages.HDNodePathType( node=btc.get_public_node( diff --git a/tests/device_tests/bitcoin/test_op_return.py b/tests/device_tests/bitcoin/test_op_return.py index ef2dd46c9..f7410680b 100644 --- a/tests/device_tests/bitcoin/test_op_return.py +++ b/tests/device_tests/bitcoin/test_op_return.py @@ -63,13 +63,13 @@ def test_opreturn(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), messages.ButtonRequest(code=B.SignTx), diff --git a/tests/device_tests/bitcoin/test_signmessage.py b/tests/device_tests/bitcoin/test_signmessage.py index d76601f15..581bb8aac 100644 --- a/tests/device_tests/bitcoin/test_signmessage.py +++ b/tests/device_tests/bitcoin/test_signmessage.py @@ -28,12 +28,20 @@ from ...input_flows import InputFlowSignMessagePagination S = messages.InputScriptType -def case(id: str, *args: Any, altcoin: bool = False, skip_t1: bool = False): +def case( + id: str, + *args: Any, + altcoin: bool = False, + skip_t1: bool = False, + skip_tr: bool = False +): marks = [] if altcoin: marks.append(pytest.mark.altcoin) if skip_t1: marks.append(pytest.mark.skip_t1) + if skip_tr: + marks.append(pytest.mark.skip_tr) return pytest.param(*args, id=id, marks=marks) @@ -253,6 +261,7 @@ VECTORS = ( # case name, coin_name, path, script_type, address, message, signat "This is an example of a signed message.", "206b1f8ba47ef9eaf87aa900e41ab1e97f67e8c09292faa4acf825228d074c4b774484046dcb1d9bbf0603045dbfb328c3e1b0c09c5ae133e89e604a67a1fc6cca", altcoin=True, + skip_tr=True, ), case( "decred-empty", @@ -264,6 +273,7 @@ VECTORS = ( # case name, coin_name, path, script_type, address, message, signat "", "1fd2d57490b44a0361c7809768cad032d41ba1d4b7a297f935fc65ae05f71de7ea0c6c6fd265cc5154f1fa4acd7006b6a00ddd67fb7333c1594aff9120b3ba8024", altcoin=True, + skip_tr=True, ), ) diff --git a/tests/device_tests/bitcoin/test_signtx.py b/tests/device_tests/bitcoin/test_signtx.py index 7a6dc6d78..42a2ac77c 100644 --- a/tests/device_tests/bitcoin/test_signtx.py +++ b/tests/device_tests/bitcoin/test_signtx.py @@ -127,13 +127,13 @@ def test_one_one_fee(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_0dac36), @@ -181,13 +181,13 @@ def test_testnet_one_two_fee(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -232,13 +232,13 @@ def test_testnet_fee_high_warning(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.FeeOverThreshold), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -285,14 +285,14 @@ def test_one_two_fee(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_50f6f1), @@ -318,7 +318,8 @@ def test_one_two_fee(client: Client): ) -def test_one_three_fee(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_one_three_fee(client: Client, chunkify: bool): # input tx: bb5169091f09e833e155b291b662019df56870effe388c626221c5ea84274bc4 inp1 = messages.TxInputType( @@ -347,16 +348,16 @@ def test_one_three_fee(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(2), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -379,6 +380,7 @@ def test_one_three_fee(client: Client): [inp1], [out1, out2, out3], prev_txes=TX_CACHE_TESTNET, + chunkify=chunkify, ) assert_tx_matches( @@ -418,7 +420,7 @@ def test_two_two(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), @@ -426,7 +428,7 @@ def test_two_two(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_ac4ca0), @@ -563,13 +565,13 @@ def test_lots_of_change(client: Client): request_change_outputs = [request_output(i + 1) for i in range(cnt)] with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), ] + request_change_outputs + [ @@ -615,13 +617,13 @@ def test_fee_high_warning(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.FeeOverThreshold), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -704,13 +706,13 @@ def test_not_enough_funds(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.Failure(code=messages.FailureType.NotEnoughFunds), ] ) @@ -735,13 +737,13 @@ def test_p2sh(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_58d56a), @@ -823,7 +825,7 @@ def test_attack_change_outputs(client: Client): # Test if the transaction can be signed normally with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), @@ -831,7 +833,7 @@ def test_attack_change_outputs(client: Client): request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_ac4ca0), @@ -991,14 +993,14 @@ def test_attack_change_input_address(client: Client): # Now run the attack, must trigger the exception with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -1043,13 +1045,13 @@ def test_spend_coinbase(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_005f6f), @@ -1102,13 +1104,13 @@ def test_two_changes(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), request_output(2), messages.ButtonRequest(code=B.SignTx), @@ -1162,13 +1164,13 @@ def test_change_on_main_chain_allowed(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -1427,13 +1429,13 @@ def test_lock_time(client: Client, lock_time: int, sequence: int): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), messages.ButtonRequest(code=B.SignTx), request_input(0), diff --git a/tests/device_tests/bitcoin/test_signtx_external.py b/tests/device_tests/bitcoin/test_signtx_external.py index 8bed24dbf..15702acd4 100644 --- a/tests/device_tests/bitcoin/test_signtx_external.py +++ b/tests/device_tests/bitcoin/test_signtx_external.py @@ -216,20 +216,20 @@ def test_p2wpkh_in_p2sh_presigned(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(2), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_20912f), @@ -268,20 +268,20 @@ def test_p2wpkh_in_p2sh_presigned(client: Client): # Test corrupted script hash in scriptsig. inp1.script_sig[10] ^= 1 with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(2), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_20912f), @@ -401,14 +401,14 @@ def test_p2wsh_external_presigned(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_ec16dc), @@ -447,14 +447,14 @@ def test_p2wsh_external_presigned(client: Client): # Test corrupted signature in witness. inp2.witness[10] ^= 1 with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_ec16dc), @@ -513,14 +513,14 @@ def test_p2tr_external_presigned(client: Client): script_type=messages.OutputScriptType.PAYTOTAPROOT, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(1), @@ -546,14 +546,14 @@ def test_p2tr_external_presigned(client: Client): # Test corrupted signature in witness. inp2.witness[10] ^= 1 with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(1), @@ -616,18 +616,18 @@ def test_p2wpkh_with_proof(client: Client): ) with client: - t1 = client.features.model == "1" - tt = client.features.model == "T" + is_t1 = client.features.model == "1" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_e5b7e2), @@ -643,7 +643,7 @@ def test_p2wpkh_with_proof(client: Client): request_input(1), request_output(0), request_output(1), - (t1, request_input(0)), + (is_t1, request_input(0)), request_input(1), request_finished(), ] @@ -710,20 +710,20 @@ def test_p2tr_with_proof(client: Client): ) with client: - t1 = client.features.model == "1" - tt = client.features.model == "T" + is_t1 = client.features.model == "1" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_input(1), request_output(0), - (t1, request_input(0)), + (is_t1, request_input(0)), request_input(1), request_finished(), ] diff --git a/tests/device_tests/bitcoin/test_signtx_payreq.py b/tests/device_tests/bitcoin/test_signtx_payreq.py index d199c7ade..9b590931c 100644 --- a/tests/device_tests/bitcoin/test_signtx_payreq.py +++ b/tests/device_tests/bitcoin/test_signtx_payreq.py @@ -36,11 +36,12 @@ PREV_TXES = {PREV_HASH: PREV_TX} pytestmark = [pytest.mark.skip_t1, pytest.mark.experimental] -def case(id, *args, altcoin=False): +def case(id, *args, altcoin: bool = False, skip_tr: bool = False): + marks = [] if altcoin: - marks = pytest.mark.altcoin - else: - marks = () + marks.append(pytest.mark.altcoin) + if skip_tr: + marks.append(pytest.mark.skip_tr) return pytest.param(*args, id=id, marks=marks) @@ -110,10 +111,16 @@ SERIALIZED_TX = "01000000000101e29305e85821ea86f2bca1fcfe45e7cb0c8de87b612479ee6 "payment_request_params", ( case( - "out0", (PaymentRequestParams([0], memos1, get_nonce=True),), altcoin=True + "out0", + (PaymentRequestParams([0], memos1, get_nonce=True),), + altcoin=True, + skip_tr=True, ), case( - "out1", (PaymentRequestParams([1], memos2, get_nonce=True),), altcoin=True + "out1", + (PaymentRequestParams([1], memos2, get_nonce=True),), + altcoin=True, + skip_tr=True, ), case("out2", (PaymentRequestParams([2], [], get_nonce=True),)), case( @@ -268,6 +275,7 @@ def test_payment_req_wrong_mac_refund(client: Client): @pytest.mark.altcoin +@pytest.mark.skip_tr def test_payment_req_wrong_mac_purchase(client: Client): # Test wrong MAC in payment request memo. memo = CoinPurchaseMemo( diff --git a/tests/device_tests/bitcoin/test_signtx_replacement.py b/tests/device_tests/bitcoin/test_signtx_replacement.py index 9c1556d12..ab4292527 100644 --- a/tests/device_tests/bitcoin/test_signtx_replacement.py +++ b/tests/device_tests/bitcoin/test_signtx_replacement.py @@ -115,7 +115,7 @@ def test_p2pkh_fee_bump(client: Client): orig_index=1, ) - new_model = client.features.model in ("T", "R") + is_core = client.features.model in ("T", "R") with client: client.set_expected_responses( @@ -133,7 +133,7 @@ def test_p2pkh_fee_bump(client: Client): request_meta(TXHASH_beafc7), request_input(0, TXHASH_beafc7), request_output(0, TXHASH_beafc7), - (new_model, request_orig_input(0, TXHASH_50f6f1)), + (is_core, request_orig_input(0, TXHASH_50f6f1)), request_orig_input(0, TXHASH_50f6f1), request_orig_output(0, TXHASH_50f6f1), request_orig_output(1, TXHASH_50f6f1), @@ -600,7 +600,7 @@ def test_p2wpkh_in_p2sh_fee_bump_from_external(client: Client): orig_index=0, ) - tr = client.features.model == "R" + is_tr = client.features.model == "R" with client: client.set_expected_responses( [ @@ -613,7 +613,7 @@ def test_p2wpkh_in_p2sh_fee_bump_from_external(client: Client): request_output(0), request_orig_output(0, TXHASH_334cd7), messages.ButtonRequest(code=B.ConfirmOutput), - (not tr, messages.ButtonRequest(code=B.ConfirmOutput)), + (not is_tr, messages.ButtonRequest(code=B.ConfirmOutput)), request_orig_output(1, TXHASH_334cd7), messages.ButtonRequest(code=B.SignTx), request_input(0), diff --git a/tests/device_tests/bitcoin/test_signtx_segwit.py b/tests/device_tests/bitcoin/test_signtx_segwit.py index 072a3cb8b..2c9862678 100644 --- a/tests/device_tests/bitcoin/test_signtx_segwit.py +++ b/tests/device_tests/bitcoin/test_signtx_segwit.py @@ -45,7 +45,8 @@ TXHASH_e5040e = bytes.fromhex( ) -def test_send_p2sh(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_send_p2sh(client: Client, chunkify: bool): inp1 = messages.TxInputType( address_n=parse_path("m/49h/1h/0h/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX @@ -65,16 +66,16 @@ def test_send_p2sh(client: Client): amount=123_456_789 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_20912f), @@ -89,7 +90,12 @@ def test_send_p2sh(client: Client): ] ) _, serialized_tx = btc.sign_tx( - client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API_TESTNET + client, + "Testnet", + [inp1], + [out1, out2], + prev_txes=TX_API_TESTNET, + chunkify=chunkify, ) # Transaction does not exist on the blockchain, not using assert_tx_matches() @@ -119,13 +125,13 @@ def test_send_p2sh_change(client: Client): amount=123_456_789 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -175,13 +181,13 @@ def test_testnet_segwit_big_amount(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(prev_hash), @@ -233,12 +239,12 @@ def test_send_multisig_1(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_338e2d), @@ -301,17 +307,17 @@ def test_attack_change_input_address(client: Client): # Test if the transaction can be signed normally. with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), # The user is required to confirm transfer to another account. messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_20912f), @@ -381,13 +387,17 @@ def test_attack_mixed_inputs(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput), - (tt, messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput)), + ( + is_core, + messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput), + ), + (is_core, messages.ButtonRequest(code=messages.ButtonRequestType.SignTx)), messages.ButtonRequest(code=messages.ButtonRequestType.FeeOverThreshold), messages.ButtonRequest(code=messages.ButtonRequestType.SignTx), request_input(0), diff --git a/tests/device_tests/bitcoin/test_signtx_segwit_native.py b/tests/device_tests/bitcoin/test_signtx_segwit_native.py index 178762607..f2ad71b21 100644 --- a/tests/device_tests/bitcoin/test_signtx_segwit_native.py +++ b/tests/device_tests/bitcoin/test_signtx_segwit_native.py @@ -81,16 +81,16 @@ def test_send_p2sh(client: Client): amount=123_456_789 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_20912f), @@ -137,13 +137,13 @@ def test_send_p2sh_change(client: Client): amount=123_456_789 - 11_000 - 12_300_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -191,16 +191,16 @@ def test_send_native(client: Client): amount=100_000 - 40_000 - 10_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_b36780), @@ -279,13 +279,13 @@ def test_send_native_change(client: Client): amount=100_000 - 40_000 - 10_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -347,20 +347,22 @@ def test_send_both(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(2), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.SignTx)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_65047a), @@ -431,12 +433,12 @@ def test_send_multisig_1(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_b9abfa), @@ -509,12 +511,12 @@ def test_send_multisig_2(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_b9abfa), @@ -594,13 +596,13 @@ def test_send_multisig_3_change(client: Client): script_type=messages.OutputScriptType.PAYTOP2SHWITNESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.UnknownDerivationPath), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_b9abfa), @@ -681,13 +683,13 @@ def test_send_multisig_4_change(client: Client): script_type=messages.OutputScriptType.PAYTOWITNESS, ) - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.UnknownDerivationPath), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_b9abfa), @@ -783,18 +785,18 @@ def test_multisig_mismatch_inputs_single(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), # Ensure that the multisig output is not identified as a change output. messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_1c022d), diff --git a/tests/device_tests/bitcoin/test_signtx_taproot.py b/tests/device_tests/bitcoin/test_signtx_taproot.py index 5c0c30b8f..af7cf0282 100644 --- a/tests/device_tests/bitcoin/test_signtx_taproot.py +++ b/tests/device_tests/bitcoin/test_signtx_taproot.py @@ -62,7 +62,8 @@ TXHASH_c96621 = bytes.fromhex( ) -def test_send_p2tr(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_send_p2tr(client: Client, chunkify: bool): inp1 = messages.TxInputType( # tb1pn2d0yjeedavnkd8z8lhm566p0f2utm3lgvxrsdehnl94y34txmts5s7t4c address_n=parse_path("m/86h/1h/0h/1/0"), @@ -78,13 +79,13 @@ def test_send_p2tr(client: Client): script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), @@ -93,7 +94,7 @@ def test_send_p2tr(client: Client): ] ) _, serialized_tx = btc.sign_tx( - client, "Testnet", [inp1], [out1], prev_txes=TX_API + client, "Testnet", [inp1], [out1], prev_txes=TX_API, chunkify=chunkify ) assert_tx_matches( @@ -133,14 +134,14 @@ def test_send_two_with_change(client: Client): amount=6_800 + 13_000 - 200 - 15_000, ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -223,7 +224,8 @@ def test_send_mixed(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ # process inputs @@ -234,18 +236,19 @@ def test_send_mixed(client: Client): # approve outputs request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(2), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(3), messages.ButtonRequest(code=B.ConfirmOutput), request_output(4), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.SignTx)), messages.ButtonRequest(code=B.SignTx), # verify inputs request_input(0), @@ -355,7 +358,8 @@ def test_attack_script_type(client: Client): return msg with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") + is_core = client.features.model in ("T", "R") client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses( [ @@ -363,7 +367,8 @@ def test_attack_script_type(client: Client): request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.SignTx)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_input(1), diff --git a/tests/device_tests/bitcoin/test_zcash.py b/tests/device_tests/bitcoin/test_zcash.py index 96ad3e753..256a6ed02 100644 --- a/tests/device_tests/bitcoin/test_zcash.py +++ b/tests/device_tests/bitcoin/test_zcash.py @@ -106,13 +106,13 @@ def test_one_one_fee_sapling(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_e38206), @@ -260,14 +260,14 @@ def test_external_presigned(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_e38206), diff --git a/tests/device_tests/cardano/test_address_public_key.py b/tests/device_tests/cardano/test_address_public_key.py index 149c95951..e56b798a5 100644 --- a/tests/device_tests/cardano/test_address_public_key.py +++ b/tests/device_tests/cardano/test_address_public_key.py @@ -27,6 +27,7 @@ from trezorlib.messages import CardanoAddressType, CardanoDerivationType from trezorlib.tools import parse_path from ...common import parametrize_using_common_fixtures +from ...input_flows import InputFlowShowXpubQRCode pytestmark = [ pytest.mark.altcoin, @@ -46,7 +47,8 @@ pytestmark = [ "cardano/get_reward_address.json", "cardano/get_base_address.derivations.json", ) -def test_cardano_get_address(client: Client, parameters, result): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_cardano_get_address(client: Client, chunkify: bool, parameters, result): client.init_device(new_session=True, derive_cardano=True) derivation_type = CardanoDerivationType.__members__[ @@ -80,6 +82,7 @@ def test_cardano_get_address(client: Client, parameters, result): network_id=parameters["network_id"], show_display=True, derivation_type=derivation_type, + chunkify=chunkify, ) assert address == result["expected_address"] @@ -90,13 +93,18 @@ def test_cardano_get_address(client: Client, parameters, result): "cardano/get_public_key.derivations.json", ) def test_cardano_get_public_key(client: Client, parameters, result): - client.init_device(new_session=True, derive_cardano=True) + with client: + IF = InputFlowShowXpubQRCode(client, passphrase=bool(client.ui.passphrase)) + client.set_input_flow(IF.get()) + client.init_device(new_session=True, derive_cardano=True) - derivation_type = CardanoDerivationType.__members__[ - parameters.get("derivation_type", "ICARUS_TREZOR") - ] - key = get_public_key(client, parse_path(parameters["path"]), derivation_type) + derivation_type = CardanoDerivationType.__members__[ + parameters.get("derivation_type", "ICARUS_TREZOR") + ] + key = get_public_key( + client, parse_path(parameters["path"]), derivation_type, show_display=True + ) - assert key.node.public_key.hex() == result["public_key"] - assert key.node.chain_code.hex() == result["chain_code"] - assert key.xpub == result["public_key"] + result["chain_code"] + assert key.node.public_key.hex() == result["public_key"] + assert key.node.chain_code.hex() == result["chain_code"] + assert key.xpub == result["public_key"] + result["chain_code"] diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index 2a58bd0b2..bbb41e495 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -57,7 +57,7 @@ def test_cardano_sign_tx(client: Client, parameters, result): @parametrize_using_common_fixtures("cardano/sign_tx.show_details.json") def test_cardano_sign_tx_show_details(client: Client, parameters, result): - response = call_sign_tx(client, parameters, show_details_input_flow) + response = call_sign_tx(client, parameters, show_details_input_flow, chunkify=True) assert response == _transform_expected_result(result) @@ -72,7 +72,7 @@ def test_cardano_sign_tx_failed(client: Client, parameters, result): call_sign_tx(client, parameters, None) -def call_sign_tx(client: Client, parameters, input_flow=None): +def call_sign_tx(client: Client, parameters, input_flow=None, chunkify: bool = False): client.init_device(new_session=True, derive_cardano=True) signing_mode = messages.CardanoTxSigningMode.__members__[parameters["signing_mode"]] @@ -136,6 +136,7 @@ def call_sign_tx(client: Client, parameters, input_flow=None): reference_inputs=reference_inputs, additional_witness_requests=additional_witness_requests, include_network_id=parameters["include_network_id"], + chunkify=chunkify, ) diff --git a/tests/device_tests/eos/test_get_public_key.py b/tests/device_tests/eos/test_get_public_key.py index 97cc2d57e..cda429ab1 100644 --- a/tests/device_tests/eos/test_get_public_key.py +++ b/tests/device_tests/eos/test_get_public_key.py @@ -21,39 +21,44 @@ from trezorlib.eos import get_public_key from trezorlib.tools import parse_path from ...common import MNEMONIC12 +from ...input_flows import InputFlowShowXpubQRCode @pytest.mark.altcoin @pytest.mark.eos @pytest.mark.skip_t1 +@pytest.mark.skip_tr # coin not supported @pytest.mark.setup_client(mnemonic=MNEMONIC12) def test_eos_get_public_key(client: Client): - public_key = get_public_key( - client, parse_path("m/44h/194h/0h/0/0"), show_display=True - ) - assert ( - public_key.wif_public_key - == "EOS4u6Sfnzj4Sh2pEQnkXyZQJqH3PkKjGByDCbsqqmyq6PttM9KyB" - ) - assert ( - public_key.raw_public_key.hex() - == "02015fabe197c955036bab25f4e7c16558f9f672f9f625314ab1ec8f64f7b1198e" - ) - public_key = get_public_key(client, parse_path("m/44h/194h/0h/0/1")) - assert ( - public_key.wif_public_key - == "EOS5d1VP15RKxT4dSakWu2TFuEgnmaGC2ckfSvQwND7pZC1tXkfLP" - ) - assert ( - public_key.raw_public_key.hex() - == "02608bc2c431521dee0b9d5f2fe34053e15fc3b20d2895e0abda857b9ed8e77a78" - ) - public_key = get_public_key(client, parse_path("m/44h/194h/1h/0/0")) - assert ( - public_key.wif_public_key - == "EOS7UuNeTf13nfcG85rDB7AHGugZi4C4wJ4ft12QRotqNfxdV2NvP" - ) - assert ( - public_key.raw_public_key.hex() - == "035588a197bd5a7356e8a702361b2d535c6372f843874bed6617cd1afe1dfcb502" - ) + with client: + IF = InputFlowShowXpubQRCode(client) + client.set_input_flow(IF.get()) + public_key = get_public_key( + client, parse_path("m/44h/194h/0h/0/0"), show_display=True + ) + assert ( + public_key.wif_public_key + == "EOS4u6Sfnzj4Sh2pEQnkXyZQJqH3PkKjGByDCbsqqmyq6PttM9KyB" + ) + assert ( + public_key.raw_public_key.hex() + == "02015fabe197c955036bab25f4e7c16558f9f672f9f625314ab1ec8f64f7b1198e" + ) + public_key = get_public_key(client, parse_path("m/44h/194h/0h/0/1")) + assert ( + public_key.wif_public_key + == "EOS5d1VP15RKxT4dSakWu2TFuEgnmaGC2ckfSvQwND7pZC1tXkfLP" + ) + assert ( + public_key.raw_public_key.hex() + == "02608bc2c431521dee0b9d5f2fe34053e15fc3b20d2895e0abda857b9ed8e77a78" + ) + public_key = get_public_key(client, parse_path("m/44h/194h/1h/0/0")) + assert ( + public_key.wif_public_key + == "EOS7UuNeTf13nfcG85rDB7AHGugZi4C4wJ4ft12QRotqNfxdV2NvP" + ) + assert ( + public_key.raw_public_key.hex() + == "035588a197bd5a7356e8a702361b2d535c6372f843874bed6617cd1afe1dfcb502" + ) diff --git a/tests/device_tests/eos/test_signtx.py b/tests/device_tests/eos/test_signtx.py index b05c4ad68..803fdb033 100644 --- a/tests/device_tests/eos/test_signtx.py +++ b/tests/device_tests/eos/test_signtx.py @@ -30,11 +30,13 @@ pytestmark = [ pytest.mark.altcoin, pytest.mark.eos, pytest.mark.skip_t1, + pytest.mark.skip_tr, # coin not supported pytest.mark.setup_client(mnemonic=MNEMONIC12), ] -def test_eos_signtx_transfer_token(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_eos_signtx_transfer_token(client: Client, chunkify: bool): transaction = { "expiration": "2018-07-14T10:43:28", "ref_block_num": 6439, @@ -60,7 +62,7 @@ def test_eos_signtx_transfer_token(client: Client): } with client: - resp = eos.sign_tx(client, ADDRESS_N, transaction, CHAIN_ID) + resp = eos.sign_tx(client, ADDRESS_N, transaction, CHAIN_ID, chunkify=chunkify) assert isinstance(resp, EosSignedTx) assert ( resp.signature diff --git a/tests/device_tests/ethereum/test_getaddress.py b/tests/device_tests/ethereum/test_getaddress.py index 36ab62d2a..0720197b0 100644 --- a/tests/device_tests/ethereum/test_getaddress.py +++ b/tests/device_tests/ethereum/test_getaddress.py @@ -26,8 +26,10 @@ pytestmark = [pytest.mark.altcoin, pytest.mark.ethereum] @parametrize_using_common_fixtures("ethereum/getaddress.json") -def test_getaddress(client: Client, parameters, result): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_getaddress(client: Client, chunkify: bool, parameters, result): address_n = parse_path(parameters["path"]) assert ( - ethereum.get_address(client, address_n, show_display=True) == result["address"] + ethereum.get_address(client, address_n, show_display=True, chunkify=chunkify) + == result["address"] ) diff --git a/tests/device_tests/ethereum/test_signtx.py b/tests/device_tests/ethereum/test_signtx.py index 91ff44b5f..28df5d075 100644 --- a/tests/device_tests/ethereum/test_signtx.py +++ b/tests/device_tests/ethereum/test_signtx.py @@ -24,9 +24,10 @@ from trezorlib.tools import parse_path, unharden from ...common import parametrize_using_common_fixtures from ...input_flows import ( - InputFlowEthereumSignTxGoBack, - InputFlowEthereumSignTxScrollDown, - InputFlowEthereumSignTxSkip, + InputFlowEthereumSignTxDataGoBack, + InputFlowEthereumSignTxDataScrollDown, + InputFlowEthereumSignTxDataSkip, + InputFlowEthereumSignTxShowFeeInfo, ) from .common import encode_network @@ -51,8 +52,22 @@ def make_defs(parameters: dict) -> messages.EthereumDefinitions: "ethereum/sign_tx.json", "ethereum/sign_tx_eip155.json", ) -def test_signtx(client: Client, parameters, result): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_signtx(client: Client, chunkify: bool, parameters: dict, result: dict): + _do_test_signtx(client, parameters, result, chunkify=chunkify) + + +def _do_test_signtx( + client: Client, + parameters: dict, + result: dict, + input_flow=None, + chunkify: bool = False, +): with client: + if input_flow: + client.watch_layout() + client.set_input_flow(input_flow) sig_v, sig_r, sig_s = ethereum.sign_tx( client, n=parse_path(parameters["path"]), @@ -65,6 +80,7 @@ def test_signtx(client: Client, parameters, result): tx_type=parameters["tx_type"], data=bytes.fromhex(parameters["data"]), definitions=make_defs(parameters), + chunkify=chunkify, ) expected_v = 2 * parameters["chain_id"] + 35 @@ -74,8 +90,32 @@ def test_signtx(client: Client, parameters, result): assert sig_v == result["sig_v"] +@pytest.mark.skip_t1("T1 does not support input flows") +def test_signtx_fee_info(client: Client): + input_flow = InputFlowEthereumSignTxShowFeeInfo(client).get() + # Data taken from sign_tx_eip1559.json["tests"][0] + parameters = { + "chain_id": 1, + "path": "m/44'/60'/0'/0/0", + "nonce": "0x0", + "gas_price": "0x4a817c800", + "gas_limit": "0x5208", + "value": "0x2540be400", + "to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98", + "tx_type": None, + "data": "", + } + result = { + "sig_v": 38, + "sig_r": "6a6349bddb5749bb8b96ce2566a035ef87a09dbf89b5c7e3dfdf9ed725912f24", + "sig_s": "4ae58ccd3bacee07cdc4a3e8540544fd009c4311af7048122da60f2054c07ee4", + } + _do_test_signtx(client, parameters, result, input_flow) + + @parametrize_using_common_fixtures("ethereum/sign_tx_eip1559.json") -def test_signtx_eip1559(client: Client, parameters, result): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_signtx_eip1559(client: Client, chunkify: bool, parameters: dict, result: dict): with client: sig_v, sig_r, sig_s = ethereum.sign_tx_eip1559( client, @@ -89,6 +129,7 @@ def test_signtx_eip1559(client: Client, parameters, result): value=int(parameters["value"], 16), data=bytes.fromhex(parameters["data"]), definitions=make_defs(parameters), + chunkify=chunkify, ) assert sig_r.hex() == result["sig_r"] @@ -145,14 +186,13 @@ def test_data_streaming(client: Client): checked in vectorized function above. """ with client: - tt = client.features.model == "T" - not_t1 = client.features.model != "1" + is_t1 = client.features.model == "1" + is_tt = client.features.model == "T" client.set_expected_responses( [ messages.ButtonRequest(code=messages.ButtonRequestType.SignTx), - messages.ButtonRequest(code=messages.ButtonRequestType.SignTx), - (tt, messages.ButtonRequest(code=messages.ButtonRequestType.SignTx)), - (not_t1, messages.ButtonRequest(code=messages.ButtonRequestType.Other)), + (is_t1, messages.ButtonRequest(code=messages.ButtonRequestType.SignTx)), + (is_tt, messages.ButtonRequest(code=messages.ButtonRequestType.Other)), messages.ButtonRequest(code=messages.ButtonRequestType.SignTx), message_filters.EthereumTxRequest( data_length=1_024, @@ -348,25 +388,23 @@ def test_sanity_checks_eip1559(client: Client): ) -def input_flow_skip(client: Client, cancel: bool = False): - return InputFlowEthereumSignTxSkip(client, cancel).get() +def input_flow_data_skip(client: Client, cancel: bool = False): + return InputFlowEthereumSignTxDataSkip(client, cancel).get() -def input_flow_scroll_down(client: Client, cancel: bool = False): - return InputFlowEthereumSignTxScrollDown(client, cancel).get() +def input_flow_data_scroll_down(client: Client, cancel: bool = False): + return InputFlowEthereumSignTxDataScrollDown(client, cancel).get() -def input_flow_go_back(client: Client, cancel: bool = False): - if client.features.model == "R": - pytest.skip("Go back not supported for model R") - return InputFlowEthereumSignTxGoBack(client, cancel).get() +def input_flow_data_go_back(client: Client, cancel: bool = False): + return InputFlowEthereumSignTxDataGoBack(client, cancel).get() HEXDATA = "0123456789abcd000023456789abcd010003456789abcd020000456789abcd030000056789abcd040000006789abcd050000000789abcd060000000089abcd070000000009abcd080000000000abcd090000000001abcd0a0000000011abcd0b0000000111abcd0c0000001111abcd0d0000011111abcd0e0000111111abcd0f0000000002abcd100000000022abcd110000000222abcd120000002222abcd130000022222abcd140000222222abcd15" @pytest.mark.parametrize( - "flow", (input_flow_skip, input_flow_scroll_down, input_flow_go_back) + "flow", (input_flow_data_skip, input_flow_data_scroll_down, input_flow_data_go_back) ) @pytest.mark.skip_t1 def test_signtx_data_pagination(client: Client, flow): diff --git a/tests/device_tests/monero/test_getaddress.py b/tests/device_tests/monero/test_getaddress.py index 37cee4aa4..1e056b585 100644 --- a/tests/device_tests/monero/test_getaddress.py +++ b/tests/device_tests/monero/test_getaddress.py @@ -27,16 +27,23 @@ from ...common import MNEMONIC12 @pytest.mark.monero @pytest.mark.skip_t1 @pytest.mark.setup_client(mnemonic=MNEMONIC12) -def test_monero_getaddress(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_monero_getaddress(client: Client, chunkify: bool): assert ( - monero.get_address(client, parse_path("m/44h/128h/0h"), show_display=True) + monero.get_address( + client, parse_path("m/44h/128h/0h"), show_display=True, chunkify=chunkify + ) == b"4Ahp23WfMrMFK3wYL2hLWQFGt87ZTeRkufS6JoQZu6MEFDokAQeGWmu9MA3GFq1yVLSJQbKJqVAn9F9DLYGpRzRAEXqAXKM" ) assert ( - monero.get_address(client, parse_path("m/44h/128h/1h"), show_display=True) + monero.get_address( + client, parse_path("m/44h/128h/1h"), show_display=True, chunkify=chunkify + ) == b"44iAazhoAkv5a5RqLNVyh82a1n3ceNggmN4Ho7bUBJ14WkEVR8uFTe9f7v5rNnJ2kEbVXxfXiRzsD5Jtc6NvBi4D6WNHPie" ) assert ( - monero.get_address(client, parse_path("m/44h/128h/2h"), show_display=True) + monero.get_address( + client, parse_path("m/44h/128h/2h"), show_display=True, chunkify=chunkify + ) == b"47ejhmbZ4wHUhXaqA4b7PN667oPMkokf4ZkNdWrMSPy9TNaLVr7vLqVUQHh2MnmaAEiyrvLsX8xUf99q3j1iAeMV8YvSFcH" ) diff --git a/tests/device_tests/nem/test_getaddress.py b/tests/device_tests/nem/test_getaddress.py index 7e72e716a..af33e88f3 100644 --- a/tests/device_tests/nem/test_getaddress.py +++ b/tests/device_tests/nem/test_getaddress.py @@ -25,17 +25,27 @@ from ...common import MNEMONIC12 @pytest.mark.altcoin @pytest.mark.nem +@pytest.mark.skip_tr # coin not supported, @pytest.mark.setup_client(mnemonic=MNEMONIC12) -def test_nem_getaddress(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_nem_getaddress(client: Client, chunkify: bool): assert ( nem.get_address( - client, parse_path("m/44h/1h/0h/0h/0h"), 0x68, show_display=True + client, + parse_path("m/44h/1h/0h/0h/0h"), + 0x68, + show_display=True, + chunkify=chunkify, ) == "NB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQGHUBWQN" ) assert ( nem.get_address( - client, parse_path("m/44h/1h/0h/0h/0h"), 0x98, show_display=True + client, + parse_path("m/44h/1h/0h/0h/0h"), + 0x98, + show_display=True, + chunkify=chunkify, ) == "TB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQHSBNBMF" ) diff --git a/tests/device_tests/nem/test_signtx_mosaics.py b/tests/device_tests/nem/test_signtx_mosaics.py index ad6377f26..6c07c9d37 100644 --- a/tests/device_tests/nem/test_signtx_mosaics.py +++ b/tests/device_tests/nem/test_signtx_mosaics.py @@ -27,6 +27,7 @@ ADDRESS_N = parse_path("m/44h/1h/0h/0h/0h") pytestmark = [ pytest.mark.altcoin, pytest.mark.nem, + pytest.mark.skip_tr, # coin not supported, pytest.mark.setup_client(mnemonic=MNEMONIC12), ] diff --git a/tests/device_tests/nem/test_signtx_multisig.py b/tests/device_tests/nem/test_signtx_multisig.py index a438d09b7..3efa7352a 100644 --- a/tests/device_tests/nem/test_signtx_multisig.py +++ b/tests/device_tests/nem/test_signtx_multisig.py @@ -25,6 +25,7 @@ from ...common import MNEMONIC12 pytestmark = [ pytest.mark.altcoin, pytest.mark.nem, + pytest.mark.skip_tr, # coin not supported, pytest.mark.setup_client(mnemonic=MNEMONIC12), ] diff --git a/tests/device_tests/nem/test_signtx_others.py b/tests/device_tests/nem/test_signtx_others.py index e9ca78880..bfd357bd7 100644 --- a/tests/device_tests/nem/test_signtx_others.py +++ b/tests/device_tests/nem/test_signtx_others.py @@ -25,6 +25,7 @@ from ...common import MNEMONIC12 pytestmark = [ pytest.mark.altcoin, pytest.mark.nem, + pytest.mark.skip_tr, # coin not supported, pytest.mark.setup_client(mnemonic=MNEMONIC12), ] diff --git a/tests/device_tests/nem/test_signtx_transfers.py b/tests/device_tests/nem/test_signtx_transfers.py index a3b96f69a..40491669a 100644 --- a/tests/device_tests/nem/test_signtx_transfers.py +++ b/tests/device_tests/nem/test_signtx_transfers.py @@ -25,13 +25,15 @@ from ...common import MNEMONIC12 pytestmark = [ pytest.mark.altcoin, pytest.mark.nem, + pytest.mark.skip_tr, # coin not supported, pytest.mark.setup_client(mnemonic=MNEMONIC12), ] # assertion data from T1 -def test_nem_signtx_simple(client: Client): - tt = client.features.model == "T" +@pytest.mark.parametrize("chunkify", (True, False)) +def test_nem_signtx_simple(client: Client, chunkify: bool): + is_core = client.features.model in ("T", "R") with client: client.set_expected_responses( [ @@ -40,7 +42,7 @@ def test_nem_signtx_simple(client: Client): # Unencrypted message messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput), ( - tt, + is_core, messages.ButtonRequest( code=messages.ButtonRequestType.ConfirmOutput ), @@ -67,6 +69,7 @@ def test_nem_signtx_simple(client: Client): }, "version": (0x98 << 24), }, + chunkify=chunkify, ) assert ( @@ -82,7 +85,7 @@ def test_nem_signtx_simple(client: Client): @pytest.mark.setup_client(mnemonic=MNEMONIC12) def test_nem_signtx_encrypted_payload(client: Client): with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ # Confirm transfer and network fee @@ -90,7 +93,7 @@ def test_nem_signtx_encrypted_payload(client: Client): # Ask for encryption messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput), ( - tt, + is_core, messages.ButtonRequest( code=messages.ButtonRequestType.ConfirmOutput ), diff --git a/tests/device_tests/ripple/test_sign_tx.py b/tests/device_tests/ripple/test_sign_tx.py index ef3f03aa6..2dac93378 100644 --- a/tests/device_tests/ripple/test_sign_tx.py +++ b/tests/device_tests/ripple/test_sign_tx.py @@ -28,7 +28,8 @@ pytestmark = [ ] -def test_ripple_sign_simple_tx(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_ripple_sign_simple_tx(client: Client, chunkify: bool): msg = ripple.create_sign_tx_msg( { "TransactionType": "Payment", @@ -41,7 +42,9 @@ def test_ripple_sign_simple_tx(client: Client): "Sequence": 25, } ) - resp = ripple.sign_tx(client, parse_path("m/44h/144h/0h/0/0"), msg) + resp = ripple.sign_tx( + client, parse_path("m/44h/144h/0h/0/0"), msg, chunkify=chunkify + ) assert ( resp.signature.hex() == "3045022100e243ef623675eeeb95965c35c3e06d63a9fc68bb37e17dc87af9c0af83ec057e02206ca8aa5eaab8396397aef6d38d25710441faf7c79d292ee1d627df15ad9346c0" @@ -62,7 +65,9 @@ def test_ripple_sign_simple_tx(client: Client): "Sequence": 1, } ) - resp = ripple.sign_tx(client, parse_path("m/44h/144h/0h/0/2"), msg) + resp = ripple.sign_tx( + client, parse_path("m/44h/144h/0h/0/2"), msg, chunkify=chunkify + ) assert ( resp.signature.hex() == "3044022069900e6e578997fad5189981b74b16badc7ba8b9f1052694033fa2779113ddc002206c8006ada310edf099fb22c0c12073550c8fc73247b236a974c5f1144831dd5f" @@ -86,7 +91,9 @@ def test_ripple_sign_simple_tx(client: Client): "LastLedgerSequence": 333111, } ) - resp = ripple.sign_tx(client, parse_path("m/44h/144h/0h/0/2"), msg) + resp = ripple.sign_tx( + client, parse_path("m/44h/144h/0h/0/2"), msg, chunkify=chunkify + ) assert ( resp.signature.hex() == "30450221008770743a472bb2d1c746a53ef131cc17cc118d538ec910ca928d221db4494cf702201e4ef242d6c3bff110c3cc3897a471fed0f5ac10987ea57da63f98dfa01e94df" diff --git a/tests/device_tests/stellar/test_stellar.py b/tests/device_tests/stellar/test_stellar.py index b87b891fa..4916123e8 100644 --- a/tests/device_tests/stellar/test_stellar.py +++ b/tests/device_tests/stellar/test_stellar.py @@ -112,8 +112,11 @@ def test_xdr(parameters, result): @pytest.mark.altcoin @pytest.mark.stellar +@pytest.mark.parametrize("chunkify", (True, False)) @parametrize_using_common_fixtures("stellar/get_address.json") -def test_get_address(client: Client, parameters, result): +def test_get_address(client: Client, chunkify: bool, parameters, result): address_n = parse_path(parameters["path"]) - address = stellar.get_address(client, address_n, show_display=True) + address = stellar.get_address( + client, address_n, show_display=True, chunkify=chunkify + ) assert address == result["address"] diff --git a/tests/device_tests/test_authenticate_device.py b/tests/device_tests/test_authenticate_device.py new file mode 100644 index 000000000..f197b13f4 --- /dev/null +++ b/tests/device_tests/test_authenticate_device.py @@ -0,0 +1,77 @@ +import pytest +from cryptography import x509 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.x509 import extensions as ext + +from trezorlib import device +from trezorlib.debuglink import TrezorClientDebugLink as Client + +from ..common import compact_size + +pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_t2] + +ROOT_PUBLIC_KEY = bytes.fromhex( + "04626d58aca84f0fcb52ea63f0eb08de1067b8d406574a715d5e7928f4b67f113a00fb5c5918e74d2327311946c446b242c20fe7347482999bdc1e229b94e27d96" +) + + +@pytest.mark.parametrize( + "challenge", + ( + b"", + b"hello world", + b"\x00" * 1024, + bytes.fromhex( + "21f3d40e63c304d0312f62eb824113efd72ba1ee02bef6777e7f8a7b6f67ba16" + ), + ), +) +def test_authenticate_device(client: Client, challenge: bytes) -> None: + # NOTE Applications must generate a random challenge for each request. + + # Issue an AuthenticateDevice challenge to Trezor. + proof = device.authenticate(client, challenge) + certs = [x509.load_der_x509_certificate(cert) for cert in proof.certificates] + + # Verify the last certificate in the certificate chain against trust anchor. + root_public_key = ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP256R1(), ROOT_PUBLIC_KEY + ) + root_public_key.verify( + certs[-1].signature, + certs[-1].tbs_certificate_bytes, + certs[-1].signature_algorithm_parameters, + ) + + # Verify the certificate chain. + for cert, ca_cert in zip(certs, certs[1:]): + assert cert.issuer == ca_cert.subject + + ca_basic_constraints = ca_cert.extensions.get_extension_for_class( + ext.BasicConstraints + ).value + assert ca_basic_constraints.ca is True + + try: + basic_constraints = cert.extensions.get_extension_for_class( + ext.BasicConstraints + ).value + if basic_constraints.ca: + assert basic_constraints.path_length < ca_basic_constraints.path_length + except ext.ExtensionNotFound: + pass + + ca_cert.public_key().verify( + cert.signature, + cert.tbs_certificate_bytes, + cert.signature_algorithm_parameters, + ) + + # Verify that the common name matches the Trezor model. + common_name = cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)[0] + assert common_name.value.startswith(client.features.internal_model) + + # Verify the signature of the challenge. + data = b"\x13AuthenticateDevice:" + compact_size(len(challenge)) + challenge + certs[0].public_key().verify(proof.signature, data, ec.ECDSA(hashes.SHA256())) diff --git a/tests/device_tests/test_cancel.py b/tests/device_tests/test_cancel.py index be15f763e..ebf73ccc1 100644 --- a/tests/device_tests/test_cancel.py +++ b/tests/device_tests/test_cancel.py @@ -90,6 +90,15 @@ def test_cancel_on_paginated(client: Client): resp = client._raw_read() assert isinstance(resp, m.ButtonRequest) + + # In TR, confirm message is no longer paginated by default, + # user needs to click info button + if client.debug.model == "R": + client._raw_write(m.ButtonAck()) + client.debug.press_right() + resp = client._raw_read() + assert isinstance(resp, m.ButtonRequest) + assert resp.pages is not None client._raw_write(m.ButtonAck()) diff --git a/tests/device_tests/test_protection_levels.py b/tests/device_tests/test_protection_levels.py index e09147b7f..b919e7d2b 100644 --- a/tests/device_tests/test_protection_levels.py +++ b/tests/device_tests/test_protection_levels.py @@ -362,7 +362,7 @@ def test_signtx(client: Client): _assert_protection(client) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.use_pin_sequence([PIN4]) client.set_expected_responses( [ @@ -371,7 +371,7 @@ def test_signtx(client: Client): request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_50f6f1), diff --git a/tests/device_tests/test_session.py b/tests/device_tests/test_session.py index 03c91332e..7c2e78639 100644 --- a/tests/device_tests/test_session.py +++ b/tests/device_tests/test_session.py @@ -32,9 +32,9 @@ PIN4 = "1234" @pytest.mark.setup_client(pin=PIN4, passphrase="") def test_clear_session(client: Client): - is_trezor1 = client.features.model == "1" + is_t1 = client.features.model == "1" init_responses = [ - messages.PinMatrixRequest if is_trezor1 else messages.ButtonRequest, + messages.PinMatrixRequest if is_t1 else messages.ButtonRequest, messages.PassphraseRequest, ] diff --git a/tests/device_tests/tezos/test_getaddress.py b/tests/device_tests/tezos/test_getaddress.py index 12c53fe31..5330d132c 100644 --- a/tests/device_tests/tezos/test_getaddress.py +++ b/tests/device_tests/tezos/test_getaddress.py @@ -24,11 +24,12 @@ from trezorlib.tools import parse_path @pytest.mark.altcoin @pytest.mark.tezos @pytest.mark.skip_t1 -def test_tezos_get_address(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_tezos_get_address(client: Client, chunkify: bool): path = parse_path("m/44h/1729h/0h") - address = get_address(client, path, show_display=True) + address = get_address(client, path, show_display=True, chunkify=chunkify) assert address == "tz1Kef7BSg6fo75jk37WkKRYSnJDs69KVqt9" path = parse_path("m/44h/1729h/1h") - address = get_address(client, path, show_display=True) + address = get_address(client, path, show_display=True, chunkify=chunkify) assert address == "tz1ekQapZCX4AXxTJhJZhroDKDYLHDHegvm1" diff --git a/tests/device_tests/tezos/test_sign_tx.py b/tests/device_tests/tezos/test_sign_tx.py index 30c13d6b7..f4a729b54 100644 --- a/tests/device_tests/tezos/test_sign_tx.py +++ b/tests/device_tests/tezos/test_sign_tx.py @@ -166,7 +166,8 @@ def test_tezos_sing_tx_ballot_pass(client: Client): ) -def test_tezos_sign_tx_tranasaction(client: Client): +@pytest.mark.parametrize("chunkify", (True, False)) +def test_tezos_sign_tx_tranasaction(client: Client, chunkify: bool): resp = tezos.sign_tx( client, TEZOS_PATH_10, @@ -188,6 +189,7 @@ def test_tezos_sign_tx_tranasaction(client: Client): }, }, ), + chunkify=chunkify, ) assert ( resp.signature diff --git a/tests/device_tests/zcash/test_sign_tx.py b/tests/device_tests/zcash/test_sign_tx.py index 7ddc34e32..388c8040e 100644 --- a/tests/device_tests/zcash/test_sign_tx.py +++ b/tests/device_tests/zcash/test_sign_tx.py @@ -95,13 +95,13 @@ def test_spend_v4_input(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), @@ -144,13 +144,13 @@ def test_send_to_multisig(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), @@ -192,13 +192,13 @@ def test_spend_v5_input(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), @@ -246,13 +246,13 @@ def test_one_two(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -305,13 +305,13 @@ def test_unified_address(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), @@ -370,14 +370,14 @@ def test_external_presigned(client: Client): ) with client: - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(1), request_input(0), @@ -483,12 +483,12 @@ def test_spend_multisig(client: Client): ) # Expected responses are the same for both two signings - tt = client.features.model == "T" + is_core = client.features.model in ("T", "R") expected_responses = [ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), - (tt, messages.ButtonRequest(code=B.ConfirmOutput)), + (is_core, messages.ButtonRequest(code=B.ConfirmOutput)), messages.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), diff --git a/tests/input_flows.py b/tests/input_flows.py index bdab88e72..ae90db4ba 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -27,7 +27,7 @@ from .common import ( click_through, read_and_confirm_mnemonic, ) -from .input_flows_helpers import BackupFlow, PinFlow, RecoveryFlow +from .input_flows_helpers import BackupFlow, EthereumFlow, PinFlow, RecoveryFlow B = messages.ButtonRequestType @@ -48,6 +48,7 @@ class InputFlowBase: self.PIN = PinFlow(self.client) self.REC = RecoveryFlow(self.client) self.BAK = BackupFlow(self.client) + self.ETH = EthereumFlow(self.client) def model(self) -> str | None: return self.client.features.model @@ -235,6 +236,11 @@ class InputFlowSignMessagePagination(InputFlowBase): yield self.debug.press_yes() + # press info + yield + self.debug.press_right() + + # paginate through the whole message br = yield # TODO: try load the message_read the same way as in model T if br.pages is not None: @@ -243,6 +249,10 @@ class InputFlowSignMessagePagination(InputFlowBase): self.debug.swipe_up() self.debug.press_yes() + # confirm message + yield + self.debug.press_yes() + class InputFlowShowAddressQRCode(InputFlowBase): def __init__(self, client: Client): @@ -311,6 +321,9 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): self.index = index def input_flow_tt(self) -> BRGeneratorType: + yield # multisig address warning + self.debug.press_yes() + yield # show address layout = self.debug.wait_layout() assert "RECEIVE ADDRESS\n(MULTISIG)" == layout.title() @@ -343,6 +356,9 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): self.debug.press_yes() def input_flow_tr(self) -> BRGeneratorType: + yield # multisig address warning + self.debug.press_middle() + yield # show address layout = self.debug.wait_layout() assert "RECEIVE ADDRESS (MULTISIG)" in layout.title() @@ -381,6 +397,65 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): self.debug.press_middle() +class InputFlowShowXpubQRCode(InputFlowBase): + def __init__(self, client: Client, passphrase: bool = False): + super().__init__(client) + self.passphrase = passphrase + + def input_flow_tt(self) -> BRGeneratorType: + if self.passphrase: + yield + self.debug.press_yes() + yield + self.debug.press_yes() + + br = yield + layout = self.debug.wait_layout() + if "coinjoin" in layout.title().lower() or br.code == B.UnknownDerivationPath: + self.debug.press_yes() + br = yield + + self.debug.click(buttons.CORNER_BUTTON, wait=True) + # synchronize; TODO get rid of this once we have single-global-layout + self.debug.synchronize_at("HorizontalPage") + + self.debug.swipe_left(wait=True) + self.debug.swipe_right(wait=True) + self.debug.swipe_left(wait=True) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.press_no(wait=True) + self.debug.press_no(wait=True) + for _ in range(br.pages - 1): + self.debug.swipe_up(wait=True) + self.debug.press_yes() + + def input_flow_tr(self) -> BRGeneratorType: + if self.passphrase: + yield + self.debug.press_right() + yield + self.debug.press_right() + + br = yield + layout = self.debug.wait_layout() + if "coinjoin" in layout.title().lower() or br.code == B.UnknownDerivationPath: + self.debug.press_yes() + br = yield + + # Go into details + self.debug.press_right(wait=True) + # Go through details and back + self.debug.press_right(wait=True) + self.debug.press_right(wait=True) + self.debug.press_left(wait=True) + self.debug.press_left(wait=True) + assert br.pages is not None + for _ in range(br.pages - 1): + self.debug.press_right() + # Confirm + self.debug.press_middle() + + class InputFlowPaymentRequestDetails(InputFlowBase): def __init__(self, client: Client, outputs: list[messages.TxOutputType]): super().__init__(client) @@ -424,7 +499,7 @@ class InputFlowSignTxHighFee(InputFlowBase): self.finished = True - def input_flow_tt(self) -> BRGeneratorType: + def input_flow_common(self) -> BRGeneratorType: screens = [ B.ConfirmOutput, B.ConfirmOutput, @@ -433,14 +508,6 @@ class InputFlowSignTxHighFee(InputFlowBase): ] yield from self.go_through_all_screens(screens) - def input_flow_tr(self) -> BRGeneratorType: - screens = [ - B.ConfirmOutput, - B.FeeOverThreshold, - B.SignTx, - ] - yield from self.go_through_all_screens(screens) - def sign_tx_go_to_info(client: Client) -> Generator[None, None, str]: yield # confirm output @@ -465,15 +532,21 @@ def sign_tx_go_to_info(client: Client) -> Generator[None, None, str]: def sign_tx_go_to_info_tr( client: Client, ) -> Generator[None, None, str]: - yield # confirm output + yield # confirm address client.debug.wait_layout() - client.debug.press_right() # CONTINUE + client.debug.press_yes() # CONTINUE + yield # confirm amount client.debug.wait_layout() - client.debug.press_right() # CONFIRM + client.debug.press_yes() # CONFIRM screen_texts: list[str] = [] yield # confirm total + layout = client.debug.wait_layout() + if "multiple accounts" in layout.text_content().lower(): + client.debug.press_middle() + yield + layout = client.debug.press_right(wait=True) screen_texts.append(layout.text_content()) @@ -518,6 +591,10 @@ class InputFlowSignTxInformationMixed(InputFlowBase): assert "18.33 sat" in content def input_flow_tt(self) -> BRGeneratorType: + # multiple accounts warning + yield + self.debug.press_yes() + content = yield from sign_tx_go_to_info(self.client) self.assert_content(content) self.debug.press_yes() @@ -602,9 +679,10 @@ def lock_time_input_flow_tt( def lock_time_input_flow_tr( debug: DebugLink, layout_assert_func: Callable[[DebugLink], None] ) -> BRGeneratorType: - yield # confirm output + yield # confirm address debug.wait_layout() - debug.swipe_up() + debug.press_yes() + yield # confirm amount debug.wait_layout() debug.press_yes() @@ -722,134 +800,53 @@ class InputFlowEIP712Cancel(InputFlowBase): self.debug.press_no() -class InputFlowEthereumSignTxSkip(InputFlowBase): +class InputFlowEthereumSignTxShowFeeInfo(InputFlowBase): def __init__(self, client: Client, cancel: bool = False): super().__init__(client) self.cancel = cancel def input_flow_common(self) -> BRGeneratorType: - yield # confirm address - self.debug.press_yes() - yield # confirm amount - self.debug.wait_layout() - self.debug.press_yes() - yield # confirm data - if self.cancel: - self.debug.press_no() - else: - self.debug.press_yes() - yield # gas price - self.debug.press_yes() - yield # maximum fee - self.debug.press_yes() - yield # hold to confirm - self.debug.press_yes() + yield from self.ETH.confirm_tx(info=True) -class InputFlowEthereumSignTxScrollDown(InputFlowBase): - SHOW_ALL = (143, 167) - +class InputFlowEthereumSignTxDataSkip(InputFlowBase): def __init__(self, client: Client, cancel: bool = False): super().__init__(client) self.cancel = cancel - def input_flow_tt(self) -> BRGeneratorType: - yield # confirm address - self.debug.wait_layout() - self.debug.press_yes() - yield # confirm amount - self.debug.wait_layout() - self.debug.press_yes() - yield # confirm data - self.debug.wait_layout() - self.debug.click(self.SHOW_ALL) - - br = yield # paginated data - assert br.pages is not None - for i in range(br.pages): - self.debug.wait_layout() - if i < br.pages - 1: - self.debug.swipe_up() - - self.debug.press_yes() - yield # confirm data - if self.cancel: - self.debug.press_no() - else: - self.debug.press_yes() - yield # gas price - self.debug.press_yes() - yield # maximum fee - self.debug.press_yes() - yield # hold to confirm - self.debug.press_yes() + def input_flow_common(self) -> BRGeneratorType: + yield from self.ETH.confirm_data() + yield from self.ETH.confirm_tx(cancel=self.cancel) - def input_flow_tr(self) -> BRGeneratorType: - yield # confirm address - self.debug.wait_layout() - self.debug.press_yes() - br = yield # paginated data - assert br.pages is not None - for _ in range(br.pages): - self.debug.wait_layout() - self.debug.swipe_up() - - yield # confirm amount - self.debug.wait_layout() - self.debug.press_yes() +class InputFlowEthereumSignTxDataScrollDown(InputFlowBase): + def __init__(self, client: Client, cancel: bool = False): + super().__init__(client) + self.cancel = cancel - yield # confirm before send + def input_flow_common(self) -> BRGeneratorType: + yield from self.ETH.confirm_data(info=True) + yield from self.ETH.paginate_data() if self.cancel: - self.debug.press_no() + yield from self.ETH.confirm_data(cancel=True) else: - self.debug.press_yes() - + yield from self.ETH.confirm_data() + yield from self.ETH.confirm_tx() -class InputFlowEthereumSignTxGoBack(InputFlowBase): - SHOW_ALL = (143, 167) - GO_BACK = (16, 220) +class InputFlowEthereumSignTxDataGoBack(InputFlowBase): def __init__(self, client: Client, cancel: bool = False): super().__init__(client) self.cancel = cancel - def input_flow_tt(self) -> BRGeneratorType: - br = yield # confirm address - self.debug.wait_layout() - self.debug.press_yes() - br = yield # confirm amount - self.debug.wait_layout() - self.debug.press_yes() - br = yield # confirm data - self.debug.wait_layout() - self.debug.click(self.SHOW_ALL) - - br = yield # paginated data - assert br.pages is not None - for i in range(br.pages): - self.debug.wait_layout() - if i == 2: - self.debug.click(self.GO_BACK) - yield # confirm data - self.debug.wait_layout() - if self.cancel: - self.debug.press_no() - else: - self.debug.press_yes() - yield # confirm address - self.debug.wait_layout() - self.debug.press_yes() - yield # confirm amount - self.debug.wait_layout() - self.debug.press_yes() - yield # hold to confirm - self.debug.wait_layout() - self.debug.press_yes() - return - - elif i < br.pages - 1: - self.debug.swipe_up() + def input_flow_common(self) -> BRGeneratorType: + yield from self.ETH.confirm_data(info=True) + yield from self.ETH.paginate_data_go_back() + if self.cancel: + yield from self.ETH.confirm_data(cancel=True) + else: + yield from self.ETH.confirm_data() + yield from self.ETH.confirm_tx() def get_mnemonic_and_confirm_success( diff --git a/tests/input_flows_helpers.py b/tests/input_flows_helpers.py index 52fa35c45..4e189ac95 100644 --- a/tests/input_flows_helpers.py +++ b/tests/input_flows_helpers.py @@ -247,3 +247,81 @@ class RecoveryFlow: yield self.debug.swipe_up() self.debug.press_yes() + + +class EthereumFlow: + GO_BACK = (16, 220) + + def __init__(self, client: Client): + self.client = client + self.debug = self.client.debug + + def confirm_data(self, info: bool = False, cancel: bool = False) -> BRGeneratorType: + yield + assert self.debug.wait_layout().title() == "CONFIRM DATA" + assert "Size:" in self.debug.wait_layout().text_content() + if info: + self.debug.press_info() + elif cancel: + self.debug.press_no() + else: + self.debug.press_yes() + + def paginate_data(self) -> BRGeneratorType: + br = yield + assert self.debug.wait_layout().title() == "CONFIRM DATA" + assert br.pages is not None + for i in range(br.pages): + self.debug.wait_layout() + if i < br.pages - 1: + self.debug.swipe_up() + self.debug.press_yes() + + def paginate_data_go_back(self) -> BRGeneratorType: + br = yield + assert self.debug.wait_layout().title() == "CONFIRM DATA" + assert br.pages is not None + assert br.pages > 2 + if self.debug.model == "T": + self.debug.swipe_up(wait=True) + self.debug.swipe_up(wait=True) + self.debug.click(self.GO_BACK) + else: + self.debug.press_right() + self.debug.press_right() + self.debug.press_left() + self.debug.press_left() + self.debug.press_left() + + def confirm_tx(self, cancel: bool = False, info: bool = False) -> BRGeneratorType: + yield + assert self.debug.wait_layout().title() == "RECIPIENT" + + if self.debug.model == "T": + if cancel: + self.debug.press_no() + else: + self.debug.press_yes() + yield + assert self.debug.wait_layout().title() == "SUMMARY" + assert "Maximum fee:" in self.debug.wait_layout().text_content() + if info: + self.debug.press_info(wait=True) + assert "Gas limit:" in self.debug.wait_layout().text_content() + assert "Gas price:" in self.debug.wait_layout().text_content() + self.debug.press_no(wait=True) + self.debug.press_yes() + else: + if cancel: + self.debug.press_left() + else: + self.debug.press_right() + assert "Maximum fee:" in self.debug.wait_layout().text_content() + if info: + self.debug.press_right(wait=True) + assert "Gas limit:" in self.debug.wait_layout().text_content() + self.debug.press_right(wait=True) + assert "Gas price:" in self.debug.wait_layout().text_content() + self.debug.press_left(wait=True) + self.debug.press_left(wait=True) + self.debug.press_middle() diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index e649aa34e..7b0ad78aa 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -2,10 +2,11 @@ "T1": { "device_tests": { "T1_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "84d5223f94a7a31dc23d278121c4829f446611582065a67673be3b7d6a5b1274", -"T1_bitcoin-test_authorize_coinjoin.py::test_get_address": "08338bd37d8fb2d53055b5e749a8bb0bf85b95cf13c78d3d17a4dd75b120e81b", +"T1_bitcoin-test_authorize_coinjoin.py::test_get_address": "098f8204516ea6e563b1ff07ef645db5df81dacd6985dc5cdfbd495846cd3683", "T1_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "1257ec89d4620ed9f34c986cd925717676c9b1e9e143e040c33f1a88d1f8c8a7", "T1_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "5628b8419edd4c5211aab8af46f146542c605e8e24e6cd79ef0d3b378c98982a", -"T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx": "0ffc9ee5242b69975c12aa901d47dc80e44c2bbc42f98e12bf35d36adbca70b7", +"T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "0ffc9ee5242b69975c12aa901d47dc80e44c2bbc42f98e12bf35d36adbca70b7", +"T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "0ffc9ee5242b69975c12aa901d47dc80e44c2bbc42f98e12bf35d36adbca70b7", "T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "39ce1d721b7516f90c027c8abf28ebad28dce18b82618764624c93a5e2bf1736", "T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "3560ac3e7258a710c75827cf6eb0bdf2456d448c3c270b7971eaa0ea94670d3f", "T1_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "dd06d17f855486ae857c7d26e19f738e0743cabd2c88d6aad23e5aead1e51ba8", @@ -160,7 +161,8 @@ "T1_bitcoin-test_komodo.py::test_one_one_fee_sapling": "ec2dfb6deb2400f35d42c9f626a55eddc07cc34162b26f721113913d0b0e349c", "T1_bitcoin-test_komodo.py::test_one_one_rewards_claim": "e623e85329341afa146fd5f4b93eef09eaecfcd66478b2a096c9930b5b6bede8", "T1_bitcoin-test_multisig.py::test_15_of_15": "41c00a3dcdeec1120d72df9a16a6d38047cf60407f5b1116aa5ca892dfcde7c3", -"T1_bitcoin-test_multisig.py::test_2_of_3": "ce96277e0a7b026144ee6cdd501c160c27a6d4a2ad8451d9f4de8114eebe0cde", +"T1_bitcoin-test_multisig.py::test_2_of_3[False]": "ce96277e0a7b026144ee6cdd501c160c27a6d4a2ad8451d9f4de8114eebe0cde", +"T1_bitcoin-test_multisig.py::test_2_of_3[True]": "ce96277e0a7b026144ee6cdd501c160c27a6d4a2ad8451d9f4de8114eebe0cde", "T1_bitcoin-test_multisig.py::test_attack_change_input": "d8731108a403d5853de526b27e506d00909603ec0c89d1c20f917ca2ef012ab3", "T1_bitcoin-test_multisig.py::test_missing_pubkey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_bitcoin-test_multisig_change.py::test_external_external": "e4a9c75e35046d5605d3663717ec025e7c7919ce757cdd9df66eba3bd7790d1d", @@ -171,11 +173,16 @@ "T1_bitcoin-test_multisig_change.py::test_multisig_external_external": "0c398595da3162afee0f4734a155c0cf8d96b830350b58670b47aba40659e3cc", "T1_bitcoin-test_multisig_change.py::test_multisig_mismatch_change": "25d6670f1a30d56fccf78d3119aaa876b5f31655b6901a3a4ef1838748045cae", "T1_bitcoin-test_multisig_change.py::test_multisig_mismatch_inputs": "601dbfefbebf6dcf988a3c1c5508dc75c59df753b0788a2f017eb4346f3ab55c", -"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3]": "c968d01488a358a7287c4e631996081bb490ff6e702b5ff84c3addba1c7b0974", -"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2]": "814c415655b03a6757056456544852a7ec88f8e96fbc97728eba7874d03782f8", -"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1]": "f1d7f1ba4255576af0ffe4dd11dbc31dda17fec533495992a26bc1d22ade567a", -"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0]": "df99b6bcfaf86d8ca67713ba64c085fb57b6fc6004494ef1cf83ccb4b57b8d4b", -"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4]": "670669469e2de75d1164e7a0d5c8ad9c96520b0bf9d7aef85e5796853a375cdd", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-False]": "c968d01488a358a7287c4e631996081bb490ff6e702b5ff84c3addba1c7b0974", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-True]": "c968d01488a358a7287c4e631996081bb490ff6e702b5ff84c3addba1c7b0974", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-False]": "814c415655b03a6757056456544852a7ec88f8e96fbc97728eba7874d03782f8", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-True]": "814c415655b03a6757056456544852a7ec88f8e96fbc97728eba7874d03782f8", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-False]": "f1d7f1ba4255576af0ffe4dd11dbc31dda17fec533495992a26bc1d22ade567a", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-True]": "f1d7f1ba4255576af0ffe4dd11dbc31dda17fec533495992a26bc1d22ade567a", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-False]": "df99b6bcfaf86d8ca67713ba64c085fb57b6fc6004494ef1cf83ccb4b57b8d4b", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-True]": "df99b6bcfaf86d8ca67713ba64c085fb57b6fc6004494ef1cf83ccb4b57b8d4b", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-False]": "670669469e2de75d1164e7a0d5c8ad9c96520b0bf9d7aef85e5796853a375cdd", +"T1_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-True]": "670669469e2de75d1164e7a0d5c8ad9c96520b0bf9d7aef85e5796853a375cdd", "T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "3f11a25075140b6bb74d03d2eaf67559003cf5f46d07a778e2552bb281eaaaa8", "T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "7c888498d7a49466b2ec128d523f5b7a4af29beccab3e4da8fdf3de2cc3e0e1e", "T1_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "e8723bbbe5cb2484f3d1eda6fe19c48f23df6e96c36f6ff0d5d9d499ffc034a6", @@ -252,7 +259,8 @@ "T1_bitcoin-test_signtx.py::test_not_enough_funds": "8d684112b826d1902e8a1a2106618b6a6f4983ce790e939fc3db476b20e30dea", "T1_bitcoin-test_signtx.py::test_not_enough_vouts": "3413455a90c3e1dfb0c907c844fab0b82c6f5acabb013d0b5e7e843a3bfe76c2", "T1_bitcoin-test_signtx.py::test_one_one_fee": "013ca83fd68c5b3d74b66b90a9485392543c95b792e97110142c34def21914ee", -"T1_bitcoin-test_signtx.py::test_one_three_fee": "09f36a6d9e41309459ec4ff7ee075e5e8e227eb05f6b722c8e9f2898c6840678", +"T1_bitcoin-test_signtx.py::test_one_three_fee[False]": "09f36a6d9e41309459ec4ff7ee075e5e8e227eb05f6b722c8e9f2898c6840678", +"T1_bitcoin-test_signtx.py::test_one_three_fee[True]": "09f36a6d9e41309459ec4ff7ee075e5e8e227eb05f6b722c8e9f2898c6840678", "T1_bitcoin-test_signtx.py::test_one_two_fee": "a208d646da6116f842df4df320e2409f2ffbae88459916d9b094764501011ea8", "T1_bitcoin-test_signtx.py::test_p2sh": "e1d834b1512fd9018a81313ce1aabebc8a61d45ae5d32992074029b93c5342ee", "T1_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[branch_id-13]": "56a27ac97a3af3279a1cbffc109658301a185f4fbd65654e4003419acb76934b", @@ -319,7 +327,8 @@ "T1_bitcoin-test_signtx_segwit.py::test_attack_change_input_address": "ddd46015ad9e958929a0fe9ad37a5aa07944807f08be6d3f9c3086c4876f6af4", "T1_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "05fba4bc7c52f1ae8154b8d55d52795900b7e1598a1d965200d36b5f44f93ccd", "T1_bitcoin-test_signtx_segwit.py::test_send_multisig_1": "4799cbd3de2dad5255880a807f15d9d0d857b2ca0bb1afb287a4810964144833", -"T1_bitcoin-test_signtx_segwit.py::test_send_p2sh": "4d0e5e5699cf3173fa6361dee03b9c51cfad6e21f5937ac899719ac63602c60c", +"T1_bitcoin-test_signtx_segwit.py::test_send_p2sh[False]": "4d0e5e5699cf3173fa6361dee03b9c51cfad6e21f5937ac899719ac63602c60c", +"T1_bitcoin-test_signtx_segwit.py::test_send_p2sh[True]": "4d0e5e5699cf3173fa6361dee03b9c51cfad6e21f5937ac899719ac63602c60c", "T1_bitcoin-test_signtx_segwit.py::test_send_p2sh_change": "26ce46c162932aab4a51fe6ab40b60e061d33c9cefac85db857ca6a1b1edb047", "T1_bitcoin-test_signtx_segwit.py::test_testnet_segwit_big_amount": "32f4561974abff85a6569299f3fadbd88eadf1669e6159f42143553f9eaa9192", "T1_bitcoin-test_signtx_segwit_native.py::test_multisig_mismatch_inputs_single": "d2090fa198da39a988f8f6c6469dcc449c4763a0cde0b795117ed35efbacff79", @@ -339,7 +348,8 @@ "T1_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1plycg5qvjtrp3qjf5f7zl382j9x6nr-5447628e": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1zlycg5qvjtrp3qjf5f7zl382j9x6nr-880d4a6b": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_bitcoin-test_signtx_taproot.py::test_send_mixed": "3f94ff30dff867fd58667cd1f26025939856212f8cf3eefee4eafbfa5f2c6003", -"T1_bitcoin-test_signtx_taproot.py::test_send_p2tr": "0367ba2a029f686d2313ab464ffa5199727d9ade4e715a9c69963e208c648f51", +"T1_bitcoin-test_signtx_taproot.py::test_send_p2tr[False]": "0367ba2a029f686d2313ab464ffa5199727d9ade4e715a9c69963e208c648f51", +"T1_bitcoin-test_signtx_taproot.py::test_send_p2tr[True]": "0367ba2a029f686d2313ab464ffa5199727d9ade4e715a9c69963e208c648f51", "T1_bitcoin-test_signtx_taproot.py::test_send_two_with_change": "6e32c316b41ad35dbc46a10713ad569b832651dc54efa935dbdc0a05f5ccf990", "T1_bitcoin-test_verifymessage.py::test_message_grs": "3a99e790a5d48dbaf76e15d314b46113f10daba5ad4cbb652d162033b0d3b02e", "T1_bitcoin-test_verifymessage.py::test_message_long": "ed4a40daa108bb66f076da8c3b30e905c54a0917d0b9fab12ea381bf6f5a2036", @@ -398,12 +408,18 @@ "T1_ethereum-test_definitions_bad.py::test_short_message": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_ethereum-test_definitions_bad.py::test_trailing_garbage": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_ethereum-test_definitions_bad.py::test_trimmed_proof": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", -"T1_ethereum-test_getaddress.py::test_getaddress[ETC]": "efe11a5e9959ba001e33298ec4e00c4f224e325bd41fd713cf01192ac4dfb01a", -"T1_ethereum-test_getaddress.py::test_getaddress[Ledger Live legacy path]": "16ccd6cf4421b1002d479f9ca633ac1ee8dca0fa3f1339fa66380d14e5109e2a", -"T1_ethereum-test_getaddress.py::test_getaddress[parameters0-result0]": "a229f91ee8c13470faa74e086d582032072f8f2e3a38cf5e9941bef634abb626", -"T1_ethereum-test_getaddress.py::test_getaddress[parameters1-result1]": "5eaa807f7ac37df989696049a1a5e19751f0c32b7541167e88f56a7aff353f42", -"T1_ethereum-test_getaddress.py::test_getaddress[parameters2-result2]": "d2f4a0194a0dfeb082daec10639c0489ebe30389d7baf1a26dfe20538421592a", -"T1_ethereum-test_getaddress.py::test_getaddress[parameters3-result3]": "c6323cb37b60ce8effa98da2fbeee0a734d8d3566fe7f2932b55ffee6d146f45", +"T1_ethereum-test_getaddress.py::test_getaddress[False-ETC]": "efe11a5e9959ba001e33298ec4e00c4f224e325bd41fd713cf01192ac4dfb01a", +"T1_ethereum-test_getaddress.py::test_getaddress[False-Ledger Live legacy path]": "16ccd6cf4421b1002d479f9ca633ac1ee8dca0fa3f1339fa66380d14e5109e2a", +"T1_ethereum-test_getaddress.py::test_getaddress[False-parameters0-result0]": "a229f91ee8c13470faa74e086d582032072f8f2e3a38cf5e9941bef634abb626", +"T1_ethereum-test_getaddress.py::test_getaddress[False-parameters1-result1]": "5eaa807f7ac37df989696049a1a5e19751f0c32b7541167e88f56a7aff353f42", +"T1_ethereum-test_getaddress.py::test_getaddress[False-parameters2-result2]": "d2f4a0194a0dfeb082daec10639c0489ebe30389d7baf1a26dfe20538421592a", +"T1_ethereum-test_getaddress.py::test_getaddress[False-parameters3-result3]": "c6323cb37b60ce8effa98da2fbeee0a734d8d3566fe7f2932b55ffee6d146f45", +"T1_ethereum-test_getaddress.py::test_getaddress[True-ETC]": "efe11a5e9959ba001e33298ec4e00c4f224e325bd41fd713cf01192ac4dfb01a", +"T1_ethereum-test_getaddress.py::test_getaddress[True-Ledger Live legacy path]": "16ccd6cf4421b1002d479f9ca633ac1ee8dca0fa3f1339fa66380d14e5109e2a", +"T1_ethereum-test_getaddress.py::test_getaddress[True-parameters0-result0]": "a229f91ee8c13470faa74e086d582032072f8f2e3a38cf5e9941bef634abb626", +"T1_ethereum-test_getaddress.py::test_getaddress[True-parameters1-result1]": "5eaa807f7ac37df989696049a1a5e19751f0c32b7541167e88f56a7aff353f42", +"T1_ethereum-test_getaddress.py::test_getaddress[True-parameters2-result2]": "d2f4a0194a0dfeb082daec10639c0489ebe30389d7baf1a26dfe20538421592a", +"T1_ethereum-test_getaddress.py::test_getaddress[True-parameters3-result3]": "c6323cb37b60ce8effa98da2fbeee0a734d8d3566fe7f2932b55ffee6d146f45", "T1_ethereum-test_getpublickey.py::test_ethereum_getpublickey[Ledger Live legacy path]": "37e446e17465ce9823c34c9162d94e4ad3c84faa86bae7966c753be5c5fd77a2", "T1_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters0-result0]": "37e446e17465ce9823c34c9162d94e4ad3c84faa86bae7966c753be5c5fd77a2", "T1_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters1-result1]": "37e446e17465ce9823c34c9162d94e4ad3c84faa86bae7966c753be5c5fd77a2", @@ -440,34 +456,62 @@ "T1_ethereum-test_signtx.py::test_data_streaming": "058a66e82bb733d5c5c687b5537887022acfd7401bb0b5aa4a12f6f35b209239", "T1_ethereum-test_signtx.py::test_sanity_checks": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_ethereum-test_signtx.py::test_sanity_checks_eip1559": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", -"T1_ethereum-test_signtx.py::test_signtx[Auxilium]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[ETC]": "05b7842c03625104ae3459a55097bc96e878eca465bf69ea2691407868e5dd4b", -"T1_ethereum-test_signtx.py::test_signtx[Ethereum]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", -"T1_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path0]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", -"T1_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path1]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", -"T1_ethereum-test_signtx.py::test_signtx[Palm]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[Pirl]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[Rinkeby]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", -"T1_ethereum-test_signtx.py::test_signtx[Ropsten]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", -"T1_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_eth_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_testnet_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[data_1]": "8b432aba21bc4344814cceaf693e114b9d3e3d6ceb83c3a6af7c3ed0f9b37449", -"T1_ethereum-test_signtx.py::test_signtx[data_2_bigdata]": "445286b7501ca67dd16dafd7ea09c57cc4a37a642ae50f0c812d74353c37c017", -"T1_ethereum-test_signtx.py::test_signtx[erc20_token]": "d797c970429f1e974a69b9f5bd814a4f13f15b1b5d6ab1c117e65b919a434cf9", -"T1_ethereum-test_signtx.py::test_signtx[max_chain_id]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[max_chain_plus_one]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", -"T1_ethereum-test_signtx.py::test_signtx[max_uint64]": "a6e6d63cba839c897e80dc0b7cf5c2263be8ff64a5281a43fca992380cca872b", -"T1_ethereum-test_signtx.py::test_signtx[newcontract]": "a7efa7f690d1448dc48f642f69688e8b266417901cc014e5930c94c9087b3e08", -"T1_ethereum-test_signtx.py::test_signtx[nodata_1]": "6bd90f2c98122de19159e60fd4dcf9f4b16a600407ac84ea1e447d561ea9decb", -"T1_ethereum-test_signtx.py::test_signtx[nodata_2_bigvalue]": "538f7be885ce6ea3a6dc842ef10797fa45184d7737f6f179c42d36fe92fadd45", -"T1_ethereum-test_signtx.py::test_signtx[wanchain]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[Ledger Live legacy path]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[data_1]": "171ffadf61a2520274bedf6a8543127f23a8948c2689e034f996e170289b1822", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[data_2_bigdata]": "28d2a0d397b4e9865ca8286cc1a3669c3a7d34bb31b430662354bf3ec69d1cc5", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[erc20]": "4b97bba97b14f40c36a793e8a842d5c6fd13c4465b4d3b47b96bab943eb649f3", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[large_chainid]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[long_fees]": "ef84e6b4ae6ff0b4c9d22a4b6356c8c67affbf28882e83cef4aea6e93b4bdcf5", -"T1_ethereum-test_signtx.py::test_signtx_eip1559[nodata]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx[False-Auxilium]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-ETC]": "05b7842c03625104ae3459a55097bc96e878eca465bf69ea2691407868e5dd4b", +"T1_ethereum-test_signtx.py::test_signtx[False-Ethereum]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", +"T1_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path0]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", +"T1_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path1]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", +"T1_ethereum-test_signtx.py::test_signtx[False-Palm]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-Pirl]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-Rinkeby]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", +"T1_ethereum-test_signtx.py::test_signtx[False-Ropsten]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", +"T1_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_eth_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_testnet_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-data_1]": "8b432aba21bc4344814cceaf693e114b9d3e3d6ceb83c3a6af7c3ed0f9b37449", +"T1_ethereum-test_signtx.py::test_signtx[False-data_2_bigdata]": "445286b7501ca67dd16dafd7ea09c57cc4a37a642ae50f0c812d74353c37c017", +"T1_ethereum-test_signtx.py::test_signtx[False-erc20_token]": "d797c970429f1e974a69b9f5bd814a4f13f15b1b5d6ab1c117e65b919a434cf9", +"T1_ethereum-test_signtx.py::test_signtx[False-max_chain_id]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-max_chain_plus_one]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[False-max_uint64]": "a6e6d63cba839c897e80dc0b7cf5c2263be8ff64a5281a43fca992380cca872b", +"T1_ethereum-test_signtx.py::test_signtx[False-newcontract]": "a7efa7f690d1448dc48f642f69688e8b266417901cc014e5930c94c9087b3e08", +"T1_ethereum-test_signtx.py::test_signtx[False-nodata_1]": "6bd90f2c98122de19159e60fd4dcf9f4b16a600407ac84ea1e447d561ea9decb", +"T1_ethereum-test_signtx.py::test_signtx[False-nodata_2_bigvalue]": "538f7be885ce6ea3a6dc842ef10797fa45184d7737f6f179c42d36fe92fadd45", +"T1_ethereum-test_signtx.py::test_signtx[False-wanchain]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", +"T1_ethereum-test_signtx.py::test_signtx[True-Auxilium]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-ETC]": "05b7842c03625104ae3459a55097bc96e878eca465bf69ea2691407868e5dd4b", +"T1_ethereum-test_signtx.py::test_signtx[True-Ethereum]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", +"T1_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path0]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", +"T1_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path1]": "90feef1fdcd162209a948c127df638c09bee0444fee40f2d30dbff21658d83ef", +"T1_ethereum-test_signtx.py::test_signtx[True-Palm]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-Pirl]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-Rinkeby]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", +"T1_ethereum-test_signtx.py::test_signtx[True-Ropsten]": "937894301354c759d2221ed56286e7df6c6696fa4be3d61846cb3307fd428d21", +"T1_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_eth_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_testnet_path]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-data_1]": "8b432aba21bc4344814cceaf693e114b9d3e3d6ceb83c3a6af7c3ed0f9b37449", +"T1_ethereum-test_signtx.py::test_signtx[True-data_2_bigdata]": "445286b7501ca67dd16dafd7ea09c57cc4a37a642ae50f0c812d74353c37c017", +"T1_ethereum-test_signtx.py::test_signtx[True-erc20_token]": "d797c970429f1e974a69b9f5bd814a4f13f15b1b5d6ab1c117e65b919a434cf9", +"T1_ethereum-test_signtx.py::test_signtx[True-max_chain_id]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-max_chain_plus_one]": "4552f9a68c62613e1ef7df68c1f47f7d4888c4505f0586012b71c07acba1fbcb", +"T1_ethereum-test_signtx.py::test_signtx[True-max_uint64]": "a6e6d63cba839c897e80dc0b7cf5c2263be8ff64a5281a43fca992380cca872b", +"T1_ethereum-test_signtx.py::test_signtx[True-newcontract]": "a7efa7f690d1448dc48f642f69688e8b266417901cc014e5930c94c9087b3e08", +"T1_ethereum-test_signtx.py::test_signtx[True-nodata_1]": "6bd90f2c98122de19159e60fd4dcf9f4b16a600407ac84ea1e447d561ea9decb", +"T1_ethereum-test_signtx.py::test_signtx[True-nodata_2_bigvalue]": "538f7be885ce6ea3a6dc842ef10797fa45184d7737f6f179c42d36fe92fadd45", +"T1_ethereum-test_signtx.py::test_signtx[True-wanchain]": "37aa64fbab44b89757833df6ee78e302c97fe24c4cb74175f1843f635cb2dbec", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "171ffadf61a2520274bedf6a8543127f23a8948c2689e034f996e170289b1822", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-data_2_bigdata]": "28d2a0d397b4e9865ca8286cc1a3669c3a7d34bb31b430662354bf3ec69d1cc5", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-erc20]": "4b97bba97b14f40c36a793e8a842d5c6fd13c4465b4d3b47b96bab943eb649f3", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-large_chainid]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-long_fees]": "ef84e6b4ae6ff0b4c9d22a4b6356c8c67affbf28882e83cef4aea6e93b4bdcf5", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[False-nodata]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-Ledger Live legacy path]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-data_1]": "171ffadf61a2520274bedf6a8543127f23a8948c2689e034f996e170289b1822", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-data_2_bigdata]": "28d2a0d397b4e9865ca8286cc1a3669c3a7d34bb31b430662354bf3ec69d1cc5", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-erc20]": "4b97bba97b14f40c36a793e8a842d5c6fd13c4465b4d3b47b96bab943eb649f3", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-large_chainid]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-long_fees]": "ef84e6b4ae6ff0b4c9d22a4b6356c8c67affbf28882e83cef4aea6e93b4bdcf5", +"T1_ethereum-test_signtx.py::test_signtx_eip1559[True-nodata]": "5b008a081b4ef9e7b47c9d0c1fc4bb24d729d77841193694232bd2da4a386515", "T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1", "T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1", "T1_misc-test_cosi.py::test_cosi_nonce": "6990c238036b79368fea1dc1e3e8871d7788322bbee7425d14c53623bc8182e8", @@ -507,7 +551,8 @@ "T1_misc-test_msg_getentropy.py::test_entropy[8]": "10ee154b5db5599420a26df724cf2301afafb9bdb55429e4e091046881d589cb", "T1_misc-test_msg_getentropy.py::test_entropy[9]": "10ee154b5db5599420a26df724cf2301afafb9bdb55429e4e091046881d589cb", "T1_misc-test_msg_signidentity.py::test_sign": "237d6575385f61c32b574a23168330e40025eb9351202698f2d115db0e146934", -"T1_nem-test_getaddress.py::test_nem_getaddress": "647dbd437bc7d5913ca7cbc8027d0230c3617e8b266f2c89e63c2d1342313557", +"T1_nem-test_getaddress.py::test_nem_getaddress[False]": "647dbd437bc7d5913ca7cbc8027d0230c3617e8b266f2c89e63c2d1342313557", +"T1_nem-test_getaddress.py::test_nem_getaddress[True]": "647dbd437bc7d5913ca7cbc8027d0230c3617e8b266f2c89e63c2d1342313557", "T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation": "74f2ed8d59e1aa1185ef7f06fe63e49380dfb185faa0e0d01656bc2bc8ff8c0c", "T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_levy": "d782d6c77ea579238f6c5fc81adef34e0a47b4006ee4cf4556747ddc4afa998b", "T1_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_properties": "014cdfbc54f7e6861fbc74e2c5729d6d5ce75b9774130d2cc62de413a96d05c9", @@ -521,7 +566,8 @@ "T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "4de1af57a9f25b81ab5d29a6c96e2cd117145aae6cba3fedd083cac7f8cff1d7", "T1_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "ebc2635064a4469a98c2a4db2608ec3d006a69386d47e78bbbb8800bb0e7dc2a", "T1_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "ac772c16bacef88ec59bc4e1561520ed57e8d0ac74045136f5849a665b92978f", -"T1_nem-test_signtx_transfers.py::test_nem_signtx_simple": "3dac9a2abaab139be3b670d6f8e22d34db0171d09101b447c9de7011ad59b465", +"T1_nem-test_signtx_transfers.py::test_nem_signtx_simple[False]": "3dac9a2abaab139be3b670d6f8e22d34db0171d09101b447c9de7011ad59b465", +"T1_nem-test_signtx_transfers.py::test_nem_signtx_simple[True]": "3dac9a2abaab139be3b670d6f8e22d34db0171d09101b447c9de7011ad59b465", "T1_nem-test_signtx_transfers.py::test_nem_signtx_unknown_mosaic": "df352a677aa8f591effe241d0a384cea282934d5735c4bf34734616237fb96ca", "T1_nem-test_signtx_transfers.py::test_nem_signtx_xem_as_mosaic": "9cc4d7978b6296e0d107a20912e4dedcc9ed6eb3229749a7fb515827c85f18ee", "T1_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[label-test]": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", @@ -547,16 +593,26 @@ "T1_reset_recovery-test_reset_bip39_t1.py::test_reset_device_128": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_reset_recovery-test_reset_bip39_t1.py::test_reset_device_192": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_reset_recovery-test_reset_bip39_t1.py::test_reset_device_256_pin": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", -"T1_stellar-test_stellar.py::test_get_address[parameters0-result0]": "b004cb1a815072ae3ba9f4aadeeb9d37d3309513e973f7ddeb2ee23a056db726", -"T1_stellar-test_stellar.py::test_get_address[parameters1-result1]": "101692e06782269486e3f1093fdf03200e0cdce4b4ffc7cc5fc779b80f69d1fc", -"T1_stellar-test_stellar.py::test_get_address[parameters2-result2]": "508bbd5285d2f3087fa3b872ff053a286630b80beacd0b8b30c8577aa5396c86", -"T1_stellar-test_stellar.py::test_get_address[parameters3-result3]": "a2b19a4e0337cb47b02c4d79f571a7297ac273f3bd95d3d5886d908fa8313c8c", -"T1_stellar-test_stellar.py::test_get_address[parameters4-result4]": "0d855560df510dfbb5cdb668fa84e3c6ba10b306c65929a6138d8c07d52f9087", -"T1_stellar-test_stellar.py::test_get_address[parameters5-result5]": "953bd04ca03df48a1635b944044914676e3d397080d1f86c25a5605ba4c103c2", -"T1_stellar-test_stellar.py::test_get_address[parameters6-result6]": "42b9120cba355febf542b6f6162c2ef2fe0265270f680802ce0aff1833c152aa", -"T1_stellar-test_stellar.py::test_get_address[parameters7-result7]": "bd662518d9e136e5eae64e507994f7b74075294634317a38669dd2671001a188", -"T1_stellar-test_stellar.py::test_get_address[parameters8-result8]": "c03fc37c6a4d2341b0081900b90ffc2faf09a228607d9d6c807efaff8ecc8fde", -"T1_stellar-test_stellar.py::test_get_address[parameters9-result9]": "9f1f4cae47cb5e9602450d110fd1945dbdb059996955d74067204966c0cc1702", +"T1_stellar-test_stellar.py::test_get_address[parameters0-result0-False]": "b004cb1a815072ae3ba9f4aadeeb9d37d3309513e973f7ddeb2ee23a056db726", +"T1_stellar-test_stellar.py::test_get_address[parameters0-result0-True]": "b004cb1a815072ae3ba9f4aadeeb9d37d3309513e973f7ddeb2ee23a056db726", +"T1_stellar-test_stellar.py::test_get_address[parameters1-result1-False]": "101692e06782269486e3f1093fdf03200e0cdce4b4ffc7cc5fc779b80f69d1fc", +"T1_stellar-test_stellar.py::test_get_address[parameters1-result1-True]": "101692e06782269486e3f1093fdf03200e0cdce4b4ffc7cc5fc779b80f69d1fc", +"T1_stellar-test_stellar.py::test_get_address[parameters2-result2-False]": "508bbd5285d2f3087fa3b872ff053a286630b80beacd0b8b30c8577aa5396c86", +"T1_stellar-test_stellar.py::test_get_address[parameters2-result2-True]": "508bbd5285d2f3087fa3b872ff053a286630b80beacd0b8b30c8577aa5396c86", +"T1_stellar-test_stellar.py::test_get_address[parameters3-result3-False]": "a2b19a4e0337cb47b02c4d79f571a7297ac273f3bd95d3d5886d908fa8313c8c", +"T1_stellar-test_stellar.py::test_get_address[parameters3-result3-True]": "a2b19a4e0337cb47b02c4d79f571a7297ac273f3bd95d3d5886d908fa8313c8c", +"T1_stellar-test_stellar.py::test_get_address[parameters4-result4-False]": "0d855560df510dfbb5cdb668fa84e3c6ba10b306c65929a6138d8c07d52f9087", +"T1_stellar-test_stellar.py::test_get_address[parameters4-result4-True]": "0d855560df510dfbb5cdb668fa84e3c6ba10b306c65929a6138d8c07d52f9087", +"T1_stellar-test_stellar.py::test_get_address[parameters5-result5-False]": "953bd04ca03df48a1635b944044914676e3d397080d1f86c25a5605ba4c103c2", +"T1_stellar-test_stellar.py::test_get_address[parameters5-result5-True]": "953bd04ca03df48a1635b944044914676e3d397080d1f86c25a5605ba4c103c2", +"T1_stellar-test_stellar.py::test_get_address[parameters6-result6-False]": "42b9120cba355febf542b6f6162c2ef2fe0265270f680802ce0aff1833c152aa", +"T1_stellar-test_stellar.py::test_get_address[parameters6-result6-True]": "42b9120cba355febf542b6f6162c2ef2fe0265270f680802ce0aff1833c152aa", +"T1_stellar-test_stellar.py::test_get_address[parameters7-result7-False]": "bd662518d9e136e5eae64e507994f7b74075294634317a38669dd2671001a188", +"T1_stellar-test_stellar.py::test_get_address[parameters7-result7-True]": "bd662518d9e136e5eae64e507994f7b74075294634317a38669dd2671001a188", +"T1_stellar-test_stellar.py::test_get_address[parameters8-result8-False]": "c03fc37c6a4d2341b0081900b90ffc2faf09a228607d9d6c807efaff8ecc8fde", +"T1_stellar-test_stellar.py::test_get_address[parameters8-result8-True]": "c03fc37c6a4d2341b0081900b90ffc2faf09a228607d9d6c807efaff8ecc8fde", +"T1_stellar-test_stellar.py::test_get_address[parameters9-result9-False]": "9f1f4cae47cb5e9602450d110fd1945dbdb059996955d74067204966c0cc1702", +"T1_stellar-test_stellar.py::test_get_address[parameters9-result9-True]": "9f1f4cae47cb5e9602450d110fd1945dbdb059996955d74067204966c0cc1702", "T1_stellar-test_stellar.py::test_sign_tx[StellarAccountMergeOp]": "3f55b35c47b3f0cf896793263006d9bc4089227f21e46e4e68f67386c1c85040", "T1_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-allow]": "8fd4d210bda197e57ee660e71158b295dd3f51f8df9a235e245d5a72f54c68e8", "T1_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-revoke]": "0834c3ffb6c8a792cfa8146de3641e3a4b95276b9583cd729350aca372528ed8", @@ -698,183 +754,177 @@ "TR": { "click_tests": { "TR_test_autolock.py::test_autolock_does_not_interrupt_preauthorized": "757b981b1f41c948785e339e9f678b08925b2c310a1baad2ccb909689ac42e2b", -"TR_test_autolock.py::test_autolock_does_not_interrupt_signing": "006a10d78cadec6cb90c7dcc14951615ce1c2b251109f4d8a819e49373230762", -"TR_test_autolock.py::test_autolock_interrupts_passphrase": "e3d269b18d1538203cb6f32267c65e707f326e3045c9f9a006e906951579a070", -"TR_test_autolock.py::test_autolock_interrupts_signing": "b2386dbc5699d438f9d0f7ae9b8097dec8f11690112dcfeea01ec7df2eee821c", +"TR_test_autolock.py::test_autolock_does_not_interrupt_signing": "5a29597827a8d454bda6b9483eaa1afb96b3c9dca27398108179cd734c6f6eab", +"TR_test_autolock.py::test_autolock_interrupts_passphrase": "f9d7ed2e337655c998791595cc84fe1b35b13972e671d564bc889e7bae0fe8ba", +"TR_test_autolock.py::test_autolock_interrupts_signing": "ef2f840ebd3a9a1abc9491f5e8dc68471947f2ae676e6e15627e41cb2610ccee", "TR_test_autolock.py::test_autolock_passphrase_keyboard": "2f071e084ca8fc21f9304b87174d1326a5083f032be73a5bc075688851369b76", "TR_test_autolock.py::test_dryrun_enter_word_slowly": "11cb67a7ea462746dc33d09b9b62521d2658a818a611b9ca4fe587dcbc1926ee", "TR_test_autolock.py::test_dryrun_locks_at_number_of_words": "7771f9227f39f19c84308873b0fffdbeea0704380d8e19387fc6bae2ff1651fe", "TR_test_autolock.py::test_dryrun_locks_at_word_entry": "d63a8c93f357f702d1296bce173ed3a4e4a36a36c58d070fd36591de5d71d0cd", "TR_test_lock.py::test_hold_to_lock": "fdb2743cdb7290647a0fe5f1beb0f52016955d36e53cfa517d5eb3f96f16165f", -"TR_test_passphrase_tr.py::test_cancel": "c00642bff2cfd0135022c1b3fe2d4a62f104645a53202685b024fcefedee43a1", -"TR_test_passphrase_tr.py::test_passphrase_delete": "ab0c76339b53e5ee50d054bfd1ba8bbdb593de1c77fb1f277da38614fb66df56", -"TR_test_passphrase_tr.py::test_passphrase_input[Y@14lw%p)JN@f54MYvys@zj'g-mnkoxeaMzLgfCxUdDSZW-381132c0": "798acdbce7ef69919c59775b050c92d191ac1ad09fcef61b74279bcdbf88bd65", -"TR_test_passphrase_tr.py::test_passphrase_input[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-166c898a": "3fedccf8c20e6a16a313ec9c4c5f58b0228c51da7d95bc109f36268ddbf83c40", -"TR_test_passphrase_tr.py::test_passphrase_input[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-334262e9": "45e41e29a72a27355a8d70dc2bca054da0407e3b69e8aa4f6e74ad3e39e34bb6", -"TR_test_passphrase_tr.py::test_passphrase_input[abc 123-mvqzZUb9NaUc62Buk9WCP4L7hunsXFyamT]": "3f03d7c0b86449500c259ab61a139c718fc1a2a4997557e0f268ddf79f54c622", -"TR_test_passphrase_tr.py::test_passphrase_input[abc123ABC_<>-mtHHfh6uHtJiACwp7kzJZ97yueT6sEdQiG]": "24c6fd959267efeaa11241aaa84c73779f9f41635df32a083c065ec43b1425aa", -"TR_test_passphrase_tr.py::test_passphrase_input_over_50_chars": "211a3400024ee8f47ce429db1a3868315d70b0996449d84360437e31bcf4d61c", +"TR_test_passphrase_tr.py::test_cancel": "89322822d981b2209ef55903a1c0709acbf112ad0543c63ed93dc0d4e261e595", +"TR_test_passphrase_tr.py::test_passphrase_delete": "067a81d4f244beb3973165c5d469cf3864eee9d5dca98e546a4cc560a3abc326", +"TR_test_passphrase_tr.py::test_passphrase_input[Y@14lw%p)JN@f54MYvys@zj'g-mnkoxeaMzLgfCxUdDSZW-381132c0": "773ced6f96e6bc83260cf6f9592ae331201448a706ed1740938876be912bd38c", +"TR_test_passphrase_tr.py::test_passphrase_input[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-166c898a": "8225828a81c3d19ca44e4e065d38ce5e150bea5d2b09475cfaaf36f77628f865", +"TR_test_passphrase_tr.py::test_passphrase_input[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-334262e9": "3ff54628778e9fef8d26a834f14b9dda412571313f53e946266a4e86b868887b", +"TR_test_passphrase_tr.py::test_passphrase_input[abc 123-mvqzZUb9NaUc62Buk9WCP4L7hunsXFyamT]": "5b83179c8c74914ae62bf60ebdad90b4e50673ec31f439313856f428067d4875", +"TR_test_passphrase_tr.py::test_passphrase_input[abc123ABC_<>-mtHHfh6uHtJiACwp7kzJZ97yueT6sEdQiG]": "bb5234712e02482af7f79871041d830f95bce0d8f145cb0089125a9f24a0b4f9", +"TR_test_passphrase_tr.py::test_passphrase_input_over_50_chars": "fb72ed83469687d2919536642823874de06958829703b0d3fee945b6a92d9fb3", "TR_test_passphrase_tr.py::test_passphrase_loop_all_characters": "d3d488b83bce42229e9c493159d143ed9a58477e65e7b86d8143f2ca0b862ba3", "TR_test_pin.py::test_pin_change": "0d309ac15f08341d9a88aaf156bf06c044acfbf58e8fc34c7ef6d05deb597d8a", -"TR_test_pin.py::test_pin_incorrect": "64ae7c68844bff8a75f0c77a57ebb2958c0068033e8cc0640d18a8d6ecde8ac7", +"TR_test_pin.py::test_pin_incorrect": "7f4748f112fef97fff978524fe911a58e6a2406993330da2fb1343f04aef8050", "TR_test_pin.py::test_pin_long": "a7e26e67545d218848ba488b9e30ae40c500e8fcb7d46bb945178867f78b71cf", "TR_test_pin.py::test_pin_long_delete": "b79d0dda5f77754a6ca92c0fb9cdd31362aa07cd36bfc2ce81b6551a814db48e", "TR_test_pin.py::test_pin_longer_than_max": "f6faf34a87a21bf46a81b072d984dc4d1f5b96276b4fd76108633506ec3de594", -"TR_test_pin.py::test_pin_same_as_wipe_code": "bb6faffdcd4123890718a994a76d12979077c3cd71bc2d3f14b38e232549fc21", -"TR_test_pin.py::test_pin_setup": "790910b20d28c2cc9857e3726864d842f9ffae4c88aacd36f582c2b8a03b3490", -"TR_test_pin.py::test_pin_setup_mismatch": "dc04a03897f392455e46bfab549a5c1d8d38c70f3d47a9754be9501c9a7dce45", +"TR_test_pin.py::test_pin_same_as_wipe_code": "bf1972d45717c8f519d74df04c389dfef3733c9161246e7cd3156e4ed9dc4a50", +"TR_test_pin.py::test_pin_setup": "8b6254dd03d897290be4a3d7e371bd714aa2333990bcb059834435d940db867f", +"TR_test_pin.py::test_pin_setup_mismatch": "4cafbb73ee107509f8766d73d2389ef246d27ade3540b835cdfaf83d2cb4a416", "TR_test_pin.py::test_pin_short": "20acadc34173f58ce9eb9d712e47732f1c8b03868f0f197be4213b314832ee4c", -"TR_test_pin.py::test_wipe_code_same_as_pin": "26e1b89dc30dae66d596f6772affb2645f8d5cd72d55895861ca923f756b0cc9", -"TR_test_pin.py::test_wipe_code_setup": "ffccd6bf18eb4ed26b7ac689038cf73a360a2be4c2ee0605f1a661b0d8285d21", -"TR_test_recovery.py::test_recovery_bip39": "cb3be25d32b5ce93156111f259ae7857ce78ebbe4704b69c8475b0494d2243e9", -"TR_test_recovery.py::test_recovery_slip39_basic": "1cfb27674ba9dff14d8b8b366a0573fbdf1d4deb2de0fc4ab3187042220c3b81", -"TR_test_reset_bip39.py::test_reset_bip39": "2b75ec223a68cf63f97815dc17209424cd1b70c66282782c15368018f106ead6", -"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[16of16]": "3f9c19f3387eaa08d8217dfa2ec1162eddfc9daa8719b58211011e43da59f9bd", -"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "7513254126c7f3eb188d2dad1e3397798c58bd63aecf74a19441122c81177cb6", -"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "75c29bcbcc03dd2bbc844b9cb819dbd10e26b8f99f261e4e125df7dad6dd099b", -"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "dfb9892a7e2b88e18c067c9b7e368922d362c1c151b88d28a4d9c160e26da19b", -"TR_test_tutorial.py::test_tutorial_again_and_skip": "696843e0f83fa214083b78a25fd3152ad60fe8789f1a36a7a530f1508cc6f863", -"TR_test_tutorial.py::test_tutorial_finish": "ac357a44929914b9d7e373149f6a2a74e5b336dfa4b3cadd072fc7164afb9cd3", +"TR_test_pin.py::test_wipe_code_same_as_pin": "17bb952006f42c3948370d1257618be76cf39d2892fd5c491488d9544cdc205d", +"TR_test_pin.py::test_wipe_code_setup": "2f1d097810aa38ff87acef79133ccc735a9523118a1d83420efb84db21a05d97", +"TR_test_recovery.py::test_recovery_bip39": "7f969a6623c767e62e50e246bb67e57fdcc7447b8bdd14155d98a6e6c7675a57", +"TR_test_recovery.py::test_recovery_slip39_basic": "c2efcb8016f9fa4771297f535e9eed1dc12d898a07936c9fc047b290705a6def", +"TR_test_reset_bip39.py::test_reset_bip39": "7dee2da63f3d220b4a1466b59da6c89a623d1a55c3d5300efe37761d064435db", +"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[16of16]": "0442794f3b952b6362d6569eaf15af002e7af5ccd3fedcf5339a9e75a61cb6e7", +"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "83d29833c99068a474c7b1c841cd0a88c92d3fba0e471d5e10dcd0d58b164d7a", +"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "11239923e51327c518bcb6123c8e645b0e34174b1857ff64a2e7cbd49b3bcc21", +"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "b51e9c4b3fc6962c128a75676a0ef5a08d72e69abe825707195fcdaf7b114760", +"TR_test_tutorial.py::test_tutorial_again_and_skip": "c611a049ccc584fd69abf55bac3b185e370e0680990afb3139b755fd1f41a19e", +"TR_test_tutorial.py::test_tutorial_finish": "1ae785e1ff678241aa18a254ae755a002ccd62550cbbd1dd92fa3cbd53d071b0", "TR_test_tutorial.py::test_tutorial_skip": "00a893066c2578f14ae9ab749791f1dde753b43be460d69a304aaae8704cfe8a" }, "device_tests": { -"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-68e2cb5a": "48399ff32222aabc3d366a55c571b042df2fc3e1b795fb18ee1fff7439a109ba", -"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-1adfb691": "d41f7ab804b82b106b0c945be7bdcb23f9b309463385d59d40bf5f5b68c75eb5", -"TR_binance-test_get_public_key.py::test_binance_get_public_key": "7a3176519ef2ceb1ab5b8ce73057d9dcaf5fb41696f170b47753021852f8b509", -"TR_binance-test_sign_tx.py::test_binance_sign_message[message0-expected_response0]": "5139b56d0e5eb96be85f3f9f2b003506f0c89cb3d35e26863e731a5b554c166b", -"TR_binance-test_sign_tx.py::test_binance_sign_message[message1-expected_response1]": "ca1085c7d0d77e511bc4f7ea0a654b656edcc5cf9fc2242099b0fe0c0509f58c", -"TR_binance-test_sign_tx.py::test_binance_sign_message[message2-expected_response2]": "73e7a54e90ba4f6a66b480c127618cfcda6c23b8f2271b2b6b3500d91408dfec", +"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-0327b239": "333bc9a0ecbffb09c7b6379e96b8e528e3538a252551f5523f125707cdf4b9b6", +"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-726415f5": "4b4d4c8e1477672ad0632703fa32fd16537387b93ca82668f0b8910522397425", +"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-2752eea7": "b9f843ad724e3ff89f13dcf46ef96bd3b1b961dfb275c43fd19ad96b84068e82", +"TR_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-9b9dcba2": "ef27cf5ef4f13bb26c11a56e8ab292f984c8375c8a8b2db8b36f404d0692c4c8", +"TR_binance-test_get_public_key.py::test_binance_get_public_key": "2a05936cbe3a4b5e63261826200b01f11c0e8a8f3f9a9550b2c2c2bda3402860", +"TR_binance-test_sign_tx.py::test_binance_sign_message[False-message0-expected_response0]": "b4e7f80083f27c6ce79ddb8b43e1f1140c70f5c949577b217a0714ff46f52dd3", +"TR_binance-test_sign_tx.py::test_binance_sign_message[False-message1-expected_response1]": "90550c15d961c266fca6762929c29b9273240cf29d8b0e8d1d80174deeafad3b", +"TR_binance-test_sign_tx.py::test_binance_sign_message[False-message2-expected_response2]": "3b7cc29d50393b7b69bbe7d2f9c8fc22560779bb28503b3301d7c67b824b05c5", +"TR_binance-test_sign_tx.py::test_binance_sign_message[True-message0-expected_response0]": "b4e7f80083f27c6ce79ddb8b43e1f1140c70f5c949577b217a0714ff46f52dd3", +"TR_binance-test_sign_tx.py::test_binance_sign_message[True-message1-expected_response1]": "90550c15d961c266fca6762929c29b9273240cf29d8b0e8d1d80174deeafad3b", +"TR_binance-test_sign_tx.py::test_binance_sign_message[True-message2-expected_response2]": "3b7cc29d50393b7b69bbe7d2f9c8fc22560779bb28503b3301d7c67b824b05c5", "TR_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "96f583f815e053d2ed5763d7841b2572c112476fb9d1131a1516e2e8d3f8ec20", -"TR_bitcoin-test_authorize_coinjoin.py::test_get_address": "e64903de9dcf6261ffe40e5533682d66635a78f3ffa336f68336b8329d8a0100", +"TR_bitcoin-test_authorize_coinjoin.py::test_get_address": "c79f5d87e7cd9baead660a6e17cc82a0275edb89804cc0f47e07eec9ade4b81f", "TR_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "4c2bba305bab30de2fcff0cec5ab1192f2e4d826d86f91f7172dfa624f5f3139", "TR_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "5f70b535406a6254113ed2a5f780ba98b8205abf6425eb7038d22395953aa560", -"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx": "cf587c961927f76a8e2f361c2c303b913f5ef951f99330c0f081dc9dbdbe7b17", +"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "cf587c961927f76a8e2f361c2c303b913f5ef951f99330c0f081dc9dbdbe7b17", +"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "cf587c961927f76a8e2f361c2c303b913f5ef951f99330c0f081dc9dbdbe7b17", "TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "4f275de439c812363140d3839ebddd9243e2bb34d80d02a487361148b2bbab71", -"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "4df95d3e51676290d6ffaf733def365ea727a6600e5859542e40de6cb8f679c3", -"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "3175a7c8fff73d65417966936bfe169f8ddffe079f62df17caf6c1d506333bca", +"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "38a8226a012b8fa17ecc485467ca1fd6ae02070095b8dcfde4ae3fd55beca5ab", +"TR_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "5d3942ebdaa7cb1f09d55bf2b358a7de3d2b66e9faaf4cf8568881ea2dc405d5", "TR_bitcoin-test_authorize_coinjoin.py::test_wrong_account_type": "9321620fe3fa3eaf6c83d313cc3c40b4b59b454ad24d6954440d3bb9285b9b5c", "TR_bitcoin-test_authorize_coinjoin.py::test_wrong_coordinator": "9321620fe3fa3eaf6c83d313cc3c40b4b59b454ad24d6954440d3bb9285b9b5c", -"TR_bitcoin-test_bcash.py::test_attack_change_input": "992df1077f93d23e4a69da51970cb097b68e78b1de8fb4d35ecefaefa5d7130e", -"TR_bitcoin-test_bcash.py::test_send_bch_change": "7974f0a14625efe76a9303796f5af1ce5463d00797ad11d9c07843b609556e22", -"TR_bitcoin-test_bcash.py::test_send_bch_external_presigned": "93b2bd66d1ee892e32bb27db67625efd327a4ce61f5f41920b6d5d7ef375df9e", -"TR_bitcoin-test_bcash.py::test_send_bch_multisig_change": "440fe5fbf4f17746036deb6dd84287232e1ce9727c7cd6a73eafb6a887ce8f3b", -"TR_bitcoin-test_bcash.py::test_send_bch_multisig_wrongchange": "f14980395451dcd20720ee54ccb1f8d9e5e348509c718c1d9d4bc6fca20776b6", -"TR_bitcoin-test_bcash.py::test_send_bch_nochange": "e70b022fd1c9e68d86f5f99333974426429e677c3670ec991f6fb1ed50ce542a", -"TR_bitcoin-test_bcash.py::test_send_bch_oldaddr": "aa8fc12ca1ca24ecbd9abd1bd52cd94953883502a122f25dbc33750c7fb29c39", -"TR_bitcoin-test_bgold.py::test_attack_change_input": "f1b3603792dcd1145c2811fd5aa9e0866d5c9aee580e7dd714ed7af9e2c173bd", -"TR_bitcoin-test_bgold.py::test_send_bitcoin_gold_change": "f1b3603792dcd1145c2811fd5aa9e0866d5c9aee580e7dd714ed7af9e2c173bd", -"TR_bitcoin-test_bgold.py::test_send_bitcoin_gold_nochange": "4bb39382d22a4d35d2f0cb9fdbd4eb4d5d2bdf0e9c9ecaa7b06f3801f7c5b80d", -"TR_bitcoin-test_bgold.py::test_send_btg_external_presigned": "82ee5352aa3feb17a89ef9e63beafbb0956126cb21950faff23902f8671221fa", -"TR_bitcoin-test_bgold.py::test_send_btg_multisig_change": "28bb67e96d88cab11a088a4fe0684638e8b152f852959d8dbd9d3c5395e5ff31", -"TR_bitcoin-test_bgold.py::test_send_mixed_inputs": "24707205195fe340ae5f05b85ffef538d23873d926d233e033314ff9c216bd1e", -"TR_bitcoin-test_bgold.py::test_send_multisig_1": "b559155b27153d2d3ebe6c9f6c1b3f2e1c5754a1e73895b62906d75773c25be6", -"TR_bitcoin-test_bgold.py::test_send_p2sh": "7e02253987e07720ddf675d84ef4e9f50060435ed1cf5a7765fafdb1468d6898", -"TR_bitcoin-test_bgold.py::test_send_p2sh_witness_change": "2950d58b5e81738926fb337724bf91892c109b59a6afbf5b15b6316aa0c85077", -"TR_bitcoin-test_dash.py::test_send_dash": "fcda9c6b511696bce919977193eabe11c1bb8d6bedfd52a7af562e08d16fb6fb", -"TR_bitcoin-test_dash.py::test_send_dash_dip2_input": "780919dfb35048f119769547400dc4eb5a05bf0532e46619ee2e11de73fcd374", -"TR_bitcoin-test_decred.py::test_decred_multisig_change": "a9d7eb6d0055d01715e2893213fee2f46f4cfb13f7602c83747ecefb22e40047", -"TR_bitcoin-test_decred.py::test_purchase_ticket_decred": "bcc0984b233a98bea521f76b8a6774e48f84f3e33043785c5647ef45291efb6d", -"TR_bitcoin-test_decred.py::test_send_decred": "8a1c4f7b329bf29d31524d0d20fac43ed78964be9e5b9d454dfe8b82570579ca", -"TR_bitcoin-test_decred.py::test_send_decred_change": "500a2e0b60f4950e08b2085ddc12eaa512c99f4e13e041eafee53c6d04f98af5", -"TR_bitcoin-test_decred.py::test_spend_from_stake_generation_and_revocation_decred": "5c4df29fb19c8b18cf423e8b4e5a05a83b3f9ab45d8eb4209702925295ff0fcf", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "e0becb2ceea649b54c27da205d5294c9d07ce4523568c85ca3ac3adb1841c456", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-44-InputScriptType.SPENDADDRESS-pkh-efa37663": "a3ad682e5a25835b045739b4cfa23d9406049fead49b35bae6c944742b560138", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-49-InputScriptType.SPENDP2SHWITNESS-77f1e2d2": "425272479db949beda549c3530e5cf03610f6761b1be066da5b10763f1d1b1cd", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-84-InputScriptType.SPENDWITNESS-wpk-16507754": "532bed442c8c282192bbbb8f6b519bdee29f3bfe9fd79a74c7c93adf50f5819d", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-86-InputScriptType.SPENDTAPROOT-tr(-2c28c019": "94b7b084a5c1a1519e9f9c1c52be9f850fb8fa5bffa4078d628467621b7a6b0e", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-44-InputScriptType.SPENDADDRESS-pkh-b15b8a1d": "642d144e00d8b7f34e0a4f887625374a6c4ed68bd10016bd66bbc33226e691db", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-49-InputScriptType.SPENDP2SHWITNESS-965f4fa3": "21eb93175421a037e9fa6f03a16e061dea6eaf854c7e2af59ad3f556ca609acc", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-84-InputScriptType.SPENDWITNESS-wpk-c761bcc8": "a510d120cd2882a09c2d138aa5bb11aee9945fdf855a4785ff8d2d4912e72fb1", -"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-86-InputScriptType.SPENDTAPROOT-tr(-686799ea": "3ff03a60bc4abbea447952b2a794645db2591162004f950da833312a8cfcfb46", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "80f3cc6e1a20261e64b4cf87c54af330ed0edfa4cc1eb95abad7bd5e7d937f46", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-44-InputScriptType.SPENDADDRESS-pkh-a26143a7": "b084b29c5cef52b37ca1284d2a66258beeb4cfb495bbfd99393434f58a0b40a0", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-49-InputScriptType.SPENDP2SHWITNESS-195ebda5": "4aebfa4011c40ab3d2dddb07d7015618cbd9b7b1282cccf9332e905f9928c650", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-84-InputScriptType.SPENDWITNESS-wpk-68f8b526": "defce2886c5e19c8e6c879b993c3feb7661647bf8b849a95b5224a2a072be5bc", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-86-InputScriptType.SPENDTAPROOT-tr(-07da691f": "e6b1f01ef4d011835ed0aa605d7778f88e15e8987ba7762a57e4dd13306f8e4d", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-44-InputScriptType.SPENDADDRESS-pkh-ca853567": "fb965e9537f24df6096c2986d83aa2392419670148203e7c0959d52035709862", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-49-InputScriptType.SPENDP2SHWITNESS-5da04067": "77bae039974c859ea87a1e5967d94bc6026be3d82219faad5d71f927ef3fe90d", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-84-InputScriptType.SPENDWITNESS-wpk-adba8950": "d173df60f55a2a510f486c2d4b3ecc3c0ae717488c124c6bb57f5b8cf8bdf32c", -"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-86-InputScriptType.SPENDTAPROOT-tr(-e31edeff": "3db7e69d09d1f367de4925d276249b52fb7e1a02f1782618d330b65c59b6e590", -"TR_bitcoin-test_firo.py::test_spend_lelantus": "ffa671a5d5a66e1d27fb9348dc0d063a66987c8d828ba81f480260d227c9ab1d", -"TR_bitcoin-test_fujicoin.py::test_send_p2tr": "d408ab679400e6148f98d87375c8c9b0cb0eb5a01e10308a3685b95b26da7ec6", +"TR_bitcoin-test_bcash.py::test_attack_change_input": "8dadce41cc80255da26fd5cd97aa7bf15e0f9674dc356a610c59615d5d484e03", +"TR_bitcoin-test_bcash.py::test_send_bch_change": "953dd551d34c11417ebc08dd4c7b1497c86b4097b74f9bc6c5d82a8993eb39ab", +"TR_bitcoin-test_bcash.py::test_send_bch_external_presigned": "0cc2f38562a3eb89564b6e85a3af51704433675decfb10472e8f34c08060d1fb", +"TR_bitcoin-test_bcash.py::test_send_bch_multisig_change": "39f9d5908384c63e5f6d0076f1184208a7e30eddeefcd6cd78919415fdeac7b1", +"TR_bitcoin-test_bcash.py::test_send_bch_multisig_wrongchange": "9a389dbadfe81ee05862a173837272aae01a8af2dd853ff438592705f9c25085", +"TR_bitcoin-test_bcash.py::test_send_bch_nochange": "dd48917ad9613b1f453ed637f1891476319d592971171156bbc96713235e97f0", +"TR_bitcoin-test_bcash.py::test_send_bch_oldaddr": "e498b6d2f7138e4e19736bb9bb96d14a04d829a485675e1616a1abfa75fe2573", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "b548cc09a709153638392cd940bf0297c85b9bc7442cc06ff370590b9a91c6dc", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-44-InputScriptType.SPENDADDRESS-pkh-efa37663": "55af89626933a7d87a0ce9d7f3d1ad74a80afb2ea304e57245424891d1f4c9a3", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-49-InputScriptType.SPENDP2SHWITNESS-77f1e2d2": "9ba1431983d453d93d279f12730710fc846aa62af391b488aaa0de93e6d89eea", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-84-InputScriptType.SPENDWITNESS-wpk-16507754": "546e7f836fc95fb4023a551aebce27a99fa047b0aef3ffe2a7ed46a6203a626a", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-86-InputScriptType.SPENDTAPROOT-tr(-2c28c019": "16dbdf86b57fce411b1c78b34308f948b124df98f9c62be64038cf3bc098c907", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-44-InputScriptType.SPENDADDRESS-pkh-b15b8a1d": "df805b6b92064891866753f5ce351483550d9ab0b01c7535a6f5aecb4425179a", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-49-InputScriptType.SPENDP2SHWITNESS-965f4fa3": "a70b7085ddbab0e58da2b5544a54d4b05a51e02187c7cb40cefa84989e84aa42", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-84-InputScriptType.SPENDWITNESS-wpk-c761bcc8": "27fd41422fd76b75343be6f9f87015b42be3e3553f34036b6910cf490ffa6f2d", +"TR_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-86-InputScriptType.SPENDTAPROOT-tr(-686799ea": "12f3c9d750a1cb0bf024a59a9accdf51eadf7d94abb8cad61af22668a582ab61", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "750ac9c0630b7f05d26690a2c6e67ca23783f519759fb31eba0ef72cacf5661e", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-44-InputScriptType.SPENDADDRESS-pkh-a26143a7": "2c40616f735d15cc45384f7bb3d0a3f8c9cb4ab68b124444a6ef1d80fcaf87c5", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-49-InputScriptType.SPENDP2SHWITNESS-195ebda5": "9f8bb41a4e018a3233c4bbc1e8e733f1682c2229b520c3404b3929364f166383", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-84-InputScriptType.SPENDWITNESS-wpk-68f8b526": "bf51fb2f664f4f356c70a191fe98db311005198c0bd19ed920d7b4aacbb8799c", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-86-InputScriptType.SPENDTAPROOT-tr(-07da691f": "ce58018528207c65edc737bafbc0034dbdd03c2993cf3e0ed173e39f167517dd", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-44-InputScriptType.SPENDADDRESS-pkh-ca853567": "4f52cd0a50a6e59fca5d702aee43db30226b06fe85138d160e9ddd3161c92c3b", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-49-InputScriptType.SPENDP2SHWITNESS-5da04067": "e9dcc7844450a92851ccd15b01df7750ba321fafbf23ad25dbe6e2dcc48d71f4", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-84-InputScriptType.SPENDWITNESS-wpk-adba8950": "aa8e4f0dc94feb84ee362efbfb4bb2cd9ad875d74d6de9d21592306cc9e4e236", +"TR_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-86-InputScriptType.SPENDTAPROOT-tr(-e31edeff": "f69ebf59ce7cfefef7cbd3e1a3a1c89acc9ad77e06b66c517990059237e7e412", +"TR_bitcoin-test_firo.py::test_spend_lelantus": "7c4179d0861980549d8e2b162b1e6b45aaa1f9cf795cb1d15a9645dc932b9e3b", +"TR_bitcoin-test_fujicoin.py::test_send_p2tr": "a6fa780a4bf69443b7fb4a081b8b410743a9dafff56b8ad766d6df12f6637638", "TR_bitcoin-test_getaddress.py::test_address_mac": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_altcoin_address_mac": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_bch": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress.py::test_bch_multisig": "22a5529ced287f544fdc4c1e3a0911fd9280226fccfaa7f44da9676d59c22655", +"TR_bitcoin-test_getaddress.py::test_bch_multisig": "f2fa3c72270eae22f50516ea3d9663553503563cc7d98907de74e86c7a453d30", "TR_bitcoin-test_getaddress.py::test_btc": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_crw": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_elements": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_grs": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_invalid_path": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_ltc": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress.py::test_multisig": "c1abb7aedc8ed16d8020cf3cb777ed7cf232d446091e2192d1b72bdd4f73a1c5", +"TR_bitcoin-test_getaddress.py::test_multisig": "ec7fbb53bfa047306d357697ae309ca90321c9464fda6bfd3a6b225be7ee1345", "TR_bitcoin-test_getaddress.py::test_multisig_missing[False]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_multisig_missing[True]": "f4a9b7935b7d870f13eceb6efa481095adfb4b5e9dd43d7cf2670415210c9319", "TR_bitcoin-test_getaddress.py::test_public_ckd": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_tbtc": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress.py::test_tgrs": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress.py::test_unknown_path": "28e2a9c2396598c269f990a2353d61d5441dfa82a19a275421a1be2e338781e4", +"TR_bitcoin-test_getaddress.py::test_unknown_path": "9c78bcf68b4481a947f9cae1845d5b9b2716da4c66fa1e4551cae17374d31e22", "TR_bitcoin-test_getaddress_segwit.py::test_multisig_missing[False]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit.py::test_multisig_missing[True]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit.py::test_show_multisig_3": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit.py::test_show_segwit": "fb65cf8185d1db4e702a1d8e8b65f3bfd8cc5654c5173d39d921cb6399be0962", -"TR_bitcoin-test_getaddress_segwit.py::test_show_segwit_altcoin": "a2cfb4e31d3b061d47615527cd8451857a8a00b455510890b9c95ae1ca364725", +"TR_bitcoin-test_getaddress_segwit.py::test_show_segwit": "aa56ef13e71b539927f2132f120d662c560dbaaf8115917db6d2f8493162ffd7", +"TR_bitcoin-test_getaddress_segwit.py::test_show_segwit_altcoin": "5370d5ba931530b1e14b2d6cc405c585b9e0c7261c5d1596b2c3e36d10fc1bb6", "TR_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-0-0-bc1p5cyxnuxmeuwuvkwfem-dc12f29f": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-0-1-bc1p4qhjn9zdvkux4e44uh-1f521bf2": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-1-0-bc1p3qkhfews2uk44qtvau-d8b57624": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_multisig_missing[False]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_multisig_missing[True]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_multisig_3": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-0-0-InputScr-6bc4ffc3": "55e29f3796df2895d8701f163c3f738fc746a6f1222473b07b3eb1fa4e08c836", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-0-0-InputScr-6bc4ffc3": "3c4a8b78580d73d17407543fbec8e292ef2afb39b155bfe4f46eefdff69c54b9", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-0-0-InputScr-8943c1dc": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-1-0-InputScr-016718c1": "0836141155ae032d42a8a817054359e7dcc94cee7eee08ff2dd0a69b8143479b", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-1-0-InputScr-016718c1": "e74bfa9f13386952707fdb0ce65f74f913fcd4d17f8f7fceea2bc208ab2e7477", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-84h-0h-0h-1-0-InputScr-7656a4db": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-0-0-InputScr-3d3cc8eb": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-0-0-InputScr-8571d5e0": "e1634840defa4ed0a04dc91ff2bdb46fc24618c5865ceb758e7f22ef805f1490", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-0-0-InputScr-8571d5e0": "def02ead4c21e297ffd177014aa80b55c09675fe0b60654ae41d2cf6e774f1a8", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-1-0-InputScr-ab700de2": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-1-0-InputScr-da3803e0": "aed3baa9f3ff9f3427c42b82f5045bb85672c3232e56b4286ce37fe90d57d777", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Elements-m-84h-1h-0h-0-0-InputSc-490228be": "fcfd82faf717e3fa92e45c1e0fe18793b101955f6c926537c29b01861a9fb580", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Bitcoin-m-86h-0h-0h-1-0-InputScr-da3803e0": "9ce8e5b79cea456d0939834831e1cc944366a0f3baae994e6168b769f95e280c", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Elements-m-84h-1h-0h-0-0-InputSc-490228be": "3c8db6bfc99d141efe3a1d4f7897191dd775c3a4c6005821e226fccf7ade5d59", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Elements-m-84h-1h-0h-0-0-InputSc-ed587e90": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--40b95144": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--45b4ff5d": "2a27e842098fe7fc50ab2b3356a0f27fe3dd243dd253b251c01628d6f6f0a1ba", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--45b4ff5d": "ce3a1e6007fdbf95f0b96eaeba28c7bccfa6151c10a74f94695394a12fcf0695", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--8f7c658b": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--93c9c3ff": "f8bf176c206eedd67ae376fa675e6d4e392f1c95ac208df20d419a7784ce9068", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-84h-1h-0h--93c9c3ff": "2fa22e4a6eeb5c6ed167c447414279d293c2914cf75f722ff38e56c052e3430e", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-86h-1h-0h--5feb8c64": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-86h-1h-0h--8d4476a1": "69a86a0217a2fa96bdef5021ae6af64be0903d2daf9523e3674e38887f7a1e81", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-0-0-Inp-0200a67b": "f305c326b8f18f70ab75e0f5138dc1034a29cb8f3e2d4d35a4cbda9d5f2dc74c", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin Testnet-m-86h-1h-0h--8d4476a1": "240eb084f3e7746b3c16d94d8a8886d1942ef2ccae11870e59ee6374b394008b", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-0-0-Inp-0200a67b": "307df925ae526b59953ae2d00b77d4f54f60006f4bc57a6df1f402b969a3eaa5", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-0-0-Inp-e6c1098a": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-1-0-Inp-9688a507": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-1-0-Inp-f825f217": "e7ff35dd0ab924a942e3b34ba3906f9b9596dde6f8795e3bf6d29596b64b2c05", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-84h-17h-0h-1-0-Inp-f825f217": "78a0a2e832d6210a6a03f7b94672d54ad9b952cfdc6dad582033f5795cfcffb9", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-86h-17h-0h-0-0-Inp-38cd93cf": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-86h-17h-0h-0-0-Inp-ebecce6e": "1bdeb84e326751e8038d0cf065f216427638daaae3a98fd4af2171a5c422209a", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-0-0-InputScr-313b9443": "fd397e70bd9e497f4a6fb6fe0b4e309ed3b7cd32310d69cfebabeb2ad34778f3", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Groestlcoin-m-86h-17h-0h-0-0-Inp-ebecce6e": "7f8f57e52f82917ea300ebdb67bb88580047ff62627a2d67fb153e1768269b4f", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-0-0-InputScr-313b9443": "4691d3526e1b445f06a9fa227a39ad9dadabc112730245d5e9527350b2a0b84a", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-0-0-InputScr-ce15ec92": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-1-0-InputScr-040186c0": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-1-0-InputScr-b10918be": "0eaff4b1cf29ac0346f0848963341f2a786b86dc2f0d7110e06dde14150bf4fd", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-0-0-InputScr-55ae0ae6": "caf067c9bd94069999b124d3da9f6446fcba2ccd1ae9dbfd5b1502b5c36bcdf1", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-84h-1h-0h-1-0-InputScr-b10918be": "900884e151a8e18c950276698c8916e2d5ec46ca9092e8140870bbcc28a04597", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-0-0-InputScr-55ae0ae6": "83266fb568deaeef3dc84a31b9f1e5a64a26c18d76fb1bb0945f71979f56c045", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-0-0-InputScr-821a199d": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-1-0-InputScr-9d2fa8bc": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-1-0-InputScr-d5b7f8fc": "10a12d28269a2091c577e4ec3c406efbd9cc19107e4e975d4b6ae77c0ea6e7b1", -"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-44h-0h-12h-0-0-InputScriptType.SPENDADD-4eca71e0": "8bdb5ddd9ab0032f60ba329efa1589d7cf1c0b9f5b2cd24ae48c6693a3fd4d7d", -"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-49h-0h-12h-0-0-InputScriptType.SPENDP2S-4ec777e0": "d27c466c10ea314bc92579350aac95228d02c7ca6d07dcf6aae5e1a331d21e07", -"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-84h-0h-12h-0-0-InputScriptType.SPENDWIT-d6991e22": "3b9f58ed18cd7cf66ca7fd4f95ea2dbc0abf51285e91fbe649fa2a667dcde78b", -"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-86h-0h-12h-0-0-InputScriptType.SPENDTAP-4c5b2b38": "6dc182e19b40adf4ca57ef70ca51f125e617cb2679cb3011ae14abcfb40ddd84", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_15": "8fce503b08fbaa4a5e5a9dd75c0dde2ab2cdbd5d56776f2094207662238fb690", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_3": "87c29c513ce51ddacf1546243c38f3a172242cb96b022be9d6bbf1fd2643fed9", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-4efd9cf3": "25f03d82d2ca98a03c923c987368d0308d1c51d6389774f9a9b6fc259bdf5a91", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-98a7e339": "25f03d82d2ca98a03c923c987368d0308d1c51d6389774f9a9b6fc259bdf5a91", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--2cf5f03c": "52315ea8b62cc0149e8fb54ab5552fdd3f6df35c789582fe60f9ba2ff47ae97e", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--5ea18367": "b0956d088fc0a1bdb2ca75e0078a59f213aca93a209859e3f235b7bde77467e6", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-e70b56ea": "b1ce781c4f10a5207c1f41d3f38227abe10f2fda8752196d61ab63009e95a09a", -"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-f3c4650f": "5dd13f9615e4d1d051af609a41f971344fdaa766f5c7530ee11f1c247f504c7a", -"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-7e3bc134": "f2d14b4193c6e7cbbcc905f3c2820e4a64c10bd629fc8646eaa6ecd8a76d3c14", -"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-fffcf75c": "01f1d349bb7ab583b269109d94aa9f425efe603dd20848ee40db3c77c9358557", -"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-2ad0a0fd": "08b93040d77975635e2ffaec9b0f5858450c8dc835b50b7e6fc9321710c8bf53", -"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-299be1ac": "b95d7788085196eeeae98ceb5c0b1a378465fc795d1914bb9943d86120fc3745", +"TR_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-1-0-InputScr-d5b7f8fc": "4f8348ba87ab6fec8ffb5ec7efe7112f2a6f640c47ba53161fcd501b51dae871", +"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-44h-0h-12h-0-0-InputScriptType.SPENDADD-4eca71e0": "12f150ea48e6455c959182cdd70d1a17c3748aba319c83c6de00f16322994ac4", +"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-49h-0h-12h-0-0-InputScriptType.SPENDP2S-4ec777e0": "26f01c36eff83ed5a3619789517921c50023fab43efb5f150a5dc837ccadb3a2", +"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-84h-0h-12h-0-0-InputScriptType.SPENDWIT-d6991e22": "fb006463a0b8b98f82a78c9ede0bd93d06d30cc5e720aa9d9ffe70706023b46a", +"TR_bitcoin-test_getaddress_show.py::test_show_cancel[m-86h-0h-12h-0-0-InputScriptType.SPENDTAP-4c5b2b38": "664085a8ff0c24c931aa243156c4a4551d0b0850cd8b242c6dad776953f93af7", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_15": "ee188228c993e977c9f12798273ef683a9fd84663cef21d6a0bc0525adb3313b", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_3": "b395f8b1de82b06482a60af42e75edd90a2d4b6fdb7395f3b62dd25bd7eaa507", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-4efd9cf3": "fa591fedd8798b2b29f388b62191e5741d718d6a4d5203a905df0774941dc166", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-98a7e339": "fa591fedd8798b2b29f388b62191e5741d718d6a4d5203a905df0774941dc166", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--2cf5f03c": "0763c8cd6d188c95430cd94818a615f66ba32f58e34fd930c12d0ee17b30dc9d", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--5ea18367": "8daf00fa0295c9c45d7adcba44574c9298769805d2ba5e473f38db61f9861b17", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-e70b56ea": "bc107ae7ab945ca9037c1e9fe4a73e8794e520f341bac6442fac3a543777b1e5", +"TR_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-f3c4650f": "a4e8926f0a2946713cc71cc7b97dc350ddc5054d1f6b3d7a078d129faa7c770f", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-5c88d0fd": "48652d2eefc46d22d11b1e0e186835e920fa7afcb02f4b5950a23225796a073e", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-87490d4e": "9b3a8e127c08af16b28c3a820e7d58b17cb0a448dc06c829a85edfb4f68e2486", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-9bc227c1": "e76e479311a66d9236b3f969b121b9f708189f833c751072e5dba5e186256785", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-aca0623f": "1f088c4d05a95eddb3dd7498ef9be5b0a1ff1569346985c27d2eab550a43cb9f", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-747c079d": "7cc25ffce835348d0d3810a0d71a70ac7b0fab9c534efee9d4da9f3cfc6ad70b", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-e4302080": "52e191201a89b65e34c55a0d919925445e16a77488b1ffd925235a8af2f335e8", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-071a4a07": "d8b8fca926ebbee4bd10539903ac18b474a4da98413464ebaf4d4ed6b426aefe", +"TR_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-25ee9808": "410968f7951175b062378bd94f1c53b6b0523d1993edb6483868f50d6d532b2c", "TR_bitcoin-test_getaddress_show.py::test_show_unrecognized_path": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getownershipproof.py::test_attack_ownership_id": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getownershipproof.py::test_confirm_ownership_proof": "0f0c521b22014f32e8c4cd78a80d00272db4e363e67e64ca5fd6c277292449da", -"TR_bitcoin-test_getownershipproof.py::test_confirm_ownership_proof_with_data": "eb533ce4f3aa44faff0ba7c2a825fb210544565d736ee763794f3adf503c6204", +"TR_bitcoin-test_getownershipproof.py::test_confirm_ownership_proof_with_data": "0ac142dc76b4931d0eb1db2afcf7162898a3ea35f09efc03e43563a087cb061c", "TR_bitcoin-test_getownershipproof.py::test_fake_ownership_id": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getownershipproof.py::test_p2tr_ownership_id": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getownershipproof.py::test_p2tr_ownership_proof": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -891,6 +941,17 @@ "TR_bitcoin-test_getpublickey.py::test_get_public_node[Litecoin-27108450-path9-Ltub2dTvwC4v7GNe-8d6d95fb": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey.py::test_get_public_node[Testnet-70617039-path4-tpubDDKn3FtHc74Ca-f3b70aff": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey.py::test_get_public_node[Testnet-70617039-path5-tpubDGwNSs8z8jZU2-8b5efa13": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path0-xpub6BiVtCpG-d791cce2": "55af89626933a7d87a0ce9d7f3d1ad74a80afb2ea304e57245424891d1f4c9a3", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path1-xpub6BiVtCpG-74c78643": "05df2076f9cb68c73576e2f76b248b991f866961ba2470a83ea5050b8df6749c", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path2-xpub6FVDRC1j-3074f5a6": "4fe67534636f714c739d89ddba6139796e949fbb2752e6839dc7f77efb36d70d", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path3-xpub6GhTNegK-1b073ed9": "8adda1b70c7cdc184740bfcd1f0669ed70d4a587144792821ca19b9af361b8db", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path6-xpub68Zyu13q-eb190bf2": "ae04cf6e903d5c74ac3544e40c0ba8245acb616c4d43678dabf8382676d8a496", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path10-Ltub2dcb6N-d2ef4e5a": "e98af2b19e90627689bf6c87f3eb8d0465e70d92a1d769a5b2c131754cbe97ab", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path7-Ltub2Y8PyEM-b9a6bf56": "b9dd7269ecda74ed0f3d23c37fb42bf08d795ec4b34dbb493225269b6a4c8f02", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path8-Ltub2Y8PyEM-d598ed84": "ecb2a5b3e99915e80dd238eea00e351a6c94cf41ca7f64deeb0e0a272fc62bc8", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path9-Ltub2dTvwC4-bfef8b2e": "af43d0b587c9645e5c945b26e72f4f7a3f42ae3b7c460e6c4fddc5c0dc4c4056", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Testnet-70617039-path4-tpubDDKn3FtH-5ca1cba5": "2c40616f735d15cc45384f7bb3d0a3f8c9cb4ab68b124444a6ef1d80fcaf87c5", +"TR_bitcoin-test_getpublickey.py::test_get_public_node_show[Testnet-70617039-path5-tpubDGwNSs8z-60ca5612": "9e8700f25ba5cca9a712182dee3d5f03bb508b9b9b1dad0670f497760020731c", "TR_bitcoin-test_getpublickey.py::test_invalid_path[Bcash-path5]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey.py::test_invalid_path[Bitcoin-path0]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey.py::test_invalid_path[Bitcoin-path2]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -909,587 +970,614 @@ "TR_bitcoin-test_getpublickey_curve.py::test_publickey_curve[nist256p1-path3-03b93f7e6c777143ad-2d6b178b": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey_curve.py::test_publickey_curve[secp256k1-path0-02f65ce170451f66f4-9c982c22": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_getpublickey_curve.py::test_publickey_curve[secp256k1-path1-0212f4629f4f224db0-0209bb73": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_grs.py::test_legacy": "1ca33869f017854853856506a7de91e2279be31ed59abe5654b710fab3ae1d1a", +"TR_bitcoin-test_grs.py::test_legacy": "63988af009f90bda4c910e9ce887fdb69d34cd4435b2ab8b5a25916ec3a50a84", "TR_bitcoin-test_grs.py::test_legacy_change": "c24250da19b0bd73d13211b264f7efd11c4189816257964a38abc92bfee9adfa", -"TR_bitcoin-test_grs.py::test_send_p2tr": "305056ecb4038d3fde2fb402af67a9531dff797fd1365f2f6a00d3536b352050", -"TR_bitcoin-test_grs.py::test_send_segwit_native": "7a9426ac9eded97e525a52b22b1a1e3cb89676af45168eba86480e4738ae0df1", -"TR_bitcoin-test_grs.py::test_send_segwit_native_change": "8f39a558dccae06fb0e818ab85d6c2d82dbc5c8150875a05a35d24791906cf00", -"TR_bitcoin-test_grs.py::test_send_segwit_p2sh": "4f0063ca203406113d648920555c0a2693798c764adf65a39cc879365d1c2895", -"TR_bitcoin-test_grs.py::test_send_segwit_p2sh_change": "2d63e05ff1ded4f121eca121b003f7ca3813b22db0ecc8d49ee7bbea6c87d4a3", -"TR_bitcoin-test_komodo.py::test_one_one_fee_sapling": "b4c9c24bee970b9bde135897f77586328cd302960a3aa00a32c11e424721911e", -"TR_bitcoin-test_komodo.py::test_one_one_rewards_claim": "3a18374a9bf37c0d8eeb3f18e1ec441991a93fffd59357c1ed841547ad53f600", -"TR_bitcoin-test_multisig.py::test_15_of_15": "1a1b450614968b896b070eec6a9859a70bba2a911548c1f06834295855df59ac", -"TR_bitcoin-test_multisig.py::test_2_of_3": "fee3ff0b4dfa24acd887c43e8d98948f73bb99eb0d964052021e042b014792c7", -"TR_bitcoin-test_multisig.py::test_attack_change_input": "12e3f05305dfa530eac9bfdb7b8d824847b2219c59460ea22efd1ace90e3d8e7", +"TR_bitcoin-test_grs.py::test_send_p2tr": "f35e2228dd6ddffbb54d1a5bde22ed77a96b97e442bb3a055f4b60cc5355b1c8", +"TR_bitcoin-test_grs.py::test_send_segwit_native": "079996f83cd2f4c9017cd0e8b4d49551b24be6838c9676715b80623fca789370", +"TR_bitcoin-test_grs.py::test_send_segwit_native_change": "52f2d5ce6a13faf2b4563199d5e694a922d34d046789a9a4666df2a3561f16f6", +"TR_bitcoin-test_grs.py::test_send_segwit_p2sh": "9fef99cb7a263b62ad16f835e8e528fbeb4e2dfd8b77685bea8f3138af337c6d", +"TR_bitcoin-test_grs.py::test_send_segwit_p2sh_change": "c21e458bf30d5266fe4cc419eebe5c0986500d713f6345a44aef20d14d0ed989", +"TR_bitcoin-test_komodo.py::test_one_one_fee_sapling": "578f43ea775c6d53967049d154f9d10c70eb6d322f4003c1999ccbc451be1204", +"TR_bitcoin-test_komodo.py::test_one_one_rewards_claim": "a072cc0092c0e229a3240e29d568f470b33c64785c33a91bdceef6c6f215b1bd", +"TR_bitcoin-test_multisig.py::test_15_of_15": "88af62161e60893c54298415b249aa0c8feae1b121068b656fe233bb9ab6d0c9", +"TR_bitcoin-test_multisig.py::test_2_of_3[False]": "b60896d98c34671ad26093ad68ac9498545384ecef07ef651762bbc4c741e7a3", +"TR_bitcoin-test_multisig.py::test_2_of_3[True]": "bcbefef9fba68fd367e7b8f45abb402616f3697369a0fb42136e9ef8d3ffe0a6", +"TR_bitcoin-test_multisig.py::test_attack_change_input": "18fde1fab9105702edb3e3a7989d20eb2fd46cc683f484cd9bf3998e18b33c33", "TR_bitcoin-test_multisig.py::test_missing_pubkey": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_multisig_change.py::test_external_external": "49fcc9eeb4e577670592e15ae213fbb08490d0b9b6a1c2c8db981e9aaee44f09", -"TR_bitcoin-test_multisig_change.py::test_external_internal": "0e317c1ffd8112eaac903e348ec31c4396f3620ab73a4d205a20f09cf76fd412", -"TR_bitcoin-test_multisig_change.py::test_internal_external": "c210a016871d1b71c9f9be4236aa4a9d0b72dd1b4f8461f4b01d7ec14f9118d1", -"TR_bitcoin-test_multisig_change.py::test_multisig_change_match_first": "a2a76557aadd9a9ec66ff0ccac437bdcc52137887a44ed63a0547704756787a0", -"TR_bitcoin-test_multisig_change.py::test_multisig_change_match_second": "6f1b6606a531d5836482424ce669eaf483ccbbaf0b1981e140445dfe0328413e", -"TR_bitcoin-test_multisig_change.py::test_multisig_external_external": "594a4a79a40b054667fc01ebdb36ab6316971adb735a1445fa936244111c25da", -"TR_bitcoin-test_multisig_change.py::test_multisig_mismatch_change": "83b8155b01042bd69d3ff922f1e72c4bd475732481de88c670ad46d0a6123a61", -"TR_bitcoin-test_multisig_change.py::test_multisig_mismatch_inputs": "a5ebb4bceb39074ae440ed7619ca172eb44bc858d9c7e7fcf299f2ebea15720c", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3]": "ef5c1ec6a1508389d46f7c980cda49fff03b4ef514cebc6ed13e60b4fc7db206", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2]": "fdd38ac5202c19c88d010df700deb4caf3e2ca9bb465f6b87eb8fcaf7bc571a7", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1]": "61672bd096c3dfc8c65c391b1cdd588be91b2a7c77f8357f48a2cba4345b1d40", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0]": "b4200cb29a5ac17e5e066c42e09a2beb10a524a6efababe1cfef31dd19fb5bf0", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4]": "4cbfa472fbcc29afbf18d1946f44279be06b1857b77127cd21870592a0d5c3a3", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "ed40b789608b3c3b363c8d78c93b5d314880d81ae53e043df3cdf42358073917", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "f9db11d948ae2508566f396df24d57be71464b5ded115126d97364f246d08682", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "b1223e393b440db8bd0e79373470f2cf30c279fb98704be6ca31ad7e38409b1e", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "062dad8e56d9a66dbfd0e9cf4f50d612b65f41ed13a914e16378c4ba194e0fa0", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths4-address_index4]": "4d28de282569f129fa3f0d54069183fd0289810f112cc2fd817a596a7da28a9c", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths5-address_index5]": "b4fa77409b5ba0c262f8f330cfad452e9bc3e56569ce0f8410106f5f8d7c3cbf", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths6-address_index6]": "66f81af9ab29de179b87bf12afae3493b95bdf7c3965d07551c1241129a2ba35", -"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths7-address_index7]": "cca87db98b2858ef68c2669df3f8f9793fe221025d2467eb9a0b836a60d7643a", +"TR_bitcoin-test_multisig_change.py::test_external_external": "ddde78e6e0799bc8e2d13a5a674696c4dfe075550addf2ebf8800d41756a8d76", +"TR_bitcoin-test_multisig_change.py::test_external_internal": "61804c8e210a0d28875894a894d99667f940f7fb61d1c2f3e9b79d1720aae5b3", +"TR_bitcoin-test_multisig_change.py::test_internal_external": "3dec06a02d5e94f7e2958b61e3ccd61281ec3e8b1c9d3112fa28e2a05eadaf53", +"TR_bitcoin-test_multisig_change.py::test_multisig_change_match_first": "381b47450d1f1fb8df21f1403927f305adb20cea54c2b5325b0fbd1181a34767", +"TR_bitcoin-test_multisig_change.py::test_multisig_change_match_second": "d462530b01f32809b0e7ba4304c783dffefe8e829cee506ec1697635bd6b5ebf", +"TR_bitcoin-test_multisig_change.py::test_multisig_external_external": "769256799ea8796dd375c2b9cc7451f7cc64a26dd2b46598716188fbcc4d3a7d", +"TR_bitcoin-test_multisig_change.py::test_multisig_mismatch_change": "61ba26ee6a6e6863e3e6caa34cbe081385cc9e2d14b87c119c25098c5385efdd", +"TR_bitcoin-test_multisig_change.py::test_multisig_mismatch_inputs": "44486e2c0140f8dc58a31b754b465922cdfc0ab7cedeb4c5d5718bb879f417b2", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-False]": "901d7bbbd36b598936ad4143739dca3f4335d076742db1272b15139fa8b04c47", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-True]": "6ef3523b4be935a73f10817819d17c330eead48011daabdc7a068824b5fc6ad5", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-False]": "a4a54c409da0c24f511004b2f96b53772a0709c10f96a0520dcb838ff8ca8328", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-True]": "13e222ed927408dc71ab21306a7ca7530a394a142650b3dcbe4ef8dc984e6cae", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-False]": "1c2a3d415ca3c0d0b25a882931142e1169336f0bc796249d70b60d0d55328d5f", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-True]": "25c1c43ff606505f3c5e2b8b558427828f6946add7152a7585b08fc545907d59", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-False]": "c3f10abd868f02ca7906ffd5ae8b72659ed857ef463d89e76dd72cbc4884c271", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-True]": "157eec4756c267f73fe9c19f1bc16140af5d3b95bcf440e9e58228ba7e5cb919", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-False]": "752c3d052b7e7b89648625b4b491724b0e69b99d44a48fc5a13173bf843fdfd4", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-True]": "2238ba590d1fa716a5a55ab4eca4afcfb7f9bf7df7560e93b46e6ad45364c464", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "fc58c9fc6aab5c6bb31e4f793e843a902a866e76bdc6942ecf81be0a531dcaf0", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "193a3c841c501a0bfef881ff37b567e5b85cb0a1b082ae3a1eda1db6803f6403", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "054284e4095fbb64af3f1a2c4a91c743c670e2f14c50eff0f6271a68a9e94483", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "9e81876f74b204dabd8797b30942fcb9c42ec87e8471d658352cace7edbb8cf2", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths4-address_index4]": "fc779979159961e77ae8db6e49415a12a8333cb29eb3ba68a61409d2724784d1", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths5-address_index5]": "ff8007bf949b2857c4b2b1f30da546ba7f8d32e0f6268b6d06ecce907277aca1", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths6-address_index6]": "f04e8c03f748bf0cc8a50646f70ddc7310077783fe3354b127a1c259b882e638", +"TR_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths7-address_index7]": "ba38e4e32b8f0037e737f2ff32ae2ccf53c06c3420c6916dc03e276bcd289fa6", "TR_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-1195487518-6-255-script_types3]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-1195487518-script_types2]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-3h-100h-4-255-script_types1]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-4-255-script_types0]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-49-0-63-0-255-script_types4]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "37708c8740a6c22daa63542ed0fb38bfc1e69b986bf944de07f7f529c366b3ab", -"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "0a7599abe57dfc1c74ca6f5325aa37661c349aa68fe389d2d40baf8e4cbd07f3", -"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-3h-100h-4-255-script_types1]": "b0acbaed6c55c72a69e8286cf208bf8c85f0d546345e4664060750c4279eb04b", -"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-4-255-script_types0]": "3c09e0b4f502f867ef1b958c24cc5e7bf8022153fc0a7eb83824fa7b0f0b40e9", -"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-49-0-63-0-255-script_types4]": "a2f36227b24063ccb33d49d1343d83809095b69c30abecc2075c192fd82ac8b5", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "3205beaa4dd01627e39bf88b569cc2b0cce99bb83292781aca959d8bff67950e", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "07a159acb1d7b403fcf76b2c9051fde4c13c98d15e193ff1f6b6694e4a4925d6", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-3h-100h-4-255-script_types1]": "2550233e2e9437f999d086025cdccefdd5329b628643cef979e2a1039779c6da", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-4-255-script_types0]": "2e6c0e55a887c7a20e58f8a8ea4282978beea0bb94e9f00fdbb528f21d1458a3", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-49-0-63-0-255-script_types4]": "c32719f6bc34c47beb556e53a80613e6696fe7b34befa780ff06423f49de1b93", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths0-address_index0]": "995eaab9a92f5b1581abd2965e29d87c0240a75147dff38c82ad326d4401342e", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths1-address_index1]": "a16404e58aa3fd482138049c6501b8b3c67343bd2a9a2f1f7f918db8b68dc289", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "90d99a1dc19d5fb483953d79a310c518bbdd497e5ace60d3bfff3b19c395ee52", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "f5617fa94c387b6505dd7d9541174a8d2f703879085604b1f965c86ee1847c36", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths4-address_index4]": "5fc21bdc5155a54052f52d2655d7ba3151c3b9d60d2df008d864f2ad5152b2a4", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths5-address_index5]": "0b696f857e9e2a0570963664eaa9191e4f25a9b71e99f5b2b83616897aa76253", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths6-address_index6]": "201662790f3d3054f8d0ba4eb47c793a1888abfba2609e8c7fc423981f356668", -"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths7-address_index7]": "bee7e44f130ea6aa88a9d1a82641ed6114032f2e9f9c1956be470f02d0600ab4", +"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "d4b9707b7729c2c9e7bef83b8055c4f58bd6ebc73c97b77a5f735525216111a4", +"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "0d485ba9e7f1ccef4d699afb786d18c689bcc7b487200258472ce1132773f2d2", +"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-3h-100h-4-255-script_types1]": "2660d1e5b53bc938f651f35c89dfb454e04498b007b3df8d31770db3a9c4e59f", +"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-4-255-script_types0]": "12f8e2c1adf0f92f34227c1273c5f9fded7bd2e539228ae99965e05bb8833484", +"TR_bitcoin-test_nonstandard_paths.py::test_signmessage[m-49-0-63-0-255-script_types4]": "aedec68b804c19df9b9153a029d549e6eb6388b33d95f1efb4e6be13968a53a3", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "81ffde0b1ed70d999892319d25700966797f6173a6aa5d8e619d4aed68132a2b", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "bb2aa54888b9f10a63f7c4f07617d896556abec66c9228ee1fe8850cfb1954e3", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-3h-100h-4-255-script_types1]": "0e69bd2084dff871e91c9a9f10039c492c3da8ed4ca8b5df5a19ff880adb5793", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-4-255-script_types0]": "de2e250774ada4bc41314b6e83efbb2362f4fbb5fc7a9496397d052bafb94c51", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx[m-49-0-63-0-255-script_types4]": "7dec06279c95cfa4f78c35f34ca785aa9bac6dc3480742e8f0a26b54c8a29a23", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths0-address_index0]": "1f7725135fdbfd509c5e4d00604b67c3a742ce2dbbf81bbcdc090ab1e1e65482", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths1-address_index1]": "99b747c6c338bfa0b70ad07dcf0119706e0eeaa5c0133eeee557d14bcd0c307b", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "d7e53359454be58ad058a3659e9a71bada8490723e6a197ff42ab41f32186831", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "b6b291e4e0cb917bd6864ae8c6d7270d7eaef37ef90f41e6704b2ce7b5dabab0", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths4-address_index4]": "47406c7b3d4139e7527e44e63050237b623b12901c855cd937e6234b8368ea4b", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths5-address_index5]": "8a496c51ef36579249d1684867e70bd8fc7258ba2c9fd234b5cc725acebe15c0", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths6-address_index6]": "bf528546d05ace068fd0daa01ec8d5c8e1f750efd8887b1568893c14b61c21c2", +"TR_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths7-address_index7]": "c6dfd6d1ffdc9243c8677641acfe09eead167d2c7b64fc66606e802a01603d60", "TR_bitcoin-test_op_return.py::test_nonzero_opreturn": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_op_return.py::test_opreturn": "d1d1c5086dcf44a4a32bff1d83c624ca68da61d5ef3a9ecfbca28e1447f24b9f", +"TR_bitcoin-test_op_return.py::test_opreturn": "7890082abda2fb8b70706a139ee59c32a5a80c5e9cbda7938117cc8c5599cbed", "TR_bitcoin-test_op_return.py::test_opreturn_address": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_peercoin.py::test_timestamp_included": "f778f4c744d0438a8dcdc6921337f3e769806019369adc8ab510943c7fdb14e8", +"TR_bitcoin-test_peercoin.py::test_timestamp_included": "4f9f73329507df245afb8b259fa99f944008daad486ef94d85bac7a7e158b766", "TR_bitcoin-test_peercoin.py::test_timestamp_missing": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_peercoin.py::test_timestamp_missing_prevtx": "84bd888dd9a8c8edba3a5147aaa1a150f6fef33d7d2400de6c87b5994f7b9f23", -"TR_bitcoin-test_signmessage.py::test_signmessage[NFC message]": "1e9c41b363471d8e140d19a233f53390f106f03336a8a660202b3442ab31220b", -"TR_bitcoin-test_signmessage.py::test_signmessage[NFKD message]": "1e9c41b363471d8e140d19a233f53390f106f03336a8a660202b3442ab31220b", -"TR_bitcoin-test_signmessage.py::test_signmessage[bcash]": "f610cfcaff050bd29d4b814d12d99b6484755b9fc613667b966432040ed5141d", -"TR_bitcoin-test_signmessage.py::test_signmessage[decred-empty]": "97c8b28e949ce9c9a050ac3ce0ed0a08bf751e32ed1afc6aea2f3bc5f2719eae", -"TR_bitcoin-test_signmessage.py::test_signmessage[decred]": "444700fd477e627fd37ba3ca3e588261fd63fcd19f7d4ad5c6351607f6f1ce35", -"TR_bitcoin-test_signmessage.py::test_signmessage[grs-p2pkh]": "b97b029fbcf9360aebc3ec38f656f403fc577f944f40bd052c5b3d1d717d4d81", -"TR_bitcoin-test_signmessage.py::test_signmessage[grs-segwit-native]": "dfcbe164953bad9a0ec67f8dd68f756b3ccd0054b8c6ea50c2edeff8bd58f463", -"TR_bitcoin-test_signmessage.py::test_signmessage[grs-segwit-p2sh]": "840c1d4b4d24a5e6884ed49fde5de08dbaec4da0dcd01e320ccede8187f35435", -"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh long message]": "8c99cc93397ec3a93804db304a996380cdca05a6f5f25432a82b6a4169be7a97", -"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh0]": "73a5fbd251466d86f1bafe800c4636c1ad8fb3d08a0d4af79bee7fba7bd1135e", -"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh1]": "73a5fbd251466d86f1bafe800c4636c1ad8fb3d08a0d4af79bee7fba7bd1135e", -"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh2]": "52cbbd7dc2eb79bac598010624f19a8667a67876e96f89283f8d17cb8be9129a", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native long message]": "f2c6a4000f65dbc0855155f0146d769233b25db24da9ce47b11635a0b1b9652c", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native0]": "23ca1cf212f71719738dc08a452064dc59dde388b301bc9e5c56cda17d2d1029", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native1]": "23ca1cf212f71719738dc08a452064dc59dde388b301bc9e5c56cda17d2d1029", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native2]": "a4e9d2bfc731ef8fa452556f248ecc66a3575e0c8cb30f9a563f850e39c06a7e", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh long message]": "ab95e32f74b70335d9a04ae545356257d636f7ad8c2efc5d129f02be9a9de2b6", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh0]": "8d513e541cf7a5862d2632aee5d9beed7c350da00b2056bc92efbf2d0c3e856b", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh1]": "8d513e541cf7a5862d2632aee5d9beed7c350da00b2056bc92efbf2d0c3e856b", -"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh2]": "b2c43f9f80c9f90c9f8ebe7debe18ef990f8af2c07e69e969dcb9995109fb4bd", -"TR_bitcoin-test_signmessage.py::test_signmessage[t1 firmware path]": "fa0b2a1032ed089f8b5556011d07a3f417947015d82bb6b3a6c1422e62768fb4", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[long_words]": "8602da47e7ec4f906ead3da2af55cc144bbfe29026e5d76df3371169267594cb", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[newlines]": "5fe0b39a18c1b9cbd40487107ff93386cf0049207fa11e19641bce78cb8ad089", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[no_spaces]": "fcd976b97a3fff11de7a7394d46533cf6eceeadf97cb444e956d8b31ab77b1be", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[normal_text]": "71223fb36c94c5f778397874f2b76879cd7b4bb431878b83ea2c587be27af3bb", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[single_line_over]": "2acfea8fb91eab9bad78c46306ef408568d95a0b5330c18ac9a25f98f9b6d428", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_nospace]": "d61ce69d12ec1a70e15f70ad59e20585500fca86d1aac5f75c49ab334023f001", -"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_text]": "cc72adfb31f47ae8c46d41fc86efd37d130fb56c006177796e89adc77df8ae8f", -"TR_bitcoin-test_signmessage.py::test_signmessage_path_warning": "26989fc60405eff141342f5f0b053c00b4a65debbde58be17a89b399c0018049", -"TR_bitcoin-test_signtx.py::test_attack_change_input_address": "297ff436f4e664ea6cc586596022aebfcc7b1c2c5c4b007e3a9768ff70671772", -"TR_bitcoin-test_signtx.py::test_attack_change_outputs": "13a8b4a2eeb40f7c05f2e6e33014328b58a0071c30aa112a6ec926db978493c5", -"TR_bitcoin-test_signtx.py::test_attack_modify_change_address": "ea582809fc46d6181d362cd7c950c822ad54f7375b62e5a5c5465e722f1f8363", -"TR_bitcoin-test_signtx.py::test_change_on_main_chain_allowed": "ea582809fc46d6181d362cd7c950c822ad54f7375b62e5a5c5465e722f1f8363", -"TR_bitcoin-test_signtx.py::test_fee_high_hardfail": "ed77061af170c5fe2ae18ece89ac122dafdbfcb43846f34b53d8968a52b1dbf2", -"TR_bitcoin-test_signtx.py::test_fee_high_warning": "f9acd02bd047e87a17a2f17d467fedff72a48225e295deb91fc73c3e66fce158", +"TR_bitcoin-test_peercoin.py::test_timestamp_missing_prevtx": "ae53144c620a709fec6ea971fdfae58480953abda1e588260e571fb461546bc1", +"TR_bitcoin-test_signmessage.py::test_signmessage[NFC message]": "ab3a71cb3e8eb516bdba44aa751d6f0fd4715a4635a84b54c2c0adaaf08319d5", +"TR_bitcoin-test_signmessage.py::test_signmessage[NFKD message]": "ab3a71cb3e8eb516bdba44aa751d6f0fd4715a4635a84b54c2c0adaaf08319d5", +"TR_bitcoin-test_signmessage.py::test_signmessage[bcash]": "c960bf499d53b56189fa15acc27115ed1b3ccbb5cab8b87036fc675c6ddf6992", +"TR_bitcoin-test_signmessage.py::test_signmessage[grs-p2pkh]": "05019729b386a6380eec9109c41651e09050d5c61bf99ffa4ee266b85b70d67c", +"TR_bitcoin-test_signmessage.py::test_signmessage[grs-segwit-native]": "b3d94052b376384494ac5645cf8ad2f1839fe51fc104e1a4cab8297e688a50d4", +"TR_bitcoin-test_signmessage.py::test_signmessage[grs-segwit-p2sh]": "5f162905b7772ce35bdb42f17f9ffafe80cba2a1397623f2036551393ff04848", +"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh long message]": "59b2b3ee83ef46b1846c2be1ef40b8cb38bf08aff9dbaf8e035948ae6ca0969e", +"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh0]": "f69ce108ef99f4ac9979f1e201a528d9d9d77924bfb52cc78beceabeee106b07", +"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh1]": "f69ce108ef99f4ac9979f1e201a528d9d9d77924bfb52cc78beceabeee106b07", +"TR_bitcoin-test_signmessage.py::test_signmessage[p2pkh2]": "41c8b335582277eec58d1994aa88967506bf39fbffed1e192c8c1c00c4cd9314", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native long message]": "cf9789f4e3a81bc2d7677bff376d310e02e3ef1e4a7a5bd3692a75553ca5f166", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native0]": "e786fe2be27eda10239edad5fb6af9a579162a4ef367a7d34288d7c99ff4d307", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native1]": "e786fe2be27eda10239edad5fb6af9a579162a4ef367a7d34288d7c99ff4d307", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-native2]": "d81139a5d5ca2fae89b885dd08ca805032cfec43d1e8cde3a976ecdbfefb82c0", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh long message]": "db81e4c58c84573f3309911b8809ff577085ef46da313b44052ed43adc523222", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh0]": "fa72eeac08430483272e74cae667cbb7ea7b280eec4d8129054407f382271b8e", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh1]": "fa72eeac08430483272e74cae667cbb7ea7b280eec4d8129054407f382271b8e", +"TR_bitcoin-test_signmessage.py::test_signmessage[segwit-p2sh2]": "e6d5153a8777b7e763998146b2a0a4e011481b3f2dd21b280a9ec4b84a12d660", +"TR_bitcoin-test_signmessage.py::test_signmessage[t1 firmware path]": "e1c8b0b2a0feff6256cd985cdf7abbcb68c0d76ebc1141758c5821c4bc5bde69", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[long_words]": "d9c030d4bf985c61823c0afff33dd8e88d54f7f98e67790f8f770fe0d34ffe7a", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[newlines]": "4cc497ecc331b1577525303075edd7386a6f77db4fd5e14e6b0bb344c14e9bbd", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[no_spaces]": "6d55b9267c88908ccf0213cb7b139ee7bb99547fc7f5163a56195edda6c98e9e", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[normal_text]": "c53cb90d10c40b74fa8222a90f6803c6673c7719cf4060a4f58fc9497924c4b9", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[single_line_over]": "76d2ceaba273fdaab37fbb1ea1077b2bf8b44083eaa2e7cbfb94b4902ba8a2da", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_nospace]": "97e0545a86de2b4c9bf02bb31cd6ca7b8a8be9305a2194eaf08ee4299c48f7a7", +"TR_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_text]": "b484fbffca429a01f16bf3982a1803d3963e96eae2da0c8cff0a855462ace6f1", +"TR_bitcoin-test_signmessage.py::test_signmessage_path_warning": "8c9dd94bf631fdfcc3cd207dafc9a4abbd6205bf692e7d68b85d719052da6932", +"TR_bitcoin-test_signtx.py::test_attack_change_input_address": "151683b6ee777c55d40badbb81327fc0e5cecc75aa4aa1718e274c6ece8761fe", +"TR_bitcoin-test_signtx.py::test_attack_change_outputs": "9cb93903b7a53bf5fcbc231651c7d77307a43139afbc4132fc30f7f0186d9974", +"TR_bitcoin-test_signtx.py::test_attack_modify_change_address": "376b665af3eafc6a7adcc65c62ac0399cc773bbcae0a03203574e3e4362e5621", +"TR_bitcoin-test_signtx.py::test_change_on_main_chain_allowed": "376b665af3eafc6a7adcc65c62ac0399cc773bbcae0a03203574e3e4362e5621", +"TR_bitcoin-test_signtx.py::test_fee_high_hardfail": "2aab3f48718c32d14e57036c6829846f23e6e03f8f6aa6f3428241edcfd6fa66", +"TR_bitcoin-test_signtx.py::test_fee_high_warning": "6e6a01c16568ddc59fc593f597bec332f2db133bcc1664b7bb75a48f7fcc61c9", "TR_bitcoin-test_signtx.py::test_incorrect_input_script_type[InputScriptType.EXTERNAL]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx.py::test_incorrect_input_script_type[InputScriptType.SPENDADDRESS]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx.py::test_incorrect_output_script_type[OutputScriptType.PAYTOADDRESS]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx.py::test_incorrect_output_script_type[OutputScriptType.PAYTOSCRIPTHASH]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx.py::test_information": "04e2b45aed65983504b43088347b5e91e6dfe8160ae6b103ec330cea47f09670", -"TR_bitcoin-test_signtx.py::test_information_cancel": "1d28d10c48c03b59f4385527b0013adac0a0a064e691762995c8aeaa88a64f4f", -"TR_bitcoin-test_signtx.py::test_information_mixed": "b9b978b607634cb19bfced66451230741c19bc61af52a727a217e44bc96ccb9c", -"TR_bitcoin-test_signtx.py::test_information_replacement": "1eae80041992598b7a046be0f2102e8ef607767064895158e7812e91f3add3b0", -"TR_bitcoin-test_signtx.py::test_lock_time[1-4294967295]": "8d32ab967f215cfcb99addd66b54546bed1d9acbc6ec029ae062e077bb1a2cb1", -"TR_bitcoin-test_signtx.py::test_lock_time[499999999-4294967294]": "930f45e0135306d381cc79ecefe6c2ec9bf8c8a04064797f12ff6569326aa15c", -"TR_bitcoin-test_signtx.py::test_lock_time[500000000-4294967294]": "08b67fc89031cbea94057d4a13f5c585751845c63c98d4a8a3a72ea5882b993e", -"TR_bitcoin-test_signtx.py::test_lock_time_blockheight": "764d788fcb2a15e58a8e367e9d16e8d7373c47c826289cbe9d6b05d4596e2404", -"TR_bitcoin-test_signtx.py::test_lock_time_datetime[1985-11-05 00:53:20]": "575e27fb5ee3c283ac585dc1bb321fd6f05c05d2fd8aa9fe431634e133ea6de2", -"TR_bitcoin-test_signtx.py::test_lock_time_datetime[2048-08-16 22:14:00]": "a086cca77dd0b80561ecc0e8d1b69bcd1eaa036c11c85520e29db217a94477a1", -"TR_bitcoin-test_signtx.py::test_lots_of_change": "9195bbc2628ce0baaaf121f857196bbc173e28e820d741492b5365d7ccf764b5", -"TR_bitcoin-test_signtx.py::test_lots_of_inputs": "35dc6843ddd4200e36c2ff526af92ab2e3479409dc6436f99615a4e9fb0dd071", -"TR_bitcoin-test_signtx.py::test_lots_of_outputs": "e36e0be594af44dc8afc4f726602ae00375816dcceccfc6393af2c5aa62ab48a", -"TR_bitcoin-test_signtx.py::test_not_enough_funds": "e242af8f75da4a2e0d94a7d29ba075295e665e776d97192a2961e60ce099c183", -"TR_bitcoin-test_signtx.py::test_not_enough_vouts": "eee366d6f31641bc1d30a00d42c0369f893bc9673e5634c4d0fc97491d38957c", -"TR_bitcoin-test_signtx.py::test_one_one_fee": "a7812a9a606eaf48a2aec7ed67b2dc5eeca18d08165572f4bfa9d6256b73e857", -"TR_bitcoin-test_signtx.py::test_one_three_fee": "871df75d6acbad99db7d43637973fc7853573ffd1018e3235cab448d9772e939", -"TR_bitcoin-test_signtx.py::test_one_two_fee": "d2c545173ad02f7bd92a5c94c141794283c721f2e037a11dc3949ddc8a19c51e", -"TR_bitcoin-test_signtx.py::test_p2sh": "721626ec4419b44f0cf7718ca735936140db171a47178469720a33c88c5a856f", -"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[branch_id-13]": "3aa1b61c0a25b514a0b6ae2a4c3ff0075e78e7431680ac1d8f7ba4ed4cc4a046", -"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[expiry-9]": "3aa1b61c0a25b514a0b6ae2a4c3ff0075e78e7431680ac1d8f7ba4ed4cc4a046", -"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[extra_data-hello world]": "3aa1b61c0a25b514a0b6ae2a4c3ff0075e78e7431680ac1d8f7ba4ed4cc4a046", -"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[timestamp-42]": "3aa1b61c0a25b514a0b6ae2a4c3ff0075e78e7431680ac1d8f7ba4ed4cc4a046", -"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[version_group_id-69]": "3aa1b61c0a25b514a0b6ae2a4c3ff0075e78e7431680ac1d8f7ba4ed4cc4a046", +"TR_bitcoin-test_signtx.py::test_information": "987f1cee89ff0f30f52a7f1127c4334cf9ef41e7932982bd863da4f1c3710848", +"TR_bitcoin-test_signtx.py::test_information_cancel": "d49ac73c9c025665a9ff66645fb4de493fa669b2994f72361af24e264ee6222f", +"TR_bitcoin-test_signtx.py::test_information_mixed": "e3057b8a8d018a8d64ca8f446621429b0f61f1fefb5348ff5e7a461f4e6b8c98", +"TR_bitcoin-test_signtx.py::test_information_replacement": "a63cb64ad80df0ccf4ed29df498f6ab775ee87c50d6873807b0ff031a6ea4e73", +"TR_bitcoin-test_signtx.py::test_lock_time[1-4294967295]": "cda0ad267b5b9038e21071838a016a535406c37bc71cb966fa0db01d46e03902", +"TR_bitcoin-test_signtx.py::test_lock_time[499999999-4294967294]": "ce1f37765d072a2780b780d7bea8fa7580020a36c43f97ff7e1a4d3e6d03e269", +"TR_bitcoin-test_signtx.py::test_lock_time[500000000-4294967294]": "afca79c907d1b6bdd3ea89d633db12376cb118bea81dce56d97412d5f0ed01b6", +"TR_bitcoin-test_signtx.py::test_lock_time_blockheight": "cb49ac4f5b446e38a9a7b85808554082fff77d68fc591ad1c2abfc772bebdc88", +"TR_bitcoin-test_signtx.py::test_lock_time_datetime[1985-11-05 00:53:20]": "51454f8f653c4c2b56e8abba86a9a072f4f0c386064c946dbd3579d050a9b405", +"TR_bitcoin-test_signtx.py::test_lock_time_datetime[2048-08-16 22:14:00]": "fc19657cf87112a83bde95fc121e4ff17f77822d932f0afb552fb1de0f16994c", +"TR_bitcoin-test_signtx.py::test_lots_of_change": "63087f043fe98c1acd99fd70af4d22e272f8b41cdd8e3f41c1a2c0249d4fb657", +"TR_bitcoin-test_signtx.py::test_lots_of_inputs": "b344fb78c03712d37744e0f249c3f73d70a6e23e1ba651197aa0f2eac74d4c21", +"TR_bitcoin-test_signtx.py::test_lots_of_outputs": "6b1e74c9f9a104e7c76b9c63646e5ba0722341a36df2ec9d0f54001102aaee6d", +"TR_bitcoin-test_signtx.py::test_not_enough_funds": "c0665c8fb1c28bf15796987aa920b6957c6b485f7173bbb6f7fd14a5bbd5761b", +"TR_bitcoin-test_signtx.py::test_not_enough_vouts": "5f9eb8bfaaa04c54d714417189bcc17a586aa56b5b1b2d0fedda59c450a5ef7c", +"TR_bitcoin-test_signtx.py::test_one_one_fee": "22b0c88801eba50f6cb506377e02f01fd49a0e94b159c67d54a65a4f66cce5ca", +"TR_bitcoin-test_signtx.py::test_one_three_fee[False]": "b009fcda304ac0dc18b354ae1a39495b99db81067825d4f20a25ddb9057fe645", +"TR_bitcoin-test_signtx.py::test_one_three_fee[True]": "5ebdeb1f97ab1b380477fa42bcb2fdc20319d8edc8b6d94e045a06ea95459cdc", +"TR_bitcoin-test_signtx.py::test_one_two_fee": "aaae3dfbea00e5c257fee19efa89966390edeb7053afce2286cd654c80a18492", +"TR_bitcoin-test_signtx.py::test_p2sh": "5d520e0d05dd36b274a10f668c7a144426644f73f37a05b6c15e28ace8f78e95", +"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[branch_id-13]": "7a6529b2f37f721436478a4535953d93100e2cd86a739649469b01b4116f49dc", +"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[expiry-9]": "7a6529b2f37f721436478a4535953d93100e2cd86a739649469b01b4116f49dc", +"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[extra_data-hello world]": "7a6529b2f37f721436478a4535953d93100e2cd86a739649469b01b4116f49dc", +"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[timestamp-42]": "7a6529b2f37f721436478a4535953d93100e2cd86a739649469b01b4116f49dc", +"TR_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[version_group_id-69]": "7a6529b2f37f721436478a4535953d93100e2cd86a739649469b01b4116f49dc", "TR_bitcoin-test_signtx.py::test_signtx_forbidden_fields[branch_id-13]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_signtx.py::test_signtx_forbidden_fields[expiry-9]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_signtx.py::test_signtx_forbidden_fields[timestamp-42]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_signtx.py::test_signtx_forbidden_fields[version_group_id-69]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_signtx.py::test_spend_coinbase": "f92775f1719473c669ab260e96394f07bdbce08f0187a7dbe3340c9cd9f5b8ad", -"TR_bitcoin-test_signtx.py::test_testnet_big_amount": "7e689ca1108bc0e320ba34ad3d70150cf46089298f63ee1b4efeb4ac981117f3", -"TR_bitcoin-test_signtx.py::test_testnet_fee_high_warning": "c96e0c3859423a83ea1ca5d7ac327e0705b6d93e2227ca6739cac6895198a955", -"TR_bitcoin-test_signtx.py::test_testnet_one_two_fee": "ea582809fc46d6181d362cd7c950c822ad54f7375b62e5a5c5465e722f1f8363", -"TR_bitcoin-test_signtx.py::test_two_changes": "3244d029946e10a08506fbc54e9e5659b8a8de1f6e226852cf6acc66b9fbb0bb", -"TR_bitcoin-test_signtx.py::test_two_two": "20a910d497f8ee1052d23ccab774ed232a70ee7ffbf12d84f7e185b2da7b1fa6", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.BITCOIN]": "a7812a9a606eaf48a2aec7ed67b2dc5eeca18d08165572f4bfa9d6256b73e857", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.MICROBITCOIN]": "999e025200583ffe4c9dc27940c6c5c9fef1cbf6800526fb670c312c23d5b806", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.MILLIBITCOIN]": "87ce684c6dbbd48ab83d64633770377728de28e94982536989b8777976295195", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.SATOSHI]": "e4106d6a650329f30fd1a20d444d1fd40db26dc043628874aa50d6415ca52ba4", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[None]": "a7812a9a606eaf48a2aec7ed67b2dc5eeca18d08165572f4bfa9d6256b73e857", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.BITCOIN]": "49ebf16769a8500311116a6fb7dfb8d941e49ed370bf2539c5cfceecd9368170", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.MICROBITCOIN]": "eb697bbbf65763567956f15af2b9f270d7e5f1565ea61f206b70cc732135f0eb", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.MILLIBITCOIN]": "fe6889aa38f27a5a1d3ac30d2d23d5b4f477803b87533c35b8465de30207c234", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.SATOSHI]": "399fa4bf1e4e21f8ef2348c4977ae440d7cc253a8353b477d932575041d2b6d5", -"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[None]": "49ebf16769a8500311116a6fb7dfb8d941e49ed370bf2539c5cfceecd9368170", -"TR_bitcoin-test_signtx_external.py::test_p2pkh_presigned": "80526b7b4cdfc7c2d01e603adc780b6d44dc8f86a733a93cd4c807d09b85c248", +"TR_bitcoin-test_signtx.py::test_spend_coinbase": "f8ad9d1870a8299487027966bb70c23e1345dd8e291bfc876937da58b286c113", +"TR_bitcoin-test_signtx.py::test_testnet_big_amount": "fba525c320a6c036d4b8e40add09e2ddeab542bf730f32cd8ecbf0f925efc38b", +"TR_bitcoin-test_signtx.py::test_testnet_fee_high_warning": "9d34996769fe4e55f22ff43b960d4d51485f930bfc9418219cb08e61b7cde175", +"TR_bitcoin-test_signtx.py::test_testnet_one_two_fee": "376b665af3eafc6a7adcc65c62ac0399cc773bbcae0a03203574e3e4362e5621", +"TR_bitcoin-test_signtx.py::test_two_changes": "ae558452eb1d8786310465e4fd6bfdeec3f305fc8f66ccbe81ed0f1e7d582205", +"TR_bitcoin-test_signtx.py::test_two_two": "44e8e001c13580857fb29b7b8849062e02d9f721d830ae10c693943d87256074", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.BITCOIN]": "22b0c88801eba50f6cb506377e02f01fd49a0e94b159c67d54a65a4f66cce5ca", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.MICROBITCOIN]": "b404cb8094b2e1332355918567698b5cf7682875e3fc1ea8d11e493e6e9df767", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.MILLIBITCOIN]": "1d14b96b96d4511e736e634905daf789c67665576c7d38dec296a25e3fe3ebc1", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[AmountUnit.SATOSHI]": "9a1b3a663bb87bda347db5d4d33f2e70f60054d1eb70d1d0d4649e92761b2711", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_btc[None]": "22b0c88801eba50f6cb506377e02f01fd49a0e94b159c67d54a65a4f66cce5ca", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.BITCOIN]": "68b8d594582e571733bbf5a2c0617fbf9fd8953bf3051a6e3d938133017397af", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.MICROBITCOIN]": "1343109d5dfe35a302e2e392026fd3ee71347bb7123ab8f8fb94d6b087fd5e26", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.MILLIBITCOIN]": "7fe8d7b6f8a5b11ba86a1a73b097cad0e29193385080e2187e3ed3d64d2b4505", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[AmountUnit.SATOSHI]": "1fd6bb276dd0121093983c26f0cb9bc109db0d8f895b51adc9b317e1abe7d6f1", +"TR_bitcoin-test_signtx_amount_unit.py::test_signtx_testnet[None]": "68b8d594582e571733bbf5a2c0617fbf9fd8953bf3051a6e3d938133017397af", +"TR_bitcoin-test_signtx_external.py::test_p2pkh_presigned": "b86c389ee6d81ecc94b8ef7742f581b6c181838f3f1e9ea29723e1f5b9dddb46", "TR_bitcoin-test_signtx_external.py::test_p2pkh_with_proof": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_signtx_external.py::test_p2tr_external_presigned": "a621af0aef4ef29667f51f9ea88faf3c4d76f5677dce8eb8225cc768713f5bcf", -"TR_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "fd0ef278db1d75248db147a576ccc6e4a7a8761bb2a62f1ac3f3a746fe973a9c", -"TR_bitcoin-test_signtx_external.py::test_p2tr_with_proof": "273595f6683fda7652c330d3423b6b149744a4145b185f719856d090abf12b1e", -"TR_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "22fa430fbad11d60826325b5dfe938bc0d982442fd6b741ca0056a58c0712adb", -"TR_bitcoin-test_signtx_external.py::test_p2wpkh_in_p2sh_presigned": "7cbd1103d3a3336e8a2aafa9b65ae487a86b8edccd2885b169b32e79110476fb", +"TR_bitcoin-test_signtx_external.py::test_p2tr_external_presigned": "10517bdbe7e530082ada2e0246fe11bce0dfdc741ff71b5ce0b1bb33d4d4bcae", +"TR_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "a6f48f63cd7074f8ce7b6d2604f8b7dcdfe89dce9bbcbe1ec1db68ce84444e1c", +"TR_bitcoin-test_signtx_external.py::test_p2tr_with_proof": "7bc2898d29247fc8b3454873b96ad1a38d59299aa19aaec389973b2458cd001e", +"TR_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "54ac2025ebac2ce8b8af0e11d3b2f211ffc41a98d2dad2c52bbb4c286fa7620b", +"TR_bitcoin-test_signtx_external.py::test_p2wpkh_in_p2sh_presigned": "cbbea8c9a12a6e7aa827037a4d1845bec18b26b97223b63b7cd4269f41dd5945", "TR_bitcoin-test_signtx_external.py::test_p2wpkh_in_p2sh_with_proof": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_bitcoin-test_signtx_external.py::test_p2wpkh_presigned": "f7dedc9d2f9bca4fc5dd1b1052a824f6b1cbc4da194b9c7b872404534ca86ce3", +"TR_bitcoin-test_signtx_external.py::test_p2wpkh_presigned": "ebbee3579e15b1947797d7c10c2a918fc7706498dbe574b66ed392094135ba15", "TR_bitcoin-test_signtx_external.py::test_p2wpkh_with_false_proof": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx_external.py::test_p2wpkh_with_proof": "3240a390525bf7312327063eb65418a078b16902fa9b1ac7b8dea231a0220d3f", -"TR_bitcoin-test_signtx_external.py::test_p2wsh_external_presigned": "cf93734a65410834bc51c1e4d01662f69ff1b715a2f2cf897906af5e9ffc9c52", -"TR_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "36b796223ed86f58d7a8c29dd3f09988fffbbb874c5c1da97f43cc03ef223345", +"TR_bitcoin-test_signtx_external.py::test_p2wpkh_with_proof": "666a73a9dd8cb0900d95be1a3b52c4c1ecea5b57f5a9730ff4c0dac680606ab5", +"TR_bitcoin-test_signtx_external.py::test_p2wsh_external_presigned": "ea9fbae00a804acb645a4c432c587a2adcce77453bdf7494d405969844c734de", +"TR_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "69627ac78eeef92c6505a17bf9da62e65c600b212903aae4bd0a09bead2f50f5", "TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail_asap": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "96cf3fa6e15b0d9554c9d3ef8f932f1b424dc80c3bb9b71e95f554a9ad468f93", -"TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "88bb39882abef1506ef97c2ee914e05bff1abbe3232eda92a1548ce50ab75b1d", -"TR_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_inputs": "4003173b1142e28b00eea913d2df2f62627a6b69eb98ad1c46841e66f14a3a8f", -"TR_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_non_segwit_inputs": "1817494bd2cf62b56056382f3fcf91b367391e1640acc2b0ab56fbce15f63623", -"TR_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_inputs": "4003173b1142e28b00eea913d2df2f62627a6b69eb98ad1c46841e66f14a3a8f", -"TR_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_segwit_inputs": "f26e44f2b853926b019f640e16840754fac816803fd73c1bf91f545ac929e484", +"TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "4d68fc2009f59bc30ec2903f9f1a2c14374c89ba062085ddddf35b48b7894c20", +"TR_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "4c00b20549d9b9b66ac46cefc1b0c89e88abd6b0ee57ca77bb953d5898a8f3fc", +"TR_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_inputs": "bb4413f52686b7e9e465599d42606866de77ec85ff67ad10eb905e6eff1442f9", +"TR_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_non_segwit_inputs": "7076bafa950a471ecfa587bae588736af537ddc5884a544f7086c8ca6f4732be", +"TR_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_inputs": "bb4413f52686b7e9e465599d42606866de77ec85ff67ad10eb905e6eff1442f9", +"TR_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_segwit_inputs": "ad7cbb53106d94880ba0f60fac1b60546805bdac7370e2ac3df670459b2faed2", "TR_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_amount": "c072f90fecb07a693c09038a26d44eadae88854df02e0537aa99f946d641af83", -"TR_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_mac_purchase": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_mac_refund": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_output": "249e65809ac735eec03907514834fa347df6fa2f44d63dfc09cc89defd85885e", "TR_bitcoin-test_signtx_payreq.py::test_payment_request[out0+out1]": "a573b011d1a31fc79e2cfdb6e687b5c8eb8d1803286d94afd09215a33c2ffb14", "TR_bitcoin-test_signtx_payreq.py::test_payment_request[out012]": "1594934f96bd424c407a5c77eaa18d8b613b02d8eb5831cee980d18b08cdc522", "TR_bitcoin-test_signtx_payreq.py::test_payment_request[out01]": "25c87a158b0c4cc2cc0e35fb28222170ef79ed3bf7f376ed69587c9111910dc8", -"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out0]": "4f0fafff0fc1e466cb434df46f38b2c1eab5b34041cacef523a231974b225bdd", -"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out12]": "2bc5bdd141b41660fa7cc04d740080561edcb575be2fe8cc0cb3598b51935786", -"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out1]": "2c43fec53fd0d4f008ace73c0eacfdcfcb4825acf813d27f5e32b624ff36193a", -"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out2]": "bd240d2cda76a4a40674b398a62736ad32cbd4d75985c6071828c873b87416f2", +"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out12]": "1c983952013779da23eac0741079fe5728e4669bd6d517d6c3c5aba6700cb603", +"TR_bitcoin-test_signtx_payreq.py::test_payment_request[out2]": "299d8bae7c45d62aa8f9c7d33b01f1b78c2a280cc27e60e652540e2c08aa4ba8", "TR_bitcoin-test_signtx_payreq.py::test_payment_request_details": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[hello world]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[x]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "6f49bc83035d08c9767735fd96273cdc6e3d30b6b2539a3086e90d4208a6b339", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "6f49bc83035d08c9767735fd96273cdc6e3d30b6b2539a3086e90d4208a6b339", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "6f49bc83035d08c9767735fd96273cdc6e3d30b6b2539a3086e90d4208a6b339", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "6f49bc83035d08c9767735fd96273cdc6e3d30b6b2539a3086e90d4208a6b339", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[]": "0a1e2ea7021a54cd3cbef97aa56c92fae1e44b26efc0e659eff0d566e2a496b9", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[hello world]": "0a1e2ea7021a54cd3cbef97aa56c92fae1e44b26efc0e659eff0d566e2a496b9", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[x]": "0a1e2ea7021a54cd3cbef97aa56c92fae1e44b26efc0e659eff0d566e2a496b9", -"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "0a1e2ea7021a54cd3cbef97aa56c92fae1e44b26efc0e659eff0d566e2a496b9", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "6aa704d1250aa7c248ad8ad72d9b9815095eba18158db44d63381bfa8e554dd7", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "6aa704d1250aa7c248ad8ad72d9b9815095eba18158db44d63381bfa8e554dd7", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "6aa704d1250aa7c248ad8ad72d9b9815095eba18158db44d63381bfa8e554dd7", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "6aa704d1250aa7c248ad8ad72d9b9815095eba18158db44d63381bfa8e554dd7", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[]": "b3827ffb2ec0287220a1bda28ed417718ab9fc095b641a10734bf81056946eac", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[hello world]": "b3827ffb2ec0287220a1bda28ed417718ab9fc095b641a10734bf81056946eac", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[x]": "b3827ffb2ec0287220a1bda28ed417718ab9fc095b641a10734bf81056946eac", +"TR_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "b3827ffb2ec0287220a1bda28ed417718ab9fc095b641a10734bf81056946eac", "TR_bitcoin-test_signtx_replacement.py::test_attack_fake_ext_input_amount": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_replacement.py::test_attack_fake_int_input_amount": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_replacement.py::test_attack_false_internal": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx_replacement.py::test_attack_steal_change": "396444b2e3ecd3e6ceb41a164be242bae968792a3396473bb01e590846b8f0ac", -"TR_bitcoin-test_signtx_replacement.py::test_p2pkh_fee_bump": "93a1cb988817a8740c767bd1420a15658695b778550fa4d66a8d3d497d18c628", -"TR_bitcoin-test_signtx_replacement.py::test_p2tr_fee_bump": "27060bc1905524d10a72f1c4b567de6708519a810ab83ff3adccaaec526be2be", -"TR_bitcoin-test_signtx_replacement.py::test_p2tr_invalid_signature": "27060bc1905524d10a72f1c4b567de6708519a810ab83ff3adccaaec526be2be", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_finalize": "1c7b4804db69f7b6130162f96d38262ff6c11eb6e65a01a765f1a7e0a64dea9c", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_fee_bump_from_external": "4fe4e57acf9d7f63ad2fd3533567160c60fd84ba2d2a6cb9e3256b13ce9d2799", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_remove_change": "a3799118092d6983b9e9eae4f8f282982d10f70e11b590bc9cd50ab2718af5a6", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_invalid_signature": "1c7b4804db69f7b6130162f96d38262ff6c11eb6e65a01a765f1a7e0a64dea9c", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_op_return_fee_bump": "4b9d2ef7183304b06a78bcd1219c6ac27c0fee906a7dc0bf9af05fe65e8f805a", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909659-90000-02483045022100aa1b91-c9b963ae": "5a6b1596b2ecaf232744d7d5d294a9dce7559f444d0eb49f1114dd7b3dd3e0b8", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909718-90000-024730440220753f5304-ecb983d1": "5a6b1596b2ecaf232744d7d5d294a9dce7559f444d0eb49f1114dd7b3dd3e0b8", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909800-89859-0248304502210097a42b-7a89e474": "5a6b1596b2ecaf232744d7d5d294a9dce7559f444d0eb49f1114dd7b3dd3e0b8", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909859-89800-02483045022100af3a87-80428fad": "0fd1e73b3e7db9eab94a8d885489c1cfb822ab5e0bfa3e27137206f30a4d62ec", -"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909859-89859-02483045022100eb74ab-881c7bef": "5a6b1596b2ecaf232744d7d5d294a9dce7559f444d0eb49f1114dd7b3dd3e0b8", -"TR_bitcoin-test_signtx_replacement.py::test_tx_meld": "f7262a8ecbe181c2d03bfbba021d9dbe4aba9fffb40f2acafcc14b044d57d2a4", -"TR_bitcoin-test_signtx_segwit.py::test_attack_change_input_address": "73dfafe1268408dda79f922fec1f16c3b7b0c1f1110c4caf8248ad42ad51524a", -"TR_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "5e53ecf3838c0d0c077fe9e13ba9aaddc12c4abf230fdaf7d5edd9058beaaa46", -"TR_bitcoin-test_signtx_segwit.py::test_send_multisig_1": "90293f3af8a2efcccb133029f65e890096aacde4debec461c9770ad43d872306", -"TR_bitcoin-test_signtx_segwit.py::test_send_p2sh": "ecfb0d5a7457af426d471ea2eb87308a8ed1bb5aa6fdcc5c608b6669d4516292", -"TR_bitcoin-test_signtx_segwit.py::test_send_p2sh_change": "951950e4f8b7278b834a1b2efd0b5c7643c6fcba4917019d395a9b64f53411a1", -"TR_bitcoin-test_signtx_segwit.py::test_testnet_segwit_big_amount": "7166a65e81fc57165c3631d4c428368899af58c8505b95a1a54e541de921c347", -"TR_bitcoin-test_signtx_segwit_native.py::test_multisig_mismatch_inputs_single": "ba32a94cc6f408713c8a186a2a8c49cfef17071e72d28894292233117389c97d", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_both": "62c8dc416689eaac8d39772ade99a881db023c98c8007d94c3d3755fe5a40fae", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_1": "b59eadd90eedefce178f17f34b46ffe1d916b9b74df841d68407920b4dfebaf0", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_2": "c55a40b74c27f1444ea5cb736ec539f9a3816c773d9a4f54644a05f434019002", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_3_change": "ebe5a5fe95b8b3a9c67b8a551a40227b88d320da67ff08e95cbdb6e3be2255ed", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_4_change": "1acae4e7895272fe83696dd43af865f806cb7429367fe0e836e76428f3998e19", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_native": "49ebf16769a8500311116a6fb7dfb8d941e49ed370bf2539c5cfceecd9368170", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_native_change": "d2a7484ab4df82e11967510ea04b3692b70e89b87eb83d63f176e65f4e80aed9", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_p2sh": "d6538a0b6b8c06eaf003f9c1ab954e156164a66a3f98ae6034bdfb3b0bd21f4a", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_p2sh_change": "7194d3304884027fb8cd5c1944564af39012eaf175f97a50af965c110173a4ef", -"TR_bitcoin-test_signtx_segwit_native.py::test_send_to_taproot": "2b652f5fd38695bce4a31cd708a4738c14992022e5456be09db5f686256272e0", -"TR_bitcoin-test_signtx_taproot.py::test_attack_script_type": "cbc24c40169bae76b228ba9453dbbe1eed345406546d34f872fde4a20e3ce3fb", +"TR_bitcoin-test_signtx_replacement.py::test_attack_steal_change": "2143dc83a562569771091087d89d164a2f6218ba7e0fa8e2adbb5f802a305ead", +"TR_bitcoin-test_signtx_replacement.py::test_p2pkh_fee_bump": "bd1c6ebb4d702ad4172f710e0760acebcd8b657b176ab09d694fc793eaaff849", +"TR_bitcoin-test_signtx_replacement.py::test_p2tr_fee_bump": "10a40e65979497c3133baaadcef00665c7c224b03babe623a2b56dacf936d8d3", +"TR_bitcoin-test_signtx_replacement.py::test_p2tr_invalid_signature": "10a40e65979497c3133baaadcef00665c7c224b03babe623a2b56dacf936d8d3", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_finalize": "ad5b171dc879b4c19c6fd16cefd75e677bebd5ad4f2a95670d7a71c6a83f2614", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_fee_bump_from_external": "849604cad0ebce8ac57018fa4215956a179c3b97fb50d88885a84a6ac730a9f3", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_in_p2sh_remove_change": "60947b5820e78cec105c9f2d7f2cb18d080e6f9ab4e786655eda6adeafbf5b92", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_invalid_signature": "ad5b171dc879b4c19c6fd16cefd75e677bebd5ad4f2a95670d7a71c6a83f2614", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_op_return_fee_bump": "3d655937ab909053a65198be3b9728822c8a732efb1fcb8da3e1db897cb894ab", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909659-90000-02483045022100aa1b91-c9b963ae": "977e9399088b1939b139701bf27d2162ef208b6311a2d229f288cc7582f91a26", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909718-90000-024730440220753f5304-ecb983d1": "977e9399088b1939b139701bf27d2162ef208b6311a2d229f288cc7582f91a26", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909800-89859-0248304502210097a42b-7a89e474": "977e9399088b1939b139701bf27d2162ef208b6311a2d229f288cc7582f91a26", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909859-89800-02483045022100af3a87-80428fad": "8bfba86abe6ddf1ebdb50310bb124f3b3906dacf7c5ea57f06f75c1570a9665d", +"TR_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909859-89859-02483045022100eb74ab-881c7bef": "977e9399088b1939b139701bf27d2162ef208b6311a2d229f288cc7582f91a26", +"TR_bitcoin-test_signtx_replacement.py::test_tx_meld": "a43be3c1b450871626dfde9f083bcde77e81543475db79bbc5b92a38fdb86c9f", +"TR_bitcoin-test_signtx_segwit.py::test_attack_change_input_address": "58ac2c9a484c3633ede7efdfe5516599818f6e57a0965218483c96fc4a804732", +"TR_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "be4f92a085248ae2ce92c5f232b5cc04c325358d0063b18400c104d2218a682e", +"TR_bitcoin-test_signtx_segwit.py::test_send_multisig_1": "b705f7e12c8cf40d40929daadfc3d2d1ba79895f71681162ad0547845fa8565f", +"TR_bitcoin-test_signtx_segwit.py::test_send_p2sh[False]": "c87bd9abcfa91c7be19cd914f62b0875a24647d4297e4995245ff1a1237aa985", +"TR_bitcoin-test_signtx_segwit.py::test_send_p2sh[True]": "76f86d17f6f24132d9dc717963cf0b7bef4cf6131aa5e936b30d413c99964024", +"TR_bitcoin-test_signtx_segwit.py::test_send_p2sh_change": "71a64992ed7d7c290ab9b2e0b0ac3bad9dea146a344bca4dc623e83951f3c11d", +"TR_bitcoin-test_signtx_segwit.py::test_testnet_segwit_big_amount": "5671529bc3e6ec073ffb475132720879524d20caafc4e78658e3a23594864eaa", +"TR_bitcoin-test_signtx_segwit_native.py::test_multisig_mismatch_inputs_single": "e98e92cd0e04a66f97c6c415d9fa4e91b45f0cf6586855f30253aa22e2f8a7a6", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_both": "090b88a56070f2de0d86906aba2723e87094f565e7a80acc15254fa0012a18cc", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_1": "90881957322e64d738bc9fb75a908f7e702a5d49a548d16c69f352ad51bc2ae3", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_2": "0b6731acf7f71d764106520a20747cc537e2c4a9c2bab8dc750debbbd46c44d6", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_3_change": "4ba3c0a50c2819c51af14e3d5be5a9f56b90e1dea4ca2cea48824453456bead0", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_multisig_4_change": "c5866b506af6661cbebd288aaf63dae60a6ea202801a1ee3a34b66201cf26ef8", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_native": "68b8d594582e571733bbf5a2c0617fbf9fd8953bf3051a6e3d938133017397af", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_native_change": "fc15afed019ed14f918ca418ee6852acf7abfe0891f3d1ca5e1d7bae80efcb34", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_p2sh": "35911b9fa6b82947e6e96d12d87a081db89c4bcce59ad84ee4fb588632283f05", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_p2sh_change": "204574a86a636c30d9c9a2cd286efc7da50e2129a2393a40f5d9c7f02d299ba1", +"TR_bitcoin-test_signtx_segwit_native.py::test_send_to_taproot": "c579cdce62daf5514ed876a9a4cc4806e7e4183d5758f9b4ceb356ddb7cb4c36", +"TR_bitcoin-test_signtx_taproot.py::test_attack_script_type": "ae951ee23d9c610e59212f855c9599aa51cc2d93a6b65048323e3a58942ef7f2", "TR_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1pam775nxmvam4pfpqlm5q06k0y84e3-a257be51": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1plllllllllllllllllllllllllllll-aaa668e3": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1plycg5qvjtrp3qjf5f7zl382j9x6nr-5447628e": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", "TR_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1zlycg5qvjtrp3qjf5f7zl382j9x6nr-880d4a6b": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_bitcoin-test_signtx_taproot.py::test_send_mixed": "20004e1165fcd19cad3b2a71a4b45a44bfb946a2c4f0d0130d07bcbdd0014b82", -"TR_bitcoin-test_signtx_taproot.py::test_send_p2tr": "693ad32f3a18e1e918743fbd640e5696f9bec525cddd08e049c0dcb9ad61fe7c", -"TR_bitcoin-test_signtx_taproot.py::test_send_two_with_change": "b7132a982b03380ddfc6338f2e05d249976ba9fdc7574dcf427a560a418de849", -"TR_bitcoin-test_verifymessage.py::test_message_grs": "1c922c785bd0ad1c186aef9efaa60ed61cd3348130d5d89439e29c3c3675c36f", -"TR_bitcoin-test_verifymessage.py::test_message_long": "b35f32353ad441d0ef34bf5f78c082608da9676559e586ac5e3a554cfff73671", -"TR_bitcoin-test_verifymessage.py::test_message_testnet": "eb63d6d4e4eee3e8f77d063fc1d3865a69bdd988c9c826cbb9c1f817ee9eb3c6", -"TR_bitcoin-test_verifymessage.py::test_message_verify": "9771cc053009f77f361ef94a7a11cbec9bc280708f6dc594e994d60f330d0225", -"TR_bitcoin-test_verifymessage.py::test_message_verify_bcash": "e35e63c7794e67e2f4b7e7f7c139f645f5b1effe95624661dac6549b87590680", -"TR_bitcoin-test_verifymessage.py::test_verify_bitcoind": "ffde03d1a6631507200b4ebfffd8eae66f916528ef1558f66caee9f13f8fabfe", -"TR_bitcoin-test_verifymessage.py::test_verify_utf": "a16d6768bafe8e4ce221c08bc457a92316af2495bfa548a20a3cd74cf05c37c2", -"TR_bitcoin-test_verifymessage_segwit.py::test_message_long": "3c1536f2c1dca1d473e55987f1f39118e429ffb00cfc70544984a6e7f1728a65", -"TR_bitcoin-test_verifymessage_segwit.py::test_message_testnet": "b52e913521cf5062be6bf715878012e8a6b2f1755c70f4da335f95f7c5001f0c", -"TR_bitcoin-test_verifymessage_segwit.py::test_message_verify": "5f9a62890c2668d909e8d66aa3d472af5d71b9ec4b6cd0386e809cbefc05f643", -"TR_bitcoin-test_verifymessage_segwit.py::test_verify_utf": "0688925e51efc30bdf0b75880e1d65959f7653de9efa1403b95f767fbca59a0f", -"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_long": "f6b3d1eaa6afa4331da324501b9eac2f5258a075019ec42204b715aacb05d919", -"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_testnet": "5142c42e8feeaa032a83adb6d3554ad87b8402fc7b4329a49173b07464f2b041", -"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_verify": "cc145de23fa9e17d6bb85cf677906488e12b4682f76dee6fb5e097de5e5e343d", -"TR_bitcoin-test_verifymessage_segwit_native.py::test_verify_utf": "dbbdaac7fe9a666bbaef370e4ec0248ced07e7d1f4a89d350a6878e86f3bef09", -"TR_bitcoin-test_zcash.py::test_external_presigned": "c3ced7dadbac511abe2a0d43fc7073beeaa023d9b2150cbcd1db4ad967c7f97b", -"TR_bitcoin-test_zcash.py::test_one_one_fee_sapling": "6addea0e6a4d2bae9ad61a62c8192d730d225bd1e5e73ffd01d8762fea6cac57", -"TR_bitcoin-test_zcash.py::test_spend_old_versions": "e9a3d37eb9991a411c78f1233ababdc1a980d3f0d31ab481642e4cc857e7b7c8", +"TR_bitcoin-test_signtx_taproot.py::test_send_mixed": "4e3252957ddf7b8bf48960e81445ee571e7f91fcfadf8d7c437cacb1c3fe6f75", +"TR_bitcoin-test_signtx_taproot.py::test_send_p2tr[False]": "061222a8924e33f8b4fab42d59a7b1d7cabf3539168a881e66d81466b88942ed", +"TR_bitcoin-test_signtx_taproot.py::test_send_p2tr[True]": "5cdb1587c8d4d1bb89cf5a134e49bd046d9b6768208ce31b2c36ef1a477f53bd", +"TR_bitcoin-test_signtx_taproot.py::test_send_two_with_change": "826e23d425a1da9e43aa65965c86d8aa671df79a0368f05a628ac0b9fb8a9823", +"TR_bitcoin-test_verifymessage.py::test_message_grs": "a8e95f8ee4d4f88054e2b642020dc236331247f7d4e03fa80f10244749787ad0", +"TR_bitcoin-test_verifymessage.py::test_message_long": "e0e01af7edc1711b7d53303d00c8766dca658cf0540c146eaeb58c698b4546ee", +"TR_bitcoin-test_verifymessage.py::test_message_testnet": "6574d12a7bc4757a7ee2aec649e68b20ab41abe988a6a10041f33bf93ae5aa83", +"TR_bitcoin-test_verifymessage.py::test_message_verify": "480bc6ff2b324fe22a044a7b88f4707565c3dc7657de1947acfb119decd93e0e", +"TR_bitcoin-test_verifymessage.py::test_message_verify_bcash": "379ae5a47a6dec2ebc8a98f67801a5d33acbb500eb182cf7fb9c6b4aab4f47fb", +"TR_bitcoin-test_verifymessage.py::test_verify_bitcoind": "85fa497e2ea676db8d189cb2f4b8fb0b265797fa9a0bbec1920a8aec215ae519", +"TR_bitcoin-test_verifymessage.py::test_verify_utf": "d3536bddea2bd29e4ca5d18006cd1ecef67f42c9038fe74b6f4aadac104f7ca1", +"TR_bitcoin-test_verifymessage_segwit.py::test_message_long": "0ed3e4a367f3b6e7f4c53678fd051ae6a36e25dcdfe8b3ccdd2005a7fc316efb", +"TR_bitcoin-test_verifymessage_segwit.py::test_message_testnet": "9089f42bc76c6e6e332b802e8709dacae8f16bfe2fec1516051ef007c7ae2bf1", +"TR_bitcoin-test_verifymessage_segwit.py::test_message_verify": "2f8c908cc151547d73f28e62cc851450e12c49f054984d40d062acf8780fe0cb", +"TR_bitcoin-test_verifymessage_segwit.py::test_verify_utf": "d863102298b74f0f543bf3f2899bab10be88e4f7b158f5b63a1e00a95e129fad", +"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_long": "a7a8a20e230571ac0bee16640ea9d32db51a5152223d8f4095eb249b705e4040", +"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_testnet": "69ba9e7141b7563050e5c6d53ae09ea707236780238fb1c920e58ca01d232c95", +"TR_bitcoin-test_verifymessage_segwit_native.py::test_message_verify": "0296bd1e41484ffea53ed8d4394dc20d6cfb0e49d489c5e324c48535cf0693eb", +"TR_bitcoin-test_verifymessage_segwit_native.py::test_verify_utf": "65da5042d596ac266340e47328a4ef609f70a201617dbfa92d28828894a4fa84", +"TR_bitcoin-test_zcash.py::test_external_presigned": "5d75328a0595298af947a4c4b85dcb21a6006098858da9b0ae797601bec6689b", +"TR_bitcoin-test_zcash.py::test_one_one_fee_sapling": "f7a155fab0eb72c5c7bd1ea98baafd6337cec42654de3ea50d0b7c9daf6883f4", +"TR_bitcoin-test_zcash.py::test_spend_old_versions": "1047d455f6904e2d0f76c14183067e468db1ed0ec972e1b131cd06b4ba8a5434", "TR_bitcoin-test_zcash.py::test_v3_not_supported": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_bitcoin-test_zcash.py::test_version_group_id_missing": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[icarus-derivation]": "565d3d0566208e47d8f0d39e57611222b7508b2268a2fb0a41334067bab7feab", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[icarus-trezor-derivation]": "7f4f008c6414149d0aa1c555998bd6df1c90a2661e0e877127c008b5fbb5971c", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[ledger-derivation]": "ea2f43f899d5ea8bb77d5458ddde3ab21f57d8c231cb890b617d7646a7b0a63e", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters0-result0]": "c92c4e5022e6e539d44dc6f8777c88893155e082a1b8c4c4633189c7f42a018f", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters1-result1]": "5e19e05f29242a1838a3d6e28fc26e836ac573bbff68c604f7e5aba73748c34b", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters10-result10]": "407f6bafda7c7a2a65db18fca15459fb875f9f49d06aba38d19b4ca6e46c8316", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters11-result11]": "bb46e4a22e879edff00db5e3b699eea528a9149edf9ba66f4ae219a6050601f1", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters12-result12]": "52b783278486733857252da7b81b8e88e7ca764514e5105b05114cc9120d31e7", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters13-result13]": "032f4f16cb933140cf1f8d4722cc3e0f3a946a7a73fd970397a3b52f01f6acdf", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters14-result14]": "1042c52fd966f19f74e4a50f71442594f37e6cbe6320df85e1ed1b8e8a9ad058", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters15-result15]": "4c144b5df1622f34f52ed88f479e0161d11d68328cea5a2322c634658c2e707c", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters16-result16]": "90ad572ca228eefe89810e0688b3f5b42f721b98451df9bf43d7f167d59aa06b", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters17-result17]": "12538c1ed323eb497cd46472d7d6de57f1ab8d99d6b8d970379ba2920c0068e9", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters18-result18]": "37635d856b106c82f816646d8adf36429efc60d0813b5d5b03f64407a5c17366", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters19-result19]": "fc981b851b67b6b72a306b9cbc061606d1078c074fd3587c3f6bf7b8cfa17095", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters2-result2]": "6f8e6f7ed488bb29b014e5ed66d717c77479dedb10b5b2b824a0d63d61f557d3", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters20-result20]": "3607b70b41d3e551cb9e67f6b078bd0bbd28002b04b517cf8a763c75d4440979", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters21-result21]": "fae7cd92aa0d66585bd43378790f005d66bcbd8b4a4d1e032bb447d87f636c34", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters22-result22]": "d8c1303d1f13b09eb97f1c9c8e8159d2f2f5feb87ad5d35bc5047c853d918875", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters23-result23]": "ba314bb63407a96f1cd42c13d2e0962f2208dd00857084166db505e10b3b9ff6", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters24-result24]": "61f3e3c2d4f9d3f1620142cdd99a60a9053b5858da9d4d10a56178dea23ab7ba", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters25-result25]": "65208a4414fd42518df29034dbfc99545d952d1e92bb9ff0a38954379b825a63", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters26-result26]": "fa830bf79ed9cf720598eb54004521ccee7ba59534a23347ed1d30b806ffaa36", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters27-result27]": "a53b06d56bff77fabaac635e68839193b2efb259af2519f81a7aa5c553baac7a", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters28-result28]": "49c9fcd4dbe8d96469db6223a788aec7b84cbad322c26aab27c54a038fa6312e", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters29-result29]": "ef5895d40f2f6e846ecd58840f3d1c0929697466798a6022813e94cf916ecf4f", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters3-result3]": "1c1d4fde0afb878e7e78e53878514f9b732f0a8b296396db4866bef232e435b3", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters30-result30]": "6dc10a014f76323401eff4207eff21254826fdd8d7a4e4a8aaa53c3a3b5f28a0", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters31-result31]": "8b9ac087cc4de1de462cad059a3ec99b418c036731b3fc43804e3dd5f6cfb64a", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters32-result32]": "0a31a619cfe91cab25e6e0f40af626db266a5dfd352922ac34b6c37ac78ea00c", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters33-result33]": "f6d39d299a62a76a16084ac9ebdc66eec29e6e610b00e1b628f5ff85d8067ca7", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters34-result34]": "1765c9f08c84085f2c65a9cdf3e57f4f38c24f192f79c0210d1ca662b0e2a7a9", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters35-result35]": "b710b487f17ce9a5b5622e2d31960370c5de925e2b60b09913debaedec0e3a42", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters36-result36]": "96f958cbe288cec88eda090e4700d99090a930ed7be17f16a24237948fcc2d8f", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters4-result4]": "cae35acbf13166daf1d041bd1819aceddcb45247c08dd4c21e28236a8fa48057", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters5-result5]": "57483a19de5f31a5450f91dd47e3504dba01d99b4b7a5955a9e675c1beb045f2", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters6-result6]": "6b08e60cfabedbd69cddace06f321f2650b84d90d2a66d9b3111f1f32b6e4f06", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters7-result7]": "edfc8f2601a60f55a68b0aa29f2a63362a3ce3afb3e25bd72b084695e2bd100a", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters8-result8]": "274d473f898309348ff28fd98706c848e5b83271fa77921a8f608ef507510f66", -"TR_cardano-test_address_public_key.py::test_cardano_get_address[parameters9-result9]": "914be178e6257d371cfda53099521efddcc9de87556b7939a608a1e197cd4956", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-derivation]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-trezor-derivation]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[ledger-derivation]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters0-result0]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters1-result1]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters10-result10]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters11-result11]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters12-result12]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters13-result13]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters14-result14]": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters15-result15]": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters16-result16]": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters2-result2]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters3-result3]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters4-result4]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters5-result5]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters6-result6]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters7-result7]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters8-result8]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", -"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters9-result9]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-icarus-derivation]": "4d6c01d19acadabd86d07c3158a6ceee51bc7daf8940ce4fba361a2f42977234", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-icarus-trezor-derivation]": "2d97e41904f885cb2d1c51e8f13a5a2bb89eba71c2c6d1867c11b548d37393b0", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-ledger-derivation]": "a978e28258782425b4de0c007d1907bd5d7a660a856682927840bd8fc85ca0e6", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters0-result0]": "a8f1ce5284625a20956b2690c71abd3b83cb839ab122d6de3bbdc2a8d4a98ceb", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters1-result1]": "b6b7d31583759abdf3e0e06fed1340438614881e25bc6298e932aa9aec405613", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters10-result10]": "4842ae40f6ff96c9dcc76967776778d5af7ebd79b1a4e94834a76f85fbf2d4b3", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters11-result11]": "396899e0bb3efff3756d21c0482e52af812d106ba35302c7d8d320fd96df1736", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters12-result12]": "bb53972665042394bae75e14bf2438a63be25fa4f064a73230743ac08e5a21cd", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters13-result13]": "de400c7a186e4c8618684423d0067b50729310932185f5df22e8780a68177eac", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters14-result14]": "cf26e5e5e610f0acd6fe5137a45da37e04a554fc67a27eba3676b1ef42949098", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters15-result15]": "0f14b7038e11dbdd39bff55bd7adc7959933618dea0fd608fe59a82e429bf953", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters16-result16]": "614c66481b6854231fe21cd4d63148bb61aabe547d4ceb567ced64b7e3e5897e", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters17-result17]": "70c2bd900c965fe1bb4cb677fb656d4e2ec91f88cfcd7645e726a3ccd99917db", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters18-result18]": "fc5169f85c768343ea058aa09677ea0b8d55538daa81d8c03505402de3c71f96", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters19-result19]": "fe165a7a53bd425865cf4672aa6ef62637ffa648b32f23d33475807b89e24303", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters2-result2]": "b527d18b1c2262f9e49954a8fbf89811c1d5dfd0a850fdd84d619c78bb399d8c", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters20-result20]": "514c5a4e891ae4b33f06ac642a4de5fcf4bfcda4556bd7bdd2bc857638312919", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters21-result21]": "37cc4016cf2d0f54e4554716943aec9e80b327a311d1cfda71f1c3f9d1527ef3", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters22-result22]": "a7416197716d3ee958ca2916abeefec76c543af38ea61175e91f03376d280337", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters23-result23]": "09bbe95733953c2d4b0d41ea2fa1ed8d8a3fb63858bee831d5ab633b675b68bf", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters24-result24]": "bdc6158d4acbd7b93d60bb2b439deb4f616def2e68ab4725af6237d066812fc7", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters25-result25]": "b634ce1953ac6f104c8388d1d824c68bb5ea657a5c76d85daf4edc1a0c90729c", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters26-result26]": "6cc90e1105b1595ee7e861737b6b6352bf23a5331e8b9ea0609a9ba0c00d6d57", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters27-result27]": "5715492f5cb1c1f1994e535b6240ec3030bc649c059b8eed57f18527444eae5d", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters28-result28]": "a86ba988b076e6c81b29479bd4ae7dfa310e6882dfa626dcb00f79c898508813", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters29-result29]": "c6828ba072df1266fb4a196e8ceeaa7981c1c983cd31abb6aeea3593274c705b", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters3-result3]": "95e5a28b051b8c1623f8eef689146698962daa680979111e885f1131d4bb38cc", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters30-result30]": "afd32dd28341e846e1cada0814a953f0511fb1fa9796812e9d16cbca3a5c1d62", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters31-result31]": "a54cedeb39700776d47c0a853bc1885bf8a978664de4495adcc92319cded8cfc", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters32-result32]": "4f9d886530afa0441bfc2f7d0923752f08f901e19c196d24c3995b9f4ed24e9b", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters33-result33]": "21cd6533f8ff9360e931ec1cc9d9796cd55d0c5375afa96d59d52753fda4a7ce", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters34-result34]": "94ca7562bb4796ec44f5f41d386fb347dcd01561b875b3aeaaf77977193d56ad", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters35-result35]": "9839253838109be867e1afc3f5ddd5678e0536b947debb83c34e002db75b583d", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters36-result36]": "61d6b690c6153916749b42af874792c82e12c5541be3b887b3fb09cf7d13d972", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters4-result4]": "f418b5e3ac7b9e9aead05064a95b09d47e8663be0b0feb6cae192ef0af729833", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters5-result5]": "b568086a626f98d501e7363f105c8dcb3ef974591d2adbcbf82b558c97090733", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters6-result6]": "ac5c8ab282c3834df02c05dc5cfeb388ddabb607dbac8c943bf44525cb0a305a", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters7-result7]": "791c2cc61159cab8632d6000d7d729b4b02a435a3805c535b5d96eed550b2abe", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters8-result8]": "a85ad9dfc829fd4fbed390cf223032809bdc420b1be895490e33248b57ac6e8e", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters9-result9]": "e72ae62f8bd36eca534a1a95a957cd1fce43ed7552617ee115857fc9a1641b28", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-icarus-derivation]": "975672fb207277a8398a67a7b3f1343c8b3d110a7ea81ed074cef774438ca08d", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-icarus-trezor-derivation]": "c2087554c3797ae5267bb3507eb704c958cd54fa05988909154cc2cee518cd7b", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-ledger-derivation]": "41d2317fe697c28175e9a35bab4d144cf5d11376646c732fc0acd2cb06bf5a5f", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters0-result0]": "66ccb52fac968b849dc297df9d022cf0aa2e7aaa3d6dc46f1ea3b4d987dda9a4", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters1-result1]": "027e36a67434daa64d01ea7f82c7d3713a7e954e543657cf56ea24acb9ccbf98", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters10-result10]": "0170e39b0c764de4179a5c60ac67461d2c43aad5afaa80e787039290500db4d0", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters11-result11]": "9e688c104879b1b617852f16f79f3a18d64297cef583999e1307306697bc3d25", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters12-result12]": "7dd337b67563cfe654d8fe9271178649cf81aa4f868a39636cd0e16fd1d82f2a", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters13-result13]": "b65ef003b9811ab8752a72604f406e5bd64564852d36b92623403fcec0419e86", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters14-result14]": "9c85ac810276bc555a92f49357a3e1e05a2862631a4e552815f31b42b577e8ae", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters15-result15]": "f0463d415fc3cae7a89a056cbb4892ca90a4c40fb7b891720e1e65010b3c4d57", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters16-result16]": "0ec3b06be632e58d15f5254aaba2f6f0528ccbf9d6040b932ff3d8b41b2488ea", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters17-result17]": "01922c0018f810adbc0af1a94023651b4a240dfd9efc15feef686d49e5db8846", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters18-result18]": "bae7b1c7050c4ca6990c2eb5cf1b511fa8f46485f84b8e736134dc9f556e8241", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters19-result19]": "f3793bd2041d90d3cb1e078d3e291cdcac06c25004dac0177503f684dde356d4", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters2-result2]": "e9ede185f61a561459a9cf2c4c4b6c92f128aec222a27eeba8c4a0fbaf694e65", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters20-result20]": "5be4852c1b4f40bb852b8af46f0fdb99750f89688c98e6638ad57fd07a420e3d", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters21-result21]": "2aa5d81e6e454a902322e826dc31e643671eaecc0bb6acab9bd5b17ad20b6b7c", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters22-result22]": "9e7b535bda874cec080a1c455390c20156724b7e4424c9c7757d74fabbcc19a5", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters23-result23]": "aba5b7e610a17e8d6faa816c666ad8280185e85c5ecd11a0a6615208045349d3", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters24-result24]": "8aa65efb7e87ead8bb67ccbb6293ed5753e796a9fdaa4bc0b5a5b16329c0091e", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters25-result25]": "4de8f6f1c66a82bba2cf52fb80a3ebd3cbe5ec74bcbbf2c98237c1e2dcfeb1e2", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters26-result26]": "da98485f471d95231e8a0103ad12f31cfa5967cc99049fbbccf714dcdf66b6d0", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters27-result27]": "f1c8a4cc349b38b80da95316ff1b9f1ba5495dd562ff967b3d1cfefd3d74917b", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters28-result28]": "b5019cc37e5b35d9eb9eac4fbbe20f4c1cf473ae6529b900d995c10bc70f49e3", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters29-result29]": "9d1a4e79b6de30b984927e49e22c8ebfb4902e2cd74f3da9cee7e9f27a5383c5", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters3-result3]": "9e970d8137c3e0aa58bc135480e207c347649dd1fa559f757a4311dbb0c0d560", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters30-result30]": "383e52aca8616272e9d29ecd036d3d3fee5509810f7275c4f2905cb804ff51de", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters31-result31]": "7a761bb94eb5788e679bdc6f73b7812eaf3d98daecf048378e7c8aa1b649f9f9", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters32-result32]": "0e1be6a09b3d6c5a842de9a9613eb766ad77f3cdf9efbdd3ffe6d6017e3df716", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters33-result33]": "bc6bfcac27cf52c9a4875748c05b67c4bdcf75cd956a75bbfb800698ef9a2ad9", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters34-result34]": "0c573d8b4b630e97470e1d37bacc31c4b787ead487ecf027c7137432eab66098", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters35-result35]": "c106736d3bd9101c484c0fae40b15bfc18c0f73c9bce57d97c152aa291bc2ef8", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters36-result36]": "71652a22cc088afc22da0daffff5e2ad66a4f2d4ef35458c815e3cda45db2279", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters4-result4]": "2507e5a9e1d9b55476de34878a3b829b005dc96f426fb7789758f169ca7355a7", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters5-result5]": "1f79a3d61acddfdede3e24a3c4275fd98e5e024e269479668583729cfeed6136", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters6-result6]": "bf53357e7ba1218f99c2e69cfe421cf2c5ab201b6131ca4d29475e048e3f9f1d", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters7-result7]": "f534645a2251f28b293abb3d3023c9b647fee7f17547513674485ea4403935da", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters8-result8]": "9be9c58a39057aba1ac5dcd05f4626806181139c50350b3362bb35edfe7668e7", +"TR_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters9-result9]": "a1b2f206a9bfeb24ebcc2393d436590c515433ed108e99dc2fdf896950397e8b", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-derivation]": "6bd1d1c65a15962a6a02a1e2473b6de540b61604e6dc84e62a5163ebad442310", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-trezor-derivation]": "805040dae65922a865fa7a5c7f5acbffb69551e9a2afcb3c18c1baf0b24d0d90", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[ledger-derivation]": "0a4d162846e17e2c2fb92dd3f0e90485d62aaad51caadcc214358eeefa6d0ba8", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters0-result0]": "ab9fbe63f062c99604c14aa9716ee3585a6336823885045570036f7a357c92a4", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters1-result1]": "a2a91c80669ecfbb1ea007ca216cd67f6bd089a41af50a99a9c01692bd87bd78", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters10-result10]": "b60c6d382adbcb7bfdc15d88d33ed4c2c52858e8ff51af8046fe1814175b34ab", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters11-result11]": "46366511cf25fc15fa46a372e86d43843b41d98d2e765723017bed55c06cec4c", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters12-result12]": "5cc4c144eaf04e5481d54e5ca25115e196b77792f55453ae7c326066aa394fab", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters13-result13]": "4808dcc60782e2506ca64a5aad321089afc433aff0f40f00dce55e46f69995d8", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters14-result14]": "963497fe5313db14f178e55160d0d6973794d9aba3700b0ded4876f3d7710de8", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters15-result15]": "0f9810950dff91d673d86fe2a54e1f3eb6b957f06db7fd414dbb5f286816a515", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters16-result16]": "fb8864acde11c98f050bcbe0ed27f995b14b541f3227c147a923ef29b89a01b8", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters2-result2]": "47df0fa6267d2b672b1db8415e8558c04bfaf76771785143d386502a61ef6471", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters3-result3]": "254d1f89a32fcc9ec5f91c59e0a26eda23904b9baf70cff5f17dd21154811223", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters4-result4]": "1ad423fa2d2346f35e89dbe30f0d29850d6f3d9f4db05b3514e2d19835e6062b", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters5-result5]": "72cc08ed29c55b7aececb23b289964db3a03da2f5cd67124c48ef09ff74ea80a", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters6-result6]": "c61800654e7807e02c6072d3c95f7734ad70321b19adc048bb83772e73d75a95", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters7-result7]": "c622bf466fcfe475ebd32fe866a2a5612163109ae92c18984aa5136323c48874", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters8-result8]": "866dcc3d6cae2a2521609c7ddc951abb0dccc815a817ace8198d25c21f21d582", +"TR_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters9-result9]": "87e6be3080ddb6d2d230cda6257ee3476a25cda9198c7240570dd4a2bbc2baf5", "TR_cardano-test_derivations.py::test_bad_session": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_cardano-test_derivations.py::test_derivation_irrelevant_on_slip39[CardanoDerivationType.ICA-3b0af713": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_cardano-test_derivations.py::test_derivation_irrelevant_on_slip39[CardanoDerivationType.ICARUS]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_cardano-test_derivations.py::test_derivation_irrelevant_on_slip39[CardanoDerivationType.LEDGER]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_cardano-test_derivations.py::test_ledger_available_always": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script]": "fa8c39a667f7b43dc4e59105b330e9382e9d626d524192ae547c2b0435297c18", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script_cont-aae1e6c3": "25a5d9ae82b43cf121ff18a39c5c855677653b3a007cec1c931a9c0ef005b322", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script_cont-e4ca0ea5": "2ad25426da1cbf204ed991a608870488d5ae0cd7fa5803bcb05e363f396fa93b", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[any_script]": "3026f665374114bb1c1fe52535e80648b839de582c65f9bd9938ba4751f3f760", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[any_script_with-f2466a2e": "c548160b07dacb93dbc81166f5e716be193d6fa838d02ef13457538f2b5f7d43", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[invalid_before_script]": "9e6343fe09b737cbe2216b1fe746ede8fc1963e0ed86ed6fab857ecd6a414716", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[invalid_hereaft-d01d7292": "c2f91b52bc5757e162f37cb6e8ce6d4d19ea5b1672e975e38836b66f8c92ff5b", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[n_of_k_script]": "764a6907de28750bfdcdabd4cc9e2f634e0463c3470a31f1df18aec6d698d15d", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[n_of_k_script_c-d93f5fb0": "70906d2d347f362136986353a6bd25bbc73b652bafa3cf93cdd086809abbfe3c", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[nested_script]": "bddf875eb5b44cd9dfae6fbeac8ed2fdb427f91e7604c2cd96334c5754b5ca77", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[nested_script_w-789238e6": "70809b2bd0ce5eb1f5c565b02abaa2f46d341631fc72763360c9cc6b5349cac2", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script]": "3be2e6ee5ba394701efc73b42532bb8f7118bfd7efd52c2ecf2bd79d3199e1ce", -"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script_-1579fe2a": "31bb79f00702ca071bfb3fcc9a3deba9d8e648a69028a7f80fbcd991e1d8eb8a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[byron_to_shelley_transfer]": "04c01e4d81a1024de783689fea1691b6835bfbc62d601e95c3ec022da2d5c1f7", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "7864e4b3a6bf40591c667fe8fc0dfa6be0d5c6528a18ff136bec0c50f6407023", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "7d932874f47a625032a3d98619611a1e3ad09b635b817fdca7fb59c5b640103b", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "7de2d22fa5d66a5d4b8c24064e4fd6285664c5ac58d9cffaf2cf0c46eb7c79bc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "ddc7998a73ab1efbd039eafd6628ad6fb3ec58936907833eebb15d2ad21ad821", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "00f8929f651441dd4ef415d25a76eb376e82e0869b598b3c24e275e4b8ec6c52", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "144ffbf88d7d9830b821fe468993c18b4a62458c045579c438d3cd9361b9e3e4", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_a_required_signer]": "2aa69663aa444b47a5b4a40815a55a48b814c9da5204b732d20cbc972eee99fa", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_most_elements_fille-29691455": "f208b1c2c481f84b106e58abda308dcb5cc1aa12d01f0633719a07c8d874cc93", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_output_datum_hash]": "60595e793304a94ac9e8ce8f8c185d2a6362a6485c7a1cef36f2098bb2591fc6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_script_data_hash]": "50c6e61741e1999474b84dde9665944b9e9ce15b7db56fb499ffc6571fdcc54e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_deregistratio-1ab28f77": "835b592c0ebb8eacb1252d8ae60577cf5b9e7bfe2322513bb631a06697596d42", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_deregistration]": "835b592c0ebb8eacb1252d8ae60577cf5b9e7bfe2322513bb631a06697596d42", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_registration_-a144c34c": "f5ed96577e9596ca1b07781db5d48610253943964d6b2ff84bc7b959c98422e0", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_registration_-bf5f9707": "48168e661e93598d47397b547c904b9d1dd44278a2c3d04f1a6e5011822bb5a6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_token_minting]": "983cd2a8edf7189299f4a615c96761e79931730b4b0340b6f962db14fa2d7605", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_a_required_signer]": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_both_output_formats]": "809ad0b83090dc58ba04698bb13df6e392459c25a3a86e7a3f61150bda871e22", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_inline_datum,_refer-d1082570": "f3523f3e5ffa8d2b3bef05cb5f97fdbd20783a4289e4620fe5dcb82bec3e995c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_long_inline_datum,_-1f681aaa": "a3a8d217c79101f3640de49929205aec7e3962c6bc2498ee66820efb1135ec81", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_multiple_correctly_-6545455a": "8c3c7123a002c1030b9b8b7d75e7ac78ae6116169fc2e3bfc1292db862fc3c1d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_network_id_included-d9df16f9": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_output_datum_hash]": "f3523f3e5ffa8d2b3bef05cb5f97fdbd20783a4289e4620fe5dcb82bec3e995c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_output_datum_hash_a-84ad587a": "a3a8d217c79101f3640de49929205aec7e3962c6bc2498ee66820efb1135ec81", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_script_address_but_-b0da7209": "a6ece20bd57d80328c3033151e6a8124e7672761c1a4146c4e1016753c3b69fd", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_script_data_hash]": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_token_minting]": "3e4698c42e9b5a18714a1123a823879ab139380480b36b108b9ee9a7db65d489", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_an_ordinary_input]": "9be34b5d93b0ec90b642e859240eae89f947805f754fb9d0aabbf3b68fc97a6f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_address_device-o-a33e6741": "7ca0e607d2ad855ac1c3fa3cf5f58473b821662ed988699ca5e519a390dca3c7", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_address_device-o-a6481374": "f2f5a19aa280af0b02e125c5d625224289ae569618006e52ee02a9b4a64447fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_key_script_addre-d3366a63": "2d504435271f6ddab83023450cbde1d8102147478d9bbcff99cfc65100511f1d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_device-owned_collater-8f38b4d7": "1d19bbf70c0132258effc33664ec014646c04e652a62f75cddbe1990c9fb17c6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_external_collateral_return]": "e273253040919707fa766e678c808f768df4d215b9bd04a3455b0ec8df6b7371", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_output_datum_hash]": "f5d9dbda4a5a1a1100117d02961c1eb8af9a52c30c96a93feb582d044b6d6bfa", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_reference_input]": "04808362e9f97aeb096db30d6982aec5fa5c90939a5eaa3a1071ec69efc3afa1", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_credentials_giv-6a67c1eb": "998144b08f9ba3d119c356fc80610ad9c2f3f1c8859717ae273778fbc4394654", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_credentials_giv-72ef969e": "42d7a8295ab3e358dca3b3176e0c9928bb673488c6ff76a0675056a7ef714c49", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_deregistration]": "7053cb54fff74ac9d2b14fa4d6a5a8950a1fb5a1357023fb944a640f84fb691f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_deregistration_-78f5c748": "a56c78e4e470ba6a1819b41299a67ca3739f10c05949927cb1b9b4b8f1a20787", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_registration_an-4da9385a": "cc4e48700b9aaa034330ebd89d338e5f0acf63e831dd32fbaed3bdd3c08add9e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_registration_ce-46b0a250": "bda570c72125def83b5ead0566ed3fb75ac0d0a18fd4a5e1cf7691c067e04995", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_token_minting]": "12b686284fe73f086fc0f4f78ca52ed9c5c536894b297c4991a86a32d9140c08", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral]": "a54fd6e44b5ee8531d9ed6045776d13804791fb35f95e5b304b14a361577ab0c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral_and_-3f0b305a": "5c4307d3561fd609f57b468175da003272967289e9a42a45a87e2a2a6af1ea7a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral_and_-c92d773b": "7308c6c2da6caa73f54c812d6f7136d3478ed05940d55d623f928443f273adf3", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_without_script_data_hash_a-9590827f": "8c9ca6ccf8a3e7c57443b10aedd49ef005b74271c8f995f07195bd69f50efa1c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "3202590a4ef04faabbd3d847ae7bb122cca99bf131851c8085ae9b942d9b32fb", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-336f4a44": "3202590a4ef04faabbd3d847ae7bb122cca99bf131851c8085ae9b942d9b32fb", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "e6c6d86d9098c4e8e3f26c2b35d9935f4f14f05fd02f5faa2488d69b0baaf47e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_with_zero_margin]": "132a7b28d261547180602d91768b41168d3be06324ba2b56766dbbdd05ceaf33", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction]": "9f3e8a0e7d7a3bfc0a2e3690fdbc092bd65f0437806b36de23460a49e4f3da5e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction_with_additional_wit-36ba8ce8": "9304d174cec5f5824ce6866de25d912ad94a019b5f1a43d34e0c0d01f7912a8f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction_with_required_signers]": "a97d91b29ea080db3ab5940435209a810357dd3cb3196381a76323b30c2677b4", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "daf3690a5726ac25f936bce4bf36e30ae2d2c311e7287e99b293eb7ad5e79a12", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-7f1d12f6": "54dee35622824569d82989422173719f368f5a2cefe992a227e057208da0fdc5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_a-56fc16f7": "188ea1fd244853eee219e8799322cdeba986d6e7a43b2b48ddbb73f577a51b9d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "9ba57b1148144e29cd7fead8a494be15b2b4cde6491977797ad8a534c7efd43f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "d4265a5e39b4126a50a0a4b735b2867e79977d083e86f62516680d6d941c3ef4", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "4687da6e2aee98aef7279c40ce6ff87ad2b5f3ebcc298bb17414c5f58c2cdf67", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "39c41f7a04e19de8b772c3f982f15846ff6a1622c573dbd23982894869a9f433", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "2c505386da674cf1122a70fb6702aacfebe5afd9651df00fd649d07dfdd6b9de", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "5476181f0eb990b2b25d636b81d83201e65b983455a1098b1c4e7d163b31d64c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_auxiliary_data_hash]": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "826101f1b94d2c23a7b23e692746c77e3830bb3ac30158d7387e4b49ab878d4d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_s-20438873": "6230e3c20f1cf0907e8555a0b1a92e78feef87b7731769fcedb23fd9e9096788", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip15_registration]": "135a055f94dc8ce136532c10b69e067c0f5b9a3cba5763d0488867546bbd4a7f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_exter-a66e1a50": "7ef6eb7bfc0cb97092d1c07d6d2cfdaedc266cfe4c72ac99e088cd1eb26e216f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_exter-b18e613a": "d6feb45e0fc1ff302fcc9ee61dc001686d10ee73f554e72316b5b431bb064bde", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_non-p-26df89e6": "5295f0091be02a049c057dc633e9b14eca4d18e6c676acf65c2c81016c690f7e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_other-6a6c5c8d": "08d6f9b1fea4545e6ad47bbf534462df177da296d095990187bcb22664911f74", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_votin-1b01d6f0": "cf7b98935bd43831e6067c226d801eebbcf1ef769c5fe63304563bd8a0f3ab8a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_everything_set_except_pool_r-1e1ef130": "6677e7511c4035ef9535d30a9edbf080a884365409208d9cc60cccb287796af9", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "4659d141a1797c8e77451f82571dbbd844a6a0501f34fe00a1699c43eb389e0e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "4659d141a1797c8e77451f82571dbbd844a6a0501f34fe00a1699c43eb389e0e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "8e815a2a7194345d33c9abc4ac36f159af77aeb1309ba450c52559af3ce9fed3", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "4fb406b68716fc0e56aeab929eb42a81f54e2b9462870269d2bf40f36696d642", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "20f1f556898d2070af551e7e608c89cfb2990d1b5b07c2f33268416e1af2a852", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "2e01ab9878c7da182d6a460effee4b7c3b3f90bfef5084fbe90e8a09d3e479dc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_ttl_equal_to_0]": "e2c3b5d55c043d111fa16ffebe40d4e50ef3a3d37ad5467c3139931844150563", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_validity_interval_start_equal_to_0]": "9c5a6d2b3fdb470fce76320cd083ac1abb6d245680f5cca5d630227553ec649e", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[1854_change_output_path_in_ordinary_tr-805f9bd0": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[1854_input_path_in_ordinary_transaction]": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[additional_witness_requests_in_ordinar-9c4f94c0": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[all_tx_inputs_must_be_external_(without_path)]": "e41338084cc7db2557b69672de967b8ca9db993baac52d0d669f1fe4d5dd8348", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[asset_names_in_mint_token_group_in_wrong_order]": "88f8b8f3cfcaae464a95b1381796ae418d0055667e552341975ce9039b0ac261", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[asset_names_in_multiasset_token_group_-7c1351bc": "c90121fd13e4be49976a276367c35ee261b437832c322f87f5c2be25030f5bf9", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[auxiliary_data_hash_has_incorrect_length]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[both_datum_hash_and_inline_datum_present]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[byron_to_shelley_transfer_input_accoun-863fee7d": "04c01e4d81a1024de783689fea1691b6835bfbc62d601e95c3ec022da2d5c1f7", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[byron_to_shelley_transfer_output_accou-5a99fb35": "144ffbf88d7d9830b821fe468993c18b4a62458c045579c438d3cd9361b9e3e4", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_both_path_and_key_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_both_path_and_script_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_invalid_pool_size]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_key_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_multisig_path]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_non_staking_path]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_script_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_and_stake_deregistration-e17db500": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_and_withdrawal_account_mismatch]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_path_larger_than_100]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_staking_path_larger_than_100]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_with_script_in_payment_part]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script]": "529892b762ef058bb576fa5e4529ce89fcd078d82a6b3e40ff22fb32f2092f83", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script_cont-aae1e6c3": "e98f054807d7bad9c57d988520476af7e224d228d0a96a51255bf067a7f73912", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[all_script_cont-e4ca0ea5": "94cef7e45085b87020b821d4a330ca2014130f4874bba187b77137cbc9fb6820", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[any_script]": "7a157d4dfb697488ad7d6a73996cb36d9e721f9843d3ebbf79864e74380653b7", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[any_script_with-f2466a2e": "a9b2665a459ede77ce87d0628583b9d566ceb42658acbd3a46df8c11e6676cb7", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[invalid_before_script]": "27187617905c5376f90df78f180f060657536de48ff3f031f4bf3d859aa30d96", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[invalid_hereaft-d01d7292": "e7f3f5a38d084b23cf772f9a7244013a6b5a913aa30b7af1c348aed51df050c6", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[n_of_k_script]": "741a47cb6360ccfe5374970e24d50b714d002399fbacac88851a7671ca8710ad", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[n_of_k_script_c-d93f5fb0": "460819c46725b3059038f5c506bb68297f85347e70647b9cdb5d57e624991be1", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[nested_script]": "a3ca071c9d90e646c35135b93d39aa4c4659c9b6e91f9a033be5607c6cc5241e", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[nested_script_w-789238e6": "4f261e201ff4aefd9e28337f47d680a7611d3fef0c6e3639b869e04a372440b0", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script]": "c54df45717dcc98f752a980a3102fb270eea9cfe343a5010ca16b62a1b76b33d", +"TR_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script_-1579fe2a": "4af997f89378130aa00581cffa0f7a120a0352d0d1ef52ab64ce12530445f1f3", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[byron_to_shelley_transfer]": "a872fc2f2ae174648f44c896296e49c7cbd9f4f1910c26712c30524d6c90bd8c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "2c7d957ca1f9f69a78a060ba9e2e6db373880f33a9f16af9b6c20135017d3112", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "596978008f17650767a3c8bd15e446038e6d05ee5308fd980f45d3a3a6261f8d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "da700e12799f1056c119558664d7684743058e57a59bb928ac4ab026246dd81d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "da700e12799f1056c119558664d7684743058e57a59bb928ac4ab026246dd81d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "f4a05debd8eaba318b9bbda5eeedb8446e99775515441122760683eb5fa6b6ff", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "4c9f4f2f2d347cb83d6c45c1bda512ca4b168b1f31fdaa33cbec463b7ff20366", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "ac8780bf2701bc6dbc7b9daf50ed836bde465f10d6bc308bb92f70b443cee705", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "318f089413ca76f85cf957dcb8803b121e6f3016146897edd6040a1043472c2a", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_a_required_signer]": "ddf03e7d2c57d4004d73be36d6ee8809368322f6ad0560f150516f6a084a7105", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_most_elements_fille-29691455": "4ed499abb4649bc4bcb31e25fb6d5c3c4e5f4d46418b447ca0cb2d2a6b0dcd76", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_output_datum_hash]": "5bb0ce68544fcbdb9a94f4e34c9a6701a2e777e4f5eae8e1d6f5c549c04496c9", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_script_data_hash]": "c202af0e1b9b7b9d3ed471de5831d4c6c0649133cdfc679f5c9e03ff2fbfc57f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_deregistratio-1ab28f77": "5e1d28e039416aaba014e87742258f9a7bc5881da3905f53ae90164bd56670d2", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_deregistration]": "5e1d28e039416aaba014e87742258f9a7bc5881da3905f53ae90164bd56670d2", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_registration_-a144c34c": "e47f3389c4b79657e1167ced9943b9e9baed0858aa0f663e5582df9869d2c332", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_stake_registration_-bf5f9707": "ba9102a7c33e16c4dc08a4917d63d98d6947dc9d1982f2284406fdfbbffc38a7", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[multisig_transaction_with_token_minting]": "96cdbc42ee022598edc0fa9ad1ca023e176f9d5d72697308441a8c59e167ed60", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_a_required_signer]": "997f93067ffa1ba506243fcdef4fdd71e9cd6a60b8a4df1ad85a5a6fec34c92c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_both_output_formats]": "7b4f2e1391bd426c7e809a02f0396dd3d4df8e27d869dc06e1dce66da6b0da1a", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_inline_datum,_refer-d1082570": "85eb03bdd7afd218abf9211cb1f7401353c628adba5200df7620b5791d11fe6f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_long_inline_datum,_-1f681aaa": "44dc4fa7d0c09b7dfc16cee4eb62c45bf048dc37ed255764418451759c96d3c5", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_multiple_correctly_-6545455a": "77a47bf36e27176ea4682daf00a672b01bc1d01fb9fa940157e5f9a6694b6742", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_network_id_included-d9df16f9": "da700e12799f1056c119558664d7684743058e57a59bb928ac4ab026246dd81d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_output_datum_hash]": "85eb03bdd7afd218abf9211cb1f7401353c628adba5200df7620b5791d11fe6f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_output_datum_hash_a-84ad587a": "44dc4fa7d0c09b7dfc16cee4eb62c45bf048dc37ed255764418451759c96d3c5", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_script_address_but_-b0da7209": "57b0c7e71959a9c0ee37b44a2b9530f116b99dfb9e60d7dc32e23b6fa5de4e81", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_script_data_hash]": "997f93067ffa1ba506243fcdef4fdd71e9cd6a60b8a4df1ad85a5a6fec34c92c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[ordinary_transaction_with_token_minting]": "1f82a7a3aa557f84674b0a34824d1257be192d46ea39202fc1652c4009a4725d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_an_ordinary_input]": "4986ab94cd356675048ad51546bd7ba6136d18262e46c3f2cb0cd0ea36ff24f5", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_address_device-o-a33e6741": "2950d53dbbd0571f90d6c2aa9b0f3e8df02f3ee97b603cb13c719ed66a01becb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_address_device-o-a6481374": "541b3b9f9ba841ce3d46fb7082d175716f98e706e4bd4027c6800dfd286e9286", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_base_key_script_addre-d3366a63": "35ff6aa82f1d66f74b5f5f24568516a7ab1b4b46b191fa1a2eaf9818dd4890e9", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_device-owned_collater-8f38b4d7": "33b26b855892695446f4ff29086b987964c610b5b170aae63c95011fd42b7f2c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_external_collateral_return]": "26484bfa9d9bc318ed84ac4a7903b86380d6b623c1b70016eafec5efbcb26505", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_output_datum_hash]": "bdaa839c18dddb31db2c435836ee3d3040b68812255ca8ab16f7fb807415ecf2", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_reference_input]": "31c9a750d4624d5b7f8b36d3139722336e55d7329e7c265c5b22083bb3226404", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_credentials_giv-6a67c1eb": "74aad86c4a2f49b6a8de6ce6a7a940765d40874f98988a0c5e29ae2c8900ff8c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_credentials_giv-72ef969e": "42b1e54fbdd5d2e6f7dd6f2fdcfe78f19f9cf6844ce038fa0159f880308aac5c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_deregistration]": "75d2ead13c0b1c254fdb3823bd51e10f82a8e8e6a2b087bc3df7ec54e3448594", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_deregistration_-78f5c748": "54fabdad3191ce10ab767b1841890639275705db183a6a077df99305c1db0571", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_registration_an-4da9385a": "39b8dffd0cb766b69948215c886a5c104c931995984f9774cf27b5629e38bf78", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_stake_registration_ce-46b0a250": "7880f1245ce76dbdc3cb20cca39ea227ebb748f8602f7f76f5285d65cc954bfa", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_token_minting]": "002cf96cfceb334a2860f4bdd75f92a014c7efa18f63ae02f172ff87a45515cb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral]": "57caa9ca520eb3de18ef8087f17f7851312fb72da03d189807f64383f9539974", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral_and_-3f0b305a": "aeec87008ef2949511d59857559b6746bebcafb6341486abc87e1464e23f95af", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_with_total_collateral_and_-c92d773b": "adf907790738fda81c84e519f08ed291b4c813cfe4a82dc28f96a0e959d9814f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_without_script_data_hash_a-9590827f": "1311f154fa784593a96df78f66cb497e02907e9096b3497405c4ee0cd06237bf", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "b1b91573fe7d4905690b5b822279bbeb2f1a6428e43ad95a59b8e55a0298f268", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-336f4a44": "b1b91573fe7d4905690b5b822279bbeb2f1a6428e43ad95a59b8e55a0298f268", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "6be021844c1758fd8f0430e08493d0b710dfe7bccd1c3277b58e50d9c1578aab", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_with_zero_margin]": "bf61eaf11202110d830b981e7975e428457a42b7b0a0ab194f40ac3bbd100a97", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction]": "888d5e73c6171f29b41794857e0f5749fe6649803317a075bea926f7ad399ca3", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction_with_additional_wit-36ba8ce8": "53d1ce2905a8e290e638cdc4d2e5444b03f3045d5719d96b6f5562f822239474", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction_with_required_signers]": "2b2a21f15294d5e83d8eec1d21f54cefcf9a05659aaec7cd6ece55da9592810c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-0c37e6dc": "683b585b59cb2ddb4be31d40444df0e17e7266acfce9f89ecd4705d352b957ce", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_o-7f1d12f6": "49fc000de47744bc7136fab52fcf6ae7edabd1d6794b3314207c21abc27556af", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_address_change_output]": "997f93067ffa1ba506243fcdef4fdd71e9cd6a60b8a4df1ad85a5a6fec34c92c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_base_script_address_a-56fc16f7": "ec509d7353a73a1c0b69fa3ee8581f780e15b7f942e81e6b0e03c6c036aafc46", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_enterprise_address_ch-15518a4c": "4e3dd27934b133816a7a14813503e8b3ea2a791c778cf114d9471299597fb03e", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_transaction_with_pointer_address_change_output]": "ebdef5af5ff66e18425c5960c8fb39913a43c1d03cfa1cbd89589ad2e7a18bd1", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_certificate_with_no_p-0bbad967": "9da2a3ca9041dd0c011bd4124e888b2f8284ae3e24bb550172f8f401fc90a50a", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[stake_pool_registration_on_testnet]": "9ea8d20d82a4093086a70e1b078ebc9ce23c443996a0a751566d43d314f6c2d2", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "a29896befec8fcf178e77ee9467fb2cd608e8e6acd5029b69613bce14929e8bb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "f2844363872ff1e49670be39879453029700b6116f6939d8d505fbb745c71cb4", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_auxiliary_data_hash]": "997f93067ffa1ba506243fcdef4fdd71e9cd6a60b8a4df1ad85a5a6fec34c92c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "d3324bf4af7eeba2c46605636fd4c62ae8992c0ba96aa413cb0b688a602a90dd", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_s-20438873": "84c7626d6c0a3e7c12e33fe21cc62dc71090d32034f7db62027dea12df78e8db", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip15_registration]": "23947474ab5473c31857e48e0775225deac41b26ff397163b9824dc972382e3d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_exter-a66e1a50": "68288d5265211f02f3a0f61ba276026739976a1565c66e746c0882bc5bae8784", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_exter-b18e613a": "82a426ff7807fdfee42722ba2cfdddd6c5c0c45b185299302a5d874be530d83c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_non-p-26df89e6": "da8126d9a69cd94d16a220a69425bab73b2ebb88b30b2f2242366e40e9997d01", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_other-6a6c5c8d": "98fa47f213ebf7e79aff5528a6e7f802a5ba4b00d005dec1f53a01a9e7362dcc", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_votin-1b01d6f0": "b9b8bae8828fec0046d89e7884c1900d33b0e7dd6eb3e9b5a39e5560897a9010", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_everything_set_except_pool_r-1e1ef130": "f3d74ab859150d0af4d20dcde1b5da5e8df225c335e84c28ea0ebb6e145a0d1b", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "6bb411f7a1376587c6f722c23da8d308f4c53d27e5a5d1491c806326d9a3687c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "6bb411f7a1376587c6f722c23da8d308f4c53d27e5a5d1491c806326d9a3687c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "79b30d7e152f368da75bc1992760210ac6578b0f95da19c714a84cefdfa74547", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "30660a21db900d0b6c0705121796e21ba05ecd7057965c3b593545eeab4bb948", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "65926ed59dcd49226936ecb77c8acb3111f841370effa457965e123985f40406", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "c73948f9bcffc6970b262c481f10c2c726236d3cecf729350d4a16684920a116", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_ttl_equal_to_0]": "21cd407e5f4cc3231ebb43ee8c03840b53eaba1ad1efbeeb1c2909b54a9c656e", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_validity_interval_start_equal_to_0]": "5b8edc6c910515a0a0ca0066d034ba3e5f8490c81da6af1945234b05c5bb604f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[1854_change_output_path_in_ordinary_tr-805f9bd0": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[1854_input_path_in_ordinary_transaction]": "da700e12799f1056c119558664d7684743058e57a59bb928ac4ab026246dd81d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[additional_witness_requests_in_ordinar-9c4f94c0": "da700e12799f1056c119558664d7684743058e57a59bb928ac4ab026246dd81d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[all_tx_inputs_must_be_external_(without_path)]": "33cd64c399c865d0a55d634b9b8de94044f6dd4fab3563392c77a3af4a679039", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[asset_names_in_mint_token_group_in_wrong_order]": "b17fb662f751a93da7a026e44e2331e617d4d2b2079e4c8519c9e691509fa327", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[asset_names_in_multiasset_token_group_-7c1351bc": "5936154462b3d0e2686b68ec4d5bbe4e623c0127355d31fbbc2349cb22d30494", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[auxiliary_data_hash_has_incorrect_length]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[both_datum_hash_and_inline_datum_present]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[byron_to_shelley_transfer_input_accoun-863fee7d": "a872fc2f2ae174648f44c896296e49c7cbd9f4f1910c26712c30524d6c90bd8c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[byron_to_shelley_transfer_output_accou-5a99fb35": "318f089413ca76f85cf957dcb8803b121e6f3016146897edd6040a1043472c2a", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_both_path_and_key_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_both_path_and_script_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_invalid_pool_size]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_key_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_multisig_path]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_non_staking_path]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[certificate_has_script_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_and_stake_deregistration-e17db500": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_and_withdrawal_account_mismatch]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_path_larger_than_100]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_staking_path_larger_than_100]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[change_output_with_script_in_payment_part]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_input_is_present]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_input_prev_hash_has_incorre-99d2dc0e": "6871d846164cbbb45ba6dca0771f6f8bc0df0bc39220cbc2f17d96cf564b8205", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_input_prev_hash_has_incorre-99d2dc0e": "ba8e61c1139d60bf53e71edf5f897b83b2c3cfb010dfec5956ae231cb09376f2", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_return_is_present]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_return_with_datum_hash]": "ce219373af13ed907c9089298a0551b68f71b63dc8b4fe9c828cd1aefde0dbb6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_return_with_script_address]": "ce219373af13ed907c9089298a0551b68f71b63dc8b4fe9c828cd1aefde0dbb6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_a_different_certificate]": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_return_with_datum_hash]": "7a77aafadd25d3e74f2a976bf5520cd38879aeba06347346ec17e7d9e15f03ca", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[collateral_return_with_script_address]": "7a77aafadd25d3e74f2a976bf5520cd38879aeba06347346ec17e7d9e15f03ca", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_a_different_certificate]": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_multiple_pool_registration_ce-3000d4f0": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[contains_withdrawal]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[fee_is_too_high]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[inline_datum_present_in_output_with_le-43c025ef": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_change_output_account_mismatch]": "176b5e269bb99fbc6e2c323b7c0ca1c41b628167e38f2056f70171a5151dc545", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_stake_deregistration_certifi-b3383de2": "d26d69d9d3d5efff0cdc49d86c1fb43b2c5fd5a9c37a411de24d9b7fe8b20025", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_withdrawal_account_mismatch]": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_prev_hash_has_incorrect_length]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[invalid_pool_id]": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[inline_datum_present_in_output_with_le-43c025ef": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_change_output_account_mismatch]": "3008eb48fc1ac3e7c6d5d0bc2f4f3a76b0d98d4471a5cb70af202708d282e20c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_stake_deregistration_certifi-b3383de2": "c7a77b1fdf1ba592616dabf61c0f4f6561fff69e4cc517419ce6ed254c566590", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_and_withdrawal_account_mismatch]": "997f93067ffa1ba506243fcdef4fdd71e9cd6a60b8a4df1ad85a5a6fec34c92c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[input_prev_hash_has_incorrect_length]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[invalid_pool_id]": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[mainnet_protocol_magic_with_testnet_network_id]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[mainnet_transaction_with_testnet_output]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[margin_higher_than_1]": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[missing_owner_with_path]": "e9bc70e6c083d1448da48ff051167ec8d4d5f4606d5462bc64c447e14c9fcefb", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_1852_multisi-b7679330": "6eca70efa6b38b53bca5137788af6f0dd2b1b90a963ff9a82497ee8adb902716", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[mainnet_transaction_with_testnet_output]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[margin_higher_than_1]": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[missing_owner_with_path]": "323c883bf880a13863ca325b46596fb2e323c43bb25e6e23e0ce4b12763dd9c6", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_1852_multisi-b7679330": "f03ceb71a9d6161b24dc1a65823a4b702af5e49310712200451019c03f644f36", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_a_collateral_input]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_collateral_return]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_long_token_m-9fb3cfe5": "e81bd02895119bb0f91af9a352749f9fda6de56b9664df7fe45dcd69be4215ba", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_output_conta-e3b36436": "6e08728047c9be68a8eb177a881c237d361ed3b630b5d23e94db564bc2b5bd22", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_long_token_m-9fb3cfe5": "1e1364a7af94610197e1a847cc49a37f2d461d0cfbf20eac3c78f4ca1a5602a0", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_output_conta-e3b36436": "3df066c28afc13f43328bae6d51e52747041e676f32f424044c525a179a7dffd", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_reference_input]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_repeated_withdrawal]": "ee9299ff1916611c563cc5c8f51024b7831db7f52d3d8b6dfbba21b0ad78afc6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_delega-19d1722c": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_delega-394991f1": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_deregi-351ce869": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_deregi-43da91d4": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_regist-456f1292": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_regist-84b1254e": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_repeated_withdrawal]": "54be745c62be41d01a6b8bd3aa4b51ba3c11289fc1d78dfe575548e7b6dfde32", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_delega-19d1722c": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_delega-394991f1": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_deregi-351ce869": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_deregi-43da91d4": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_regist-456f1292": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_stake_regist-84b1254e": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_total_collateral]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_withdrawal_c-9f7e1700": "ee9299ff1916611c563cc5c8f51024b7831db7f52d3d8b6dfbba21b0ad78afc6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_withdrawal_c-e98b1f5c": "ee9299ff1916611c563cc5c8f51024b7831db7f52d3d8b6dfbba21b0ad78afc6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_wthdrawal_ad-3291ee9e": "ee9299ff1916611c563cc5c8f51024b7831db7f52d3d8b6dfbba21b0ad78afc6", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_without_minting_b-da5ba399": "6eca70efa6b38b53bca5137788af6f0dd2b1b90a963ff9a82497ee8adb902716", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_with_long_token_m-350c65f4": "d6e4e0d3031c0f02e0d5a9ac6776291936fe769a833000b16d5880285e37d199", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_with_token_mintin-bc56f145": "45c5b2b97a95b37bfbc41fbb420641def462213c828c02975d9bcc144df478b7", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_without_token_min-a128d577": "22ab4eaced6643d3f14b89d6f48757b685fcbf85dca12fa6603c92f1e3c5f72a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_has_invalid_crc]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_a_valid_cbor_but_inv-ea3da215": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_invalid_cbor]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_too_long]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_too_short]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_datum_hash_has_incorrect_length]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_has_both_address_and_address_pa-2efc280f": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_total_is_too_high]": "b7de05fa9f183576474cdd0cdba1aa3b7640d8d79534f2510ee9d78f0512f9cb", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_with_reward_address]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[plutus_transaction_with_output_contain-74465253": "a01c87d1ca18a6480376ce8ffa41793f6359dbcc13df5ae97c1ead5d70fbc883", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[policyids_in_mint_in_wrong_order]": "e3e5fc6778281be149220a8a4d5dd349842629c75e66c833f67527a638ee6d91", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[policyids_in_multiasset_output_in_wrong_order]": "7abab76e7eaeaf23bd4f4e1f0b8da984b8de7226942f199a6617bd340ba90325", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_belongs_to_differe-e79b6855": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_is_a_base_address]": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_withdrawal_c-9f7e1700": "54be745c62be41d01a6b8bd3aa4b51ba3c11289fc1d78dfe575548e7b6dfde32", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_withdrawal_c-e98b1f5c": "54be745c62be41d01a6b8bd3aa4b51ba3c11289fc1d78dfe575548e7b6dfde32", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_with_wthdrawal_ad-3291ee9e": "54be745c62be41d01a6b8bd3aa4b51ba3c11289fc1d78dfe575548e7b6dfde32", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[multisig_transaction_without_minting_b-da5ba399": "f03ceb71a9d6161b24dc1a65823a4b702af5e49310712200451019c03f644f36", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_with_long_token_m-350c65f4": "9f6afdbebb457ca289ef3b527015d25eed7c628cec663673bc0aea58f8b72e0a", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_with_token_mintin-bc56f145": "266c67ade4b1d2c5eac4caa2d51848da68142035c5eb87c63b4fa5aae6858c3c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[ordinary_transaction_without_token_min-a128d577": "7ed816a8de3bc23072128670884e1e4154b2ea0a01e3499f3537bd53077ca828", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_has_invalid_crc]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_a_valid_cbor_but_inv-ea3da215": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_invalid_cbor]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_too_long]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_address_is_too_short]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_datum_hash_has_incorrect_length]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_has_both_address_and_address_pa-2efc280f": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_total_is_too_high]": "e8b13fae78a10ad50008951f8fea7f4380042bc5654cefda28ee3191ab45a5c8", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[output_with_reward_address]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[plutus_transaction_with_output_contain-74465253": "3cb8c35708a39a835014707de5f7f2f196264f05b2d094d162607bddbe9d8c15", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[policyids_in_mint_in_wrong_order]": "f16690d8f6d1746a3a3ac8820b36756dfbc96b542fcaebd832d037443dfa0bef", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[policyids_in_multiasset_output_in_wrong_order]": "469ca7e96a511a079e406d85f0069181d3cf68c455a5d3baa61d00bae133c241", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_belongs_to_differe-e79b6855": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[pool_reward_address_is_a_base_address]": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[reference_input_is_present]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_mint_token_group]": "51fe0fa852783c7eecb274e0a3a8e3ce9789a2629eae6f6fd0996e8f1703dc16", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_multiasset_token_group]": "0b09c6b83dad8de63649b231e2d75ee4f6dedb30f54e115386ee90b12d3138ed", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_mint]": "718c391e447623f524d872958c7dc7f0799eb1dd6b9e2547ad065ce06971ba36", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_multiasset_output]": "42c31ac1342f23e4f6c9f16a807b18da08dabb814f50fee8f78d148357653811", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[required_signer_with_both_key_path_and-7d9a3c59": "ce219373af13ed907c9089298a0551b68f71b63dc8b4fe9c828cd1aefde0dbb6", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_mint_token_group]": "ddca7a0e5454acc0eb5f9cdd27754c09e192d0644a407d5f27e109c0f58b09b0", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_asset_name_in_multiasset_token_group]": "bcd2079dbfe451f0f97eecd816af4776dbee2281faaa78215085edb2fa44d3b4", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_mint]": "fe49bce6f0408b2a5764a25d2254e52f146b2e531fe7d1bd9fdd007d392e320c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[repeated_policyid_in_multiasset_output]": "8b9f32a9a0b218ef780222f9a1b339cdd1ad645d2b993ed377990c5469a1e05f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[required_signer_with_both_key_path_and-7d9a3c59": "7a77aafadd25d3e74f2a976bf5520cd38879aeba06347346ec17e7d9e15f03ca", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-02b129f8": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-11c8b442": "3202590a4ef04faabbd3d847ae7bb122cca99bf131851c8085ae9b942d9b32fb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-11c8b442": "b1b91573fe7d4905690b5b822279bbeb2f1a6428e43ad95a59b8e55a0298f268", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-2d1899d5": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-3f8170f6": "3202590a4ef04faabbd3d847ae7bb122cca99bf131851c8085ae9b942d9b32fb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-3f8170f6": "b1b91573fe7d4905690b5b822279bbeb2f1a6428e43ad95a59b8e55a0298f268", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-60961d51": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-790fc948": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-883e81d5": "d41cb3b28b2cf6aba20506986a565c59c02fe38fc854d4d079584114340253b0", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-883e81d5": "f3fbe951f03e32e13976d0096b48de1873f68f96ce1401b8986345707d37410b", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-9ae6620c": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-d0eba163": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-e7a533e7": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-e7a533e7": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-e908b1a8": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-f9976ae8": "27a0331289728ecdf7c407fe15d5cc496fd814e50a1646ba9299849a48d9a8d1", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[script_data_hash_has_incorrect_length]": "1867afaf501930511d85cc1f338ec024852165e4cac8cbd300127e4a045c502c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_mainnet_transaction_with_testn-af110e3e": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_testnet_transaction_with_mainn-ba78ab8f": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_account_larger_than_100]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_certificate_and_w-003a1023": "62073c136af929ee07a1d94511850bc771449ecdaae6bfdd7164d6d7293c0574", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[sample_stake_pool_registration_certifi-f9976ae8": "e0ac03eb77946f93018ab65162ce43b0b630a62af13f356d71e35af8845a8deb", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[script_data_hash_has_incorrect_length]": "8544d5037928cea8bd0459d91f3f31a3275f2ef99bac5a53c98a4d682cc1d710", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_mainnet_transaction_with_testn-af110e3e": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[shelley_testnet_transaction_with_mainn-ba78ab8f": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_account_larger_than_100]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[stake_deregistration_certificate_and_w-003a1023": "63a1390231ae90deb446a4343e1d46875768e9c2cc013b74f8d967b6719028a0", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_protocol_magic_with_mainnet_network_id]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_transaction_with_mainnet_output]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[testnet_transaction_with_mainnet_output]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", "TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[total_collateral_is_present]": "e3561a951166b1fb03617de07134f0b2c85dbc612478797bfec7e54a89d92e9a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_both_auxiliary_data_b-6f1ead27": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_both_vote_public_key_-3e8cccb4": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_cvote_registration_co-2dcb1cea": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[two_owners_with_path]": "8ee10d546d46cb1b2f357bcbc1d5cdc53ac36c2a887680d01c8fa3d579f5058a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[unsupported_address_type]": "060418f7a591e63e815c1f5de64dadb74223791e94f1d81e694210fd64ca919d", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_multisig_transaction_signing_mode]": "76f47ef5aab1186195d241f92415ff0e75871dc0db29bc146d635c10e5a5dd5f", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_ordinary_transaction_signing_mode]": "606433c668d192f091f372a6a97a71e685b6db9a7c9ef794e9e6ccc7cfc984a5", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_plutus_transaction_signing_mode]": "b1f0f8dacdd7c9e06b6a9cdc5b4c384d4f5f6116dc005db085a58c6a3dbbda51", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_amount_is_too_large]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_contains_both_path_and_key_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_contains_both_path_and_script_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_key_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_multisig_path]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_non_staking_path]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_script_hash]": "6657fed23a2ea43448a9a0b612f4297006b3d5d962f199c742b48901ca194a99", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[mainnet_transaction_without_change]": "a682981a378b22993e2c49c11c6e264758170a897007705a5d9980501b20bbff", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[multisig_transaction_with_a_requ-c2fba589": "2aa69663aa444b47a5b4a40815a55a48b814c9da5204b732d20cbc972eee99fa", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_a_requ-9728607e": "3065d3519d8ff2099d7f203b124f496bb8fa8bc778a4f49dba8f4ecc8290a9fc", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_long_i-708443f3": "a3a8d217c79101f3640de49929205aec7e3962c6bc2498ee66820efb1135ec81", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_output-9ba7352d": "f3523f3e5ffa8d2b3bef05cb5f97fdbd20783a4289e4620fe5dcb82bec3e995c", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_reference_input]": "04808362e9f97aeb096db30d6982aec5fa5c90939a5eaa3a1071ec69efc3afa1", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_total_co-e846c221": "5c4307d3561fd609f57b468175da003272967289e9a42a45a87e2a2a6af1ea7a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_cip36_registrat-b9111c27": "cf7b98935bd43831e6067c226d801eebbcf1ef769c5fe63304563bd8a0f3ab8a", -"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_stake_deregistr-6e84da2f": "4659d141a1797c8e77451f82571dbbd844a6a0501f34fe00a1699c43eb389e0e", -"TR_eos-test_get_public_key.py::test_eos_get_public_key": "9c0409669034437d5172beb7fc326c0be39a48d483f7e21375b2a6d0ce17a407", -"TR_eos-test_signtx.py::test_eos_signtx_buyram": "8a8281dd3cd28086af0089a946075f7809dfb608e11e29d2e61e1ad971c4796d", -"TR_eos-test_signtx.py::test_eos_signtx_buyrambytes": "f745ebb07aff33dec4e36a5b98bffb735f206005e4aa16b3dedd21ea090d7531", -"TR_eos-test_signtx.py::test_eos_signtx_delegate": "680a4a4f3b088d24383747bf2b2a680d83b1910acf55c0fb9e8476861db7bee6", -"TR_eos-test_signtx.py::test_eos_signtx_deleteauth": "80512d688d5b223fbcf5d63677f6ff3ccb872b416c05194f7e422e21ec2efdec", -"TR_eos-test_signtx.py::test_eos_signtx_linkauth": "323e9299742eb3b34ee4db165e82af7247220a9c6e1a7a0cb935ef5815eb8e38", -"TR_eos-test_signtx.py::test_eos_signtx_newaccount": "1159ceb73f0d955dac3502daf8c5ed45a510b59b40a39f89ce2e7f940f92b7c5", -"TR_eos-test_signtx.py::test_eos_signtx_refund": "194eee782504f5b9e657066fe3c359370f0f363e1ceae05acc1bca2f35694c96", -"TR_eos-test_signtx.py::test_eos_signtx_sellram": "b02aa5a9a58a4b960c68da0e196c9497ada4e7ad5782626348f437b5f984d385", -"TR_eos-test_signtx.py::test_eos_signtx_setcontract": "087ba49a9b84ebc7de22907d0cd165f24ac8c5f5ac2fc21756400e0fbd66069a", -"TR_eos-test_signtx.py::test_eos_signtx_transfer_token": "e469d727c1fb44724893d511d813fd0e22c9346fc9bd8da8976bfa34fbec39e4", -"TR_eos-test_signtx.py::test_eos_signtx_undelegate": "ce8b8ab60d6386810c55951dbcd5d311dde54af725c34fa53956286d4fbc186d", -"TR_eos-test_signtx.py::test_eos_signtx_unknown": "73559c1e0d180320438ed13a0eb6a407e1e1c6b1861f4b30f0f864f614f294dd", -"TR_eos-test_signtx.py::test_eos_signtx_unlinkauth": "02b86c2ae12a025011c04623e88d663a5e6201d33b77345d0a8c215adbca39df", -"TR_eos-test_signtx.py::test_eos_signtx_updateauth": "877eaa82987f441192a229df337a47abcb29e2caee362436d23474c97d5fdba5", -"TR_eos-test_signtx.py::test_eos_signtx_vote": "9407884f162eda47ad94c7f3aa7528d672779ab17a638f97e63c723923df4968", -"TR_eos-test_signtx.py::test_eos_signtx_vote_proxy": "76cd6c2d2c7676b04df7492b5ae1d884b1862c3423540ce49324d13601a3ee6e", -"TR_ethereum-test_definitions.py::test_builtin": "d13b1b6e63f6c9152d269b4e258ef7962dee1cd151edacdf4c7eebb3f7b32387", -"TR_ethereum-test_definitions.py::test_builtin_token": "2846be10fe8f3b7749ceb9d431e47e5c6b3b8248c2bf5087d95f213f32bb43ed", -"TR_ethereum-test_definitions.py::test_chain_id_allowed": "82039cc8e344a4bdca3f105548f74ff04b090ea5b5fdc4e1a19f374fed94e299", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_both_auxiliary_data_b-6f1ead27": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_both_vote_public_key_-3e8cccb4": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[transaction_with_cvote_registration_co-2dcb1cea": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[two_owners_with_path]": "9cbae65adc5f32718ec13e6d600334cebe0aee28fc0bae761109ab03085efa93", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[unsupported_address_type]": "1916be21a0781817644bf2d39da26454b7af232cf8594a938bf10dabac0a007c", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_multisig_transaction_signing_mode]": "8e5c7105dd4977df155771dfc6409045c64d93b0762dccdcd1a9876f0dbedb4d", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_ordinary_transaction_signing_mode]": "87ec6465f3d6ba54134f97b83a35421e6e4cb72fbf8b9717547b2d5de84b3471", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[with_plutus_transaction_signing_mode]": "d3b7d5dfffc46937c8f176e314719df4ff481ffceab5c6f3534d7fa472668617", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_amount_is_too_large]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_contains_both_path_and_key_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_contains_both_path_and_script_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_key_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_multisig_path]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_non_staking_path]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_script_hash]": "5f45676b3eab8acdecdb6b8387920650570e981f9ab8fb2d73e0b57d3208ad13", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[mainnet_transaction_without_change]": "92848b1720d386bd7b7a2109654c3d8feb0282cef2e1aea09aa552eb383cc1c7", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[multisig_transaction_with_a_requ-c2fba589": "77e1d9cf975193979c09732519860896cc0822eebcce6c09c2649a7fa0e72214", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_a_requ-9728607e": "738625e651376eb3e89175490aaac0e92163ce28a339d06332d291e2f404cecc", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_long_i-708443f3": "44dc4fa7d0c09b7dfc16cee4eb62c45bf048dc37ed255764418451759c96d3c5", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_output-9ba7352d": "08f9622022c83ec2e976f0110a531064e6e05a3a02e8e5c993d14a9ba7c78706", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_reference_input]": "3ede055a479a2c0f75decd39437367d4af74079ad4dfcd445580602d6907341f", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_total_co-e846c221": "e0411cde02f0b326e6b527b7458fe0ab91e67e231aaae25129b34d4eef867eda", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_cip36_registrat-b9111c27": "7e4d326a3710b2f7b07750d288d94eda60438f847162665f33fe8843ef3e5954", +"TR_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_stake_deregistr-6e84da2f": "5b369f426fb3caf2686c3efaab903ee07e3ffbd15fa18ed6f324fb2fb4022a08", +"TR_ethereum-test_definitions.py::test_builtin": "0f7c5f3f28c296fa300571713636fd7f7603164a1b408b2b0319a8c30e543385", +"TR_ethereum-test_definitions.py::test_builtin_token": "7277808c8458316cf889f650886c805a3c5cc96d0c03c53c5897d790f2b87e49", +"TR_ethereum-test_definitions.py::test_chain_id_allowed": "f6a80cf048a64de10ed9c4ee49d754a3dee42c4665d59b0c5aba236fa0c20d44", "TR_ethereum-test_definitions.py::test_chain_id_mismatch": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_definition_does_not_override_builtin": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_definitions.py::test_external_chain_token_mismatch": "6596ddd50f44d6d38961fa411d4960eab36a4acb616719c3e23fb5cacc98c862", -"TR_ethereum-test_definitions.py::test_external_chain_token_ok": "4c867a1048be399a78be0d581b8aac187d4ca0d3a928d252be24ae8e05454f4b", -"TR_ethereum-test_definitions.py::test_external_chain_without_token": "6596ddd50f44d6d38961fa411d4960eab36a4acb616719c3e23fb5cacc98c862", -"TR_ethereum-test_definitions.py::test_external_token": "cc9593066c8e0f1d7fc8574e08186fc5346cfb9a09db584e634194433b7bd56d", +"TR_ethereum-test_definitions.py::test_external_chain_token_mismatch": "538f98a5c65ef5d1f178eeb7cbec35ec6e6795edeccf170b6b7b77a141b5033e", +"TR_ethereum-test_definitions.py::test_external_chain_token_ok": "5446130ff938779372dcdc11247151631fd449437c5ba9815f254c26863e4549", +"TR_ethereum-test_definitions.py::test_external_chain_without_token": "538f98a5c65ef5d1f178eeb7cbec35ec6e6795edeccf170b6b7b77a141b5033e", +"TR_ethereum-test_definitions.py::test_external_token": "50530f6219add3fbcfa42114d3b8ce00c2f5e0a8da6680519ab662e3bebf9295", "TR_ethereum-test_definitions.py::test_method_builtin[_call_getaddress]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_definitions.py::test_method_builtin[_call_sign_typed_data]": "837ad06f68664b0649a5fd79b561c8c49241178f7f6b435c01d7a5d60b62c85a", -"TR_ethereum-test_definitions.py::test_method_builtin[_call_signmessage]": "e08ef42b266f8312316d085118cbb55d99afae9430280a3807e35fe2260742a6", +"TR_ethereum-test_definitions.py::test_method_builtin[_call_sign_typed_data]": "3230e39e35585d198a19953a873b155a7279e218ac9f9cd4a9a7ba1ad53e5942", +"TR_ethereum-test_definitions.py::test_method_builtin[_call_signmessage]": "a1bb2de5c72df145f463f02344854a2e9164db148d1b836fa8e6b3d751556fcc", "TR_ethereum-test_definitions.py::test_method_def_missing[_call_getaddress]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_method_def_missing[_call_sign_typed_data]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_method_def_missing[_call_signmessage]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_method_external[_call_getaddress]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_definitions.py::test_method_external[_call_sign_typed_data]": "837ad06f68664b0649a5fd79b561c8c49241178f7f6b435c01d7a5d60b62c85a", -"TR_ethereum-test_definitions.py::test_method_external[_call_signmessage]": "dd9ef65c99f0bfb3f5ca96f7e01c9f7d3a43087896359629a28e6bf5126cfbfb", +"TR_ethereum-test_definitions.py::test_method_external[_call_sign_typed_data]": "3230e39e35585d198a19953a873b155a7279e218ac9f9cd4a9a7ba1ad53e5942", +"TR_ethereum-test_definitions.py::test_method_external[_call_signmessage]": "b5854b35ff2192047be0eb7ad867a1e07a2b4d7da4cfbc1e4966d81714571698", "TR_ethereum-test_definitions.py::test_method_external_mismatch[_call_getaddress]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_method_external_mismatch[_call_sign_typed_data]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_method_external_mismatch[_call_signmessage]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions.py::test_slip44_disallowed": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_definitions.py::test_slip44_external": "ed254ed6921508fdda050d12050852084a5cd8a769886ac765b362ae63107434", +"TR_ethereum-test_definitions.py::test_slip44_external": "0f801a2b3b68914d8efd97caa025b90032d7d913b96ae4b4b71397116e788ac8", "TR_ethereum-test_definitions.py::test_slip44_external_disallowed": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions_bad.py::test_bad_prefix": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions_bad.py::test_bad_proof": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1505,82 +1593,117 @@ "TR_ethereum-test_definitions_bad.py::test_short_message": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions_bad.py::test_trailing_garbage": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_definitions_bad.py::test_trimmed_proof": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_getaddress.py::test_getaddress[ETC]": "fa1eae279f537f60c4a969f09c40638220756e6ff0d1aec172474156808a60d1", -"TR_ethereum-test_getaddress.py::test_getaddress[Ledger Live legacy path]": "a1e8ffb94b856824f03678ebcc8f0e40967245ebc1e514e9d988776819304a51", -"TR_ethereum-test_getaddress.py::test_getaddress[parameters0-result0]": "9cecd284f55f60e254f301cf90b979bba01b9e95eda58a11833a80a2213dd1be", -"TR_ethereum-test_getaddress.py::test_getaddress[parameters1-result1]": "b7b3c1d48c998f5f3d6050418d9d0ed5f81ef664e38814b733f44d22656c5967", -"TR_ethereum-test_getaddress.py::test_getaddress[parameters2-result2]": "fa19554524f487148b45d513e8e89c5e398cc755cc2bceee3df9aa7f19f6144e", -"TR_ethereum-test_getaddress.py::test_getaddress[parameters3-result3]": "1b0ea8bd11df5f75e231ee21018e8d14db5a22357bd9314480041e3e13786e8a", +"TR_ethereum-test_getaddress.py::test_getaddress[False-ETC]": "811dc2b45a93c4ee24b821b302fe56d9091c00bd7ed2e8aa3d897a3b7e8e37cd", +"TR_ethereum-test_getaddress.py::test_getaddress[False-Ledger Live legacy path]": "31a141e0c77e58a3b4f03eb638ad1610e909652fd80a8b828672101861427578", +"TR_ethereum-test_getaddress.py::test_getaddress[False-parameters0-result0]": "cabd4b0ab3147ba837b9ffd985c1818adb682ae23f5539384b3deb28ee12a0a5", +"TR_ethereum-test_getaddress.py::test_getaddress[False-parameters1-result1]": "0c5676ea02482c8efec70f854a4f3df588981d8856074595c1600dfe00c2cde9", +"TR_ethereum-test_getaddress.py::test_getaddress[False-parameters2-result2]": "a748cc5bc5c15f9e11a1bd827089c25bec0f2326011c7425af5ebcf237d6ee7c", +"TR_ethereum-test_getaddress.py::test_getaddress[False-parameters3-result3]": "09f7b0723f16b99c91fab314631b98b12d67a75ef58de91db61c2b4d3a4289b8", +"TR_ethereum-test_getaddress.py::test_getaddress[True-ETC]": "97d59273ff51b4a45731097b28095c8d3fb83bde3beaea04c60560e2205ff135", +"TR_ethereum-test_getaddress.py::test_getaddress[True-Ledger Live legacy path]": "50d35be8855e79628c14d08c8b77eed1fdbc604468d97bd9ca325e4e04120ebe", +"TR_ethereum-test_getaddress.py::test_getaddress[True-parameters0-result0]": "0aec3559042e4c6cb170b1ff9001b2818972f582239c4c2bf4e65959dab689ad", +"TR_ethereum-test_getaddress.py::test_getaddress[True-parameters1-result1]": "33367b23e3fda68314e535ebe5dd1ac4a30cf45616c49c074a47b1ebf1292ec2", +"TR_ethereum-test_getaddress.py::test_getaddress[True-parameters2-result2]": "2795b19b471ec6a78b2d1fd8bef184c25a21d79b6af1d56d649b8854d3780d94", +"TR_ethereum-test_getaddress.py::test_getaddress[True-parameters3-result3]": "f8869b171803f15817b6aa24c98514d77f7f111ba31d51a3c34860c7eed0fecb", "TR_ethereum-test_getpublickey.py::test_ethereum_getpublickey[Ledger Live legacy path]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", "TR_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters0-result0]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", "TR_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters1-result1]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", "TR_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters2-result2]": "b70d9d2aa7a8ace3251763c1d2fcb53dd8c741b7520d717398df8f7ff8ac9128", "TR_ethereum-test_getpublickey.py::test_slip25_disallowed": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[array_of_structs]": "4363a22f81481c5f530d64b1e5e6e3a871d8106f4e9fc9f48d60b4bfedc0fccd", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[bare_minimum]": "416e7c889442caa4328985d96562d272ff0d82f6bf456a101313d25f8397a881", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[basic_data]": "00ea35be92129b2dcaf40b9d7a4e72a2b19576fc350bd17ca89a76fc1b0d6e3f", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[complex_data]": "9544b2f8a2e92f71ca1384bc2dd7910d1c62ac2d3a27f379c1c0796cf01f0224", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[full_domain_empty_message]": "92ba8e91c1ec610536e87663c031db4fbb01f95634d64717af5b6a655852b906", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[injective_testcase]": "1b27e5209b21c1c71d6e028d353c70108d24f91aca94bd4734567116c8185be7", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[struct_list_non_v4]": "00ea35be92129b2dcaf40b9d7a4e72a2b19576fc350bd17ca89a76fc1b0d6e3f", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[struct_list_v4]": "00ea35be92129b2dcaf40b9d7a4e72a2b19576fc350bd17ca89a76fc1b0d6e3f", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[structs_arrays_v4]": "00ea35be92129b2dcaf40b9d7a4e72a2b19576fc350bd17ca89a76fc1b0d6e3f", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data_cancel": "b64c0a6dae5ef3970836002d3d0504449f654f65efbaa6279ceb4dcd218d39e9", -"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data_show_more_button": "ede131ba71cd3ca680a055db83b545208b0818d755c9035275b8980236e7d48e", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters0-result0]": "8a86bacbcad1af41b69f7762ff57da199fdc8702716c89873529db65bd247d30", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters1-result1]": "88d884a8c6429d4052d08630f1db2c7cea4799e448ad1b3a05b17969752d5436", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters2-result2]": "86535d1335c0a576cedc25cde9e9fcc700c6ac8b3c10cc6771d41b74afc822f1", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters3-result3]": "0d21d626583e9f9eb19e18a0dedb2ea51b8015b76239f1d0292efcbbbfeaa958", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters4-result4]": "2703cc66fde545743d0b292a51100cb62821e53c883067e73b99f8648bb2c2a2", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters5-result5]": "4fa4581528088bb701c9e508fcb704d0476e39837b9ba2a65053f2d08c174739", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters6-result6]": "4f574e8e62c22c727f8e8b8b404fc23a01c75228098160b7706c195d8ad3a292", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters7-result7]": "43bbcc6d526a29ed3862974fcf3f30480ccddd45ed4f9c187ed80f60ad56b5bb", -"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters8-result8]": "ddd9d96336704c76b3c09e99a80218e2b396e94da2cdb30c32856d61f732da01", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters0-result0]": "4dc77ca0f8bd1aafcbcf78c6ef2bbccb8c47688cfe2bbee875ede041dba821f6", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters1-result1]": "8488de592eadad4852e9512848fa80c97561833fd66c279203e4fc2c108425b6", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters2-result2]": "3ff1c7d1eeb328688daed4b4e942805bdbaa830578514575de1250836878c41d", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters3-result3]": "855b0d7e101d62d87851e64bfa91014e59508e0dc5d66b2eb188aa694f6fe487", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters4-result4]": "fe9f6a75fa5b77533109eb76a8e89d638411632db671db3a4749a78ba60f3b5a", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters5-result5]": "715836d505c434c1f2a613e58876c56a852c1f69084198a821cd61157a2827ed", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters6-result6]": "01956eba8fe4b48e21e103acee802044384d470173dfd3dee8d24e7d27096932", -"TR_ethereum-test_sign_verify_message.py::test_verify[parameters7-result7]": "622ba6fe9e8475779ba00739ba4b43120a6e6914fa14bf080eef1c7a0a99474c", -"TR_ethereum-test_sign_verify_message.py::test_verify_invalid": "4dc77ca0f8bd1aafcbcf78c6ef2bbccb8c47688cfe2bbee875ede041dba821f6", -"TR_ethereum-test_signtx.py::test_data_streaming": "0fdb7aaa170a2feec8086dc626587a755b26a68f7f818741e6d42a5d36e166f2", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[array_of_structs]": "215c97b7ee5f594eeb0ec6c8a5ba9292f3703f02d65356517e2326c16e62c433", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[bare_minimum]": "8d059e060c9fff32510c6ae98fd63bbeffd634c114064088112b8a6199678df2", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[basic_data]": "a7280c84bb7924be90d676ff9e0e3082cfd40133fe8bfea3dad89e0cad43f31b", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[complex_data]": "e78260743be82585c4aa64f26f415a331f4d2c8879635e5f055da5849ca5e22c", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[full_domain_empty_message]": "261082198cb076075850e29f2ccd85a410b57be73cf6aed4ad6006667efb948c", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[injective_testcase]": "7ef8d58e5cab76769cf1addfefcec820e7e66c573be18615872b3ff3ac7f7094", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[struct_list_non_v4]": "a7280c84bb7924be90d676ff9e0e3082cfd40133fe8bfea3dad89e0cad43f31b", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[struct_list_v4]": "a7280c84bb7924be90d676ff9e0e3082cfd40133fe8bfea3dad89e0cad43f31b", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data[structs_arrays_v4]": "a7280c84bb7924be90d676ff9e0e3082cfd40133fe8bfea3dad89e0cad43f31b", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data_cancel": "2915e19171728bf660b14f61136e90b228a03d9605cf7db63bf78460b40e68ef", +"TR_ethereum-test_sign_typed_data.py::test_ethereum_sign_typed_data_show_more_button": "65068ee4ac263fd43ac75a53dbbdec434abd1a92bdc6078bd39f32855e5667ea", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters0-result0]": "7d9b3e16f4e5181ce93fa07ab3918302be796ae8b7d2f7c551687f951b57621e", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters1-result1]": "f41f8c0bff57e500c9b1ff0a9e595677a94e0b75b8f240410d81df1c1c2493ef", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters2-result2]": "5baf20ff21ceabd2b5c5945d340a54c8e988a75c9dc1382918b8731cddf5a838", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters3-result3]": "77ae59da3c798c284c1dd67888f6e1e6ceee8e3ebcb6e3eb32fc915065dca0e5", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters4-result4]": "b24f2213bc7addb870c91bb0d44ac086e934defeaafed24079cd4b78e5428da9", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters5-result5]": "994a530f168fd34579fe4ca78ac9e17b78776a4843d489507854cbe06f75925e", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters6-result6]": "7e27eeca282839e9ce3f93f0176a5f7f53b9a6f5d4cd01cf93cc7672e508bf2d", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters7-result7]": "daff43aed14c610517b666b9158f22784b723a8caff539ccdf16df08ddf67c2a", +"TR_ethereum-test_sign_verify_message.py::test_signmessage[parameters8-result8]": "ff2d96e0e3d5f3060616106c52e9575d85521d07aaf29da91899de2d1bf2559b", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters0-result0]": "b25ded28f14d680e202904a6c63c6e392851c6d1a0e3d4947e8f8c93a5999170", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters1-result1]": "421892756ab14ed7e971552fdd27bf5aac196a5cc5535609ddbf7f097644be7c", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters2-result2]": "ee0cc4d99a8f1991a27c40ded4c445267b8b72a3faf1f7d777bf34c2953b057f", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters3-result3]": "3ef92f3fee049feea98ddb3fdf9bb38399ce7523d25acf1ffcf6e3abe334649a", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters4-result4]": "32f2c314dacd88aa1022d710b343a361ebfa5306f22b2273c0ee52b7f0846c65", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters5-result5]": "b5d499333530aa6b1bf4dccede018cf53b44f9b5c1fe7eee93ae3ccb930a4925", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters6-result6]": "fdeb6761c450a7174f937a91f4554af1781c18906fd757711ce2566768129528", +"TR_ethereum-test_sign_verify_message.py::test_verify[parameters7-result7]": "5d45e122a95a5679d814537e68cd532d8c09785550a4f71ab86c85a627081b2a", +"TR_ethereum-test_sign_verify_message.py::test_verify_invalid": "b25ded28f14d680e202904a6c63c6e392851c6d1a0e3d4947e8f8c93a5999170", +"TR_ethereum-test_signtx.py::test_data_streaming": "7233dd79ff4e1ecd2ab5c4cf86ae29b477db3ee4d13084372fa930cbddaa54f8", "TR_ethereum-test_signtx.py::test_sanity_checks": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ethereum-test_signtx.py::test_sanity_checks_eip1559": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_signtx.py::test_signtx[Auxilium]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[ETC]": "e80c1316ddf5408b9cb261362f57019d957fe28501fec95f57cc807359d6ff15", -"TR_ethereum-test_signtx.py::test_signtx[Ethereum]": "89b1a4682096ce1a2e10948730b5c1810f744d1600f76b58060abefa63b71c63", -"TR_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path0]": "95f1d4c55029961c0e943ff1c07f67e341d45c029c383f56d2d727da3d93e8e3", -"TR_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path1]": "89b1a4682096ce1a2e10948730b5c1810f744d1600f76b58060abefa63b71c63", -"TR_ethereum-test_signtx.py::test_signtx[Palm]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[Pirl]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[Rinkeby]": "8387f3226e355a0fca6d2b60266077cd7c83f0c2497911a426ef9de7fc6dc21b", -"TR_ethereum-test_signtx.py::test_signtx[Ropsten]": "8387f3226e355a0fca6d2b60266077cd7c83f0c2497911a426ef9de7fc6dc21b", -"TR_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_eth_path]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_testnet_path]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[data_1]": "656e87c88f52ab97bd26382dd3d931ca7575002dba1c76a862be8df3d479add8", -"TR_ethereum-test_signtx.py::test_signtx[data_2_bigdata]": "f2b5ba67f75ee2afe091fe8f8bfafc14aa83117a4fcfbceb60017224b9ea0530", -"TR_ethereum-test_signtx.py::test_signtx[erc20_token]": "ec20bfc73a60d0d4cdda28e0898785bbf3e15e58f2c8c698f90b86d55835fe2a", -"TR_ethereum-test_signtx.py::test_signtx[max_chain_id]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[max_chain_plus_one]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[max_uint64]": "d6e099daab3dc81befc52e1011eedd95d68918b06127f2f1bda07450b6408700", -"TR_ethereum-test_signtx.py::test_signtx[newcontract]": "b8518f851fe3de03f52d9cbd69480497f21d916799f4177c3e52a71d90426072", -"TR_ethereum-test_signtx.py::test_signtx[nodata_1]": "d20596c1b6d46e8c92fca4f8279f181b56bd9540665e467ac16a84d6f640c8ab", -"TR_ethereum-test_signtx.py::test_signtx[nodata_2_bigvalue]": "35c40841cc883eaa85099e5b112def29e788a82495a960c4478d4c5d3de76162", -"TR_ethereum-test_signtx.py::test_signtx[wanchain]": "8d89ad1a50c5d2da1f7874048ccf8dae255a66939f29765d52dd7e90e7dbe881", -"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_go_back]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_scroll_down]": "5f681d5eda5b028acc0f0fd8157a590a2a72d932c99471ebbd126c1770e2e95e", -"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_skip]": "87cad80d17f90018ec54b09a620e402603899168e62779f48469f50ba0aca78d", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[Ledger Live legacy path]": "0f81bfea6e7b75f8a2e5aeb75267df3b9fd2a26a05516c99dbc674ae7a799403", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[data_1]": "dae79a6111750b934f075db05e84ebfa56110f4be1be562f2bfd1202f5e45612", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[data_2_bigdata]": "1f0bde031a292262c5a08f482e4a302d5f185fa2f26e44a12edfa1559af393bb", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[erc20]": "74d5c449578eab6edec149ca57288586e1ac1cf324bc310b463f78da92848ba5", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[large_chainid]": "05708c3c32332ac11dc86904534c0eb90d2bfc53e789ef49ed0915f3908168d8", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[long_fees]": "4ab9eced1830bf71ff8079f2058ee34b62e778fe83279983f5b91a0d6b322c51", -"TR_ethereum-test_signtx.py::test_signtx_eip1559[nodata]": "0f81bfea6e7b75f8a2e5aeb75267df3b9fd2a26a05516c99dbc674ae7a799403", -"TR_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "ee7cedbbf06638674d8096379cf3eaf4521bde01775d6ff0c85e42b8770e7898", -"TR_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "ee7cedbbf06638674d8096379cf3eaf4521bde01775d6ff0c85e42b8770e7898", +"TR_ethereum-test_signtx.py::test_signtx[False-Auxilium]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-ETC]": "3187e16f10d547f1b46224abd82b340e8f04310a2b03b9e2554c817139b1a3c0", +"TR_ethereum-test_signtx.py::test_signtx[False-Ethereum]": "0956f8f473f6267cb5a087079d1ce55c4572e37f84deb5d54925d24b27ca3e77", +"TR_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path0]": "6c6d86ee74265d4a95798e4c9f8501e4f1e5f1004d6ddc96a43e4ba5f6b0bbbf", +"TR_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path1]": "0956f8f473f6267cb5a087079d1ce55c4572e37f84deb5d54925d24b27ca3e77", +"TR_ethereum-test_signtx.py::test_signtx[False-Palm]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-Pirl]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-Rinkeby]": "124c91e03b54f5c82c9c40d14c3b94c5e9aceb5b78b5d22c30050c080d661768", +"TR_ethereum-test_signtx.py::test_signtx[False-Ropsten]": "124c91e03b54f5c82c9c40d14c3b94c5e9aceb5b78b5d22c30050c080d661768", +"TR_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_eth_path]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_testnet_path]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-data_1]": "aae452cd2e4a8f330257cc53c44a3294a8a620df4b5b14d5e18b9ddb73603912", +"TR_ethereum-test_signtx.py::test_signtx[False-data_2_bigdata]": "785052660b45fc67b8998274b44d1925337a16fe037ea85e6a85e66807416464", +"TR_ethereum-test_signtx.py::test_signtx[False-erc20_token]": "ac60b04fd297abd2ef5ddaabec345d95318d1c438ac43ecf36226869cdf678e4", +"TR_ethereum-test_signtx.py::test_signtx[False-max_chain_id]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-max_chain_plus_one]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-max_uint64]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[False-newcontract]": "e1bff52c1a1be493459d2081f67fc51218bec7e8457cd62826d8e8ecbca6fa4a", +"TR_ethereum-test_signtx.py::test_signtx[False-nodata_1]": "cfac2c2766c9be4d03eb3e0f1e869a19c09175ec20453c3dc6cc43e16b774d9b", +"TR_ethereum-test_signtx.py::test_signtx[False-nodata_2_bigvalue]": "164843840563c6ed8031b397d68408a082dd16beae68f4eafb5ee6c708b24f70", +"TR_ethereum-test_signtx.py::test_signtx[False-wanchain]": "bb4344a5fc4335436619d703b7ea5a2448ae34f795f5f67b96b18e6a513aad7b", +"TR_ethereum-test_signtx.py::test_signtx[True-Auxilium]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-ETC]": "3187e16f10d547f1b46224abd82b340e8f04310a2b03b9e2554c817139b1a3c0", +"TR_ethereum-test_signtx.py::test_signtx[True-Ethereum]": "0956f8f473f6267cb5a087079d1ce55c4572e37f84deb5d54925d24b27ca3e77", +"TR_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path0]": "6c6d86ee74265d4a95798e4c9f8501e4f1e5f1004d6ddc96a43e4ba5f6b0bbbf", +"TR_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path1]": "0956f8f473f6267cb5a087079d1ce55c4572e37f84deb5d54925d24b27ca3e77", +"TR_ethereum-test_signtx.py::test_signtx[True-Palm]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-Pirl]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-Rinkeby]": "124c91e03b54f5c82c9c40d14c3b94c5e9aceb5b78b5d22c30050c080d661768", +"TR_ethereum-test_signtx.py::test_signtx[True-Ropsten]": "124c91e03b54f5c82c9c40d14c3b94c5e9aceb5b78b5d22c30050c080d661768", +"TR_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_eth_path]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_testnet_path]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-data_1]": "aae452cd2e4a8f330257cc53c44a3294a8a620df4b5b14d5e18b9ddb73603912", +"TR_ethereum-test_signtx.py::test_signtx[True-data_2_bigdata]": "785052660b45fc67b8998274b44d1925337a16fe037ea85e6a85e66807416464", +"TR_ethereum-test_signtx.py::test_signtx[True-erc20_token]": "ac60b04fd297abd2ef5ddaabec345d95318d1c438ac43ecf36226869cdf678e4", +"TR_ethereum-test_signtx.py::test_signtx[True-max_chain_id]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-max_chain_plus_one]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-max_uint64]": "16c842adfb793ccc79bdef3ec1bce71ff82e49d9d87c771c343215755a8c8b5c", +"TR_ethereum-test_signtx.py::test_signtx[True-newcontract]": "e1bff52c1a1be493459d2081f67fc51218bec7e8457cd62826d8e8ecbca6fa4a", +"TR_ethereum-test_signtx.py::test_signtx[True-nodata_1]": "cfac2c2766c9be4d03eb3e0f1e869a19c09175ec20453c3dc6cc43e16b774d9b", +"TR_ethereum-test_signtx.py::test_signtx[True-nodata_2_bigvalue]": "164843840563c6ed8031b397d68408a082dd16beae68f4eafb5ee6c708b24f70", +"TR_ethereum-test_signtx.py::test_signtx[True-wanchain]": "bb4344a5fc4335436619d703b7ea5a2448ae34f795f5f67b96b18e6a513aad7b", +"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_go_back]": "2df1db26376b44b2a89c87333fcf3bf78b7687a2b1d17e693489d907b0bd2200", +"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_scroll_down]": "3feac43a3a5f8278d346cec9a129014484fe276e6b5517df53056e8d9b095f89", +"TR_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_skip]": "99460b4891603b5a0e2b9e4b15efa7d99820cde4b8c5f2fc8b09cfe524042f7c", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "3b101f527d93d9d97c1e84be9b5589e78f6dd3dcfcb909f30e56d2a5908207e0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "9f24fc38a6b89df23b767a841b631b5c36319ce1df75fff6f16a59ecb8403900", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-data_2_bigdata]": "4e341cb715f26d4b79e19bf46ab8337d0f9b60819716013ad62c8ba4d951cdd0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-erc20]": "4d6e07538cd90083df5eabcab072cf4a0e6ec808d08e35e787a363a4edd18b19", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-large_chainid]": "d97d4bac3d9c787b2101571f8abce3db1f9482db226dd3a52ad47ac083963600", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-long_fees]": "2f10b01e11c5a13c877cebcb56c6952039ba230cefeb57f5775c45c15f7229d7", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[False-nodata]": "3b101f527d93d9d97c1e84be9b5589e78f6dd3dcfcb909f30e56d2a5908207e0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-Ledger Live legacy path]": "3b101f527d93d9d97c1e84be9b5589e78f6dd3dcfcb909f30e56d2a5908207e0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-data_1]": "9f24fc38a6b89df23b767a841b631b5c36319ce1df75fff6f16a59ecb8403900", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-data_2_bigdata]": "4e341cb715f26d4b79e19bf46ab8337d0f9b60819716013ad62c8ba4d951cdd0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-erc20]": "4d6e07538cd90083df5eabcab072cf4a0e6ec808d08e35e787a363a4edd18b19", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-large_chainid]": "d97d4bac3d9c787b2101571f8abce3db1f9482db226dd3a52ad47ac083963600", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-long_fees]": "2f10b01e11c5a13c877cebcb56c6952039ba230cefeb57f5775c45c15f7229d7", +"TR_ethereum-test_signtx.py::test_signtx_eip1559[True-nodata]": "3b101f527d93d9d97c1e84be9b5589e78f6dd3dcfcb909f30e56d2a5908207e0", +"TR_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "d187dd039320d08dd1beab1966e42ffdd809ea8b4c17ffe4984efd288596e9b8", +"TR_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "d187dd039320d08dd1beab1966e42ffdd809ea8b4c17ffe4984efd288596e9b8", +"TR_ethereum-test_signtx.py::test_signtx_fee_info": "18af368ec44c0069b1be6e64f59fb1a2ede672efb24b4dc4f8ae73f4a18525f8", "TR_misc-test_cosi.py::test_cosi_different_key": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_misc-test_cosi.py::test_cosi_nonce": "df3420ca2395ced6fb2e3e5b984ece9d1a1151d877061681582c8f9404416600", "TR_misc-test_cosi.py::test_cosi_pubkey": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1610,46 +1733,30 @@ "TR_misc-test_msg_cipherkeyvalue.py::test_encrypt": "468ff13a1c14b5a9fed5b58f0f1473448828acb96638045a29c6fed73e140d91", "TR_misc-test_msg_cipherkeyvalue.py::test_encrypt_badlen": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_misc-test_msg_getecdhsessionkey.py::test_ecdh": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_misc-test_msg_getentropy.py::test_entropy[128]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[129]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[16]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[17]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[1]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[20]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[21]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[256]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[257]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[32]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[33]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[3]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[4]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[512]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[513]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[5]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[64]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[65]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[8]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", -"TR_misc-test_msg_getentropy.py::test_entropy[9]": "f8bab4ff56e6980aa67c91340b7ab521f55588e205fd936ea65f86807e0b9bc9", +"TR_misc-test_msg_getentropy.py::test_entropy[128]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[129]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[16]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[17]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[1]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[20]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[21]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[256]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[257]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[32]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[33]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[3]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[4]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[512]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[513]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[5]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[64]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[65]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[8]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", +"TR_misc-test_msg_getentropy.py::test_entropy[9]": "d50e2ba952e19254c8157bd29d3c6f29e40b6c92c02f1459fa4b9bf6b6c3f346", "TR_misc-test_msg_signidentity.py::test_sign": "4ea3ff06287458ae5c08e118e489c0b432316521fbfa47ff587d748761f9c6c2", -"TR_monero-test_getaddress.py::test_monero_getaddress": "0fb7234b57aa5daad882d3f4633949265395d582ab0c7d150a8fadb768a22eb2", +"TR_monero-test_getaddress.py::test_monero_getaddress[False]": "5dc8b30cf58003e34eb6d1fb2bbe446578a291ed979d82699fa2b932a093fb61", +"TR_monero-test_getaddress.py::test_monero_getaddress[True]": "78bb4ee6632348428fe0347ef1ba4cc8c94c7da5e4a1d784ada7830916162d16", "TR_monero-test_getwatchkey.py::test_monero_getwatchkey": "e0a4795c4167750f9b3a79ca5c8c5af31857a0aab102d1eb8f7722f6643656b9", -"TR_nem-test_getaddress.py::test_nem_getaddress": "0f86745a63bb264838700bd3235fbdc3f3f3d2778c78511e4897a28598784d32", -"TR_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation": "c406d8ff5452b2f34983aa0f0e6024205428ebb64e02b4aeb358500b8c724ce7", -"TR_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_levy": "4089ed2868291bbde2000867b11dcbea1e0cafaa1c71dcb633d127804075e517", -"TR_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_properties": "9cd6bc884025a5bb1adb8e7287b453602670798e1da5c693b718262565a80363", -"TR_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_supply_change": "60eebbde7b12755f0dbd619a71263a937b807e9ac2359d99b2fe000c694ae8de", -"TR_nem-test_signtx_multisig.py::test_nem_signtx_aggregate_modification": "2d60afa983f359691dc3f48281cde486ca3fec08cc0e981547e5b89d91b89ad0", -"TR_nem-test_signtx_multisig.py::test_nem_signtx_multisig": "d24b1becc9e8ac4300cd2f7c858b9fbaddeddef3d0dc20a2502d408de324f7e0", -"TR_nem-test_signtx_multisig.py::test_nem_signtx_multisig_signer": "f7e56109c6ebd591789c858cd30c009c212b94ddba60798dbd11b14ec92d5ec0", -"TR_nem-test_signtx_others.py::test_nem_signtx_importance_transfer": "823ce7e09df8f9c28892044ac1e937a41e57587d53792f93c6653e362bc33086", -"TR_nem-test_signtx_others.py::test_nem_signtx_provision_namespace": "e5f3adcb7a15baaa2fae2ad1165d9956fd63a9db1ae9619e92777e5b7a629823", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_encrypted_payload": "f99698692e50d1ea2edc5b2ed7494062d5ca908bf3aaa21ccb4f3c16ed5863b7", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "79b4d4cadc5bf5a991dd8bb2535105f2ed3cf055fcce544b2b95f2a63cd5884f", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "8910c49d80cbb2027cfa4b2887912386a25f46677921b691ef7e8f4b99f1c166", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "5df2e730e9edc881bfad334676cebbde535e2b95e3975e520ccdf178946ec579", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_simple": "ceb9d1ef42cd88ecbb2ba05775ff017dbf5169e16d27f6ea03ac5d5e15f9b2ca", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_unknown_mosaic": "f9df8809dfc2e9cd69c68c26581879600964c637b7de6d465d25f2b8a8d93d3e", -"TR_nem-test_signtx_transfers.py::test_nem_signtx_xem_as_mosaic": "5cde5d592aaf662ddf41d28d270452dd9277b5a961bcfcd0774423f8982885a3", "TR_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[label-test]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[language-test]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[passphrase_protection-True]": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1660,94 +1767,109 @@ "TR_reset_recovery-test_recovery_bip39_dryrun.py::test_seed_mismatch": "eda604b260ceae5e2d60a34e2d6c49ff31f0e837c9ac2d73dc12f95e9a800e28", "TR_reset_recovery-test_recovery_bip39_dryrun.py::test_uninitialized": "f49c8d846c2d56a575f0ad49463845ba641b02656783e4fcfc67d74e8fa671dd", "TR_reset_recovery-test_recovery_bip39_t2.py::test_already_initialized": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_reset_recovery-test_recovery_bip39_t2.py::test_tt_nopin_nopassphrase": "bbd98894882dee6240329873959ccf20f6c4965ab3a74069d3cf0f38dbc5d278", -"TR_reset_recovery-test_recovery_bip39_t2.py::test_tt_pin_passphrase": "a5fbe12977f23ec41b534742c84e610ba6e052b355e7752fc0af0f3ff413efb5", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_abort": "a8c811cb3e7212b7c2861d2368c1b1acc7ce829e4868619616beee29b7892127", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_extra_share_entered": "4c180c7a1b1613d28110f7263c5bf0f1d6d6af8654bbd6a0de06237a969d0957", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_group_threshold_reached": "2fdbccb8d30d2133ef94434f17e55d7bb544d7c51cacfd9ba5700371a54cb50f", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_noabort": "91ff2edde41cd0ccf94df5c39e0aeac3f150a041954c41643b859e0a13ccd1c2", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_same_share": "ca074aa5c37aa3f9d226dd07d2626fb9d6b5bc0735965bf9470e934a5c2c6334", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f1-afc2dad5": "cdec97ad68d456b46a08b0a0cd251fd7b99c26d64ae240d184fc0937720efd66", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0-eb47093e": "ea0782bd418c153e346e6c7963138e9089f7b07d3d1f6836b333b276d6c0b9d2", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "cdec97ad68d456b46a08b0a0cd251fd7b99c26d64ae240d184fc0937720efd66", -"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "ea0782bd418c153e346e6c7963138e9089f7b07d3d1f6836b333b276d6c0b9d2", +"TR_reset_recovery-test_recovery_bip39_t2.py::test_tt_nopin_nopassphrase": "d63c89e06a3d4956e464211e2cd03535c0889cb0560f5e77d5a6797dc174b376", +"TR_reset_recovery-test_recovery_bip39_t2.py::test_tt_pin_passphrase": "a8cc23c85b9220d787b789a40bc3d6dc3a540fddb0ca44551956e721ad32dc83", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_abort": "c26116210a8e29082af3e31d4a83d827e4e17e2529d08d916d6b6121f17367da", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_extra_share_entered": "7f04c785898166303b476e30d84b13600803dd6f891252213f8b4dc53ed136b4", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_group_threshold_reached": "b2d38ea370744279bea2d0af07747af3accff17146c6b49ddbe880c646c39af9", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_noabort": "6ccb5a863a3854c6be77b6ec73a3ba6ee2d1b167914dd1f08be804cbaff7aeaa", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_same_share": "655f3e6cc4990ed2030c2671f6bec7cfa12d4bff8520125a5cc8d39fdbb52ba4", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f1-afc2dad5": "187a8d1dec2667cd3da21f7991cff6e42e51859b5dd555f3db0bf5a54816dede", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0-eb47093e": "e4dce9350e2bfc3d9d751f004a2dfd29bac5e6d4c51ef5a134031f00bb8e65f9", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "187a8d1dec2667cd3da21f7991cff6e42e51859b5dd555f3db0bf5a54816dede", +"TR_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "e4dce9350e2bfc3d9d751f004a2dfd29bac5e6d4c51ef5a134031f00bb8e65f9", "TR_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_dryrun": "3affc49082ec5367c7f42c43a5e8c68250a1d571cefa9188bca2d1517e19bdea", "TR_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_invalid_seed_dryrun": "11987689382f662d2396f8922715deaab6137e24962b784291c7c7036a9f805e", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_1of1": "c480a224aff42dae251df728fb5aac04b1343d83a7bccb98d2d4decfbd754de5", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_abort": "a8c811cb3e7212b7c2861d2368c1b1acc7ce829e4868619616beee29b7892127", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_invalid_mnemonic_first_share": "e243e6497d0696db75b738f57d7d75944975b0db88e2112e3015159424abfdca", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_invalid_mnemonic_second_share": "53bb5232904a139e17b5fb607caa001517c875eedb224fa9e3d8a0da2c69b4e1", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_noabort": "d2d74417bcd5d91fd462c26fbae4d0685af2b2de777d75dd74be24ffa6fcc39b", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_recover_with_pin_passphrase": "f36eb235bf19d67640c13e2e6c906c9cdaa37740d4dde1aa6497c1b9a68d16c7", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_same_share": "b52bed9247f81ac37e2db84be9ac028ca3f917360f5c949c17bbac5fd608b65c", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "0afe6419c06b39886311f261655dd72aa1cb047762fc61445ceeca642dc54132", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39-a50896b7": "b7152a44a816365ad0493622aa4efca2955e8d63a44b818b13c012cbe49e5b2f", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "49e6e654050fdd686bbcbecd5840c7d349ac25dd894d34f1c466ea78bf28fe41", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "134948ac8508ddf43c192c359a37d9f9f863c63d5cf2847606e0a0c34d4af452", -"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "2f60fef7bcbd7e278f0c930cca667641e1c37d628e930bbe8b4f7dbde6346402", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_1of1": "403ccf4b8ddb53d06ac072bdb332e58498e1ba912ac463d3fe365b50b0737fbe", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_abort": "c26116210a8e29082af3e31d4a83d827e4e17e2529d08d916d6b6121f17367da", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_invalid_mnemonic_first_share": "98065945e7b7d2e2b4672e8cf999a258c77d9687d421c5f23afbec54be40cfee", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_invalid_mnemonic_second_share": "1c4d718683ddc95ac7636d840cc2975db56c4cff9745339916147008f9c542c2", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_noabort": "609016911b23dccc350f849c08cd2e9ed35855bbb983e5199b8ef6e95d442c42", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_recover_with_pin_passphrase": "51daf0b58612f5deae0f17091e39a88833b5d22e4569b5a7769b612afdbadc9a", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_same_share": "27044c39ba69478cd83dc50bd04a7e867977bdd23c1ab54a50858ebf1bbcadbe", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares0-491b795b80fc21ccdf466c0fbc98c8fc]": "14e7dd8bab8cd95578e198ce1a7ec2b3f89c321e29ec62856a6906993fbf85c3", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_secret[shares1-b770e0da1363247652de97a39-a50896b7": "8d028384ab19c720cadd6a24ec98e06232823aa38468214bcf782e6b61ee9944", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[0]": "454ebf6bba3b2dde05e7edbe005b90c5976dfb71655bbf28952b1bfd84bafe2f", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[1]": "96b4cc1cfbee92e5b3e1f455cbd0a4cfb86ed3e877fa157a47b373c73e7530de", +"TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "92606a46453e87a9c59a89e76568c9aad3009d4f0d15aa53cafd0eeb92885a2a", "TR_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_dryrun": "95aa55b8fc244bb61c60e602683570711b95f829587e4da469f229cac53a99f7", "TR_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_invalid_seed_dryrun": "31665a411ee0d7da0f5577a349224ee2a285b34fce5519923bc09e918aed27dc", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "e3ee4678a1c2648d32e431aec0e0f976b2d5ccf2e1b5ebce5201b0d2c88305ed", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "a58494da757ff1e4c805f6a4f932c0600c90dacaf1d062d97c28ab709d5c2591", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "9a3723028445870ac7c0624d55316b4aac86813bd68cbb9f5d3f400e92f39a49", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "00e02c1a0a300a699d386f2797bd4ac815149312bfc69fe42a44489feaddd857", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "69bfa27634aae02bdb2241f47dbcfbc066b34eec7a257a3a2ba5a250e677af6d", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "5c3c3f2a122b77e8e9412b89afd5126862dc42b50898311d979c58b90b0c4755", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "f60a5c63c74cafbfda26817acf3a409e05cb3746b916565f3510569754f579a0", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "6d270737f23bd05874d9a7a7234f42fb5e0cec3769dee0186c3337c7c78b79a8", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "809e150906fc39a019d96c88107032ab36a02796ebe6fb5c05075530a1109f60", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "fd5655cdfe6e76fd15ef57712c4ba0439ce20ef37f4ce0e540c1109f924e084c", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "a485b1ec23a04252daf716bde35a344984e538b297d86edd85a2ad30ed3e3a0a", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "ce97ecddf443af2f99d4de0403ad83f4db1d9b3db9c0f58cc429d68165785212", "TR_reset_recovery-test_reset_bip39_t2.py::test_already_initialized": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_reset_recovery-test_reset_bip39_t2.py::test_failed_pin": "fc66c325bc7946c94749f5e230a7b3ffad7b205612996ef1b1b124a95847c8d5", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "6dd07cb167527597d646d0659b2d965c41d8a3b01b694d9d3023362294719d56", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "37457698356b0c02f5bc776ada65dc0d69293dede95d037291cb75cb0b77babc", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "d37df00417bb294c8d993504e28c6c5bf5cfa9631764914d8f00e97968d9650d", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "5eb9c8508e023ef83facfd19d4b5ff2ea338b2c4db4ff9706d8984ff716b967e", -"TR_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "77206bb1ce375bf015aa497ffb2ef718936f9e6df67063892e667ec146ac0213", -"TR_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "bfaca69596327be5acb8dcb27e41d7ece9a2d99a3b665a2fe8741102cbac40af", -"TR_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "7c953ee37e040fa2f98ee73bf7d098c86c71302dbdf3fff6eb1f75c057fc8fc7", -"TR_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "dd833be82fd81ca7e7c40bcb3360d46b6c1b0d3202c472ca9def22ce392016fc", -"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "f27baaf1aa7c06878494686955d03bb533786dd6526c665f852a0069c12d2cea", -"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "2097fd90c1b6717b6991b14b053ac513466b9f47bad70aebb13e93bce8a79c59", +"TR_reset_recovery-test_reset_bip39_t2.py::test_failed_pin": "6b4f02ba25b4199d426a8238bb28fff6bfbeabe1f921352a19b3d651921a4b2b", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "ca712743e8937bc7db6265810964d20d292f8166315fd9c30c9a3b5ae82ab6c9", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "189b6effb1666f250bec4813028f8af24407c08e6be14287dca563db1c04afd6", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "b236293539ac37adb87fb07bfa6de5b4079ded32c437eb79f3fa58fd73a781bd", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "e3f1151b8480d47c00d10073fab067096f252a7982abe828f3208efb2aa6220b", +"TR_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "daccf2d9264bd4776a9d2201494e5b41f2960ad7ceaa5090eabe640009af88eb", +"TR_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "29c42c776be9cdba7a47a4df4454480e0fce21131692d4ebdd9d1ac2d343380a", +"TR_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "d6c56240ad61f1aeaf28c5de0aafa2970bbb37a7b55d01890a4fcd3dbb1db633", +"TR_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "19492556256195acbab3865f663cb3127d1bfb8a7d27b2000b870d082f8575a3", +"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "e79608b2335fba3da5b52a896e4ce0095acb5305688993617e09329b8220087b", +"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "a573066d7bedd8318c412de713743bdf3ac50775a634c7ee55435fd37e3a2987", "TR_ripple-test_get_address.py::test_ripple_get_address": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ripple-test_get_address.py::test_ripple_get_address_other": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ripple-test_sign_tx.py::test_ripple_sign_invalid_fee": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_ripple-test_sign_tx.py::test_ripple_sign_simple_tx": "6d7afc8ffe32ffcc748b187744e045257bf4369500546ec75ca00d1eaa5ee977", -"TR_stellar-test_stellar.py::test_get_address[parameters0-result0]": "dba5b9ede41b872917a8569d5bb0a3efe8a70cdca89f10764f5a15a8183ba151", -"TR_stellar-test_stellar.py::test_get_address[parameters1-result1]": "45aadb9dc6d7e19b57506c1029272b00f7dfae901b1e27ed1d3ead41c4f5d961", -"TR_stellar-test_stellar.py::test_get_address[parameters2-result2]": "adbb7796c4a84e6e27f474d0c9afe74cfeef02179f2dcb366a8cad4f8bb64a9c", -"TR_stellar-test_stellar.py::test_get_address[parameters3-result3]": "02f94b0a1e372a6067162ab472a7721945d4913f15c89e09dc822931d75c1cc3", -"TR_stellar-test_stellar.py::test_get_address[parameters4-result4]": "da50f4f24d273a86f9673e5af532e9d0b01e287efbda6c73475127836a13b17a", -"TR_stellar-test_stellar.py::test_get_address[parameters5-result5]": "2300b28afebf1dd39a0d306f27c99e110f45288004351b455166a2461be1ee6d", -"TR_stellar-test_stellar.py::test_get_address[parameters6-result6]": "2791c560c4d286fc8c529eb7a742e0773b9920d582eeac6730456541d3b1a84f", -"TR_stellar-test_stellar.py::test_get_address[parameters7-result7]": "57e31649c44710949630ac3e4394d89dedf25b50a28a35809f0d85c8a70dc44a", -"TR_stellar-test_stellar.py::test_get_address[parameters8-result8]": "49429f86bce80c12374cbbfbffaeed3f2bd60dddbf0f718018cf723a22fbeb18", -"TR_stellar-test_stellar.py::test_get_address[parameters9-result9]": "9c46602ecc768047bbc34b35c62c7bfcaf2a2b0a223b33c12df3f0fd00bfda27", -"TR_stellar-test_stellar.py::test_sign_tx[StellarAccountMergeOp]": "cff7cafef3b1f6455ed04f9ffc519926fa4049cc579e0198f5f8f7dcfc6d97fc", -"TR_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-allow]": "4dee7de858d9b03f77f4df14efe6054ec3a75f2daf2c7759f4a87816bc81430c", -"TR_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-revoke]": "80f05c884c53980ec172b61360cea501198211bd1403df716e77e9e59a73ec26", -"TR_stellar-test_stellar.py::test_sign_tx[StellarBumpSequenceOp]": "8b8239a73677525ef8d30dce1fffbbe090fe1ac3a18647656523b84475855005", -"TR_stellar-test_stellar.py::test_sign_tx[StellarChangeTrustOp-add]": "6d2641238fc47c3acc71f320d1d93c45543a1c0c6224cf3e8f7f693a67a23b16", -"TR_stellar-test_stellar.py::test_sign_tx[StellarChangeTrustOp-delete]": "e7f5b99017853204b4545160834e664d9980e9fba4f351e00cf885a427fd07b8", -"TR_stellar-test_stellar.py::test_sign_tx[StellarCreateAccountOp]": "4e9fc9fc8dc0ed307ed2d0a1c18b2b79f5276cb2f8379ce1b20438120136c9a9", -"TR_stellar-test_stellar.py::test_sign_tx[StellarCreatePassiveSellOfferOp]": "a59d1a8576c5dd7166fb0efb9db283b8781d6475c59433f2d262a468f9ff22a1", -"TR_stellar-test_stellar.py::test_sign_tx[StellarManageBuyOfferOp]": "1b45b88314fdc36b45951285f8e52b2cb9c9987c481d865d3c684d2eca978791", -"TR_stellar-test_stellar.py::test_sign_tx[StellarManageDataOp]": "d6a121bf2bd93f6035b3a62785bc05d366b75d96476c997bd9a88c61ccd048a1", -"TR_stellar-test_stellar.py::test_sign_tx[StellarManageSellOfferOp]": "07a499c851b4df95a038a284c0c2c1d9108f23a542bb302d8166cd64b65af887", -"TR_stellar-test_stellar.py::test_sign_tx[StellarPathPaymentStrictReceiveOp]": "ae66c68aa0adfd6bb75d3232286076b9f69163809906f4c0b8512e39b7395026", -"TR_stellar-test_stellar.py::test_sign_tx[StellarPathPaymentStrictSendOp]": "be89044e595320409ec54943af68597b61ec5d875fdd7d1d7f34f35419eb1729", -"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-asset12]": "a3f035dffec3d323003e67e778e5483e09045c0a6fb4f9c176690775a928067e", -"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-asset4]": "388f463a894d9c7550f906b8d90e9ed249d41fde96e7fee2bb58757039d00a3e", -"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-native_asset]": "8fcc98ebb2f76f36f85c313131478d29b3b2ba79e2ef5993afa3cb7a663ed63a", -"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-all]": "a8d286bb1363d42e02a3131bb447ea0935efdf007a1f921d9bc381305b2dabe6", -"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-one]": "dadc1839652243ba9a07da4cd139775bba4707df9ae2236f842d40f205df0d6b", -"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-some]": "5302436b26657e8169841f06c45c64e694b165520279a701579c93431ea5c8ae", -"TR_stellar-test_stellar.py::test_sign_tx[memo_hash]": "cb9c889941871587d40d813bae9290a9fb34bb9ccd931797e3b8a90389eba19b", -"TR_stellar-test_stellar.py::test_sign_tx[memo_id]": "5e2c6e94c2f7aad30059b03f18d0504997d600e71f063aa7547ba48d8ee6e172", -"TR_stellar-test_stellar.py::test_sign_tx[memo_return]": "fac4342cb0659a07eac5a39aa33157bbf638045351cb90b36136e09aa8d0ed32", -"TR_stellar-test_stellar.py::test_sign_tx[memo_text]": "c0bf6bb8bdd922c3610c0fdc089e1c8c92e285a879fe2fd5f118fc8b87aa46c6", -"TR_stellar-test_stellar.py::test_sign_tx[multiple_operations]": "2c87f966328fc94142f2070ae145b2b6ccedec6557935604400137aaaed93cac", -"TR_stellar-test_stellar.py::test_sign_tx[source_account]": "8fcc98ebb2f76f36f85c313131478d29b3b2ba79e2ef5993afa3cb7a663ed63a", -"TR_stellar-test_stellar.py::test_sign_tx[timebounds-0-0]": "611d903bea8b14c03b8b6c5ec5f15608cbd1414918e2fe7386cb3b97a959af13", -"TR_stellar-test_stellar.py::test_sign_tx[timebounds-0-1575234180]": "9e1f884816d80415ef9b925309d5502852d8bade9c632f2d715d0a2cdecb1204", -"TR_stellar-test_stellar.py::test_sign_tx[timebounds-461535181-0]": "afc84260d5f7991a516ead25a0f77c34ec14ef2b3de3595adc1c50624657ac0a", -"TR_stellar-test_stellar.py::test_sign_tx[timebounds-461535181-1575234180]": "8fcc98ebb2f76f36f85c313131478d29b3b2ba79e2ef5993afa3cb7a663ed63a", +"TR_ripple-test_sign_tx.py::test_ripple_sign_simple_tx[False]": "7383acfb8949590b431a68bf2123dd0fb17a13f710482b7752d5d6813037a6fe", +"TR_ripple-test_sign_tx.py::test_ripple_sign_simple_tx[True]": "8d92fabc456bb0d415502717b72a4c1b5bd35e81aff6477f1c806085eddf8838", +"TR_stellar-test_stellar.py::test_get_address[parameters0-result0-False]": "a51c73cc8ece1c6a08b6e8f468b87c3359855ac0cac91a66135c23cd40f4f1c1", +"TR_stellar-test_stellar.py::test_get_address[parameters0-result0-True]": "518064d22dcd4c9d44bd8525f73c41bf286dedad34e017779993039906623f30", +"TR_stellar-test_stellar.py::test_get_address[parameters1-result1-False]": "5419443adc3e8a47224d4373f811f12b27a222db7fb2370752ef03bf0a6c32db", +"TR_stellar-test_stellar.py::test_get_address[parameters1-result1-True]": "d927bea397d8e3bed5470bb6ad7930b0b97edb93c2aaeefc275052d6a18c9df2", +"TR_stellar-test_stellar.py::test_get_address[parameters2-result2-False]": "a59a558f1fbcd9bcb864821e1b8ecc6f18bc3a89b8644308171cd930b6dd60ad", +"TR_stellar-test_stellar.py::test_get_address[parameters2-result2-True]": "d4269a13986cc4d1e9cdd73c29324fb7d4153bcd4ad6772e68ce54c5d00c1492", +"TR_stellar-test_stellar.py::test_get_address[parameters3-result3-False]": "279327ef14da3d020f1845080500e81b725d33fc8917816b51082c08114945fb", +"TR_stellar-test_stellar.py::test_get_address[parameters3-result3-True]": "743018e4a3642dce1bde0210a796470832f6fb57bcdc2d29de209757739a04a4", +"TR_stellar-test_stellar.py::test_get_address[parameters4-result4-False]": "504e5389b8dd90569c98bd82f272b6cb054a4db304b1b7eee3787ea1871fb4fd", +"TR_stellar-test_stellar.py::test_get_address[parameters4-result4-True]": "17d508051372c722e4d5b3daf08bec1d4dc99ab4379c733e5e86aac3041029b2", +"TR_stellar-test_stellar.py::test_get_address[parameters5-result5-False]": "a2ec934904ad1bbe660d61d8fce3c4216f8aad49c9746d1a3346f8a3c63a9e55", +"TR_stellar-test_stellar.py::test_get_address[parameters5-result5-True]": "db14832d3b4ef5942ca4098d74df3d7e744cc519e6ac9cabda4c840908fe6aa6", +"TR_stellar-test_stellar.py::test_get_address[parameters6-result6-False]": "a4c0268d4891f2c2eb52c0f592416c448baa3fc9dc06aeb6fe19d15cdc891bfe", +"TR_stellar-test_stellar.py::test_get_address[parameters6-result6-True]": "d250db6cf4d8862cc635ffb557650c8d877c21d6cc15b2ac92885d66b8cf562f", +"TR_stellar-test_stellar.py::test_get_address[parameters7-result7-False]": "59e76f0a9bb858cc93195eca4b37ff83b307e938667f1bb7224ec915cbeecf7f", +"TR_stellar-test_stellar.py::test_get_address[parameters7-result7-True]": "2ea8c2922e0adc4bba7a74bb136ccc91d4869184a84b0d5d82749ce5c44efc12", +"TR_stellar-test_stellar.py::test_get_address[parameters8-result8-False]": "12726f0c084791d92f195bbcec3761dfe19fac3dfb1cdff9ffd1f2b89df5feaf", +"TR_stellar-test_stellar.py::test_get_address[parameters8-result8-True]": "1fa02b0423d657b25fb746cc027ec8cedba6adea86d4f1e7ae1078a7eb3679ac", +"TR_stellar-test_stellar.py::test_get_address[parameters9-result9-False]": "d5b83b62c09cf2ada5b041067f1fccbdde59bef91cae076ed56ed279421445d2", +"TR_stellar-test_stellar.py::test_get_address[parameters9-result9-True]": "febecc97aaac472b639e1f582e5c93d05ef06d61c4e578709dd531fa46195afb", +"TR_stellar-test_stellar.py::test_sign_tx[StellarAccountMergeOp]": "e4fed0b02519238c7c2f7d05068216e1606d238dccf27ae2d38d8437b5d997ed", +"TR_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-allow]": "b045920ccae0e77274e81fc2aed0e93df4e01904be91484e3e9c968e17b66d43", +"TR_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-revoke]": "46d1991bb7234cce12610963c340d00cd29e9b4298c64f867a6ad33890b6c201", +"TR_stellar-test_stellar.py::test_sign_tx[StellarBumpSequenceOp]": "d858d4763f7f7495826f9e857594f734e6df9f311d530cad94a4215042272c19", +"TR_stellar-test_stellar.py::test_sign_tx[StellarChangeTrustOp-add]": "0b25e6027eabedf70a5b134dd539a2ec733ea5b9f8f2ce71930a70e95fd8bcde", +"TR_stellar-test_stellar.py::test_sign_tx[StellarChangeTrustOp-delete]": "ee3abc50fb93723ca3a0ec923e3047bf86b7c79030e04f98af7b19d9941894d4", +"TR_stellar-test_stellar.py::test_sign_tx[StellarCreateAccountOp]": "831967a4f3ea35c3a9cf4ac42643049ac330714ad0c0098c658a374e65995972", +"TR_stellar-test_stellar.py::test_sign_tx[StellarCreatePassiveSellOfferOp]": "2391c75e6cce0854be647cdde3a016ef8211ab633c2c10f75ba9b71cfab402f7", +"TR_stellar-test_stellar.py::test_sign_tx[StellarManageBuyOfferOp]": "0565aa885c5b90f30c11b465acd05ca2ecca6ca2ce0a20a41a116c0c32c3d46e", +"TR_stellar-test_stellar.py::test_sign_tx[StellarManageDataOp]": "7be1a0d8a19a8f0bbed5936b4b3a9d9c03b7fb8225d7db77cb3d8264f38af74f", +"TR_stellar-test_stellar.py::test_sign_tx[StellarManageSellOfferOp]": "6062bd66eb6b710f0089b77bcdba3c44483d8b3d4b3899793dd7c305a16e4908", +"TR_stellar-test_stellar.py::test_sign_tx[StellarPathPaymentStrictReceiveOp]": "30a2bb6ad3ea09ca892e71c3d65792efbfda739807fd9a06f1cbb39a5acfe1fa", +"TR_stellar-test_stellar.py::test_sign_tx[StellarPathPaymentStrictSendOp]": "c0b32fff6282a5babd82d9cb39383d1b1365b09d7e1bfb378c18f1eaa42e49a7", +"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-asset12]": "83179eae59f916ba9af63f02285dc4a30682f221beab9084c435f13709dad007", +"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-asset4]": "85fac4dae2487870099fa1a900e6c6bc3b852bb84ad648f72c082f19dbefa2ae", +"TR_stellar-test_stellar.py::test_sign_tx[StellarPaymentOp-native_asset]": "5eeb4f1a916917254ce5101f79ae3373cff911af730f6c747a5b500e9b57dbe2", +"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-all]": "b93ee6231073de81a964c3c3e67813b547386b34359c492872b4565d5d4c5ea5", +"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-one]": "15c0ec0a7eb5a2ac556d960febbcb551a7d98dba2659054c10f2acbf22df0b0c", +"TR_stellar-test_stellar.py::test_sign_tx[StellarSetOptionsOp-some]": "f3f9de1a619973aeeaa32a0d93ffbaa1fbb85de6c75ad76066d9d2fdb0c730b5", +"TR_stellar-test_stellar.py::test_sign_tx[memo_hash]": "479bf654820d87648baaeed429a921afb4d3695b3085bd9476238238942018f5", +"TR_stellar-test_stellar.py::test_sign_tx[memo_id]": "5940044c11dbfd40e6e77dd94356a8f9114645e34d590c878ac910fe510ac371", +"TR_stellar-test_stellar.py::test_sign_tx[memo_return]": "dd305531a9028d081895ad3d2ea494a6a95fba88761dd7e4ad96a6a01d954e4c", +"TR_stellar-test_stellar.py::test_sign_tx[memo_text]": "53caa36880b58a15a5e685b76e9d6f4c341c96b1310abe21936d627e57d51bdc", +"TR_stellar-test_stellar.py::test_sign_tx[multiple_operations]": "3daf5fc59a2f96425c563aabec0081c938897e71c102ce25bda2d5b18a4f853a", +"TR_stellar-test_stellar.py::test_sign_tx[source_account]": "5eeb4f1a916917254ce5101f79ae3373cff911af730f6c747a5b500e9b57dbe2", +"TR_stellar-test_stellar.py::test_sign_tx[timebounds-0-0]": "cb72ecc54637d99c1edb9900729eff41ad905edf89ba028acec669bc866e897d", +"TR_stellar-test_stellar.py::test_sign_tx[timebounds-0-1575234180]": "7817a269861798cefc7fb4c8ea1ed41a2744b134acdfe984ae6305a2aa412e2c", +"TR_stellar-test_stellar.py::test_sign_tx[timebounds-461535181-0]": "abeda9596289524ad296d3405af4e2bd683d054e1ad536dd5fc04e57b1a6a8d1", +"TR_stellar-test_stellar.py::test_sign_tx[timebounds-461535181-1575234180]": "5eeb4f1a916917254ce5101f79ae3373cff911af730f6c747a5b500e9b57dbe2", +"TR_test_authenticate_device.py::test_authenticate_device[!\\xf3\\xd4\\x0ec\\xc3\\x04\\xd01-b\\xeb\\x82-e4b4eb3a": "5bbde07a26ce37bd72d0c792c4dc9807c169c9fc731d1bcf30a72a5f2da7f602", +"TR_test_authenticate_device.py::test_authenticate_device[\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\-d824e03c": "5bbde07a26ce37bd72d0c792c4dc9807c169c9fc731d1bcf30a72a5f2da7f602", +"TR_test_authenticate_device.py::test_authenticate_device[]": "5bbde07a26ce37bd72d0c792c4dc9807c169c9fc731d1bcf30a72a5f2da7f602", +"TR_test_authenticate_device.py::test_authenticate_device[hello world]": "5bbde07a26ce37bd72d0c792c4dc9807c169c9fc731d1bcf30a72a5f2da7f602", "TR_test_autolock.py::test_apply_auto_lock_delay": "cf93576944395035a45cf62f4b4b22387c595af7646e1863b07bdcc38ccfbb20", "TR_test_autolock.py::test_apply_auto_lock_delay_out_of_range[0]": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", "TR_test_autolock.py::test_apply_auto_lock_delay_out_of_range[1]": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", @@ -1760,27 +1882,27 @@ "TR_test_autolock.py::test_apply_auto_lock_delay_valid[536870]": "99ab9324e9f4301093f70c6c2e13e200c1b012a0a99fc935583d5eceebf6308f", "TR_test_autolock.py::test_apply_auto_lock_delay_valid[60]": "c5cf5b97dd7c15263ec70a377abd0864016532d7330b3a500b2ebb7a2c99bfd5", "TR_test_autolock.py::test_apply_auto_lock_delay_valid[7227]": "7688e81b6c319c61efb123ea22627a8503694733719fd6f7fb366ae9d031ff40", -"TR_test_autolock.py::test_autolock_cancels_ui": "de4a732820b7ab83ff7cfbd38cbcb24683312be3046ca63d1e43ae68e920ff85", +"TR_test_autolock.py::test_autolock_cancels_ui": "22d2113711f0eeb2b62550fb3134654fa2a605c54e37bbf658b13e8823f24086", "TR_test_autolock.py::test_autolock_default_value": "35cae6c0efc6345d2211c4373a35931a2f539e203ebaa925f2ea8e4bb1bc38a3", "TR_test_autolock.py::test_autolock_ignores_getaddress": "94b6e38aa1632c0b2a308f2ca207573cb1fcf12d1c155702135601124e9acaeb", "TR_test_autolock.py::test_autolock_ignores_initialize": "94b6e38aa1632c0b2a308f2ca207573cb1fcf12d1c155702135601124e9acaeb", -"TR_test_basic.py::test_device_id_different": "19ec0c8c46ee06bf9c6dc371a8ee73f2481eb5e2e352c2088dcec9272154d9a2", +"TR_test_basic.py::test_device_id_different": "683be74c1a68c2209b23964672b8a31a33874bf5abc2ccd3ae4caa57e252da81", "TR_test_basic.py::test_device_id_same": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_basic.py::test_features": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_basic.py::test_ping": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_busy_state.py::test_busy_expiry": "0cff54da20c3c70d5b5de75a45fc265b29683fe322ad498f947656118691eeca", -"TR_test_busy_state.py::test_busy_state": "aef28ce4a477195a1cd6069886033089d32438d06506361c15556c2ea3a6d288", +"TR_test_busy_state.py::test_busy_state": "ada5d30fba85b36abb7e25feb2499c62a19f93fa4a4334d04e3710281989c468", "TR_test_cancel.py::test_cancel_message_via_cancel[message0]": "41b9fc37f230520f9d94df226ff8433822e56ea4276a31ef99171a774e477045", "TR_test_cancel.py::test_cancel_message_via_cancel[message1]": "41b9fc37f230520f9d94df226ff8433822e56ea4276a31ef99171a774e477045", "TR_test_cancel.py::test_cancel_message_via_initialize[message0]": "41b9fc37f230520f9d94df226ff8433822e56ea4276a31ef99171a774e477045", "TR_test_cancel.py::test_cancel_message_via_initialize[message1]": "41b9fc37f230520f9d94df226ff8433822e56ea4276a31ef99171a774e477045", -"TR_test_cancel.py::test_cancel_on_paginated": "51f3c59cbd02e2b33755f2a206ae7530d7cc71d77b7b00cd6678aa7017330b5a", -"TR_test_debuglink.py::test_softlock_instability": "81177df2e7b47eebe9a23302df309080b9e4446edaf28e509cc0e59c39039a8b", +"TR_test_cancel.py::test_cancel_on_paginated": "549ab6992c508aa9cba424f6fc8949251f62648086b3074123c8cc82c4c020c6", +"TR_test_debuglink.py::test_softlock_instability": "1ce6f0c2814df27dbfa3944c4a672930744ea24ed7c75cdd9068570af7382d87", "TR_test_firmware_hash.py::test_firmware_hash_emu": "5dde95f0c09df69cdb1e6017ff3269781e499f2c1894db677e1d06971e45d0a1", "TR_test_firmware_hash.py::test_firmware_hash_hw": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_good": "ce7dc5bf3592c2040ef0a7c8bae15a1589727591904224f97d4f65446a746fb9", -"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_with_long_label": "a080a99cc6e5bb0fe291e2fdfb09bcdeb3c9e5302e684612369e0e419bd9a4d0", -"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_with_notification": "6f24270ed7030d29f642af8cfe9f7db7fa0a18d70b434ae7a4f95111b2fd3cba", +"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_good": "e9f34b78baec1c795707976055b557dc305bf365838e771959f734aa077a8599", +"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_with_long_label": "120508dda15a2bc6f04a1475a92f7578f24a6f59f5958fe5f9126c9466494d60", +"TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_with_notification": "95b6d0dc21148165f2a2316cfaad56c867abe5da3a9b85303d4bdd3e162c68ea", "TR_test_msg_applysettings.py::test_apply_homescreen_tr_toif_wrong_size": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", "TR_test_msg_applysettings.py::test_apply_homescreen_tr_upload_jpeg_fail": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", "TR_test_msg_applysettings.py::test_apply_homescreen_tr_upload_t1_fail": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", @@ -1788,58 +1910,58 @@ "TR_test_msg_applysettings.py::test_apply_settings_passphrase": "59383a2f42beae71e56133ccd06e3ac877a83e8edf9ff21c78978dfba0df14ff", "TR_test_msg_applysettings.py::test_apply_settings_passphrase_on_device": "caf5f9733414c8edd4f13800250d7d3d0d3a4012844b826ed314db5c608508eb", "TR_test_msg_applysettings.py::test_apply_settings_rotation": "ee63171d986f52e01f1e7dcd8ac6c51fd7e6285182bb1ddca834f5bc394d0435", -"TR_test_msg_applysettings.py::test_experimental_features": "e7f978b1334fa84f7d114ee02860da71a1512ba7d9cb1e654ed3dcfbd0264161", +"TR_test_msg_applysettings.py::test_experimental_features": "ff01a9d9dafdb8f92372f414b653cc25418b8ad831ed1c9792429f2b515f28c0", "TR_test_msg_applysettings.py::test_label_too_long": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", -"TR_test_msg_applysettings.py::test_safety_checks": "685ae5d7ec34611cf5c1b8b68a5ed408af15ea72ee79bad82d68b82c5c22e4f9", -"TR_test_msg_backup_device.py::test_backup_bip39": "9dd2dc8aed69e5220ae4237eca67775fc9948a106fbe7790c9e80d79e7ecbb52", +"TR_test_msg_applysettings.py::test_safety_checks": "83080cba06af0a9c47ff0316a38096a17d21fcd7034b7878db9b4e6f9c01ad06", +"TR_test_msg_backup_device.py::test_backup_bip39": "a765ee7fbf3e763d7fbfee248d7afe159e1986975e1d94635a50631828e6695b", "TR_test_msg_backup_device.py::test_backup_slip39_advanced[click_info]": "b6e34f1ccd560f41f3b33b4755e900089797898a66c8fdfd28d9f61274e873f4", -"TR_test_msg_backup_device.py::test_backup_slip39_advanced[no_click_info]": "c7d532ba90b235077740275d22facfc36ee71a7e5f91948236968b5da355172a", +"TR_test_msg_backup_device.py::test_backup_slip39_advanced[no_click_info]": "d03ec76ae176f4a7dfd3f4df83fdecd8dfd1ef29bec85e5c21e3ec97937b970b", "TR_test_msg_backup_device.py::test_backup_slip39_basic[click_info]": "b6e34f1ccd560f41f3b33b4755e900089797898a66c8fdfd28d9f61274e873f4", -"TR_test_msg_backup_device.py::test_backup_slip39_basic[no_click_info]": "b157b37225edb3d03671342f0018b517cccd92875ad28e083494b392a30215be", +"TR_test_msg_backup_device.py::test_backup_slip39_basic[no_click_info]": "9df6f18e33ff9412f0817dc2f0da2b96b1df4fed0252fbe09e1ee0f521dcba47", "TR_test_msg_backup_device.py::test_interrupt_backup_fails": "1139f673473fbf725b2ee52d4965917c6a72676e69b073707f40b556a48f4b79", "TR_test_msg_backup_device.py::test_no_backup_fails": "60c13acb4f8e40ee32f9d01415cbcbd75ffcd6a4015003d93562e84c3901a62f", "TR_test_msg_backup_device.py::test_no_backup_show_entropy_fails": "f49c8d846c2d56a575f0ad49463845ba641b02656783e4fcfc67d74e8fa671dd", -"TR_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "16b746a8c8ea21e7f33b79154cc4f6b1f6e796e2fe17886216faca181e58d211", -"TR_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "37e76eadf4421f76c5004dc53d0d77f95890770b6ac37a078ec45b85d20dfb8c", +"TR_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "90fd42f84ed0cd8a063233b4374b31b8a5a5b5cac790279eb99c26d7665e61b8", +"TR_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "fba90617dfb73988372c4e0791b64806f772378a1976cb77b8ea44f6753bf450", "TR_test_msg_change_wipe_code_t2.py::test_set_wipe_code_mismatch": "13823d892a0783ce247b3c3a807268475fe5598d7532a3d7255d33367163f7fb", -"TR_test_msg_change_wipe_code_t2.py::test_set_wipe_code_to_pin": "4525b8ba8cbddf0e6faa80fbd839a27fc5906e7d3828df8903e8eeae54961b07", +"TR_test_msg_change_wipe_code_t2.py::test_set_wipe_code_to_pin": "49ad6f7ad942fcc37ed219d2032de24eaab868eb255e855b72c82afd4522957c", "TR_test_msg_changepin_t2.py::test_change_failed": "80ada7c8760bcb529fdb59f089b16c0534d0cf1d28ae7cfd2b8b8187ea78ba29", -"TR_test_msg_changepin_t2.py::test_change_invalid_current": "22df08c2f751a506af094050d3aa2f3961079ebbecfad494bd8229c8a321197b", +"TR_test_msg_changepin_t2.py::test_change_invalid_current": "db8592d6da407ce46d41a2507ae9ad405d7476302a921b50049a3f89489fc98b", "TR_test_msg_changepin_t2.py::test_change_pin": "2d0eb7c4b71f5e888917e46dbb6f22abf3f2d5015da07ad1e82aaf5fc8b1211e", "TR_test_msg_changepin_t2.py::test_remove_pin": "e2c941bc00679380380e9264481efcfb2cfa825829cd1b043d75c47a995d8fee", -"TR_test_msg_changepin_t2.py::test_set_failed": "98a9a0bab74e2b9a10476df9bf2668e53d10dea1f4e699faf48a6d086a7edeae", -"TR_test_msg_changepin_t2.py::test_set_pin": "d5f0790eb06762ed1d7055721af5a3b8b670d4160143edec6622e73b88dd1605", -"TR_test_msg_loaddevice.py::test_load_device_1": "5f9b92022d2271d39f7dde5f7364b6eaf1d6f9e810bae783d66801421fca5698", -"TR_test_msg_loaddevice.py::test_load_device_2": "fae495b8ca84136f14eb6ce4c218a5f34bb0cf92497fb84f7176d3a6d452c82b", -"TR_test_msg_loaddevice.py::test_load_device_slip39_advanced": "5f9b92022d2271d39f7dde5f7364b6eaf1d6f9e810bae783d66801421fca5698", -"TR_test_msg_loaddevice.py::test_load_device_slip39_basic": "5f9b92022d2271d39f7dde5f7364b6eaf1d6f9e810bae783d66801421fca5698", -"TR_test_msg_loaddevice.py::test_load_device_utf": "116244c4eb27c37358a999eb18654a1b6bf4e3b89d7cc92c7b440b9104b2be43", +"TR_test_msg_changepin_t2.py::test_set_failed": "4d29ed842ceb69edae7dc48b02d6ce17867e9b4301b91a2dac27b5822a3adbfb", +"TR_test_msg_changepin_t2.py::test_set_pin": "61e4e39b7e0c1b8a7e08335a8b951abdfcfbbf1469d77e6decad1254b7bba650", +"TR_test_msg_loaddevice.py::test_load_device_1": "8423fca7398f0399843c8f28ae8422bc4f7154420e26bc2fe1b8933eb2d1d4cf", +"TR_test_msg_loaddevice.py::test_load_device_2": "b7b56fdb5978b4ab792f3e05778b0f72dfff68ce8128b718fa727555c323ec03", +"TR_test_msg_loaddevice.py::test_load_device_slip39_advanced": "8423fca7398f0399843c8f28ae8422bc4f7154420e26bc2fe1b8933eb2d1d4cf", +"TR_test_msg_loaddevice.py::test_load_device_slip39_basic": "8423fca7398f0399843c8f28ae8422bc4f7154420e26bc2fe1b8933eb2d1d4cf", +"TR_test_msg_loaddevice.py::test_load_device_utf": "f415a91b67787a265270fecbb01f3bb75daf6e72638f25a6f522ca4c66e153b9", "TR_test_msg_ping.py::test_ping": "4ffbed72e7ed7fbab85f830952200adf7758af81b658b56de4672344120456a6", -"TR_test_msg_wipedevice.py::test_autolock_not_retained": "51055d354b2d14f3e365f08ce08dfe43464e009f6ceee0dd60001217179cc57a", -"TR_test_msg_wipedevice.py::test_wipe_device": "19ec0c8c46ee06bf9c6dc371a8ee73f2481eb5e2e352c2088dcec9272154d9a2", +"TR_test_msg_wipedevice.py::test_autolock_not_retained": "0d6ac20e093c4eceb09ce0a53be10b36daa80fa72878089c0c12b5abc0949ead", +"TR_test_msg_wipedevice.py::test_wipe_device": "683be74c1a68c2209b23964672b8a31a33874bf5abc2ccd3ae4caa57e252da81", "TR_test_passphrase_slip39_advanced.py::test_128bit_passphrase": "0c1d2e8f1e4b43ee5071cf1d6e31c134297ba8315f1f4568765875438e7720f5", "TR_test_passphrase_slip39_advanced.py::test_256bit_passphrase": "0c1d2e8f1e4b43ee5071cf1d6e31c134297ba8315f1f4568765875438e7720f5", "TR_test_passphrase_slip39_basic.py::test_2of5_passphrase": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", "TR_test_passphrase_slip39_basic.py::test_3of6_passphrase": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", "TR_test_pin.py::test_correct_pin": "674ca13c50b342d80ca47ed49bcfaa846bb07db2ba30d6e1414c96db8375457b", -"TR_test_pin.py::test_exponential_backoff_t2": "37379ac1cf37f899d8920b0697bf33654394d23e50b36e5e8324d901888bbeb0", -"TR_test_pin.py::test_incorrect_pin_t2": "732d83881e4968a0e24d1346d1c4b9b7c7c2f3857585afc29a7bd745f9730a4e", +"TR_test_pin.py::test_exponential_backoff_t2": "9a97113901505dba735026399f2c0874ae965259ee719a344db5b994bbb7e625", +"TR_test_pin.py::test_incorrect_pin_t2": "b83df82840ebe780c4abe92c4a7cee106e2bf6ed308f4f79dfa9ea7eb0a1397f", "TR_test_pin.py::test_no_protection": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_protection_levels.py::test_apply_settings": "76d2aeb1881d7678828804f5d8ce09b106abd02272bdd5c1f41c58d86690c1be", "TR_test_protection_levels.py::test_change_pin_t2": "d7d219091c2ed484c8215304b6e247a34e1e52fc998da21823e75a2bb149bfcd", "TR_test_protection_levels.py::test_get_address": "ed15f789f1902f5805f37baaf21a1e36f664426358196bd61bd7b477a6bf11ee", -"TR_test_protection_levels.py::test_get_entropy": "8660fb737197cdf45868de8854a3c66eb58c960fb1f4cc4aa62698d7b6550f84", +"TR_test_protection_levels.py::test_get_entropy": "5b514ec018caf540032adb9c31246178550f1ef99f652cc9be5faf579b06182c", "TR_test_protection_levels.py::test_get_public_key": "ed15f789f1902f5805f37baaf21a1e36f664426358196bd61bd7b477a6bf11ee", "TR_test_protection_levels.py::test_initialize": "624bc73ef0907f9b7dbdd8d2177bddf9440f5d759c24f3eaf01c0f93a4980f6f", "TR_test_protection_levels.py::test_passphrase_cached": "5f2c9d15b92ca01e8c682408ddb8ec025aaeb54346a8c13d3bb9fafb682ec5df", "TR_test_protection_levels.py::test_passphrase_reporting[False]": "567264a37a2fd55ae2e90761260720f3b65a01cef700eb29143ede1804ca4cd2", "TR_test_protection_levels.py::test_passphrase_reporting[True]": "e5fd5ccf18e35cc8db539c4630c8df287484d437d9a42ff477b4cea458a1ee8b", "TR_test_protection_levels.py::test_ping": "4ffbed72e7ed7fbab85f830952200adf7758af81b658b56de4672344120456a6", -"TR_test_protection_levels.py::test_sign_message": "bce1cffe9abd181138bfd174a68a4220052ff6bcd29b472e3eb0dbe83b9c2e80", -"TR_test_protection_levels.py::test_signtx": "04369c2f6f065c8063b43a36b379e3faf0e02c02721c03bef63363ad3ab1502f", +"TR_test_protection_levels.py::test_sign_message": "553810318c5ef26d9caad8f6fee2a701119dd3d45815e62af08093434bccef49", +"TR_test_protection_levels.py::test_signtx": "0ac245609eab08e93bccf88ac339f75aa1de8937c1a2e04a6650c9a4dbcd2432", "TR_test_protection_levels.py::test_unlocked": "d3c3c239d8fcab02322f261a7786bbffa34812e84b773290b31eeaeb74d3f66b", -"TR_test_protection_levels.py::test_verify_message_t2": "58412cd225865f6e6536b7c31b5b684748f597f691f64998db2059d29f951dc3", -"TR_test_protection_levels.py::test_wipe_device": "9ecdac635f7652a13ed36b5f93c189eed0ae72d7b0f8aa8a83ca4cf38c94d1d2", +"TR_test_protection_levels.py::test_verify_message_t2": "cf6833187bbbb62020b48e3db706e50917303aeffc416b0634d110b35b46ee6f", +"TR_test_protection_levels.py::test_wipe_device": "ac946eafbd7c1942bef1349609d47eaaf7d23a995a9d539446ea7cd2c01d7267", "TR_test_session.py::test_cannot_resume_ended_session": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_session.py::test_clear_session": "88a216adced296d6623cf6b3d59b1844a6e19323723a453c2d6895a295ebd273", "TR_test_session.py::test_derive_cardano_empty_session": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1848,7 +1970,7 @@ "TR_test_session.py::test_end_session_only_current": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_test_session.py::test_session_recycling": "ed4af0c4901c1f682a4ab2f7f741721265a0829d6eac91b3696f6c2c58eb8b0d", "TR_test_session_id_and_passphrase.py::test_cardano_passphrase": "909cdb9d1b284fe0a1a0f4c0cc5ba25c0ede8ff77caf7a820b5b00f606299264", -"TR_test_session_id_and_passphrase.py::test_hide_passphrase_from_host": "34c7ae9cbdba3bb833a648eda41a65faee604c7f791740234c5d135587750f24", +"TR_test_session_id_and_passphrase.py::test_hide_passphrase_from_host": "eaf5aeeabb4bec1846ff03e81ef95fc9cd12f949fa7c5ff4be4ffe1dcffb7416", "TR_test_session_id_and_passphrase.py::test_max_sessions_with_passphrases": "cf82b64f0f242c927d6716262a70c1ec3d508b33cffcd94d1965e89fcb57e8ce", "TR_test_session_id_and_passphrase.py::test_multiple_passphrases": "de4cd16001555d8cb75a00f1d1e3f78a0c7613bf5ccc3bdde28f9780a3c0c6d8", "TR_test_session_id_and_passphrase.py::test_multiple_sessions": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1859,31 +1981,33 @@ "TR_test_session_id_and_passphrase.py::test_passphrase_on_device": "033d6c8d27b79461137aa78d9a89acea049f52539bc0d898243e392514e36ff2", "TR_test_session_id_and_passphrase.py::test_session_enable_passphrase": "69281f35174e284b0aa08b107bc7be6dfa13dfd7d315b6d15c8fb2677af0c731", "TR_test_session_id_and_passphrase.py::test_session_with_passphrase": "94d8f4f0b384923e5e2e54ab0aa86d064872915061bda987c8bd042ebe80f5ad", -"TR_tezos-test_getaddress.py::test_tezos_get_address": "bf9ffa2b33d412aad0e691f7341e1d5959a84826fe007cbeb379749eace89f65", +"TR_tezos-test_getaddress.py::test_tezos_get_address[False]": "a0f5cedea154fcc3651cb6350de24201178b2ac83c8de055823ac1c82d1532f2", +"TR_tezos-test_getaddress.py::test_tezos_get_address[True]": "42ca79f423ba81796b7dd904effc847e62be499c01521eefd168c077e681b7a6", "TR_tezos-test_getpublickey.py::test_tezos_get_public_key": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_tezos-test_sign_tx.py::test_tezos_kt_remove_delegation": "b4386ca084cb9f44c231463eb258538975c373aac4ed21072296facf0abcb7f0", "TR_tezos-test_sign_tx.py::test_tezos_sign_tx_delegation": "f41523d4377df49fdbd7168dce080d15697e284b6cb53a8b4c876817b3b1ea28", -"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_multiple_proposals": "c1de4a401eecf22d9e63d2a421e9955edfc0a56370846ddaad63b757fda52a23", -"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_origination": "e9db8844e6e3e43a9bd751022b874bbbbcc317d34c6e7e3e29654cec3115252c", +"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_multiple_proposals": "fe3c0c776cf4a094e935465dd991feea646c9b54640655acee2cda62fd2e77d1", +"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_origination": "b3ac4219d8a1bb01791c4efc43363713bb46567769a585ed7ce579809c153cc1", "TR_tezos-test_sign_tx.py::test_tezos_sign_tx_proposal": "7a81771a7cd56a69b779d9e900ae1fe6ee08a530c46cd17b461f269152d71adf", -"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_reveal": "a44b60dc09c19c1c9f5fa22c9bee2c330c09e9d8d27955dadf3c53b369a9cc83", -"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction": "ca476955fdd078ba05eabe9f3060627fc248a809a79a172f6eb64138c1cdcb6b", -"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_nay": "2ed67e83fb55c00a8dbcb1cfb3c475c8b42214b2a4d8b5fc16a1dd9b1efa7eac", -"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_pass": "b8a1b9e57ceb915197e109d1771cf4afefe2b7091e47c2bc8425e195a45c1354", -"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_yay": "7f8d73ff6df0775fd252d47be95fb129cb0d697bea9071ac5f2168fc63b3d17b", +"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_reveal": "a4a37d606cfddcfa9e7884b4e61c4e1f75b91d516b88860d2c351014e39137f5", +"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction[False]": "6f59a5800116f1cfb0bb3092d3a17c83dd15bb4046ef2ed0e1c5043e7c4d58f7", +"TR_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction[True]": "6e0b5320536f399ee0e49307924453de1ac7592e7643a63e0bc70f5474bd6630", +"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_nay": "54f51e3c1042554937f0d941400430019dc89d3d81d12beb3487438a2517b9fa", +"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_pass": "af265621ca1fc12e12f5bacfcbf97503d7d70e4095f8de9861416c338fd6298b", +"TR_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_yay": "9a4fae0cbaa1f67716d9a2178be1371eda6d8a5114c305d812a8c5c74a03a285", "TR_tezos-test_sign_tx.py::test_tezos_smart_contract_delegation": "475affbb26cf0b89cb09d24bdfe5a971da9cceb28e031f3737ddedf1851df541", -"TR_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer": "e4e7299193b38843ba16301079fb288aba5f8fbd9c546f6df62ac65200d067d3", -"TR_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer_to_contract": "87e1110c8f1b4bd605b5c9f3d00dd5ab9bad90d33df94f68ee5ca07e9b85ccc9", -"TR_webauthn-test_msg_webauthn.py::test_add_remove": "f1c69ba4800d239dbbd4286c1faba6168c3828be2be2b4de3ab9fa98b2ca4043", +"TR_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer": "3fc3487048dfbca3b622908d19192e82079ea5a32765f1f674f8d0094cb16a4d", +"TR_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer_to_contract": "4a30bc033e600e3d21f3cc28f6d0222e2e229125a6927e2c1803c4a2bf67f2ab", +"TR_webauthn-test_msg_webauthn.py::test_add_remove": "d8385fdba14ee5d71f75145ccd6574a736d2e3c3915acd15597cc40618b14c94", "TR_webauthn-test_u2f_counter.py::test_u2f_counter": "097bbc8fb0ed96383c110ee6430e1d168d837ec110ba04d29179bb0789cdc3d6", -"TR_zcash-test_sign_tx.py::test_external_presigned": "c3ced7dadbac511abe2a0d43fc7073beeaa023d9b2150cbcd1db4ad967c7f97b", -"TR_zcash-test_sign_tx.py::test_one_two": "820deae063128211d1b4671ab5df80f3d36ad46bc35690700748fcdd9f6eed28", +"TR_zcash-test_sign_tx.py::test_external_presigned": "5d75328a0595298af947a4c4b85dcb21a6006098858da9b0ae797601bec6689b", +"TR_zcash-test_sign_tx.py::test_one_two": "221dff0b34aa61aa669536de1f118422f48bcc494476903e8b732e31b74769ab", "TR_zcash-test_sign_tx.py::test_refuse_replacement_tx": "19d738c0babfd39c17793e98e5d621e147d02367f4e4a7c712bb08c0f914a04e", -"TR_zcash-test_sign_tx.py::test_send_to_multisig": "c98d3133bb1862fb40c9b15a5a65a60a092c5e9b5c0bad160c913203030d0fc0", -"TR_zcash-test_sign_tx.py::test_spend_multisig": "5cc777ce662dd6f3ae2bc8332542a0a98910f91bc3cbea14df3b69091dbd113b", -"TR_zcash-test_sign_tx.py::test_spend_v4_input": "1eb49015f81a75d52b3ba5a7849854e7b932b1f8b38626080e4fe88aa82613ef", -"TR_zcash-test_sign_tx.py::test_spend_v5_input": "b57137cab219341b71d212c72a42af9b27bb3c3a074fc011335f594cb1673c38", -"TR_zcash-test_sign_tx.py::test_unified_address": "5a8e831205e4ca398985e632f99f0d1b4d9c4defd71dd541056b41e7cdd4cc91", +"TR_zcash-test_sign_tx.py::test_send_to_multisig": "0a786b0abad93ef3cf66bdc60384134414e83aecf0bdf960c49a79fe8fbcbdb7", +"TR_zcash-test_sign_tx.py::test_spend_multisig": "38dc57cbeb15b40feb621463687b588fc3c9061092863bea47efe418d4d74371", +"TR_zcash-test_sign_tx.py::test_spend_v4_input": "496627c00809d8189301130d5cdf798b711844cc9e4238849da3e669b5b8d4fb", +"TR_zcash-test_sign_tx.py::test_spend_v5_input": "4f098593b9291db29de571b2515e8d12167414de58b19c600889dc8c1cc21d7a", +"TR_zcash-test_sign_tx.py::test_unified_address": "dd8443ffce283f2a4f293101051553704024a4d64aabd517eaa0e806ef975b44", "TR_zcash-test_sign_tx.py::test_version_group_id_missing": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095" } }, @@ -1918,7 +2042,7 @@ "TT_test_pin.py::test_pin_long": "8526208658adbe3bb1cb37e0cb48a65fa10c513bf15af5f864821391670d5de9", "TT_test_pin.py::test_pin_long_delete": "7a2e17d73c594674d37aeb5f4ba77a520792295be79872e98926542d8a9ecd10", "TT_test_pin.py::test_pin_longer_than_max": "8a39e50825ad2b2a024364cf8df9064956563139f2b93eb23bfb4cb148f9a3ff", -"TT_test_pin.py::test_pin_same_as_wipe_code": "564b13d099e118da263b7b7aa97f53cb4f219611f77b1c37f2cc7826f0dde00a", +"TT_test_pin.py::test_pin_same_as_wipe_code": "e2f3fd3aeda93e4974df1227c2270716ff72cf5d38cc6626b3b1e0b2aade9590", "TT_test_pin.py::test_pin_setup": "8ed48e3beabb14f964bea53bea1a0e7d05b5ed1eea82f9e8b9360b5742886acc", "TT_test_pin.py::test_pin_setup_mismatch": "663430644b26f4493fc3ecc03a2bbce5cecda7b6ccb5be5a8a4c0ace239f6dd5", "TT_test_pin.py::test_pin_short": "d91ec8c948d2514789931d5d8b3bda591ba2d27da26732925edfaa91c85c9507", @@ -1933,17 +2057,23 @@ "TT_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "6f5f8cfeaedac16dd51ba300ead1bef01f86d2a5b60dac7336c3f777e117e7de" }, "device_tests": { -"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-68e2cb5a": "fa3d667e1439c9c2a475fff22d94e330c14697ff8dda4bcdded775492cb40a90", -"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-1adfb691": "ceac9a64c9aff8a4226e40f068ce412556eb582d909a9f8d401e83ca10433d77", -"TT_binance-test_get_public_key.py::test_binance_get_public_key": "441fd37147102b65eeaab16f7814c437b8cb9b22f114cd73cb3a19a8ed918c79", -"TT_binance-test_sign_tx.py::test_binance_sign_message[message0-expected_response0]": "41a6a796006777557d980358271101f247847b5cab71ba36b5fa54a2dc89b671", -"TT_binance-test_sign_tx.py::test_binance_sign_message[message1-expected_response1]": "0e38ce3e1e4f0e855576fdbb590d922685ee560517ec0c56e0f23ac5fedb53cf", -"TT_binance-test_sign_tx.py::test_binance_sign_message[message2-expected_response2]": "498ef9bebc2f9cd5c151393b5cb694c08012b27b6a76a21fd2bae1b167f9a604", +"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-0327b239": "fa3d667e1439c9c2a475fff22d94e330c14697ff8dda4bcdded775492cb40a90", +"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-0-bnb1hgm0p7khfk85zpz-726415f5": "8c7aaafd0be7fcadb069eaba67417b64a099c186dd1107a197bddc1f837827d4", +"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-2752eea7": "77b14be01c63dee05fdd13195cdda84ff9e90a107d44aad2a7cc9a253810f603", +"TT_binance-test_get_address.py::test_binance_get_address[m-44h-714h-0h-0-1-bnb1egswqkszzfc2uq7-9b9dcba2": "ceac9a64c9aff8a4226e40f068ce412556eb582d909a9f8d401e83ca10433d77", +"TT_binance-test_get_public_key.py::test_binance_get_public_key": "dacf73cfa0311b2f9b7b56c52a6b051b6ecf3afa9ea62ea5a7fd14bd12b415d5", +"TT_binance-test_sign_tx.py::test_binance_sign_message[False-message0-expected_response0]": "41a6a796006777557d980358271101f247847b5cab71ba36b5fa54a2dc89b671", +"TT_binance-test_sign_tx.py::test_binance_sign_message[False-message1-expected_response1]": "0e38ce3e1e4f0e855576fdbb590d922685ee560517ec0c56e0f23ac5fedb53cf", +"TT_binance-test_sign_tx.py::test_binance_sign_message[False-message2-expected_response2]": "498ef9bebc2f9cd5c151393b5cb694c08012b27b6a76a21fd2bae1b167f9a604", +"TT_binance-test_sign_tx.py::test_binance_sign_message[True-message0-expected_response0]": "41a6a796006777557d980358271101f247847b5cab71ba36b5fa54a2dc89b671", +"TT_binance-test_sign_tx.py::test_binance_sign_message[True-message1-expected_response1]": "0e38ce3e1e4f0e855576fdbb590d922685ee560517ec0c56e0f23ac5fedb53cf", +"TT_binance-test_sign_tx.py::test_binance_sign_message[True-message2-expected_response2]": "498ef9bebc2f9cd5c151393b5cb694c08012b27b6a76a21fd2bae1b167f9a604", "TT_bitcoin-test_authorize_coinjoin.py::test_cancel_authorization": "722c888565dc01abbd5fc3bb3b6c37a032ee45ea411c9c7a0619f714acbdfbd7", -"TT_bitcoin-test_authorize_coinjoin.py::test_get_address": "d152aacc0223f1e4084c8fd49faf16f0f9ab3f595cdeff2e4a79f733e149f616", +"TT_bitcoin-test_authorize_coinjoin.py::test_get_address": "f4de0499dac628067619c6081d4ebdba0ad196af7bf9662c5387386eba9e9729", "TT_bitcoin-test_authorize_coinjoin.py::test_get_public_key": "38a7eac0cf0be45770fb28da9c2f74bac6404e85f2a3801acdd4b0107d99f2ff", "TT_bitcoin-test_authorize_coinjoin.py::test_multisession_authorization": "eae73c583d41d62bcd926f7f99866e6bd2f8d52f7935713fff7564a1be662b56", -"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx": "6465cef55d4bbceb1e86e93919e657d2474192d5ea065b40fbced8c176af0588", +"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[False]": "6465cef55d4bbceb1e86e93919e657d2474192d5ea065b40fbced8c176af0588", +"TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx[True]": "6465cef55d4bbceb1e86e93919e657d2474192d5ea065b40fbced8c176af0588", "TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_large": "e0923b25095c90df9e0e73361cd6a68cadc32963917d12f646bf592c9222d306", "TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_migration": "bae8655b0eb398a327d4dec9b188b074d7e31822d1d5fed37a7d2db28663c2ac", "TT_bitcoin-test_authorize_coinjoin.py::test_sign_tx_spend": "f544d73cdf88804e8be2667a976d9501da174c678207e72372f3e1a0cf410381", @@ -1961,7 +2091,7 @@ "TT_bitcoin-test_bgold.py::test_send_bitcoin_gold_nochange": "e1479756ea3e0ff7b0eefee179ab8c11e5b960a93c2ff394e24b550ad1df3bb4", "TT_bitcoin-test_bgold.py::test_send_btg_external_presigned": "008292c1c901d46b39e06b8995d6ac6c24166658bb00d6b4783b047570e26091", "TT_bitcoin-test_bgold.py::test_send_btg_multisig_change": "435fd9bda8b656fce005f3a1943592599ac3ce2801a53724a78dd93d1266a701", -"TT_bitcoin-test_bgold.py::test_send_mixed_inputs": "e1479756ea3e0ff7b0eefee179ab8c11e5b960a93c2ff394e24b550ad1df3bb4", +"TT_bitcoin-test_bgold.py::test_send_mixed_inputs": "8ff05094c6b70aab1b2a5c82acc66ed5644992dde7506f621a89a4703c1940fb", "TT_bitcoin-test_bgold.py::test_send_multisig_1": "5cf1b7f99b5b62a6d61bc7105fb75a6ed56600a8dd90221b5b25b9804416bf4d", "TT_bitcoin-test_bgold.py::test_send_p2sh": "c9040a11ce2986f3f015c36dd90698b0f8b3712ffa6869f2c6ad1ab50141a735", "TT_bitcoin-test_bgold.py::test_send_p2sh_witness_change": "3b45a085504588b77dac52e121e0c7dd58349de436f3c314c7c4173a919fa396", @@ -1972,48 +2102,48 @@ "TT_bitcoin-test_decred.py::test_send_decred": "444e8d47b12a6ea264ed7008506fd7f7a4dfdc6a47f1b5d7c8c8e084bb5013c2", "TT_bitcoin-test_decred.py::test_send_decred_change": "378bfdc9ccda0610c358f2ff2adee18c86cd860030b3b781bd82d3134dc5eef2", "TT_bitcoin-test_decred.py::test_spend_from_stake_generation_and_revocation_decred": "6457391a28dffb6dc5349c0daee5c9e861fd084c366634a0d01b1537b4850adb", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "35a0631e1be937ee920bf414b2bb810a771d5f745c47f73a4828aa6d5f2c9ce8", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-44-InputScriptType.SPENDADDRESS-pkh-efa37663": "e1112b197ccc2aac5b7cf5c6fc32f1d7276295197687acdfb5d7fb01abe8d33d", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-49-InputScriptType.SPENDP2SHWITNESS-77f1e2d2": "4e120ee33a46de8e9238b8e6638586ba6944f225942e6c602dbf49caff373736", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-84-InputScriptType.SPENDWITNESS-wpk-16507754": "524be8690d9c08197ae52b3fba38fc49df3a3d56ce908ec795542fffa16a1d14", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-86-InputScriptType.SPENDTAPROOT-tr(-2c28c019": "c9d3277bea3c49a4fc2bfeb6a6e30fb4b5b91e92e7c2ccf2be672a514a5175a0", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-44-InputScriptType.SPENDADDRESS-pkh-b15b8a1d": "8a3873a888d6c93a28743f4baba8b7f5cf6f749d143f102b45a2c8de8fceae6e", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-49-InputScriptType.SPENDP2SHWITNESS-965f4fa3": "460844a38ea5dad025d79aa31a94c46ad3bd0d2d8b8a753c327b15ef62c969b8", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-84-InputScriptType.SPENDWITNESS-wpk-c761bcc8": "22d8e4d5898c7ac77b22eef214202ece9a87fbffa135af60233f096c657db72e", -"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-86-InputScriptType.SPENDTAPROOT-tr(-686799ea": "b1ed83c0bfb44b76f144557bdb522b2c3c253cd33dc85561c1fc1a7181669c40", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "7b6a8b4db46ad628699e0699bb0691e0c233869cf394102272af0b1c815497ca", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-44-InputScriptType.SPENDADDRESS-pkh-a26143a7": "fadccd1972d31a8f87d83fe0a74bbef070a4a9b94a87ab161c77db3ab5d7ae29", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-49-InputScriptType.SPENDP2SHWITNESS-195ebda5": "f7ff1453344df521546dc4514c60fcff997d2071a8eec5b474cdc97f00723c2f", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-84-InputScriptType.SPENDWITNESS-wpk-68f8b526": "92c86ff7a8c646ae72ba8bd48a59e100c2c00f55c93f3917d45880da87275170", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-86-InputScriptType.SPENDTAPROOT-tr(-07da691f": "e2404d532f626554a6e16834388970ab0a3717f82774101ca39cd8c42021e90c", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-44-InputScriptType.SPENDADDRESS-pkh-ca853567": "ef139e409b7b7f708ff46197d06d54d446f83596deef11bf2f7e24f77446e082", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-49-InputScriptType.SPENDP2SHWITNESS-5da04067": "adb1fe95702499e60411ede3784465458a55da1f6d6b08ebe4ed68aab3af3254", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-84-InputScriptType.SPENDWITNESS-wpk-adba8950": "2f47dad5fbf3e7828a6503ea0bae9b0f8994fc07e87ec2af6a92984115b37aeb", -"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-86-InputScriptType.SPENDTAPROOT-tr(-e31edeff": "60470e6673282d3926c8b6ae385403e388a6ccbe550761eaa29a6d21806f8729", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-10025-InputScriptType.SPENDTAPROOT--ad9e3c78": "57c1d68b825f6d0dff4922f26a88718a969f2dd1467467f44078738a79cdc1da", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-44-InputScriptType.SPENDADDRESS-pkh-efa37663": "fdd206cd2e00972b6d6e0c1e6b79366af2519bdc703d845f31aaf98efbf0c690", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-49-InputScriptType.SPENDP2SHWITNESS-77f1e2d2": "6ba9575219f7f022f520abbb6e2c93f40ac122e6d0d2885ef5b576ea1b8fab7e", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-84-InputScriptType.SPENDWITNESS-wpk-16507754": "b4e551ac226a3d74a15570f609bb2ed4b431fda36ca139b181ec5eb558832dc7", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-0-86-InputScriptType.SPENDTAPROOT-tr(-2c28c019": "cbfd37730eeb0a57f1cb4ef79c20dc71fd412bc321c8a713a7895bd76122918c", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-44-InputScriptType.SPENDADDRESS-pkh-b15b8a1d": "20b632c7165d7009e623043c4d2b4677adb91d268c119f260f4f4c38efc98f6d", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-49-InputScriptType.SPENDP2SHWITNESS-965f4fa3": "9b366246247c74fa71ab444a68b65c7a3f4280f0baab46d8f4a17ab249900c3c", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-84-InputScriptType.SPENDWITNESS-wpk-c761bcc8": "93d3d2e2b9d135bd9a48307c464e73aa51c49be7e7ed4774de7d604007b5e48e", +"TT_bitcoin-test_descriptors.py::test_descriptors[Bitcoin-1-86-InputScriptType.SPENDTAPROOT-tr(-686799ea": "640b002fa2e215cc71c2047d4f57740f1acf0e19d12fbe60a84a8232c5721fed", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-10025-InputScriptType.SPENDTAPROOT--77d3a71b": "2e98b57e2dbbe934efa85cdcc628952506dde14152f9626ccd88cc69b1a641b8", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-44-InputScriptType.SPENDADDRESS-pkh-a26143a7": "af7809b902ebe70a3444473521c71c6d9e4c999df5c56fd7ca6647321812e33b", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-49-InputScriptType.SPENDP2SHWITNESS-195ebda5": "9270ae82eb26889042ef01f56167d43e10705474e27bbe06a0b883aa9c9eeb7f", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-84-InputScriptType.SPENDWITNESS-wpk-68f8b526": "c871aab1fd28e7377add3cb9ca9e40c9075ea0182742aded29cf782b86f82939", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-0-86-InputScriptType.SPENDTAPROOT-tr(-07da691f": "4e62cb4d96cce012d0579fb835a944f55c85b31a5d683ab305d4ade3c57dd238", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-44-InputScriptType.SPENDADDRESS-pkh-ca853567": "88eb53e7585e9b7032ba332cb06e1c5b75464202fc5a78bc07d9ad9c8c587db1", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-49-InputScriptType.SPENDP2SHWITNESS-5da04067": "b1f0a4c188002dbe2020fcc31edbbafbe2091cf717bb1441b356bbad025ba1e0", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-84-InputScriptType.SPENDWITNESS-wpk-adba8950": "0abdfa034d7adc8cecf7b0e9ca8406864bf251c20d45a3fb5647aef3c0255722", +"TT_bitcoin-test_descriptors.py::test_descriptors[Testnet-1-86-InputScriptType.SPENDTAPROOT-tr(-e31edeff": "49fb1df01aa2a37ce9782a96b1e9554c6a4c6a4e15beb6c38897b5a80bf373f2", "TT_bitcoin-test_firo.py::test_spend_lelantus": "8467f703d0f2bcaada714d2662295422f724b8dccbac571c4065912968e3e112", "TT_bitcoin-test_fujicoin.py::test_send_p2tr": "89d1cc8f6de1c81195f6d0938c997eba93cb9faf82db8428eabde85d2ce94c3a", "TT_bitcoin-test_getaddress.py::test_address_mac": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_altcoin_address_mac": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_bch": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_bitcoin-test_getaddress.py::test_bch_multisig": "9347f263cb1bbdd27fd46535fed6bb9de9cbb2ca7864e0df261b6140b193c140", +"TT_bitcoin-test_getaddress.py::test_bch_multisig": "ef8a33a6700d369cbb842ef4bc0a853c10a06ddcff7abde6a1d84e7d55a0361f", "TT_bitcoin-test_getaddress.py::test_btc": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_crw": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_elements": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_grs": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_invalid_path": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_ltc": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_bitcoin-test_getaddress.py::test_multisig": "d1500edf5ce304b12e9d4271f4568a93317f47ea98721a10a8f5b7a386025f47", +"TT_bitcoin-test_getaddress.py::test_multisig": "f2ba49011a093ad530f0f3c3f60e1386add863c76ff5e3587ac90262a9f4676f", "TT_bitcoin-test_getaddress.py::test_multisig_missing[False]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_bitcoin-test_getaddress.py::test_multisig_missing[True]": "7f33d30f37353874541d4808ed45570400abe80f5173bb7022bc53e081701238", +"TT_bitcoin-test_getaddress.py::test_multisig_missing[True]": "0fe493c41775e7992c88e1bace001577f6d8737500005399cfd73522c7459b0d", "TT_bitcoin-test_getaddress.py::test_public_ckd": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_tbtc": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress.py::test_tgrs": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_bitcoin-test_getaddress.py::test_unknown_path": "d1176e2af8d5b427b4f41898c30eb7481479fd1968cfc15f8eb7ae8111efb2f0", +"TT_bitcoin-test_getaddress.py::test_unknown_path": "7aa90691e4b6cf93b14d9b0dbb060c0920c4a609bf2e1650ce51159b4b50f7c5", "TT_bitcoin-test_getaddress_segwit.py::test_multisig_missing[False]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit.py::test_multisig_missing[True]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit.py::test_show_multisig_3": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit.py::test_show_segwit": "cbf5dd38da807d68f93cd9e276f8f0b7a92826e3e3bdc40bdbb30f4a63bcd4fd", -"TT_bitcoin-test_getaddress_segwit.py::test_show_segwit_altcoin": "bc821c551afb91b484ab6f1688224f18e11527f2b8a721c9e621118ae3af11a6", +"TT_bitcoin-test_getaddress_segwit.py::test_show_segwit_altcoin": "a704cd1bed4d13c243f86af77390bf15d8287ab33ad0457eca6697ce68f5121e", "TT_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-0-0-bc1p5cyxnuxmeuwuvkwfem-dc12f29f": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-0-1-bc1p4qhjn9zdvkux4e44uh-1f521bf2": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit_native.py::test_bip86[m-86h-0h-0h-1-0-bc1p3qkhfews2uk44qtvau-d8b57624": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2050,22 +2180,26 @@ "TT_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-0-0-InputScr-821a199d": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-1-0-InputScr-9d2fa8bc": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getaddress_segwit_native.py::test_show_segwit[Testnet-m-86h-1h-0h-1-0-InputScr-d5b7f8fc": "f9c524eae89e19091508c9fc40e18a2c2f167a15f28bfd59ff4aad7bd80fa016", -"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-44h-0h-12h-0-0-InputScriptType.SPENDADD-4eca71e0": "12a9edb5799df4340bd91ae3d5c49548e0915a960e9cdf4ea136a906b83690f8", -"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-49h-0h-12h-0-0-InputScriptType.SPENDP2S-4ec777e0": "77a244a9633052ffecaa78ec0de2993ca739ee570e2cd2ad48b610042c66d485", -"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-84h-0h-12h-0-0-InputScriptType.SPENDWIT-d6991e22": "7c66331707542f9fa9e2f39457c6f25c8fb2ca535c6a252b2db0afc584d586b9", -"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-86h-0h-12h-0-0-InputScriptType.SPENDTAP-4c5b2b38": "d7f8039406f63533c8c4998bcbc6d162a999b389bc8c3f5cd48a585215972197", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_15": "b4977b7caba11e2d91a70305b4dc79b721fce41b126be5afbac825fd18d31000", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_3": "06fdd0a8bb61d558785b8f5b1a1467ff735a13a655b3cc7848dc4d02364e0fdf", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-4efd9cf3": "aa01ccb4db1aaff4fefd330023dc77653ab379147c427f666fb77aa61de19224", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-98a7e339": "aa01ccb4db1aaff4fefd330023dc77653ab379147c427f666fb77aa61de19224", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--2cf5f03c": "c00e3d49f96a325e7ab25ec3c3c8f74aa3d948ef0ea351e3c94c6f9a20050499", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--5ea18367": "8dded143a745b3a28f8a8cef6e77e062095ebfa7942550e32d7ba85a9d8def47", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-e70b56ea": "8b4059c7251b53587f160cfc32ae7e1919d866f27f4b791e14f8fbbae41e2949", -"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-f3c4650f": "fe8129647d5660f100221dce714cd436d4d3b40f873257ca62e9ad2c15425c6c", -"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-7e3bc134": "58863a6ef3a361534d6a51cb09a575f8728fcbce2d765dcb31a1e2526dc2e143", -"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-fffcf75c": "4b5b54e6c46d2e23f3d58cf0679c2ac94b8bab0400b6a7105d03b54de3264563", -"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-2ad0a0fd": "0cd56db89870cd5fa29f806b44cd8b1ba36dea7cfceedb86e86bc0d7273f6cb3", -"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-299be1ac": "51685000bec2cdffe08447ecb8cf1ebf81317df59cb0d1804a7050a4a618971d", +"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-44h-0h-12h-0-0-InputScriptType.SPENDADD-4eca71e0": "e9e1685bed4796972fdf044a84d24c95981bea00df672614cad8c2ab1b2c8e74", +"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-49h-0h-12h-0-0-InputScriptType.SPENDP2S-4ec777e0": "3a15c7626541011177bc88967c72c278fc229ad8ac131cf606c8dc1f48b5df2c", +"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-84h-0h-12h-0-0-InputScriptType.SPENDWIT-d6991e22": "cbbf158f803cec0218cef4482be16b1fbce5a33c27d22089bd562cb8991f697f", +"TT_bitcoin-test_getaddress_show.py::test_show_cancel[m-86h-0h-12h-0-0-InputScriptType.SPENDTAP-4c5b2b38": "0478aa33fb21365c1d114cad7bfb3c0270b20ffc3573d1eb70821101004e30dc", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_15": "af9af600df851cfbd070139fdd4db6588e6ce4a116b45ca19a0068ce9d678f51", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_3": "94d22e1a493fa8f3c3e15a65333ef0691fcab1594ee0e767773a3a90db6814b6", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-4efd9cf3": "faa98c7c2c581c303a2b72f0a2f93bfb6c1ed504cecda4b483af17315b569e78", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDMULTISIG-0-3-98a7e339": "faa98c7c2c581c303a2b72f0a2f93bfb6c1ed504cecda4b483af17315b569e78", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--2cf5f03c": "96ea93c13ca429954e84685b85df2eafa7e9f25afbc8ca77a88eb909bd3f7c8d", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDP2SHWITNESS--5ea18367": "a93a88119c9ee255e09a87ff1e9c078a61e1e7ec61a26a4ecbccf294a70269cf", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-e70b56ea": "46b56e80439b320688feac9bd0ceb440ff83cf5d1da51a6425aeb97aaf097393", +"TT_bitcoin-test_getaddress_show.py::test_show_multisig_xpubs[InputScriptType.SPENDWITNESS-2-bc-f3c4650f": "17a274a917e5ff853a429561ef4dbceb12c41520c18714f3c3f037d008e5527e", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-5c88d0fd": "2640940dac7119c208074f263482b66323ee2ab0769c2cda32b75e91bfe9f2a3", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-44h-0h-12h-0-0-InputScriptType.SPENDADDRESS-87490d4e": "cbe6b393e10f5e4fc0b780255b19d46f53cf60706a2f2361a658a82b0b659825", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-9bc227c1": "ba1c1f8dab1121f7fdba73f9a481145ff65e383763a24a1e66d25b2b4681c58f", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-49h-0h-12h-0-0-InputScriptType.SPENDP2SHWIT-aca0623f": "62c493f4310b90d0082281c38acc314cfd059bbbbfe18a150a5d7236cf9e56f1", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-747c079d": "8ccb2c2222cbc695f5d49543e637f03eb69d60ea654636e0e8b97a0c04a21e52", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-84h-0h-12h-0-0-InputScriptType.SPENDWITNESS-e4302080": "cd5a286c516dd0bd7eb107081356863504947e9498a9d6b490760265c055c870", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-071a4a07": "a5f25a795619e2adcc3bedc07c6b12dfa605a9369705a013f276428a5a4f78d0", +"TT_bitcoin-test_getaddress_show.py::test_show_tt[m-86h-0h-12h-0-0-InputScriptType.SPENDTAPROOT-25ee9808": "508a69027cc9b71d218f65a015d963f13fffe4bc9ad435f8fb12894ee3ae298e", "TT_bitcoin-test_getaddress_show.py::test_show_unrecognized_path": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getownershipproof.py::test_attack_ownership_id": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getownershipproof.py::test_confirm_ownership_proof": "5f4e0c17cb3258af3901c7508968af36632f3e9826f6f63068b8521a4fbb36c2", @@ -2086,6 +2220,17 @@ "TT_bitcoin-test_getpublickey.py::test_get_public_node[Litecoin-27108450-path9-Ltub2dTvwC4v7GNe-8d6d95fb": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getpublickey.py::test_get_public_node[Testnet-70617039-path4-tpubDDKn3FtHc74Ca-f3b70aff": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getpublickey.py::test_get_public_node[Testnet-70617039-path5-tpubDGwNSs8z8jZU2-8b5efa13": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path0-xpub6BiVtCpG-d791cce2": "fdd206cd2e00972b6d6e0c1e6b79366af2519bdc703d845f31aaf98efbf0c690", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path1-xpub6BiVtCpG-74c78643": "7aec676a1df268c5f8c331ea7aa9bc775c3d55d314000a84db9e934c15f31a64", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path2-xpub6FVDRC1j-3074f5a6": "efeb1c376855b29694a15b356367f911dc0bd9674f6615ccdd0ef49def215cf2", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path3-xpub6GhTNegK-1b073ed9": "6210edec6f96b94c40bbb8b010dfa2f2acf720056255146eb418f7b586843c42", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Bitcoin-76067358-path6-xpub68Zyu13q-eb190bf2": "b907ee0c161f46c46c42bdc5adc1425617f2417c3eaa87e9f6ebaf629b31734c", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path10-Ltub2dcb6N-d2ef4e5a": "d7e572050cb804f5753de2fd4610d1a1f721965f79cb1555d5ce3da27f03c19b", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path7-Ltub2Y8PyEM-b9a6bf56": "01560f35bcb670ba7b9b417d59b4c8d5e2ee432b8940b3e8c0e636b336b2e6c3", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path8-Ltub2Y8PyEM-d598ed84": "8b80bfad292f880911e60a46dea3c5b88c49ffefdbb8557af39c2ef160102216", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Litecoin-27108450-path9-Ltub2dTvwC4-bfef8b2e": "e98547fc4e0032aa68c15b30066e3186410b388bbbc3d56dd63d904e6d78a52f", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Testnet-70617039-path4-tpubDDKn3FtH-5ca1cba5": "af7809b902ebe70a3444473521c71c6d9e4c999df5c56fd7ca6647321812e33b", +"TT_bitcoin-test_getpublickey.py::test_get_public_node_show[Testnet-70617039-path5-tpubDGwNSs8z-60ca5612": "3b9b57b9e97bf14c235dca53f03062eca1430f687d1435759ea2293ec63d9442", "TT_bitcoin-test_getpublickey.py::test_invalid_path[Bcash-path5]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getpublickey.py::test_invalid_path[Bitcoin-path0]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_getpublickey.py::test_invalid_path[Bitcoin-path2]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2114,53 +2259,59 @@ "TT_bitcoin-test_komodo.py::test_one_one_fee_sapling": "1dcf5ee9a91c93829e47395e4967c4031c03c2e4457846d68836e0473f29a3c2", "TT_bitcoin-test_komodo.py::test_one_one_rewards_claim": "8fbe0c978df2adfdae7d9a3bb1f34887fe81cf705981c26116464b5cddb2f557", "TT_bitcoin-test_multisig.py::test_15_of_15": "af021d2f27fdbaa7640f0ac5006e897f9a3b67b0d5eb13e9d8f80f0a4c9e7437", -"TT_bitcoin-test_multisig.py::test_2_of_3": "2c92b86da391fad5c1ea7c6a8cc9d312071702923715f6717b942417ea8b2ddf", -"TT_bitcoin-test_multisig.py::test_attack_change_input": "c57fecda569f319c3c638c4ee7f472bc644323a90e38e8e073354a3ccb34ff5c", +"TT_bitcoin-test_multisig.py::test_2_of_3[False]": "2c92b86da391fad5c1ea7c6a8cc9d312071702923715f6717b942417ea8b2ddf", +"TT_bitcoin-test_multisig.py::test_2_of_3[True]": "71c9ed1294bb8ebf69d476897f064f443e7297e4c19d582b009f0d9a7a0040c9", +"TT_bitcoin-test_multisig.py::test_attack_change_input": "7f903186e09642a2d3a9a3e0e8139000bc32da2977989d057c8f4be4bd489c94", "TT_bitcoin-test_multisig.py::test_missing_pubkey": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_multisig_change.py::test_external_external": "c90ce9887522cd88df57b73525fc2e7c0109f4ae5366da52b0403abf8cd21da4", -"TT_bitcoin-test_multisig_change.py::test_external_internal": "4f4fc609a8152854f07fa5f81a8f287e6e3cbf817684c220f1fbd7e6f66c261f", -"TT_bitcoin-test_multisig_change.py::test_internal_external": "a256a5ac788e075fcbbd02eced5ed2e5e51b58b46e49ea61516385123ad45066", +"TT_bitcoin-test_multisig_change.py::test_external_internal": "a8d7aac5e6227e3153c1ee357c92aca970c239b7491a73f995c894935351c086", +"TT_bitcoin-test_multisig_change.py::test_internal_external": "03313e2ca9987fa0cd94fef2186b3b46a8ba7c67de58040526b59f4e5c9a3a1d", "TT_bitcoin-test_multisig_change.py::test_multisig_change_match_first": "2c625782e9f28e0167811f4417ba0d5f42eb7bc650344f7153952a6116b5d0fc", "TT_bitcoin-test_multisig_change.py::test_multisig_change_match_second": "d7a8820877dd719dfe07438dba856483d9fd0f832be9dd90954150adef47f520", "TT_bitcoin-test_multisig_change.py::test_multisig_external_external": "24769268d3f4d45fac707152375b9a518fcac905d16b510266bfbf892c6b541f", "TT_bitcoin-test_multisig_change.py::test_multisig_mismatch_change": "165300318e0480850c0c7d9a3e773ca470db2e3f7a003ca85726f88d5c220ddd", "TT_bitcoin-test_multisig_change.py::test_multisig_mismatch_inputs": "c282192cd8f8f76474bd5b713edc002882059d792029c42f828c189c96962e9a", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3]": "f7e1c38dd5e494791eb2e628219cf7b6de6af731448c3401607be238cf4f92aa", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2]": "00cd08720857a5a4554562e71f1c3d9b6259e89d4d58dca00a18ea290f3a0b62", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1]": "0d2fd0b06a57c3c275bdef3eb31327935fd4990443e40f40ab5684dbda4a768f", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0]": "ec02c7840205c63d6bfb9a7a5ddd103c45009ee61c6ee0cfccaf343e920227c1", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4]": "f3f8cf5e56808b1ab3697a84911976d49d37fbe0c6652dc20c2ab11ef4177b61", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "477ae68729a740f7836e12fd4fd30ba617d9d4c113ee7efa5784cd22a2e36b26", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "fbb013095a15267db3a7fa0dc248b840982e97a8da656a8431b8c80c38fbe033", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "5c56f15bd749dc7d04f2c6a9bd10e680593dfe9a8cc7bd2d52da8fec594a95b2", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "fa0dd3483721a1ce452d86cb0026f35cc5b7c320801e8fb561ab4ca71b37dc27", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths4-address_index4]": "24a8a60c94487d1542d7840277dc990872b1a09df581630c566731f9662994e9", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths5-address_index5]": "12c7a2f40e10245c76032ae1f16d5e1cef28b738079e3050e1c9caa754077788", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths6-address_index6]": "2401dffa421d1bd3edf3ddbae23a3acc182e36d690ad72f09a8356614d5c97bb", -"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths7-address_index7]": "4cd2441aa6b7778a0379ddb7a02e07ea0001e8fe0ae2e1891277ec326ff0d77d", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-False]": "31755b656cad58d7d32dcebbf939797e416b37156a07e887b55c83f815e8968c", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-6-255-script_types3-True]": "70933a9dad255906242bebbeaa13246fe08feee20f6a4a2149541a967a0ff550", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-False]": "686e0a918898f62a77ae2fcc2ca3b9438b441416169d327a3518c5e917036fcd", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-1195487518-script_types2-True]": "aab1f46581f519c7d3d81aeab5d6ed8e35a8d492e95dddc918ca0431b6e8fd54", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-False]": "0d2fd0b06a57c3c275bdef3eb31327935fd4990443e40f40ab5684dbda4a768f", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-3h-100h-4-255-script_types1-True]": "92d41acbaa6d69fa4512de55c3004b77701d699bdde982861740a25fe785d910", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-False]": "ec02c7840205c63d6bfb9a7a5ddd103c45009ee61c6ee0cfccaf343e920227c1", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-4-255-script_types0-True]": "d212479a0542d5f2fcad9876987db10f6e1c52b9ee13411b72fa8062ea5f73c6", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-False]": "f3f8cf5e56808b1ab3697a84911976d49d37fbe0c6652dc20c2ab11ef4177b61", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress[m-49-0-63-0-255-script_types4-True]": "af8a4f016ec79439685f33edeb4ec8e228bd72ff6eed4c07d7885eb44fdeab09", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths0-address_index0]": "1f12bb3af8bcf6a6b9afafbdf6ceba9674c0d2ef159fd75be949a60748316caa", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths1-address_index1]": "0c47cd2c13f94d818545f493b5c85788024a0667ea8682add50e474347df3d48", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths2-address_index2]": "5b5e013a4b98ba8ec3dd2b44c9653c2eaaa7b5b1a949f9058d3f8da6500b16fe", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths3-address_index3]": "90c5c863c822b85e807f1f971c707bef2c32afeb763d6898f0c9b9c33f26b5ab", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths4-address_index4]": "8b4e69d84b57dc00839900e7cae25b1b9f4baee8cf2649833e467145b254ecc1", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths5-address_index5]": "ff12de01723a4a3cf4bb8c011bd81d45b9f43254ec7cb0ea43556975f5fd1fb7", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths6-address_index6]": "4c53a681a7e094c59a52c8bd2536aae2fc192a3ca93546ce348b601383447135", +"TT_bitcoin-test_nonstandard_paths.py::test_getaddress_multisig[paths7-address_index7]": "112c66c98a7c85210d619c610e0943fc83677878116565b2e2a875f130f09e0b", "TT_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-1195487518-6-255-script_types3]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-1195487518-script_types2]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-3h-100h-4-255-script_types1]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-4-255-script_types0]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_nonstandard_paths.py::test_getpublicnode[m-49-0-63-0-255-script_types4]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "ac849e5e86d80dd83bf65fba83439fc62c4ff57aed45072d12768aa374a55464", -"TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "2f91bf55f251348a9bc3932e6542e80e0fd005b7e7a3523141c4d20738b3cc75", +"TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-6-255-script_types3]": "42c36c511cb5ed43194c676c8c011a8c93e087c49ea6572e4e2fe91452c9c38f", +"TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-1195487518-script_types2]": "6cc1e34d703ce286d4985b197cc18d3726670eaf87b7f3845c9533094606905c", "TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-3h-100h-4-255-script_types1]": "c5d4a71a000eb6470c6129013243f2dc18d1757b8924a0fefd915c9a7a725eb6", "TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-4-255-script_types0]": "9acd3df638211abc279f40d672137e4accd3d60bc2bb21dc151d3be188505122", "TT_bitcoin-test_nonstandard_paths.py::test_signmessage[m-49-0-63-0-255-script_types4]": "5c0bbe53bc48f8987dca301b2e244ae6a7ef3653d0f361875d272d81f1f60d95", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "6e4244d1b8bd7f92fcc6508cf9e13e8205de3fcf1a0a42f543e47adfd16a1dd8", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "0c4e0f0585565dd58bfd456bf721abf323f71d3723d4f41bd642cd8558955587", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-6-255-script_types3]": "3979f07f0ab2a152da56364c7917128015983d9b504caa69dcccf244e3c973e3", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-1195487518-script_types2]": "b6b4a66b2d8a714d8134b71ed4cd865364cad50ee2279c20d7fb0f9f70f0987e", "TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-3h-100h-4-255-script_types1]": "de8b7023ab1fb13e758b048fea5064f52be40273f872a029d2fd1b878cd472ec", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-4-255-script_types0]": "de8b7023ab1fb13e758b048fea5064f52be40273f872a029d2fd1b878cd472ec", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-4-255-script_types0]": "f4e151cb1f5663b1f95a6049abdd3207cadf36355a5eecef1bb28b54b6d07abd", "TT_bitcoin-test_nonstandard_paths.py::test_signtx[m-49-0-63-0-255-script_types4]": "f2ba18f46140d83a460f7ede83a068be53bd9b72f9257d90cde812efd22644ab", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths0-address_index0]": "e75774c28671a22a01346600bfca58951c28b84130d6ee4ae9d231fa16b1d46b", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths0-address_index0]": "a7b14710f3bbc45578a529fcf65300a71c4eb7e906e6d88fa6f90781a3951ef2", "TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths1-address_index1]": "e75774c28671a22a01346600bfca58951c28b84130d6ee4ae9d231fa16b1d46b", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "066f20c17cd42e96dd58e5072e5f4f03ca79b0ebcd2d1cce27d0d1001b292c9e", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "9122a38cbf7ea738c2a54ad427497bd1f0ace822ae75eaedab3fdc060895d024", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths2-address_index2]": "c8dd0cd1b6e6c4da7921e94a3d0989915b9b3df4189f679e44b859403e2bb59e", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths3-address_index3]": "7b2c3db00c884c2e673908bbd063abafd317d9858450123d2ad18d0078962878", "TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths4-address_index4]": "e75774c28671a22a01346600bfca58951c28b84130d6ee4ae9d231fa16b1d46b", "TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths5-address_index5]": "e75774c28671a22a01346600bfca58951c28b84130d6ee4ae9d231fa16b1d46b", "TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths6-address_index6]": "e75774c28671a22a01346600bfca58951c28b84130d6ee4ae9d231fa16b1d46b", -"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths7-address_index7]": "ed2afca442dfed7986d664f09213d7b08e13146ca4c514c1c29174ac56ad6f23", +"TT_bitcoin-test_nonstandard_paths.py::test_signtx_multisig[paths7-address_index7]": "860ff4685021a22522d4b21b8c68b50eca600551e2f2be01b6e3f72dde76cd9f", "TT_bitcoin-test_op_return.py::test_nonzero_opreturn": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_op_return.py::test_opreturn": "7115b4618f35a0f47236ecf85c7b49b537b44ade10bf34a448dffb628e78d5d1", "TT_bitcoin-test_op_return.py::test_opreturn_address": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", @@ -2196,7 +2347,7 @@ "TT_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_nospace]": "c25ed9adb4aa36baa02b721ed59c1b9960eba416da4e890800937cb3f734afa0", "TT_bitcoin-test_signmessage.py::test_signmessage_pagination[utf_text]": "2416a6cf5bdd739a41fb91b1dc741ccf735cce1543c95427660f8a6dd99cf380", "TT_bitcoin-test_signmessage.py::test_signmessage_pagination_trailing_newline": "a865f4741b2e5f074f383957664dcbd48167f2b9480795a0236e9d79f55af6d1", -"TT_bitcoin-test_signmessage.py::test_signmessage_path_warning": "92df5b51e625e72ffe74b54e252c3ac6fbb039aa870647f58d600a029121aca8", +"TT_bitcoin-test_signmessage.py::test_signmessage_path_warning": "fc72ac07b82dd03a3f3accd23566bad0c89d98a96e92d611adb6222342c4cdd3", "TT_bitcoin-test_signtx.py::test_attack_change_input_address": "2abe894092869d01873ab573491001cb51b501e9cc8573739c4d618acec03a18", "TT_bitcoin-test_signtx.py::test_attack_change_outputs": "d06ac6ca15fd47da9e729dfaadc69cd033956be4b8a74f771271f758281193ad", "TT_bitcoin-test_signtx.py::test_attack_modify_change_address": "f3d9ed64388115399b2fe6cc81e31b22fe78ee1e92df89696b58978dccde5cab", @@ -2209,7 +2360,7 @@ "TT_bitcoin-test_signtx.py::test_incorrect_output_script_type[OutputScriptType.PAYTOSCRIPTHASH]": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx.py::test_information": "85cd988c3b13c2cdaddd22de5d75c0692d77b4a18ff32c90944ac8b04b4e2f66", "TT_bitcoin-test_signtx.py::test_information_cancel": "faae8fbd09a65487c1f4df3f2100447a75d1b5880a48272653f4574b3e022d3a", -"TT_bitcoin-test_signtx.py::test_information_mixed": "3ed2ce94160d20d543ae6112206a69fd028cecd3e48a3ea3da8197d9f6b73632", +"TT_bitcoin-test_signtx.py::test_information_mixed": "a958bb051f4e78480aca958115aa90a5e544af16c57ef27c9f89d3c7ae02bda7", "TT_bitcoin-test_signtx.py::test_information_replacement": "fe696c5d2762c49949b35991c188461369bf268fec3fd5fed7ccebf43c4c0062", "TT_bitcoin-test_signtx.py::test_lock_time[1-4294967295]": "d5b4d1a1e45fe0f5def53d4661b7ba045c24927b78546be1c5211c417a1af554", "TT_bitcoin-test_signtx.py::test_lock_time[499999999-4294967294]": "370d3e8201252c253ee4484259ddf6d6f7e9d3f98580e16f1818c07d09c9fc92", @@ -2223,7 +2374,8 @@ "TT_bitcoin-test_signtx.py::test_not_enough_funds": "6b48450b917351d6f25753b29b9df6663c1e6dcdf6a795aae5986992f002b30a", "TT_bitcoin-test_signtx.py::test_not_enough_vouts": "14f2f2685c96c990cfa778f32f09c9e6d8c3c5fd2c19b01edde97133fb7ab9e9", "TT_bitcoin-test_signtx.py::test_one_one_fee": "b34e97ccdfb033d2658ca101c01edd436391ae0c4d2697ceb4dff048b6f32df9", -"TT_bitcoin-test_signtx.py::test_one_three_fee": "29e3c8dc9037bec2805f7a72e3f640a396f2f3d6143d15d3446616e60cb7487b", +"TT_bitcoin-test_signtx.py::test_one_three_fee[False]": "29e3c8dc9037bec2805f7a72e3f640a396f2f3d6143d15d3446616e60cb7487b", +"TT_bitcoin-test_signtx.py::test_one_three_fee[True]": "33c2bd3df7cb9e3cb6c1ed992f9ce7d67a8441d2db026274cf087d9b3cd46818", "TT_bitcoin-test_signtx.py::test_one_two_fee": "5316b84c1555519886fa0ad2bfffb7f8ee9ac57848689d7753be3e9d4dfa8104", "TT_bitcoin-test_signtx.py::test_p2sh": "dcbdcfe15914a8b9e3c1796fddc35a4d4f353244e4d30419a4ba35da7b1e23ef", "TT_bitcoin-test_signtx.py::test_prevtx_forbidden_fields[branch_id-13]": "254ce2ad5c3dbe6a5d4b305e5a85e9eefeefba29aaa63e6237f730aef9373c87", @@ -2263,15 +2415,15 @@ "TT_bitcoin-test_signtx_external.py::test_p2wpkh_with_false_proof": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_external.py::test_p2wpkh_with_proof": "d9ac83576566fc584cc2b59db710e8b99ab3f049fe8a454d96d5310c189983b3", "TT_bitcoin-test_signtx_external.py::test_p2wsh_external_presigned": "663ed56ffd23c30219b70af305df9aafab1f2dbd1c96100b070e64a8dcef468d", -"TT_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "ed792d2796207a6426ce45e5e41ef1534181f021e01fae9671881d3f05d64e54", +"TT_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "596d3f63fa98c9bff450ff67a87b7572ce909439afc6d8b4b712ca921093dc17", "TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail_asap": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", -"TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "9fbab6e3d340e29a84f00af1b90eacc92f04a3bd585947acb111ae5ee883bc0d", -"TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "b0dd6b7fa203055a6215ff4aeecbea6644cd1cdddfa920b56d24895c841f8aff", -"TT_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_inputs": "7adfff87ff596a21c1d4819aceac8a5873238f2968756c9a72b5155f528fbb39", -"TT_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_non_segwit_inputs": "5f232103fdb25b319036e46b601e018132533b5435f03879a28e86c6c589a4be", -"TT_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_inputs": "7adfff87ff596a21c1d4819aceac8a5873238f2968756c9a72b5155f528fbb39", -"TT_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_segwit_inputs": "5f232103fdb25b319036e46b601e018132533b5435f03879a28e86c6c589a4be", +"TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_pass_forkid": "065f6afe761464b1911b665a28fb63996aa13cd8215a1ab7bedb1082eb4e515d", +"TT_bitcoin-test_signtx_invalid_path.py::test_invalid_path_prompt": "ec07a389ed4cde564ad42f64ab9f574d3279167d20ea74f2145b101147e331b1", +"TT_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_inputs": "a040764cf4825d7f8ce1a6e6a402829f3f375f8d35480b8c4def49a8818675e5", +"TT_bitcoin-test_signtx_mixed_inputs.py::test_non_segwit_segwit_non_segwit_inputs": "dbef68b7d9c6b0a9056065b7ac632547953e85ce7562d1683ad812422c4bae25", +"TT_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_inputs": "a040764cf4825d7f8ce1a6e6a402829f3f375f8d35480b8c4def49a8818675e5", +"TT_bitcoin-test_signtx_mixed_inputs.py::test_segwit_non_segwit_segwit_inputs": "dbef68b7d9c6b0a9056065b7ac632547953e85ce7562d1683ad812422c4bae25", "TT_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_amount": "3278de4acec9009035c80f1a9cc4dad11570582fa2eaab30aa7c034d4f8d4371", "TT_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_mac_purchase": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_payreq.py::test_payment_req_wrong_mac_refund": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", @@ -2288,10 +2440,10 @@ "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[hello world]": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[x]": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", -"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "589ee5fd2774a8317ba3f5fd404783c3886318de98ffed0a898c67e96e57942b", -"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "589ee5fd2774a8317ba3f5fd404783c3886318de98ffed0a898c67e96e57942b", -"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "589ee5fd2774a8317ba3f5fd404783c3886318de98ffed0a898c67e96e57942b", -"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "589ee5fd2774a8317ba3f5fd404783c3886318de98ffed0a898c67e96e57942b", +"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[]": "a12dc118d423e30863b48c93bf1b888dafc0b51f81a8f42d4807d7be1536f2f0", +"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[hello world]": "a12dc118d423e30863b48c93bf1b888dafc0b51f81a8f42d4807d7be1536f2f0", +"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[x]": "a12dc118d423e30863b48c93bf1b888dafc0b51f81a8f42d4807d7be1536f2f0", +"TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_attack[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]": "a12dc118d423e30863b48c93bf1b888dafc0b51f81a8f42d4807d7be1536f2f0", "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[]": "173d9d75d2349ff709d77f8217efb7ac9fed16e57ca00828fbdc8cac27ed8d9f", "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[hello world]": "173d9d75d2349ff709d77f8217efb7ac9fed16e57ca00828fbdc8cac27ed8d9f", "TT_bitcoin-test_signtx_prevhash.py::test_invalid_prev_hash_in_prevtx[x]": "173d9d75d2349ff709d77f8217efb7ac9fed16e57ca00828fbdc8cac27ed8d9f", @@ -2315,29 +2467,31 @@ "TT_bitcoin-test_signtx_replacement.py::test_p2wpkh_payjoin[19909859-89859-02483045022100eb74ab-881c7bef": "77146b5285f8f5cd30307f66929d35cbc2c51fecb78cd6e0b2a491b59545b6c3", "TT_bitcoin-test_signtx_replacement.py::test_tx_meld": "db5c3a436e02a3f7d95e94d9da9a8d7653264e16f0dde7cb021cff53a6fe735f", "TT_bitcoin-test_signtx_segwit.py::test_attack_change_input_address": "b757a33e00b9a48464a16581515583dcc2a3e7f71cfeb5a79f5ab42ae94479ce", -"TT_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "dca0056cef7063eee123ea2a446873ae3ec3623ec28309da5e3bcfbe8f037628", +"TT_bitcoin-test_signtx_segwit.py::test_attack_mixed_inputs": "47c383a7321c912450c44edeacecd27e373faa323ae12d510d2220c904f6089a", "TT_bitcoin-test_signtx_segwit.py::test_send_multisig_1": "9632d3ff27d40cdbfb30a64a36e08f0b31289842013494be6f0824ad20211a51", -"TT_bitcoin-test_signtx_segwit.py::test_send_p2sh": "e7a85ffb53fd1f4a80163dc2b1c207ac042b484c36018e1f71ae5daaadbf6e96", +"TT_bitcoin-test_signtx_segwit.py::test_send_p2sh[False]": "e7a85ffb53fd1f4a80163dc2b1c207ac042b484c36018e1f71ae5daaadbf6e96", +"TT_bitcoin-test_signtx_segwit.py::test_send_p2sh[True]": "0080eb9feb2cea10b4a906198da6f28aa449885d8b57df359ae5f431ecd4761b", "TT_bitcoin-test_signtx_segwit.py::test_send_p2sh_change": "825b350318bd0b309cb2070cb3d8235381ca42becec4d47dd5943322555862ff", "TT_bitcoin-test_signtx_segwit.py::test_testnet_segwit_big_amount": "39c4c9856b27deb054fa343d2c335fccddc4da31d8fe3b7f4a12fa76da37eb62", "TT_bitcoin-test_signtx_segwit_native.py::test_multisig_mismatch_inputs_single": "1fad85fc72fbce379b7f1753521f012d51bd7ba4d392ed90d2b0edc1adbe87b6", -"TT_bitcoin-test_signtx_segwit_native.py::test_send_both": "db76e50e96098016b72787ccc0e0004e5fa83f3e36bec7b0e660324e25703536", +"TT_bitcoin-test_signtx_segwit_native.py::test_send_both": "f7738a53eb46611c401792817d8e8a415aff201d16298b52b902ef783a69ccc7", "TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_1": "6c9f5c78e3da43ed5004429eec8644f4063b7baa9fe09c529671b119adda1f4a", "TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_2": "1a79db018a7d8cd978334dd4e603384c215d41f54d0a1bdaba7c3a508a258e5f", -"TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_3_change": "900e0b4e374aef9111530744bb864935b011610fbb0dcc91570da106341afa96", -"TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_4_change": "e81520901d59a619a23974b4a5e11feaaff6abfe841cf01a2c79d1749e92d249", +"TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_3_change": "fb11acf4a456e12fc6518ef6ccf70084b7c7683426f386b0dd9eaa4e1460aaef", +"TT_bitcoin-test_signtx_segwit_native.py::test_send_multisig_4_change": "d27e6e7afd21faeaeb3ad5fae7451a33b0f54a3804b77ae65d3b3e523e1ef6b1", "TT_bitcoin-test_signtx_segwit_native.py::test_send_native": "972015d3ef2da6d026e3442b7b31a04bcb9600d84b0abdde4b3cfbb998cb69bb", "TT_bitcoin-test_signtx_segwit_native.py::test_send_native_change": "8d29d8e6d8c77c76b76b181e3231d5479111e20f932be5979269008ac24d3504", "TT_bitcoin-test_signtx_segwit_native.py::test_send_p2sh": "5d18e1afac68fa37436e9b1d47441ac0bdac251c1a13ca7ff734bd99e1f2bedc", "TT_bitcoin-test_signtx_segwit_native.py::test_send_p2sh_change": "05213e89ec426522f178e35f9448c569ee3dbf09e6e3f252b9bd062926d4f685", "TT_bitcoin-test_signtx_segwit_native.py::test_send_to_taproot": "1695b5f9d50cf08f1aff0cd84c6412ac639c46a6e5be6214988bea180becb294", -"TT_bitcoin-test_signtx_taproot.py::test_attack_script_type": "f9dc46598cfed9f03dc4b758242b416b3528589b3a4f6b2c2cc9b9316c4ad52e", +"TT_bitcoin-test_signtx_taproot.py::test_attack_script_type": "72a2439686a08a6e079a5ef90f2c3ff6d9997bfa1ddb24b78a8939f4843967a2", "TT_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1pam775nxmvam4pfpqlm5q06k0y84e3-a257be51": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1plllllllllllllllllllllllllllll-aaa668e3": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1plycg5qvjtrp3qjf5f7zl382j9x6nr-5447628e": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", "TT_bitcoin-test_signtx_taproot.py::test_send_invalid_address[tb1zlycg5qvjtrp3qjf5f7zl382j9x6nr-880d4a6b": "c6bb77373d142024bf2b24d43f7af1867f7b0da28d18e89fb6cdba8b7c8aee81", -"TT_bitcoin-test_signtx_taproot.py::test_send_mixed": "1dd17990703a5cccd3d7ddc8386d543dd9653bf63aba9f54d335a04e50ade1a1", -"TT_bitcoin-test_signtx_taproot.py::test_send_p2tr": "2ec92060e2a461ec8cc6a73a8648a0e8d4c502b9c4baf15bf0313eb7787bfe44", +"TT_bitcoin-test_signtx_taproot.py::test_send_mixed": "b4af8936775a65e93f896275feab4a5930ded9309cc3e0874a17bab37d1c7f8d", +"TT_bitcoin-test_signtx_taproot.py::test_send_p2tr[False]": "2ec92060e2a461ec8cc6a73a8648a0e8d4c502b9c4baf15bf0313eb7787bfe44", +"TT_bitcoin-test_signtx_taproot.py::test_send_p2tr[True]": "48e03056ae1f97fcbe00f1dbdc829d0b0cef5531a10d83c8816da0022e4ff3c4", "TT_bitcoin-test_signtx_taproot.py::test_send_two_with_change": "e4ddd10470988ee49f4adc7f378d31d107293550d8e5df9a30d1838a7c732712", "TT_bitcoin-test_verifymessage.py::test_message_grs": "e10ff287f3399371f2ae44b044a38143e7ea567f72733d12004098b44403078d", "TT_bitcoin-test_verifymessage.py::test_message_long": "bb04b4ab429f1bc7d8933e656c83807c4ac1caa6eef4c0e89ce54bd668895a4c", @@ -2359,66 +2513,106 @@ "TT_bitcoin-test_zcash.py::test_spend_old_versions": "b12eef8ad8c8578c0501a26ee6453d9b4df21bd58049fa0373231142d4738aa9", "TT_bitcoin-test_zcash.py::test_v3_not_supported": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_bitcoin-test_zcash.py::test_version_group_id_missing": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[icarus-derivation]": "104bebf53fdd9f4a2f01871e2b68a720cc2252216fe8fb781188e29f695fc4e4", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[icarus-trezor-derivation]": "83703565c8ac5d10097294776e2a560d96483418559a4aa352748936de08e76d", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[ledger-derivation]": "9e50d709ca119b5b1a120c9db978931373a386dd04fc5cfd1d2c81e150cf817d", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters0-result0]": "8deed6efec61f0237dcc1e5048492e01d55c7bd833f2c70e4e8fed46e836ad61", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters1-result1]": "8ed36af60e84e1e43cf6d4e5c3fd3fff0125005ecb86f4a78e240f7837e777ea", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters10-result10]": "92b06620086f0cb3b61937db9c942d5eee357efa3fbbd2f86781732f2f692f89", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters11-result11]": "e02e6bcb1f9f6ea287ea5282600f622d52522aa463b48cdbb4ca107201e33d2d", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters12-result12]": "c03f2f5c49720e7c7b2e7ced8fa1117944a57144830ffdf0eb1171f52257a5fe", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters13-result13]": "a1e9deb5893b5d2f0ea6ee8e919bf61354883520756b98d6281537e5e75e24ca", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters14-result14]": "f33069df22ec7d129bdbb7b5a8e600ca479b4cf6afa8d032c8e8d9d12698a9da", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters15-result15]": "9a0519e0b56ce1b967223e0964c028da23e7bed896fbc4abcd57d37e77db531e", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters16-result16]": "8edd1fc633e2cfcaec867a35c18c1d0f1b4d1422eabb37fb7589768900efb80a", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters17-result17]": "4857af0c0bbc139e34904724fe37c917d3121a1c10452b05e3507e64a3af58f0", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters18-result18]": "051384130e3cb86aebd018fcab6515e1ae8549a671cdf545284ea096374c91d6", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters19-result19]": "3b2ae131900eeef53d5a2f146b03cd43a09413453ca64c93a65c322aae5a3243", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters2-result2]": "530b5b42f2d947a67c7439b9af31393ab42e70b73ce7334dd35b0d4f7fc6680c", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters20-result20]": "0d160f41c4b5b717bd4689f088d23ab528fdaa5211a07a0f1a7787bedcf3f455", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters21-result21]": "10148f97b4b6c6b611368a3c68eec546b49e6e43f7f238e1b57e32047b138145", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters22-result22]": "f047673381d6072509f8fd29bc5ed9ab959b612242d6364722b890a6f8b3984b", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters23-result23]": "17fa0bbbb225330ed854e7ceba99980cb77bff5114c5f1681f48d4837fc5e4bf", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters24-result24]": "7ca2cb3962bb95c3250789466c965f8cf34c4bd1ed058cb7eae28ee2998b6fc0", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters25-result25]": "b841eff7ee1d641a7796cf1e99dd260f0c176343ef0bd8c7bf697769430e0d51", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters26-result26]": "6176161d5744d832e208199e964b6452bc37d782654ba55d361ffeb4f0fb2dbe", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters27-result27]": "edb0279a09e1c36eda30a3d48f0de6f547bc6213fa588fded78c03c7b1cb5630", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters28-result28]": "432be76a7cedfbd3ac00de037cc9074332105770318c7b399749c7551b0b24ea", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters29-result29]": "5438e6f171f6a376e8832f50fdddb5b9f584e55018b85fcee8dea962b152ca1e", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters3-result3]": "79c1a4892f1f5c60274e3622a58b0479a678c3104d3677d4251c56056629db12", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters30-result30]": "911f9906068aba634eaed98136bb4e98c4a7b1bf3aa4fe1390a872f1547edbb8", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters31-result31]": "e429457e523144e8ea90645bf6dec8ee105e02d18eee3c4ba414c311e1ea9c5b", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters32-result32]": "42dfa0cac9ac525a24d7a1770f66d1790352b1900d614a50faa24fc7a07d9f9a", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters33-result33]": "92a896d7018181dadd4c49d4d01639d8fb454403066afff75355d59888c07b02", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters34-result34]": "aa7b2e537a9c7b9510f8298543161407ef4596088fc9c67c57f9a014b97c000a", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters35-result35]": "4ea97f8df29eb686bd4a2ac101aa6ccdf4f124ab1e2dc8b913b36e56a7950d43", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters36-result36]": "a3259e596d5f8c4ca8e9ba4de2f14fe30d269a4c3d011778b84f73ae4a4c80f0", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters4-result4]": "7fabc235b262cbb2fa45e42aeb900bbc1cdd8a684d2ad5e08b51fdb147657990", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters5-result5]": "c40565fd4fdcf558c29c67b25e2aaf88e1e41c3d35735c344ee09ec672cc1266", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters6-result6]": "0053e85ac2f8d5659d098f1d878fa7e37d712c79d3bed8a596bb639fdfc720e3", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters7-result7]": "37afe319cc51bfd117eb04d350e1d2a174030d0f21723eef23ccec7eeb887bfe", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters8-result8]": "5a9e1aedd3047e3f741f88549fb2497e2e9216ee326553efd146ae078449a5bd", -"TT_cardano-test_address_public_key.py::test_cardano_get_address[parameters9-result9]": "4b9aa38bea642c08c31c946baf12ce209b5106a5d8894939def0d899c580a4af", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-derivation]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-trezor-derivation]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[ledger-derivation]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters0-result0]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters1-result1]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters10-result10]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters11-result11]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters12-result12]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters13-result13]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters14-result14]": "fdf4b1631f9726cd27137dc3e20a78d88d223fd774fee8828a1afb33624e9a11", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters15-result15]": "fdf4b1631f9726cd27137dc3e20a78d88d223fd774fee8828a1afb33624e9a11", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters16-result16]": "fdf4b1631f9726cd27137dc3e20a78d88d223fd774fee8828a1afb33624e9a11", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters2-result2]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters3-result3]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters4-result4]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters5-result5]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters6-result6]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters7-result7]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters8-result8]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", -"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters9-result9]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-icarus-derivation]": "104bebf53fdd9f4a2f01871e2b68a720cc2252216fe8fb781188e29f695fc4e4", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-icarus-trezor-derivation]": "83703565c8ac5d10097294776e2a560d96483418559a4aa352748936de08e76d", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-ledger-derivation]": "9e50d709ca119b5b1a120c9db978931373a386dd04fc5cfd1d2c81e150cf817d", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters0-result0]": "8deed6efec61f0237dcc1e5048492e01d55c7bd833f2c70e4e8fed46e836ad61", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters1-result1]": "8ed36af60e84e1e43cf6d4e5c3fd3fff0125005ecb86f4a78e240f7837e777ea", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters10-result10]": "92b06620086f0cb3b61937db9c942d5eee357efa3fbbd2f86781732f2f692f89", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters11-result11]": "e02e6bcb1f9f6ea287ea5282600f622d52522aa463b48cdbb4ca107201e33d2d", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters12-result12]": "c03f2f5c49720e7c7b2e7ced8fa1117944a57144830ffdf0eb1171f52257a5fe", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters13-result13]": "a1e9deb5893b5d2f0ea6ee8e919bf61354883520756b98d6281537e5e75e24ca", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters14-result14]": "f33069df22ec7d129bdbb7b5a8e600ca479b4cf6afa8d032c8e8d9d12698a9da", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters15-result15]": "9a0519e0b56ce1b967223e0964c028da23e7bed896fbc4abcd57d37e77db531e", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters16-result16]": "8edd1fc633e2cfcaec867a35c18c1d0f1b4d1422eabb37fb7589768900efb80a", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters17-result17]": "4857af0c0bbc139e34904724fe37c917d3121a1c10452b05e3507e64a3af58f0", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters18-result18]": "051384130e3cb86aebd018fcab6515e1ae8549a671cdf545284ea096374c91d6", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters19-result19]": "3b2ae131900eeef53d5a2f146b03cd43a09413453ca64c93a65c322aae5a3243", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters2-result2]": "530b5b42f2d947a67c7439b9af31393ab42e70b73ce7334dd35b0d4f7fc6680c", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters20-result20]": "0d160f41c4b5b717bd4689f088d23ab528fdaa5211a07a0f1a7787bedcf3f455", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters21-result21]": "10148f97b4b6c6b611368a3c68eec546b49e6e43f7f238e1b57e32047b138145", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters22-result22]": "f047673381d6072509f8fd29bc5ed9ab959b612242d6364722b890a6f8b3984b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters23-result23]": "17fa0bbbb225330ed854e7ceba99980cb77bff5114c5f1681f48d4837fc5e4bf", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters24-result24]": "7ca2cb3962bb95c3250789466c965f8cf34c4bd1ed058cb7eae28ee2998b6fc0", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters25-result25]": "b841eff7ee1d641a7796cf1e99dd260f0c176343ef0bd8c7bf697769430e0d51", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters26-result26]": "6176161d5744d832e208199e964b6452bc37d782654ba55d361ffeb4f0fb2dbe", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters27-result27]": "edb0279a09e1c36eda30a3d48f0de6f547bc6213fa588fded78c03c7b1cb5630", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters28-result28]": "432be76a7cedfbd3ac00de037cc9074332105770318c7b399749c7551b0b24ea", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters29-result29]": "5438e6f171f6a376e8832f50fdddb5b9f584e55018b85fcee8dea962b152ca1e", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters3-result3]": "79c1a4892f1f5c60274e3622a58b0479a678c3104d3677d4251c56056629db12", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters30-result30]": "911f9906068aba634eaed98136bb4e98c4a7b1bf3aa4fe1390a872f1547edbb8", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters31-result31]": "e429457e523144e8ea90645bf6dec8ee105e02d18eee3c4ba414c311e1ea9c5b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters32-result32]": "42dfa0cac9ac525a24d7a1770f66d1790352b1900d614a50faa24fc7a07d9f9a", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters33-result33]": "92a896d7018181dadd4c49d4d01639d8fb454403066afff75355d59888c07b02", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters34-result34]": "aa7b2e537a9c7b9510f8298543161407ef4596088fc9c67c57f9a014b97c000a", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters35-result35]": "4ea97f8df29eb686bd4a2ac101aa6ccdf4f124ab1e2dc8b913b36e56a7950d43", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters36-result36]": "a3259e596d5f8c4ca8e9ba4de2f14fe30d269a4c3d011778b84f73ae4a4c80f0", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters4-result4]": "7fabc235b262cbb2fa45e42aeb900bbc1cdd8a684d2ad5e08b51fdb147657990", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters5-result5]": "c40565fd4fdcf558c29c67b25e2aaf88e1e41c3d35735c344ee09ec672cc1266", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters6-result6]": "0053e85ac2f8d5659d098f1d878fa7e37d712c79d3bed8a596bb639fdfc720e3", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters7-result7]": "37afe319cc51bfd117eb04d350e1d2a174030d0f21723eef23ccec7eeb887bfe", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters8-result8]": "5a9e1aedd3047e3f741f88549fb2497e2e9216ee326553efd146ae078449a5bd", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[False-parameters9-result9]": "4b9aa38bea642c08c31c946baf12ce209b5106a5d8894939def0d899c580a4af", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-icarus-derivation]": "f510a07ccb7be15238367ed1b481e745e3f9563c1328e80ccba58db6ff33c302", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-icarus-trezor-derivation]": "1c7d706b28298e1d6df59cf8d33231710f1124e021094dad8513f69096fb4c47", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-ledger-derivation]": "ade512d9af11c68bee5c806fb2215ac69d3da75860154123a5918390f9da526b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters0-result0]": "e8f224fe8adedfeba19c84716af802720cb4df5bb2e346f58b7e9daaefc1a129", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters1-result1]": "dca5729b439904a756b21e18660a933446881f9d4fa47b2b579717b9d6a72e52", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters10-result10]": "ad11ebf1f94a37a38505afb5e3d8d53102c52bafaa6ca0a70f5774e425cf97b3", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters11-result11]": "29a371d5271c8746e00c0c5d53816e372bdc32daacc256f3746cf1dd54000265", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters12-result12]": "c942231a64a45e002a9d071d331bd857b1f0d7043e466f286690bf8f5d0ded35", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters13-result13]": "a91cdb03fd8590f3d1446a10e4c2984dc3c3816c74a44e6de9cb3f8ca50111a7", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters14-result14]": "aeb15f5e59e0fbff0c776accf60e357c08626fc616396aa8f63dca38b79c3399", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters15-result15]": "bd42f2626b5375bc9f31059aadb1df5bfdcd471d82a5cb298ecac1c190d321fc", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters16-result16]": "ca45a33df607a22e15810dfaff7f49a875156d33a05126d5c4f80c2c4211afe0", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters17-result17]": "e855f4f9bfb1f613566c8ff976050c0682ceba8703b045324247a726397b76c6", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters18-result18]": "ce5e868706bbbc3d7f655754c7ed9cd0f639a92ac36ecbda4f08eca0974941a4", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters19-result19]": "cff1aff7bb84130d8090a08a7bbb91aeadf38f547e984fa5ee072ba86e02af19", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters2-result2]": "321abb9c816c43d6ec44ad22188bb835505c706df4f9f37ea131e82dbe83451c", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters20-result20]": "ff93bd6ee05135e81f708a862330ed2a4b8c8cd30005ce8e9e5832c984b1ab3e", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters21-result21]": "99296e88419fc697369be99342c9b68dd42899b97d0db9050153d76b5be56cc7", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters22-result22]": "3dae8e3d0c852989aa0a71d3e3d61fcb3bb357257e33793b6a615d0e29f659a9", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters23-result23]": "3c0b9c0d88a99ac92e90b93cd3a77bf75b7a3f2c9cd164f4cc1f4d30ebc3014e", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters24-result24]": "e653da10a19b3617682ee7a29c9aebbb9289b2b39a8de93b98f8d9b196096c5b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters25-result25]": "c8a2b7c44515e1faaa8269ac4c60f1f6c3d22827b924fbd564fba3c8b63b0db8", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters26-result26]": "de7594ff314db3f5c7b5f7c0cf6119411e1cd00abd731f1896470353ba22c715", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters27-result27]": "7937e85284cd08917b7db06c4feea5da46f923907a6240a86362031547841b43", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters28-result28]": "1a8888cddf4e6fdb439f0e0f479b05951b4be2016c23a89844471bbc88c60a2e", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters29-result29]": "0644211c8a04a5ef6bea4867fa7f4d008786bcadbd4a22a2a32a8203ded4053c", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters3-result3]": "9ee74c346ec67648caef8ae01d2aa0c77644576b265219350113bdab85ce9668", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters30-result30]": "27c9ac43f3baf39e07435235fbd5569930b25303a2cd73a5957e6c05e1680f86", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters31-result31]": "a6298c4cf5a17708d25f78a9866566641b349841e05dcf3c5e07fa692a622020", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters32-result32]": "acfeea74689604630d11e9921dc7951abe429db117de2209addd2bc99e5ab37b", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters33-result33]": "0d572466e8578b2bd6152e3b20ce33aa9ba69abd7da0e1ccb522108484ca53e4", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters34-result34]": "cff1f502ad40c1909378f4076fc6406e035c11473fa498a540e5ce70051649e9", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters35-result35]": "a954b7609d2c5a898ad54f1a15c2d7f190d4e2fb5eb828a1d7a2ac107b87f10d", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters36-result36]": "b27b412106627c892d795b54e9d8fb22376b15829738a9a08d4c5bc5f91d937a", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters4-result4]": "c9d6ca7b7653066bc2c23579ccf034242919ac038e386b1722f7f101c9147093", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters5-result5]": "2ab958efb727e9cab0d9be9e298b400d6ee1810a78c192ba645aba754f3a2521", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters6-result6]": "614cc13a64f35ac3247b83440cdea22a18257afef165fc54d41917500cdd409f", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters7-result7]": "1c4bf364e403371d1b4570a6d7a2b8f9ac231851cbf67f56f64fe350e0edadd1", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters8-result8]": "a9958771b2394aa3d6488f5d28d0516fb2632997be4ef3cfe272d8468b475e70", +"TT_cardano-test_address_public_key.py::test_cardano_get_address[True-parameters9-result9]": "3837db7ecbeac84af23e969ed50644ca9119abfae35486596e45f20bd3de6128", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-derivation]": "994ecd6811d4f2269e7859a1a963f119a5c1a7b352d9cd86fe5ef91ab17fafeb", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[icarus-trezor-derivation]": "329604ef9c69379a5e79baa0a243e35efb0219fa2f78a1def7051b6c5b3f77f8", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[ledger-derivation]": "69ffdba4d44678ef02199fbfcadea5155eb0b2353ea8164d2a84055e7e0dbd7f", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters0-result0]": "c1ce96f845bb2ea9e1b3214e104f24807b2f0d1317b82abcad66f6d5048dae9d", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters1-result1]": "f8ea0925c834e6802b64a15947b2246e23f92f90aa84e67edae92fda8edd128d", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters10-result10]": "a05a3b3805139867f562f0095a21f48f6de3eda4c096732910f027e1d48a2bc3", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters11-result11]": "e8ffae6fef7c149499c6b7d0037e6d34f6162ba1b0413392344faa0f9cdf8abe", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters12-result12]": "ece5905b7920fa96955784d6a8ffb92856e4f920ecf6590b87cb0aa40c5d530e", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters13-result13]": "33abe3710130d47753384cebedd3e5b6c13e90f1af46c46e1503454888b0e66c", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters14-result14]": "d77b45465a81ed6099b208e29767ec2c3a2937f6b758e0bb34a6d99ed0a2b0db", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters15-result15]": "11a07ba15d07cb95e49bf9e535bad43e828c2645f04aaceb09c9c92357c213d9", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters16-result16]": "e74a89ce74bf588b0c9c3b2d133f5723970cc9a1cf4244786a9e794c4dfa318a", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters2-result2]": "5c623e033f8cd46c08fec1eb17e070f701c6af042f9590d368b46874cd4738f0", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters3-result3]": "82fe9dd16f110a52da3479b58c52cfc23200c2d3020f9fc57f8bcfc4b5991825", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters4-result4]": "c05d6caa10e3e0fd7dfb8982a87e3c0855395bbe069035943d66ced00794b827", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters5-result5]": "fc5dc33ce477a366c3a224907932922cd708d6ee9d8f23b5fd0f9c0e36ae52ab", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters6-result6]": "43cec0bf4c1e8a33e6ab3e2eb798bfaadba91187bcc672d539ec9963b9c4fec6", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters7-result7]": "38674c76d00b1c8ca033b27d0b1494c5dcf9da9cd9b96a6ae406b3ed37544ba6", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters8-result8]": "d504b427de2716fbd057a840bd8122b2876ff26d37a3aa834bcb79d110a95cca", +"TT_cardano-test_address_public_key.py::test_cardano_get_public_key[parameters9-result9]": "436f65ec5aa714a185dbb3bf514192d37ed193610fa06db182404b22b54a859a", "TT_cardano-test_derivations.py::test_bad_session": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_cardano-test_derivations.py::test_derivation_irrelevant_on_slip39[CardanoDerivationType.ICA-3b0af713": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_cardano-test_derivations.py::test_derivation_irrelevant_on_slip39[CardanoDerivationType.ICARUS]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2487,7 +2681,7 @@ "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[plutus_transaction_without_script_data_hash_a-9590827f": "ee222ac82b914a92c6f013ca60281cdbc1def27084299ca8af180f74176c404e", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "2fcf07992be51ca62870f53eabb3a00085a1d9faafb4745e27b97fac7910d4d1", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-336f4a44": "2fcf07992be51ca62870f53eabb3a00085a1d9faafb4745e27b97fac7910d4d1", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "6eb995fc9503f437d8dea347bc4bfb2eb453f7e1be336481e8cea7cedf5c15ae", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "354253068d98c069dde1a81da1a587864e81899e449319c5a378860db9d61264", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_with_zero_margin]": "aa04fd16415a1d48eaa7c17cfc9955f94714a2357a7ec7a574c37f0750d1cab9", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction]": "9ba3184b35370c502149517b12e3c2d646d68a9aa62dcf5742ac49542e03c766", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[simple_plutus_transaction_with_additional_wit-36ba8ce8": "bb8b4fd585971e6f8d61e4549ec5adecf7ce31177f38c9e80d9eb6e56ddbf66d", @@ -2503,7 +2697,7 @@ "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction0]": "509b8d52aff32f547873de7eef5b5a54661b6b487e915ebcfb639fefc68b788c", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[testnet_transaction1]": "0f943249c920cbfbb0adfeb8d1dbf2d3557f569e7f6d2b02022cfca0835b3d8b", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_auxiliary_data_hash]": "5f533f2c7436e664544cb012aec86327bbed6c64c3071983ec20f591151e9220", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "66bbb7f6fd687c26db3a817d0978e2f8c5e2e8f7695c31b97c346299dc66e994", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_p-3c7243e1": "5be4893666490c07e2e9d047170b3aa82077eb9c8d2d8e55a9859588aadc9d81", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_base_address_change_output_s-20438873": "8af4517258b0052e446c5e2a57b1acba2622569c90d9ec293e5bf5295573c782", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip15_registration]": "b58bc2dfec38f9f169bddf7bab0c1de98d397f633c984409b21223f980cb5be8", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_cip36_registration_and_exter-a66e1a50": "38fa905ed7f15c9406787d70c2ff2b853678c2a648087947815ed718f0929fce", @@ -2514,7 +2708,7 @@ "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_everything_set_except_pool_r-1e1ef130": "14e7b5d154600a0e9db1af39f2b4c6d9f296e06db1f6dacf96e145ee08d6b8a1", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration]": "6a4c4e57a5358e69b2645c6677dd3d95a4956e36dacf3cdebdfd67c6983eca73", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_and_withdrawal]": "6a4c4e57a5358e69b2645c6677dd3d95a4956e36dacf3cdebdfd67c6983eca73", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "251d33d80ee768f81775fb21132db22675774549a775e5a95ca3345e2e614d54", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_deregistration_with_ac-9ca046f0": "c5448d97e08db3a8f4cdcdfb3336d58fef723dfb678136e8ec9a12d9b313bd57", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_and_stake-3fdfc583": "d4e7566360a9e5290f2716d6ccee1cdbcd71c293eb420c9894672bf6c908c5cb", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certifica-e7bd462a": "405e9c445aa82685e649c8567118e2a210ed9935a8b083d804d4dfd34efafe95", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx[transaction_with_stake_registration_certificate]": "420810cb871e08a9fcdcd80254ed966f2f2df255e6a67100343d90026fcf605f", @@ -2637,16 +2831,16 @@ "TT_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_multisig_path]": "0aafa2ecd08c24a6192e557a0e77e5b0abcbd4bf7e7b44af7feebfa1114e21a3", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_non_staking_path]": "0aafa2ecd08c24a6192e557a0e77e5b0abcbd4bf7e7b44af7feebfa1114e21a3", "TT_cardano-test_sign_tx.py::test_cardano_sign_tx_failed[withdrawal_has_script_hash]": "0aafa2ecd08c24a6192e557a0e77e5b0abcbd4bf7e7b44af7feebfa1114e21a3", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[mainnet_transaction_without_change]": "d31158b0ca0ec79a1a12805988a4418ba79405e660ba7a14a837da8145d748e3", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[multisig_transaction_with_a_requ-c2fba589": "38bc0a97415c84dd86f8ddcf0bbaf1f0fba4741ca4717db031a17241327c748e", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_a_requ-9728607e": "bd0db14fdde70df317f4fb1691621987082c8120e45b6ce1f45d62f974496ac7", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_long_i-708443f3": "4f791e76d34c1cfd790c5ee9cdf2b83990622580dfa4ed776c544541ae056396", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_output-9ba7352d": "ddce92fc79786d7003b2be7b91766a0ff20b6ca90b328f6852ad0dba14bcb283", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_reference_input]": "7c69b0455fb2c42239a4e6150e39b8ac2d1d8f6566d86059dfb88b95efc4d42e", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_total_co-e846c221": "5aa3b8a4ae68479c311ba6e3939ad2967c63b5f4b48939e3f8c80b708c6cc63a", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_cip36_registrat-b9111c27": "0277b3d06f489f77dfe1e9598c333b48448c1eb133894d394cc461eb5b77cdae", -"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_stake_deregistr-6e84da2f": "105a9790e32e127e4a63e0d540d92b7b84ad4dbbdceacdee05b086f8a56e4bde", -"TT_eos-test_get_public_key.py::test_eos_get_public_key": "0ff5b1721f406d3b906862ce70cd87fdcb0d2143346f371cb3bbdb9deda2d98b", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[mainnet_transaction_without_change]": "15190c831ee28d1b7ef4d085ed13d7d87f4cb30bd524eca6971d29f0d350f05c", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[multisig_transaction_with_a_requ-c2fba589": "a867ddf62f13f0d05bc10537fc72427dfb7c7f27756989ff5e361295042ca508", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_a_requ-9728607e": "bdeb05a4d150ae165d69ec36e36026222f6aa0bfce5485eb5277240f8f811e5e", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_long_i-708443f3": "8dda7ad637da1188b684e7ac585d29360816d751eaad698a15428a94d1ea0cf7", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[ordinary_transaction_with_output-9ba7352d": "3acd47bff3552e81c1a9a79eb8b279cf4f42e42d6b00b7d1e2ab3ca329d7c574", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_reference_input]": "b713b271aa5ebb44d38362488581b88cbed09bf269d7b56b590488419cbfde5e", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[plutus_transaction_with_total_co-e846c221": "4cf784dbef911f7d094b2bfd7b87b476d85abaea773c3a56a50e727958c9d199", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_cip36_registrat-b9111c27": "cfc81596d5424ad4c557a56baf8dfb5392266e6dcb4d66f150757684cf58eff0", +"TT_cardano-test_sign_tx.py::test_cardano_sign_tx_show_details[transaction_with_stake_deregistr-6e84da2f": "72af45e4222d4fece1093ad0bfb8b8645f2f01368768e89bc1f7449778505c06", +"TT_eos-test_get_public_key.py::test_eos_get_public_key": "62adfc43b348648d90cd1f670714a7bc8efa0733db7d9c829fb0642732174d3e", "TT_eos-test_signtx.py::test_eos_signtx_buyram": "56932dff31fd7ab2bbc9545ba1a9b63a81b356e8afedd9fa4b5d34b339e59743", "TT_eos-test_signtx.py::test_eos_signtx_buyrambytes": "4226b89bd9ee803fff1dddea29b7e1c99422e7d954e3db2da2ea98804ee4c347", "TT_eos-test_signtx.py::test_eos_signtx_delegate": "0e383765f07074391f142d551090fe0419fd053f6ff1297e9fb5f35114fc9dda", @@ -2656,22 +2850,23 @@ "TT_eos-test_signtx.py::test_eos_signtx_refund": "749071dbbde504f77b2855a47fb8b91c322f91af3caaf076f91a2851254d465a", "TT_eos-test_signtx.py::test_eos_signtx_sellram": "0ce5a3c0edd3a8fce9c065ad2bfb744f61eb870b7fbe7e1e6e3c1c00e7b3984f", "TT_eos-test_signtx.py::test_eos_signtx_setcontract": "08ec6ad6cf1d3f5ff37a6502b05c27738e96d26235b3b959fd510eb1ea0841fb", -"TT_eos-test_signtx.py::test_eos_signtx_transfer_token": "248cff4fe84d11a5ddb0b7806134c947ca4e27ced44fd0722469ff2074ad495b", +"TT_eos-test_signtx.py::test_eos_signtx_transfer_token[False]": "248cff4fe84d11a5ddb0b7806134c947ca4e27ced44fd0722469ff2074ad495b", +"TT_eos-test_signtx.py::test_eos_signtx_transfer_token[True]": "248cff4fe84d11a5ddb0b7806134c947ca4e27ced44fd0722469ff2074ad495b", "TT_eos-test_signtx.py::test_eos_signtx_undelegate": "fbca9810780a27e1a69372f74cb0131ad788f81edb4b9c3de2a72abec56d2ed5", "TT_eos-test_signtx.py::test_eos_signtx_unknown": "c9be160e2f259cf586b133669b1e24386d407d5f9a3d2ba34de6161ce6591bc6", "TT_eos-test_signtx.py::test_eos_signtx_unlinkauth": "299aaccb124c4b7ec38500356ed947549924b1dc76bf07ff3dca8ec5f0d6caf3", "TT_eos-test_signtx.py::test_eos_signtx_updateauth": "e087123155fbcbd6e69c43b3a1c3d9e7da14b2872c83d8d87fbdc1506e26e182", "TT_eos-test_signtx.py::test_eos_signtx_vote": "21778ec7245c1503a2478b6d7aab29a64df4d6401954deb87107bfe056b05580", "TT_eos-test_signtx.py::test_eos_signtx_vote_proxy": "8c6fdb49f4edc39a8340d52c9a0a15de7f10aa63b45591617ac0603aa44a2a1d", -"TT_ethereum-test_definitions.py::test_builtin": "a8475b35102bbb3ccc22121734453aa574ff7d5a5a9d6e023248337c7763c8f6", -"TT_ethereum-test_definitions.py::test_builtin_token": "367b012783613537494c145ad0f24220404a7759e4e940e23cefd4452d7865f3", -"TT_ethereum-test_definitions.py::test_chain_id_allowed": "d3d1805a4a2fceffae3b41ef189f7c0997f3877fb2b0c61a2c8db369bc209d46", +"TT_ethereum-test_definitions.py::test_builtin": "775fb041bf7dac8758c006a5587b0fe3d55e7765e15c0f04d4554dd6afc5880b", +"TT_ethereum-test_definitions.py::test_builtin_token": "3ae3c53e17817022e307c1bf414b48cf0ecfdb5addc2d690a6c9af653757ca62", +"TT_ethereum-test_definitions.py::test_chain_id_allowed": "6ee123ca79c356f95af6d92553ca438d307a5cca397aada41b961e08f392cbac", "TT_ethereum-test_definitions.py::test_chain_id_mismatch": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions.py::test_definition_does_not_override_builtin": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_ethereum-test_definitions.py::test_external_chain_token_mismatch": "d60145ea461aa2c547fc258370e8525619ce0d8e5e751989a44cb8a72940d8cd", -"TT_ethereum-test_definitions.py::test_external_chain_token_ok": "97ee9bbc19be8a2002278e6fd40e7f9922a6bb6c14ffd4773b3d698160c4540e", -"TT_ethereum-test_definitions.py::test_external_chain_without_token": "993ac62e66386a2eeda97096950f1dc32202496a2f2d1101f18aa9295bb22299", -"TT_ethereum-test_definitions.py::test_external_token": "f4b8ac89c4892f250d132e4733b45cf68be4739f65369b9737793af59be2a942", +"TT_ethereum-test_definitions.py::test_external_chain_token_mismatch": "79db365a25cb6758d9dac916ebc53fbb7670c8db6f75ea1a2d7ae0aa92128801", +"TT_ethereum-test_definitions.py::test_external_chain_token_ok": "fca2e1a0a6bea8f16446eb44993e386b2dc76f26592d1bb45746e293d4ac48ef", +"TT_ethereum-test_definitions.py::test_external_chain_without_token": "1e972f48f8213f0b9269dfc8b38fbc9c8b14161ac33bd24ec375e14ed041fa35", +"TT_ethereum-test_definitions.py::test_external_token": "c20cf47402b90931da7eafab54732e35ae95efef4e754349969c04bf27442cc0", "TT_ethereum-test_definitions.py::test_method_builtin[_call_getaddress]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions.py::test_method_builtin[_call_sign_typed_data]": "e0bc3ed06cc87c9ef37e6419ee81c1d0763b8825007a38a5009785f0fdcba43c", "TT_ethereum-test_definitions.py::test_method_builtin[_call_signmessage]": "b1a9fa6d9fb8d618bc4bc5217db08f47afd3ab05dd7e40d0c1dc937d901b9299", @@ -2685,7 +2880,7 @@ "TT_ethereum-test_definitions.py::test_method_external_mismatch[_call_sign_typed_data]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions.py::test_method_external_mismatch[_call_signmessage]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions.py::test_slip44_disallowed": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_ethereum-test_definitions.py::test_slip44_external": "1e00c6038c83ea36246ecc7f586ba719b24cb672ae05fffc8ec7c0a02def307a", +"TT_ethereum-test_definitions.py::test_slip44_external": "fe1ef30cfcf96e2ce29648bba5c489def95ad43bdb6e53b72be2b9cd5c47132c", "TT_ethereum-test_definitions.py::test_slip44_external_disallowed": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions_bad.py::test_bad_prefix": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions_bad.py::test_bad_proof": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2701,12 +2896,18 @@ "TT_ethereum-test_definitions_bad.py::test_short_message": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions_bad.py::test_trailing_garbage": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_definitions_bad.py::test_trimmed_proof": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_ethereum-test_getaddress.py::test_getaddress[ETC]": "dae2d0e17fc633e281c0cdf96663346e2fdc148899cfdc34ebe8143383864d19", -"TT_ethereum-test_getaddress.py::test_getaddress[Ledger Live legacy path]": "d5963af13b1a053428be488a3475b3e5b25634292f27fbe1e81263cf9edbae79", -"TT_ethereum-test_getaddress.py::test_getaddress[parameters0-result0]": "8b6d747f11a1bd32b00a92385bed4d638718e733e80ee9f145b0a9fb0d214589", -"TT_ethereum-test_getaddress.py::test_getaddress[parameters1-result1]": "3aa63c89a2693aa70258f3a46d9aad78d5926a8af63d6aebbc37a2644cbd80ef", -"TT_ethereum-test_getaddress.py::test_getaddress[parameters2-result2]": "2a03d5555eebb9b3cc7e78e0bf79d5c8b3ff991c1afb5db5078fb8f2ec486fd4", -"TT_ethereum-test_getaddress.py::test_getaddress[parameters3-result3]": "cc46d5ffd339b76744cc822e950b4f9252b993316f36fa04a6fd371424c8dff4", +"TT_ethereum-test_getaddress.py::test_getaddress[False-ETC]": "dae2d0e17fc633e281c0cdf96663346e2fdc148899cfdc34ebe8143383864d19", +"TT_ethereum-test_getaddress.py::test_getaddress[False-Ledger Live legacy path]": "d5963af13b1a053428be488a3475b3e5b25634292f27fbe1e81263cf9edbae79", +"TT_ethereum-test_getaddress.py::test_getaddress[False-parameters0-result0]": "8b6d747f11a1bd32b00a92385bed4d638718e733e80ee9f145b0a9fb0d214589", +"TT_ethereum-test_getaddress.py::test_getaddress[False-parameters1-result1]": "3aa63c89a2693aa70258f3a46d9aad78d5926a8af63d6aebbc37a2644cbd80ef", +"TT_ethereum-test_getaddress.py::test_getaddress[False-parameters2-result2]": "2a03d5555eebb9b3cc7e78e0bf79d5c8b3ff991c1afb5db5078fb8f2ec486fd4", +"TT_ethereum-test_getaddress.py::test_getaddress[False-parameters3-result3]": "cc46d5ffd339b76744cc822e950b4f9252b993316f36fa04a6fd371424c8dff4", +"TT_ethereum-test_getaddress.py::test_getaddress[True-ETC]": "f036a4f151c129b5f0ccd29b465cb4c6ec612740f7489a468512196c1b48296a", +"TT_ethereum-test_getaddress.py::test_getaddress[True-Ledger Live legacy path]": "c2b542f05a3429f11d4a1891992647dbdf43226010dfa07e76da2468f55b846d", +"TT_ethereum-test_getaddress.py::test_getaddress[True-parameters0-result0]": "c1da25541a2e27a6e7d90ca07358b2f6090223a8b2f6a170f03495d1ce4539e3", +"TT_ethereum-test_getaddress.py::test_getaddress[True-parameters1-result1]": "fa53aa069e2fd736713288f5b09eb3d062fdf55a279c938b9a84b4b8ea006e36", +"TT_ethereum-test_getaddress.py::test_getaddress[True-parameters2-result2]": "586e046bfcec8f33c9771e786793a99ab95b9e35fd1f8ebcb6cbe720e2ef9192", +"TT_ethereum-test_getaddress.py::test_getaddress[True-parameters3-result3]": "f729105ae63a0d62cd9b574aa28165d3bf2a5a9195da77b9de830fdd8086b6bc", "TT_ethereum-test_getpublickey.py::test_ethereum_getpublickey[Ledger Live legacy path]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", "TT_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters0-result0]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", "TT_ethereum-test_getpublickey.py::test_ethereum_getpublickey[parameters1-result1]": "3b6c5cf5c6512f1491b77f895d21d2f850f774c2b9d67c1b76eaeb2892e95e6b", @@ -2741,42 +2942,71 @@ "TT_ethereum-test_sign_verify_message.py::test_verify[parameters6-result6]": "eebe68d7cc910f0ae6d3833002c2ab603d7648b59724869a63741d5f7acb996d", "TT_ethereum-test_sign_verify_message.py::test_verify[parameters7-result7]": "3e27a00452b0eddd5b748fa7f2e263d4b173fd9ccead13548e9d02c4bb58d6f0", "TT_ethereum-test_sign_verify_message.py::test_verify_invalid": "722cac3140294153823df53852bcfb0a57906e5d4013baa9139eef0c09ef24a5", -"TT_ethereum-test_signtx.py::test_data_streaming": "26cce6a1780d0e0cc9bf2600e92559bb6e72dbab42b34efb05927ce5a7271036", +"TT_ethereum-test_signtx.py::test_data_streaming": "1bfeef169da1faa5ada6b987abfc8a6eb2e4aa599601058e7f4f757af7a02038", "TT_ethereum-test_signtx.py::test_sanity_checks": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ethereum-test_signtx.py::test_sanity_checks_eip1559": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_ethereum-test_signtx.py::test_signtx[Auxilium]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[ETC]": "58dc245d001d980047d7e2cc1515899f9d8c47654069db7107820afde8cde62a", -"TT_ethereum-test_signtx.py::test_signtx[Ethereum]": "2daeea2097444acbc07cb8dbf3c2cd14ef0eb331336b1caddf129ef7da53391a", -"TT_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path0]": "ed552bf4501afc96b44e3279c2fcdf93532812d3b29cc58f5cd9a367edb44225", -"TT_ethereum-test_signtx.py::test_signtx[Ledger Live legacy path1]": "2daeea2097444acbc07cb8dbf3c2cd14ef0eb331336b1caddf129ef7da53391a", -"TT_ethereum-test_signtx.py::test_signtx[Palm]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[Pirl]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[Rinkeby]": "e2b93a0891d9b2b264cc8f838e9c995199578286f0f767dc9ee744335ea738df", -"TT_ethereum-test_signtx.py::test_signtx[Ropsten]": "e2b93a0891d9b2b264cc8f838e9c995199578286f0f767dc9ee744335ea738df", -"TT_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_eth_path]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[Unknown_chain_id_testnet_path]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[data_1]": "863146c0494b76d4d8a9773a406994c3a35fb8c0cb989f372214aaa80b63b73c", -"TT_ethereum-test_signtx.py::test_signtx[data_2_bigdata]": "05aa081d00a78c3a432904b19c21df1512c7660f4be3edaec75c9bc1aad83ae8", -"TT_ethereum-test_signtx.py::test_signtx[erc20_token]": "d51cf4119a784bac447971e8e80be44985c28a9e5f14917efb7c2064d7f21752", -"TT_ethereum-test_signtx.py::test_signtx[max_chain_id]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[max_chain_plus_one]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[max_uint64]": "3723ceb0436e8d7f4669edcf36e72cb1fe65d891f910886fa79e9e406c5e9479", -"TT_ethereum-test_signtx.py::test_signtx[newcontract]": "cc24bede1529e266684765127ac9657236091acc686c5051f68ebec65b45ee82", -"TT_ethereum-test_signtx.py::test_signtx[nodata_1]": "08085423030e6828746fbf80695d1f3006bbac8a2638fb40fa1aee27c9410f2b", -"TT_ethereum-test_signtx.py::test_signtx[nodata_2_bigvalue]": "8dbd3278aa98b783387e3286ecb491963ef9e4989a1c5b33f9d8617449daf81e", -"TT_ethereum-test_signtx.py::test_signtx[wanchain]": "bd2050c78e0e958fcf566dc5a22e074cebbedd9b20247b0bda6a22b986f85a14", -"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_go_back]": "8de2c846062d9b028ba23c02d9a53c54ef2fc55d377f084a43bc5d77be56e458", -"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_scroll_down]": "ed6c9e088a12ea2e673dbcc99944aa5d6fd6e02e579442d908a3f3e245214145", -"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_skip]": "d3c5c78e3b92dc3e32fd8d0c1a4b02ed9d826caf2d0e140c604c50ba39158082", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[Ledger Live legacy path]": "6dafe7c724f262a4fff5448b475ce848d3a74f76cb0ebaf60a5eb83bd20abb82", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[data_1]": "2eb0129b9fd3c9123920b8f47d3150b0023f4455aa171b76c5e82c17f2747cc9", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[data_2_bigdata]": "f9fff4dd81fbe5d950a7e699afbb58a8b2e8a87423ea10e25906f21d1c769dd4", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[erc20]": "6248ae4760cb69b7bb072ab21122e76b6ffe2b62ff5c44f2a61b3dae65937228", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[large_chainid]": "2b928f2a7ab544012ec6d5b74aa42898e38b149df7892b7631818401f65abaff", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[long_fees]": "f3f4f91ae6c9b265b36ef83887c4250a8056302b56830ae3a083eb8ecc893bcb", -"TT_ethereum-test_signtx.py::test_signtx_eip1559[nodata]": "6dafe7c724f262a4fff5448b475ce848d3a74f76cb0ebaf60a5eb83bd20abb82", -"TT_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "ab9bbfe802be7301a0612f6662f1ef6d51315d969e46f493198162615f8b8bf3", -"TT_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "ab9bbfe802be7301a0612f6662f1ef6d51315d969e46f493198162615f8b8bf3", +"TT_ethereum-test_signtx.py::test_signtx[False-Auxilium]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-ETC]": "2fce25b9e71dad6c52f68bf0cd8f2d17e73e38730f1e3bfe73903e41bff46080", +"TT_ethereum-test_signtx.py::test_signtx[False-Ethereum]": "9c0f1fda0416c2d37643bb18dcdcbbf9149e2215227aeef4df2d797112d40b4a", +"TT_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path0]": "3acfd7fedae9147e9e79dace2c2defd0f35ed064b0443939e2b308f7f7f5e05e", +"TT_ethereum-test_signtx.py::test_signtx[False-Ledger Live legacy path1]": "9c0f1fda0416c2d37643bb18dcdcbbf9149e2215227aeef4df2d797112d40b4a", +"TT_ethereum-test_signtx.py::test_signtx[False-Palm]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-Pirl]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-Rinkeby]": "2bcc5752d2d5ce8c6dd694761cd4b0a1ce34cdc3266d98e30a85f3201a78edf3", +"TT_ethereum-test_signtx.py::test_signtx[False-Ropsten]": "2bcc5752d2d5ce8c6dd694761cd4b0a1ce34cdc3266d98e30a85f3201a78edf3", +"TT_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_eth_path]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-Unknown_chain_id_testnet_path]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-data_1]": "fba78bb1969a3207a8e4342db521fe37c2d2b705070d333661c7aece3f46fff4", +"TT_ethereum-test_signtx.py::test_signtx[False-data_2_bigdata]": "eca03057e956c37de912f1da6ee2fc36c52b33499d5af00b0eba86750405d381", +"TT_ethereum-test_signtx.py::test_signtx[False-erc20_token]": "c7747106027ccb8d407a167549a4618963d4d8710f43c19636137f8fad74323d", +"TT_ethereum-test_signtx.py::test_signtx[False-max_chain_id]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-max_chain_plus_one]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-max_uint64]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[False-newcontract]": "dc53ad4464ba2a8468083dedb8ddb48c9efdc1335a16574a56ec3cb8ee2216df", +"TT_ethereum-test_signtx.py::test_signtx[False-nodata_1]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx[False-nodata_2_bigvalue]": "2ebc7340c7291706b125c90988540946ba6722632a70b453fdcd1bbbe21fb15c", +"TT_ethereum-test_signtx.py::test_signtx[False-wanchain]": "8065fd5b3568990033cfe750aa861d5398e7bec2e77b916bbb2ff8850a8131e4", +"TT_ethereum-test_signtx.py::test_signtx[True-Auxilium]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-ETC]": "2fce25b9e71dad6c52f68bf0cd8f2d17e73e38730f1e3bfe73903e41bff46080", +"TT_ethereum-test_signtx.py::test_signtx[True-Ethereum]": "9c0f1fda0416c2d37643bb18dcdcbbf9149e2215227aeef4df2d797112d40b4a", +"TT_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path0]": "3acfd7fedae9147e9e79dace2c2defd0f35ed064b0443939e2b308f7f7f5e05e", +"TT_ethereum-test_signtx.py::test_signtx[True-Ledger Live legacy path1]": "9c0f1fda0416c2d37643bb18dcdcbbf9149e2215227aeef4df2d797112d40b4a", +"TT_ethereum-test_signtx.py::test_signtx[True-Palm]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-Pirl]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-Rinkeby]": "2bcc5752d2d5ce8c6dd694761cd4b0a1ce34cdc3266d98e30a85f3201a78edf3", +"TT_ethereum-test_signtx.py::test_signtx[True-Ropsten]": "2bcc5752d2d5ce8c6dd694761cd4b0a1ce34cdc3266d98e30a85f3201a78edf3", +"TT_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_eth_path]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-Unknown_chain_id_testnet_path]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-data_1]": "fba78bb1969a3207a8e4342db521fe37c2d2b705070d333661c7aece3f46fff4", +"TT_ethereum-test_signtx.py::test_signtx[True-data_2_bigdata]": "eca03057e956c37de912f1da6ee2fc36c52b33499d5af00b0eba86750405d381", +"TT_ethereum-test_signtx.py::test_signtx[True-erc20_token]": "c7747106027ccb8d407a167549a4618963d4d8710f43c19636137f8fad74323d", +"TT_ethereum-test_signtx.py::test_signtx[True-max_chain_id]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-max_chain_plus_one]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-max_uint64]": "c06991cfbd22f76c4f8da34c8e96c25ead1d6ad063e77067c3dba60dec5c669e", +"TT_ethereum-test_signtx.py::test_signtx[True-newcontract]": "dc53ad4464ba2a8468083dedb8ddb48c9efdc1335a16574a56ec3cb8ee2216df", +"TT_ethereum-test_signtx.py::test_signtx[True-nodata_1]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx[True-nodata_2_bigvalue]": "2ebc7340c7291706b125c90988540946ba6722632a70b453fdcd1bbbe21fb15c", +"TT_ethereum-test_signtx.py::test_signtx[True-wanchain]": "8065fd5b3568990033cfe750aa861d5398e7bec2e77b916bbb2ff8850a8131e4", +"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_go_back]": "ba64e3d44d23b6338218c5a073d4c8a4e0d585edfc29c18d1327af1d24c1773d", +"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_scroll_down]": "316303ef4667c3c94ddb03a14698314443b87d857ab60b6d9633fe52e7f58563", +"TT_ethereum-test_signtx.py::test_signtx_data_pagination[input_flow_data_skip]": "7c7298ea25d24a4fd52cceb63329a6bdc610b4b604418b47915b48f9e80261b4", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "fba78bb1969a3207a8e4342db521fe37c2d2b705070d333661c7aece3f46fff4", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-data_2_bigdata]": "cc1530c0520f4def08cb607d5ddd92f9854a9fd99e26c924f72472e04caac389", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-erc20]": "c7747106027ccb8d407a167549a4618963d4d8710f43c19636137f8fad74323d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-large_chainid]": "07fd36537eb0177acd4caf46b0af59c7bec483944182e04794ea64ee09037dee", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-long_fees]": "4101f13397d36e717ec44a76265c43c7ce2953ed5971fe56fa7948257796422e", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[False-nodata]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-Ledger Live legacy path]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-data_1]": "fba78bb1969a3207a8e4342db521fe37c2d2b705070d333661c7aece3f46fff4", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-data_2_bigdata]": "cc1530c0520f4def08cb607d5ddd92f9854a9fd99e26c924f72472e04caac389", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-erc20]": "c7747106027ccb8d407a167549a4618963d4d8710f43c19636137f8fad74323d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-large_chainid]": "07fd36537eb0177acd4caf46b0af59c7bec483944182e04794ea64ee09037dee", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-long_fees]": "4101f13397d36e717ec44a76265c43c7ce2953ed5971fe56fa7948257796422e", +"TT_ethereum-test_signtx.py::test_signtx_eip1559[True-nodata]": "fd5425fca864ae2d93d6d277fdaa32a578df0e3a484e37a60a6b9e2614b8241d", +"TT_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "35c2cf1b22efc8ef867539c2d688434b05b1d35cd5e28c1566dbc4204981c0a5", +"TT_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "35c2cf1b22efc8ef867539c2d688434b05b1d35cd5e28c1566dbc4204981c0a5", +"TT_ethereum-test_signtx.py::test_signtx_fee_info": "976164db91b26e19c273291a12c46dff672765922b5e7b3e7382c747ca8ae2cf", "TT_misc-test_cosi.py::test_cosi_different_key": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_misc-test_cosi.py::test_cosi_nonce": "25a47ec1384fb563a6495d92d9319d19220cbb15b0f33fbdc26f01d3ccde1980", "TT_misc-test_cosi.py::test_cosi_pubkey": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2827,9 +3057,11 @@ "TT_misc-test_msg_getentropy.py::test_entropy[8]": "4dd8a541e8181aac2011a397360f8450c048536a0af77d0360c5b048657fff2b", "TT_misc-test_msg_getentropy.py::test_entropy[9]": "4dd8a541e8181aac2011a397360f8450c048536a0af77d0360c5b048657fff2b", "TT_misc-test_msg_signidentity.py::test_sign": "641820cdb6496ddcbe402cba9b3d24bee009ed212c6c1f54a87ba158b6b05049", -"TT_monero-test_getaddress.py::test_monero_getaddress": "a8c3585de2549d0a10daf32436d1200f83ff6100f6d700e19f4bf6276eba9871", +"TT_monero-test_getaddress.py::test_monero_getaddress[False]": "a8c3585de2549d0a10daf32436d1200f83ff6100f6d700e19f4bf6276eba9871", +"TT_monero-test_getaddress.py::test_monero_getaddress[True]": "cfbd89b1c18d98666f36e85f54872df3b4ecb40640182473c242743caa133bdf", "TT_monero-test_getwatchkey.py::test_monero_getwatchkey": "132fcbf2f28d368ed826f8ea2bd096572fc9807c6cc9be8f6ada25847b0a0adb", -"TT_nem-test_getaddress.py::test_nem_getaddress": "e5153912963797bb395bb51298abaca09c2bb31f22884c844fac3cd1f08100fc", +"TT_nem-test_getaddress.py::test_nem_getaddress[False]": "a7871f1b2e8d835fd40f378b1bdfcadaede0556bd5295ab174748527db53fd82", +"TT_nem-test_getaddress.py::test_nem_getaddress[True]": "f1eb22b7aee59711693245c866324c9780aacd340c54d2d99c41a69151ba267f", "TT_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation": "38ddbc0179bb3a75a4ea08e30574c29e77660e5dc22c38a56ca81cbed83340c2", "TT_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_levy": "f146c21651971c1d83888deb5244dbfc4b083f918c65b859e38d085ac130ba2e", "TT_nem-test_signtx_mosaics.py::test_nem_signtx_mosaic_creation_properties": "ab47a3bab70722c1411259253d2b357b5de86cff4da48a0c5c2b96f5e6df8906", @@ -2840,10 +3072,11 @@ "TT_nem-test_signtx_others.py::test_nem_signtx_importance_transfer": "eae87a12043b57e234d20d43ab2f3fd8788441127db2b74befc141faf7ed36c5", "TT_nem-test_signtx_others.py::test_nem_signtx_provision_namespace": "011c65e95d384bc16acba09096fcf7e9fedf9f10a13d94e28fe0d2f55fb36b5c", "TT_nem-test_signtx_transfers.py::test_nem_signtx_encrypted_payload": "2309d9692fb315aeebaff11bcad7a9ff6cf8f3e97d075012db8bad767682386e", -"TT_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "a15eda35bd899526f3ca55b7632098fc2bf248c6bd0ce13c8af53655ba2421fd", -"TT_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "b3824938ad64df7425d23abf298312be475417d515167e50a854e8796294caae", -"TT_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "e14abac52b9cf30d5edf0528ffaa1f177c9db87442fc71f506d422fe9789bfd6", -"TT_nem-test_signtx_transfers.py::test_nem_signtx_simple": "c84035c76dfc7d22d516d87b5381578823e927b418d4ff277a2c4b94276b82e5", +"TT_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic": "d7edc2b7797715c6a99d771a3175bbeb4e4169158c0a58e796d61fb423573c7f", +"TT_nem-test_signtx_transfers.py::test_nem_signtx_known_mosaic_with_levy": "fed2dc7a2bb5b6d7fc9ec29b734c2d396f3c38f760a4a1fabd030bfe4aea5fa7", +"TT_nem-test_signtx_transfers.py::test_nem_signtx_multiple_mosaics": "d5b473baa76606d09d57f590543f76b1641af61063b3b07e1ac0ea2f6be208cb", +"TT_nem-test_signtx_transfers.py::test_nem_signtx_simple[False]": "c84035c76dfc7d22d516d87b5381578823e927b418d4ff277a2c4b94276b82e5", +"TT_nem-test_signtx_transfers.py::test_nem_signtx_simple[True]": "731256fc1a451705e3cb61bb9614bee1f1fbb5efa5ba583a51ebac800a8ff013", "TT_nem-test_signtx_transfers.py::test_nem_signtx_unknown_mosaic": "764b3d2e009ad001cecb44a4c308a0fa75bacb903d663282c00da20f9f9b5c3e", "TT_nem-test_signtx_transfers.py::test_nem_signtx_xem_as_mosaic": "df42bff9228bc41f8bc7ae14518dfc4f16895b011eb34495b11e354b277a50d2", "TT_reset_recovery-test_recovery_bip39_dryrun.py::test_bad_parameters[label-test]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -2865,8 +3098,8 @@ "TT_reset_recovery-test_recovery_slip39_advanced.py::test_same_share": "339451bcb40803b606296294f1d463b0d342c82b78f0aa3b5c5f40c00058f370", "TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares0-c2d2e26ad06023c60145f1-afc2dad5": "5ffd13685c6e514bd0e804937d0e9f39056e7f829bcab5284103f88d3c1ac488", "TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret[shares1-c41d5cf80fed71a008a3a0-eb47093e": "9a24de4708ee2d38790c2489d67b0d4d222978b74b3e2f2340434c84887711fd", -"TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "387d5e79bf28f291930b4984734573f19bddf76536a2f6c50cf47ec71ecb67ab", -"TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "e977d6bec6c2fa3c5282e4d72a77bffb4bea897c056d5b57fb7fca6bc4db6071", +"TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares0-c2d2-850ffa77": "ef1f3f0d1fc85e41c9c02a0c048a14ed6256d308b90a9ccd3d40a284a94f1e4a", +"TT_reset_recovery-test_recovery_slip39_advanced.py::test_secret_click_info_button[shares1-c41d-ca9ddec8": "802b57885cad8331a90f44375bd08dc82858356d0d6d2dd0482e37fbc60cd831", "TT_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_dryrun": "6c20fcc4101c1cab4738817b7c06184c15172572b089fa5cb8828c47c263203d", "TT_reset_recovery-test_recovery_slip39_advanced_dryrun.py::test_2of3_invalid_seed_dryrun": "4b217d586ba1731ad70c41e3f1d8c76b553285f012902fbfbf6612c4a3d513f1", "TT_reset_recovery-test_recovery_slip39_basic.py::test_1of1": "162054c186639df3ad2688d57ba98fd69504233a5541de80c199d93b69ce832a", @@ -2904,17 +3137,28 @@ "TT_ripple-test_get_address.py::test_ripple_get_address": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ripple-test_get_address.py::test_ripple_get_address_other": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_ripple-test_sign_tx.py::test_ripple_sign_invalid_fee": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_ripple-test_sign_tx.py::test_ripple_sign_simple_tx": "38131b33c1f59c359279e5f6354ba70eaab9cefeb017f25e99e7cdd5310cf230", -"TT_stellar-test_stellar.py::test_get_address[parameters0-result0]": "18272296d219ce2f54f30820936a29d698bd7a26890336c9a326c30007a43e3f", -"TT_stellar-test_stellar.py::test_get_address[parameters1-result1]": "a9b53f23f657a00cc215987ee1289c6a86225602012ed33fe12ecb7421a960cf", -"TT_stellar-test_stellar.py::test_get_address[parameters2-result2]": "214f0ab5a2c67891e91e89ef71668fa89c0b58dd367cc5fc076ac9e1810ac344", -"TT_stellar-test_stellar.py::test_get_address[parameters3-result3]": "a2ab7d0bdac04efcab422955495d6e4f542e5c0d7770d712bf11b41e75ecb1b7", -"TT_stellar-test_stellar.py::test_get_address[parameters4-result4]": "1621736102d9ef3197b8593978875905b3978dd355937657e33af5c1054b02ac", -"TT_stellar-test_stellar.py::test_get_address[parameters5-result5]": "9fa8e800aa31d45e37da86169d03a19dd0ef6954473a7f4ebb3d3d339d4bbc4b", -"TT_stellar-test_stellar.py::test_get_address[parameters6-result6]": "a8357c843abe1124dacde751c70313f57ae0b46e6dd2dbf91c5f3027484822a5", -"TT_stellar-test_stellar.py::test_get_address[parameters7-result7]": "da742ffb1db1bb3430f6ea64f9d50813d41b15762969ffa4172d48ed62f0aa29", -"TT_stellar-test_stellar.py::test_get_address[parameters8-result8]": "e16b547bc1bcb9e11c8785fdc98514a54d53c2b2226e0778cd4b59146ba6ecb8", -"TT_stellar-test_stellar.py::test_get_address[parameters9-result9]": "4d4a0d45419529aaeadf4cf7ee391f26d15acf586b7f11212ff1a7a0b09c389b", +"TT_ripple-test_sign_tx.py::test_ripple_sign_simple_tx[False]": "38131b33c1f59c359279e5f6354ba70eaab9cefeb017f25e99e7cdd5310cf230", +"TT_ripple-test_sign_tx.py::test_ripple_sign_simple_tx[True]": "b6566112fee8f1cbf60bafcc70b7fdd4d2703d1a464604ecc260c00fb464b576", +"TT_stellar-test_stellar.py::test_get_address[parameters0-result0-False]": "18272296d219ce2f54f30820936a29d698bd7a26890336c9a326c30007a43e3f", +"TT_stellar-test_stellar.py::test_get_address[parameters0-result0-True]": "daf9775a8aaf9b2395530ec278665e21822fac2503aaf5fc422593d2f973702c", +"TT_stellar-test_stellar.py::test_get_address[parameters1-result1-False]": "a9b53f23f657a00cc215987ee1289c6a86225602012ed33fe12ecb7421a960cf", +"TT_stellar-test_stellar.py::test_get_address[parameters1-result1-True]": "0e0885e11f375c16d9d4aafb375cbe0e4da74b91d98701b82b371a3fe66fe277", +"TT_stellar-test_stellar.py::test_get_address[parameters2-result2-False]": "214f0ab5a2c67891e91e89ef71668fa89c0b58dd367cc5fc076ac9e1810ac344", +"TT_stellar-test_stellar.py::test_get_address[parameters2-result2-True]": "87aaaad67cb046e5f3cd5b7d7f35d9d966c1d5db6646b81e6ddc44b1e7651513", +"TT_stellar-test_stellar.py::test_get_address[parameters3-result3-False]": "a2ab7d0bdac04efcab422955495d6e4f542e5c0d7770d712bf11b41e75ecb1b7", +"TT_stellar-test_stellar.py::test_get_address[parameters3-result3-True]": "25300b63db8b4ce681250137e69e0a9420b9289be4b7d94d011fe618f2b3eefe", +"TT_stellar-test_stellar.py::test_get_address[parameters4-result4-False]": "1621736102d9ef3197b8593978875905b3978dd355937657e33af5c1054b02ac", +"TT_stellar-test_stellar.py::test_get_address[parameters4-result4-True]": "ee21122a0a2a2f1ffac489e6bfd5761fe3565a33079a61a0d2815dabe1da5d12", +"TT_stellar-test_stellar.py::test_get_address[parameters5-result5-False]": "9fa8e800aa31d45e37da86169d03a19dd0ef6954473a7f4ebb3d3d339d4bbc4b", +"TT_stellar-test_stellar.py::test_get_address[parameters5-result5-True]": "35258126be1a33ce0539a559d70b1d55ee02f1b38fd9142a5a31fdddb706bb19", +"TT_stellar-test_stellar.py::test_get_address[parameters6-result6-False]": "a8357c843abe1124dacde751c70313f57ae0b46e6dd2dbf91c5f3027484822a5", +"TT_stellar-test_stellar.py::test_get_address[parameters6-result6-True]": "5f996428edb6d6f3bd82fc33e5a8cf762fd0f1d86e76313ab49af59a84bb0b2b", +"TT_stellar-test_stellar.py::test_get_address[parameters7-result7-False]": "da742ffb1db1bb3430f6ea64f9d50813d41b15762969ffa4172d48ed62f0aa29", +"TT_stellar-test_stellar.py::test_get_address[parameters7-result7-True]": "400a1734e5901a7f8b02ae0e70d3968992587ae6a2d3de788423314157f61d2b", +"TT_stellar-test_stellar.py::test_get_address[parameters8-result8-False]": "e16b547bc1bcb9e11c8785fdc98514a54d53c2b2226e0778cd4b59146ba6ecb8", +"TT_stellar-test_stellar.py::test_get_address[parameters8-result8-True]": "cfa75102cc68d56902fe5599f37c221b45b8bda7d8e8f2da8dab1a0d665dac6f", +"TT_stellar-test_stellar.py::test_get_address[parameters9-result9-False]": "4d4a0d45419529aaeadf4cf7ee391f26d15acf586b7f11212ff1a7a0b09c389b", +"TT_stellar-test_stellar.py::test_get_address[parameters9-result9-True]": "59ddb21ea809748a2160605effe9063bab922dccec78544a612ec4072567d519", "TT_stellar-test_stellar.py::test_sign_tx[StellarAccountMergeOp]": "6d019238fdbfe772db858e356a7b50ba47e7f4b4bf5cf84c04a930961943b161", "TT_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-allow]": "09c21a1c229b63b98d3a5cb59ed13e7a5bff71554bcba384af59bc8767145903", "TT_stellar-test_stellar.py::test_sign_tx[StellarAllowTrustOp-revoke]": "12c2d493036e4cf7bdf9c9dd9c6925b930c695ec7226be273dcd3b150e7e3aea", @@ -2984,7 +3228,7 @@ "TT_test_msg_applysettings.py::test_apply_settings_rotation": "28bb0fb9d5296039f379a0c6e9bc38f37358928dd3938cc322d523874c628240", "TT_test_msg_applysettings.py::test_experimental_features": "38bfcb19f17cd020b3cd38a0a09c1698da86dacc62a43f59b926a50b1fadd041", "TT_test_msg_applysettings.py::test_label_too_long": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", -"TT_test_msg_applysettings.py::test_safety_checks": "b3dae10d31378b766f21260b9b363c64783806079009acc909164d14e7656c49", +"TT_test_msg_applysettings.py::test_safety_checks": "42b47ae0be7a8c86224b37ee417c1a487057974b7617b89b976b51be8fb05a04", "TT_test_msg_backup_device.py::test_backup_bip39": "0fd75efd974215a43d4b275a173b30ecb41291e5579abf6c15c196c0fc3aa87a", "TT_test_msg_backup_device.py::test_backup_slip39_advanced[click_info]": "2cf95cb4d4c83ea9895dd7bb95c1fa4802a84a1f35770db5eaf876700a6e344d", "TT_test_msg_backup_device.py::test_backup_slip39_advanced[no_click_info]": "991e151009e73c62b037008bd9eef82507ff0f441d408969f63876bfb73d9c1e", @@ -2993,12 +3237,12 @@ "TT_test_msg_backup_device.py::test_interrupt_backup_fails": "ae147498028d68aa71c7337544e4a5049c4c943897f905c6fe29e88e5c3ab056", "TT_test_msg_backup_device.py::test_no_backup_fails": "fada9d38ec099b3c6a4fd8bf994bb1f3431e40085128b4e0cd9deb8344dec53e", "TT_test_msg_backup_device.py::test_no_backup_show_entropy_fails": "001377ce61dcd189e6a9d17e20dcd71130e951dc3314b40ff26f816bd9355bdd", -"TT_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "22f045aff4ba5c629ae398144287006a7576b14be64cbb3ebefb31e671835ea5", -"TT_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "f3728af99cec286eee448931978ad9d0340f19bb82853fecd8cfd0d2e97bf440", +"TT_test_msg_change_wipe_code_t2.py::test_set_pin_to_wipe_code": "e77155a1f0b3c79a1713c3f57c520b51282a972768567d4048c9789cff9640da", +"TT_test_msg_change_wipe_code_t2.py::test_set_remove_wipe_code": "63ee5efe996b936c3e395b950b78adff40887eb005a2a18289b6194e2e6027cb", "TT_test_msg_change_wipe_code_t2.py::test_set_wipe_code_mismatch": "a98ec36a1945f91956ca63a558206d21a5bbf714dfe420f1404d1a5df634a9c3", -"TT_test_msg_change_wipe_code_t2.py::test_set_wipe_code_to_pin": "b6c4c714b70791b705351d45a883d46ae39621b324f9ecd07d91d231bef4bfb0", +"TT_test_msg_change_wipe_code_t2.py::test_set_wipe_code_to_pin": "ce954f765eac6510ff80fec9a90259ed6be8a0e1e22828331aa8b10b3d75b4bc", "TT_test_msg_changepin_t2.py::test_change_failed": "97f23132a32c14c8769c969c09fb202cb61c700a011ffdc557098c59112181e2", -"TT_test_msg_changepin_t2.py::test_change_invalid_current": "23d423f37f54384720867f1e1ae02b22cef9d26429615bf8ee9e7a9ae72a468a", +"TT_test_msg_changepin_t2.py::test_change_invalid_current": "e52be11ea0034a9f1dace94f7811e6f27e6a6e135572403fee50995adfcaf167", "TT_test_msg_changepin_t2.py::test_change_pin": "544f464b1460553a57011a6deedf9c0bcb650befdb7cf473bcb47752ea796b08", "TT_test_msg_changepin_t2.py::test_remove_pin": "95063d1282833732180946ddbabc7a1ea6d9b83dd7a1e4a6bb057723bd94b914", "TT_test_msg_changepin_t2.py::test_set_failed": "962ba410d395e37ad341b818c026b134891040617e3f9368c4fcaaa9b4a27efe", @@ -3039,7 +3283,7 @@ "TT_test_protection_levels.py::test_wipe_device": "f8a23360d5171de562b4de198aab78f76e4532baab3bfb85a39fd3515d533c3c", "TT_test_sdcard.py::test_sd_format": "f452c463dba5f19b684fb7738f2bd110908854a8e5981efbf301c55232f05b92", "TT_test_sdcard.py::test_sd_no_format": "14511e3d3ee535d97287d8ade25101e8c16db17c1dc5d3151b91e5e8eba61ba5", -"TT_test_sdcard.py::test_sd_protect_unlock": "437d39e03450baad6d860cf42d5b21d5a0a124b19d7cbf04a30685348c5c39a5", +"TT_test_sdcard.py::test_sd_protect_unlock": "818a8b275708e87a90dd24597ea4b63edf0b3e7ef9dea739cdc0e9a3aa96c4d3", "TT_test_session.py::test_cannot_resume_ended_session": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_test_session.py::test_clear_session": "289705a7742fdf6a0ae69cfb0ec1baa57277484485c20d1d174b880cfc0b2a4e", "TT_test_session.py::test_derive_cardano_empty_session": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", @@ -3059,7 +3303,8 @@ "TT_test_session_id_and_passphrase.py::test_passphrase_on_device": "b95cba09bd47cb9ac2df7272a1ae1e7a6d3ff3b345ad40ac3d139d99637c1ed8", "TT_test_session_id_and_passphrase.py::test_session_enable_passphrase": "5de5cbe74fe51d694ff926523f318ea3ad93f98bc5bbb13519e76c2f2c5cea43", "TT_test_session_id_and_passphrase.py::test_session_with_passphrase": "9b2d4b75a4c96cc3ab52056d4b4bc83a38d948bb35aaf422829b05c43ac0cf14", -"TT_tezos-test_getaddress.py::test_tezos_get_address": "4b6b9c08cd4536227322899aaf3c1c5c11d7f3fafd84e8ff0ac7eef7182bfa0b", +"TT_tezos-test_getaddress.py::test_tezos_get_address[False]": "4b6b9c08cd4536227322899aaf3c1c5c11d7f3fafd84e8ff0ac7eef7182bfa0b", +"TT_tezos-test_getaddress.py::test_tezos_get_address[True]": "2c1133be202367b729ded57fcec4182a88429273f26d15ba37e27dcce055a494", "TT_tezos-test_getpublickey.py::test_tezos_get_public_key": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_tezos-test_sign_tx.py::test_tezos_kt_remove_delegation": "2ba34b9c165275c38adfca7150c81882136932067814e856086c4d697fc74d76", "TT_tezos-test_sign_tx.py::test_tezos_sign_tx_delegation": "9c3802faf8ef2ad3d5277239c94fda2e27309b28bfe59d64b104804a7ca3e8db", @@ -3067,14 +3312,15 @@ "TT_tezos-test_sign_tx.py::test_tezos_sign_tx_origination": "774e06bb20aa897207e1330007a02ec0774d2c3843d1a9dd18acf3f708ee9b19", "TT_tezos-test_sign_tx.py::test_tezos_sign_tx_proposal": "3a2511734efc39a9ef4a9c17745520abdfb93a05b91092e0bdf2b32aa4488e82", "TT_tezos-test_sign_tx.py::test_tezos_sign_tx_reveal": "5a5656536636cad48e148175dd1af6e1c91ddc67d9649ff4d5524e169a477a06", -"TT_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction": "86fff3381db2d66d3d489857a42f8c972d18f39ee8e3bd58de6783bedd5b664a", +"TT_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction[False]": "86fff3381db2d66d3d489857a42f8c972d18f39ee8e3bd58de6783bedd5b664a", +"TT_tezos-test_sign_tx.py::test_tezos_sign_tx_tranasaction[True]": "bf4c76b60dd27f3a2b4636a711be1d2d9a08305c08b11de48ca9d1631dd99f43", "TT_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_nay": "e9bf0a20f79f8a8a0f93a354fa39801e4d604eae61f410a864f0d75943a589db", "TT_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_pass": "9aca8cf454e4d324b74ec6ae3b498268fdf91028b2aa89b0ed9a865805ab4738", "TT_tezos-test_sign_tx.py::test_tezos_sing_tx_ballot_yay": "676616096af684b60e3cdedb9f9c5c47e36edb148039c8300e57a72699bf5e2d", "TT_tezos-test_sign_tx.py::test_tezos_smart_contract_delegation": "8229e424f084325b88dcc8586d5d07188d6acfab66a7c9acf4235f7d57d56d01", "TT_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer": "e1344b38f88440fe95b44c99b29cbd50e50dfb2a992fb02ec4ee0b7bb3d9a2d7", "TT_tezos-test_sign_tx.py::test_tezos_smart_contract_transfer_to_contract": "75bbc1823af1c5f338888695dda11ee1d1aa96d9072598795afeea411f71c29b", -"TT_webauthn-test_msg_webauthn.py::test_add_remove": "a27cc6b06744969939df5750c90e59468c3ca41fcbc9ed0eaf87b68d463c045a", +"TT_webauthn-test_msg_webauthn.py::test_add_remove": "7a5407948b99a424d913a27023920eb5deb2b06cba1b78271c8ff6c69b56b85b", "TT_webauthn-test_u2f_counter.py::test_u2f_counter": "87f09bc2e7d3160ea1ffa7f340ed8513ec64b8bbb64e884e82f80fbb07899e1e", "TT_zcash-test_sign_tx.py::test_external_presigned": "5110eb059a3a57fc8a7555f4ea2fbdace52c520d40fef0a4f1b1b1e175dda199", "TT_zcash-test_sign_tx.py::test_one_two": "06b6b4bd3d2c43c58f7f4a4522aee5bf68123f760b541745fcd10ecaf62062a3", diff --git a/tests/ui_tests/reporting/common.py b/tests/ui_tests/reporting/common.py index b78e1ab1d..6001d333d 100644 --- a/tests/ui_tests/reporting/common.py +++ b/tests/ui_tests/reporting/common.py @@ -205,10 +205,12 @@ def _get_unique_differing_screens( master_screens_path = MASTER_CACHE_DIR / master_hash if not master_screens_path.exists(): master_screens_path.mkdir() - try: - download.fetch_recorded(master_hash, master_screens_path) - except RuntimeError as e: - print("WARNING:", e) + # master_hash may be empty, in case of new test + if master_hash: + try: + download.fetch_recorded(master_hash, master_screens_path) + except RuntimeError as e: + print("WARNING:", e) current_screens_path = get_screen_path(test_name) if not current_screens_path: @@ -217,7 +219,10 @@ def _get_unique_differing_screens( # Saving all the images to a common directory # They will be referenced from the HTML files - master_screens, master_hashes = screens_and_hashes(master_screens_path) + if master_hash: + master_screens, master_hashes = screens_and_hashes(master_screens_path) + else: + master_screens, master_hashes = [], [] current_screens, current_hashes = screens_and_hashes(current_screens_path) html.store_images(master_screens, master_hashes) html.store_images(current_screens, current_hashes) diff --git a/tests/ui_tests/reporting/testreport.py b/tests/ui_tests/reporting/testreport.py index 65eec47b2..76d2282cf 100644 --- a/tests/ui_tests/reporting/testreport.py +++ b/tests/ui_tests/reporting/testreport.py @@ -270,7 +270,10 @@ def _get_current_results() -> FixturesType: def master_diff() -> None: """Creating an HTML page showing all screens differing from master.""" current = _get_current_results() - _removed_tests, _added_tests, diff_tests = get_diff(current) + _removed_tests, added_tests, diff_tests = get_diff(current) + # Enriching the diff tests with the newly added ones (empty master hash) + for key, value in added_tests.items(): + diff_tests[key] = ("", value) generate_master_diff_report(diff_tests, TESTREPORT_PATH) diff --git a/tests/update_fixtures.py b/tests/update_fixtures.py index 335eb56c5..79fe08067 100755 --- a/tests/update_fixtures.py +++ b/tests/update_fixtures.py @@ -51,10 +51,12 @@ def _get_current_git_branch() -> str: help="Not take these jobs", multiple=True, ) +@click.option("-r", "--remove-missing", is_flag=True, help="Remove missing tests") def ci( branch: str | None, only_jobs: Iterable[str] | None, exclude_jobs: Iterable[str] | None, + remove_missing: bool, ) -> None: """Update fixtures file with results from CI.""" print("Updating from CI...") @@ -89,6 +91,15 @@ def ci( current_model = current_fixtures.setdefault(model, {}) current_group = current_model.setdefault(group, {}) # type: ignore + if remove_missing: + # get rid of tests that were not run in CI + removed = 0 + for key in list(current_group.keys()): + if key not in ui_res_dict[model][group]: + current_group.pop(key) + removed += 1 + print(f"Removed {removed} tests.") + differing = 0 for test_name, res in ui_res_dict[model][group].items(): if current_group.get(test_name) != res: diff --git a/tools/bump-version.py b/tools/bump-version.py index 7a78e1cc7..f045dc76a 100755 --- a/tools/bump-version.py +++ b/tools/bump-version.py @@ -64,7 +64,7 @@ def cli(project, version): major, minor, patch = m.group(1, 2, 3) parts = project.parts - if parts[-3:] == ("core", "embed", "bootloader"): + if (project / "version.h").is_file(): bump_header( project / "version.h", VERSION_MAJOR=major, @@ -78,23 +78,16 @@ def cli(project, version): VERSION_MINOR=minor, VERSION_PATCH=patch, ) - elif parts[-1] == "python": - bump_python( - project / "src" / "trezorlib" / "__init__.py", f"{major}.{minor}.{patch}" - ) - elif parts[-2:] == ("legacy", "firmware"): + elif parts[-1] == "legacy": bump_header( - project / "version.h", + project / "firmware" / "version.h", VERSION_MAJOR=major, VERSION_MINOR=minor, VERSION_PATCH=patch, ) - elif parts[-2:] == ("legacy", "bootloader"): - bump_header( - project / "version.h", - VERSION_MAJOR=major, - VERSION_MINOR=minor, - VERSION_PATCH=patch, + elif parts[-1] == "python": + bump_python( + project / "src" / "trezorlib" / "__init__.py", f"{major}.{minor}.{patch}" ) else: raise click.ClickException(f"Unknown project {project}.") diff --git a/tools/check-bitcoin-only b/tools/check-bitcoin-only index 8fe245c34..01f39279c 100755 --- a/tools/check-bitcoin-only +++ b/tools/check-bitcoin-only @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash RETURN=0 EXCEPTIONS=() @@ -10,6 +10,7 @@ EXCEPTIONS+=( "mnemonic" ) # has NEM in it EXCEPTIONS+=( "workflow" "overflow" ) # has Flo in it EXCEPTIONS+=( "SyntaxError" ) # has Axe in it EXCEPTIONS+=( "DKDNEM" ) # has NEM in it, some sort of weird coincidence +EXCEPTIONS+=( "confirm_ethereum_tx" ) # is model-specific, so is in layout/__init__.py instead of ethereum/layout.py GREP_ARGS=() for exception in "${EXCEPTIONS[@]}"; do @@ -17,7 +18,7 @@ for exception in "${EXCEPTIONS[@]}"; do done # dump all coins except the first 3 (Bitcoin, Testnet, Regtest) -ALTCOINS=$(./common/tools/cointool.py dump -l -p -t -d trezor1 -d trezor2 | grep '"name"' | cut -d '"' -f 4 | tail -n +4) +ALTCOINS=$(./common/tools/cointool.py dump -l -p -t -d T1B1 -d T2T1 -d T2B1 | grep '"name"' | cut -d '"' -f 4 | tail -n +4) # split on newlines only OLDIFS=$IFS IFS=" diff --git a/tools/style.c.exclude b/tools/style.c.exclude index 5ef29b507..e643d7575 100644 --- a/tools/style.c.exclude +++ b/tools/style.c.exclude @@ -1,5 +1,5 @@ ^\./core/embed/bootloader/protob/ -^\./crypto/aes/ +^\./crypto/aes/aes\(\|crypt\|key\|_modes\|opt\|tab\|tst\)\. ^\./crypto/chacha20poly1305/ ^\./crypto/ed25519-donna/ ^\./crypto/gui/