Merge remote-tracking branch 'origin/release/2020-09'

pull/1246/head
Tomas Susanka 4 years ago
commit b99b8b3df3

@ -18,7 +18,7 @@
"certificates": [], "certificates": [],
"withdrawals": [], "withdrawals": [],
"metadata": "", "metadata": "",
"input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]], "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]],
"inputs": [ "inputs": [
{ {
"path": "m/44'/1815'/0'/0/1", "path": "m/44'/1815'/0'/0/1",
@ -48,7 +48,7 @@
"certificates": [], "certificates": [],
"withdrawals": [], "withdrawals": [],
"metadata": "", "metadata": "",
"input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
"inputs": [ "inputs": [
{ {
"path": "m/44'/1815'/0'/0/1", "path": "m/44'/1815'/0'/0/1",
@ -83,7 +83,7 @@
"certificates": [], "certificates": [],
"withdrawals": [], "withdrawals": [],
"metadata": "", "metadata": "",
"input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]], "input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
"inputs": [ "inputs": [
{ {
"path": "m/44'/1815'/0'/0/1", "path": "m/44'/1815'/0'/0/1",

@ -35,13 +35,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Deprecated ### Deprecated
### Removed ### Removed
- ETP, GIN, PTC, ZEL support - Remove ETP, GIN, PTC, ZEL support.
- Drop support for signing Zcash v3 transactions. [#982]
### Fixed ### Fixed
- CRW addresses are properly generated. [#1139] - CRW addresses are properly generated. [#1139]
- Fix boot loop after uploading invalid homescreen. [#1118] - Fix boot loop after uploading invalid homescreen. [#1118]
- Allow 49/x not 49/x' for Casa. [#1190]
- Make sure Homescreen is properly initialized. [#1095]
### Security ### Security
- Show non-empty passphrase on device when it was entered on host.
- Show warning if nLockTime is set but ineffective due to all nSequence values being 0xffffffff.
## 2.3.2 [5th August 2020] ## 2.3.2 [5th August 2020]
@ -268,6 +273,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#948]: https://github.com/trezor/trezor-firmware/issues/948 [#948]: https://github.com/trezor/trezor-firmware/issues/948
[#958]: https://github.com/trezor/trezor-firmware/issues/958 [#958]: https://github.com/trezor/trezor-firmware/issues/958
[#982]: https://github.com/trezor/trezor-firmware/issues/982
[#1027]: https://github.com/trezor/trezor-firmware/issues/1027 [#1027]: https://github.com/trezor/trezor-firmware/issues/1027
[#1030]: https://github.com/trezor/trezor-firmware/issues/1030 [#1030]: https://github.com/trezor/trezor-firmware/issues/1030
[#1042]: https://github.com/trezor/trezor-firmware/issues/1042 [#1042]: https://github.com/trezor/trezor-firmware/issues/1042
@ -278,6 +284,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1074]: https://github.com/trezor/trezor-firmware/issues/1074 [#1074]: https://github.com/trezor/trezor-firmware/issues/1074
[#1087]: https://github.com/trezor/trezor-firmware/issues/1087 [#1087]: https://github.com/trezor/trezor-firmware/issues/1087
[#1089]: https://github.com/trezor/trezor-firmware/issues/1089 [#1089]: https://github.com/trezor/trezor-firmware/issues/1089
[#1095]: https://github.com/trezor/trezor-firmware/issues/1095
[#1098]: https://github.com/trezor/trezor-firmware/issues/1098 [#1098]: https://github.com/trezor/trezor-firmware/issues/1098
[#1115]: https://github.com/trezor/trezor-firmware/issues/1115 [#1115]: https://github.com/trezor/trezor-firmware/issues/1115
[#1118]: https://github.com/trezor/trezor-firmware/issues/1118 [#1118]: https://github.com/trezor/trezor-firmware/issues/1118
@ -287,3 +294,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[#1165]: https://github.com/trezor/trezor-firmware/pull/1165 [#1165]: https://github.com/trezor/trezor-firmware/pull/1165
[#1173]: https://github.com/trezor/trezor-firmware/pull/1173 [#1173]: https://github.com/trezor/trezor-firmware/pull/1173
[#1188]: https://github.com/trezor/trezor-firmware/issues/1188 [#1188]: https://github.com/trezor/trezor-firmware/issues/1188
[#1190]: https://github.com/trezor/trezor-firmware/issues/1190

@ -3,11 +3,8 @@ from trezor.messages import MessageType
def boot() -> None: def boot() -> None:
wire.add(MessageType.AuthorizeCoinJoin, __name__, "authorize_coinjoin")
wire.add(MessageType.GetPublicKey, __name__, "get_public_key") wire.add(MessageType.GetPublicKey, __name__, "get_public_key")
wire.add(MessageType.GetAddress, __name__, "get_address") wire.add(MessageType.GetAddress, __name__, "get_address")
wire.add(MessageType.GetOwnershipId, __name__, "get_ownership_id")
wire.add(MessageType.GetOwnershipProof, __name__, "get_ownership_proof")
wire.add(MessageType.SignTx, __name__, "sign_tx") wire.add(MessageType.SignTx, __name__, "sign_tx")
wire.add(MessageType.SignMessage, __name__, "sign_message") wire.add(MessageType.SignMessage, __name__, "sign_message")
wire.add(MessageType.VerifyMessage, __name__, "verify_message") wire.add(MessageType.VerifyMessage, __name__, "verify_message")

@ -4,11 +4,11 @@ from trezor.messages.SignTx import SignTx
from trezor.messages.TxAck import TxAck from trezor.messages.TxAck import TxAck
from trezor.messages.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from apps.common import coininfo, paths from apps.common import coininfo
from ..common import BITCOIN_NAMES from ..common import BITCOIN_NAMES
from ..keychain import with_keychain from ..keychain import with_keychain
from . import approvers, bitcoin, helpers, layout, progress from . import approvers, bitcoin, helpers, progress
if not utils.BITCOIN_ONLY: if not utils.BITCOIN_ONLY:
from . import bitcoinlike, decred, zcash from . import bitcoinlike, decred, zcash
@ -52,30 +52,8 @@ async def sign_tx(
if req.request_type == TXFINISHED: if req.request_type == TXFINISHED:
break break
res = await ctx.call(req, TxAck, field_cache) res = await ctx.call(req, TxAck, field_cache)
elif isinstance(req, helpers.UiConfirmOutput): elif isinstance(req, helpers.UiConfirm):
res = await layout.confirm_output(ctx, req.output, req.coin) res = await req.confirm_dialog(ctx)
progress.report_init()
elif isinstance(req, helpers.UiConfirmTotal):
res = await layout.confirm_total(ctx, req.spending, req.fee, req.coin)
progress.report_init()
elif isinstance(req, helpers.UiConfirmJointTotal):
res = await layout.confirm_joint_total(
ctx, req.spending, req.total, req.coin
)
progress.report_init()
elif isinstance(req, helpers.UiConfirmFeeOverThreshold):
res = await layout.confirm_feeoverthreshold(ctx, req.fee, req.coin)
progress.report_init()
elif isinstance(req, helpers.UiConfirmChangeCountOverThreshold):
res = await layout.confirm_change_count_over_threshold(
ctx, req.change_count
)
progress.report_init()
elif isinstance(req, helpers.UiConfirmNonDefaultLocktime):
res = await layout.confirm_nondefault_locktime(ctx, req.lock_time)
progress.report_init()
elif isinstance(req, helpers.UiConfirmForeignAddress):
res = await paths.show_path_warning(ctx, req.address_n)
progress.report_init() progress.report_init()
else: else:
raise TypeError("Invalid signing instruction") raise TypeError("Invalid signing instruction")

@ -15,6 +15,9 @@ from . import helpers, tx_weight
if False: if False:
from ..authorization import CoinJoinAuthorization from ..authorization import CoinJoinAuthorization
# Setting nSequence to this value for every input in a transaction disables nLockTime.
_SEQUENCE_FINAL = const(0xFFFFFFFF)
# An Approver object computes the transaction totals and either prompts the user # An Approver object computes the transaction totals and either prompts the user
# to confirm transaction parameters (output addresses, amounts and fees) or uses # to confirm transaction parameters (output addresses, amounts and fees) or uses
@ -25,6 +28,7 @@ class Approver:
self.tx = tx self.tx = tx
self.coin = coin self.coin = coin
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count) self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
self.min_sequence = _SEQUENCE_FINAL # the minimum nSequence of all inputs
# amounts # amounts
self.total_in = 0 # sum of input amounts self.total_in = 0 # sum of input amounts
@ -35,11 +39,13 @@ class Approver:
async def add_internal_input(self, txi: TxInputType, amount: int) -> None: async def add_internal_input(self, txi: TxInputType, amount: int) -> None:
self.weight.add_input(txi) self.weight.add_input(txi)
self.total_in += amount self.total_in += amount
self.min_sequence = min(self.min_sequence, txi.sequence)
def add_external_input(self, txi: TxInputType) -> None: def add_external_input(self, txi: TxInputType) -> None:
self.weight.add_input(txi) self.weight.add_input(txi)
self.total_in += txi.amount self.total_in += txi.amount
self.external_in += txi.amount self.external_in += txi.amount
self.min_sequence = min(self.min_sequence, txi.sequence)
def add_change_output(self, txo: TxOutputType, script_pubkey: bytes) -> None: def add_change_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
self.weight.add_output(script_pubkey) self.weight.add_output(script_pubkey)
@ -100,7 +106,10 @@ class BasicApprover(Approver):
if self.change_count > self.MAX_SILENT_CHANGE_COUNT: if self.change_count > self.MAX_SILENT_CHANGE_COUNT:
await helpers.confirm_change_count_over_threshold(self.change_count) await helpers.confirm_change_count_over_threshold(self.change_count)
if self.tx.lock_time > 0: if self.tx.lock_time > 0:
await helpers.confirm_nondefault_locktime(self.tx.lock_time) lock_time_disabled = self.min_sequence == _SEQUENCE_FINAL
await helpers.confirm_nondefault_locktime(
self.tx.lock_time, lock_time_disabled
)
if not self.external_in: if not self.external_in:
await helpers.confirm_total(total, fee, self.coin) await helpers.confirm_total(total, fee, self.coin)
else: else:

@ -14,10 +14,12 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from apps.common import paths
from apps.common.coininfo import CoinInfo from apps.common.coininfo import CoinInfo
from .. import common from .. import common
from ..writers import TX_HASH_SIZE from ..writers import TX_HASH_SIZE
from . import layout
if False: if False:
from typing import Any, Awaitable from typing import Any, Awaitable
@ -27,57 +29,86 @@ if False:
# === # ===
class UiConfirmOutput: class UiConfirm:
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
raise NotImplementedError
class UiConfirmOutput(UiConfirm):
def __init__(self, output: TxOutputType, coin: CoinInfo): def __init__(self, output: TxOutputType, coin: CoinInfo):
self.output = output self.output = output
self.coin = coin self.coin = coin
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_output(ctx, self.output, self.coin)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmTotal: class UiConfirmTotal(UiConfirm):
def __init__(self, spending: int, fee: int, coin: CoinInfo): def __init__(self, spending: int, fee: int, coin: CoinInfo):
self.spending = spending self.spending = spending
self.fee = fee self.fee = fee
self.coin = coin self.coin = coin
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_total(ctx, self.spending, self.fee, self.coin)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmJointTotal: class UiConfirmJointTotal(UiConfirm):
def __init__(self, spending: int, total: int, coin: CoinInfo): def __init__(self, spending: int, total: int, coin: CoinInfo):
self.spending = spending self.spending = spending
self.total = total self.total = total
self.coin = coin self.coin = coin
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_joint_total(ctx, self.spending, self.total, self.coin)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmFeeOverThreshold: class UiConfirmFeeOverThreshold(UiConfirm):
def __init__(self, fee: int, coin: CoinInfo): def __init__(self, fee: int, coin: CoinInfo):
self.fee = fee self.fee = fee
self.coin = coin self.coin = coin
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_feeoverthreshold(ctx, self.fee, self.coin)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmChangeCountOverThreshold: class UiConfirmChangeCountOverThreshold(UiConfirm):
def __init__(self, change_count: int): def __init__(self, change_count: int):
self.change_count = change_count self.change_count = change_count
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_change_count_over_threshold(ctx, self.change_count)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmForeignAddress: class UiConfirmForeignAddress(UiConfirm):
def __init__(self, address_n: list): def __init__(self, address_n: list):
self.address_n = address_n self.address_n = address_n
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return paths.show_path_warning(ctx, self.address_n)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
class UiConfirmNonDefaultLocktime: class UiConfirmNonDefaultLocktime(UiConfirm):
def __init__(self, lock_time: int): def __init__(self, lock_time: int, lock_time_disabled: bool):
self.lock_time = lock_time self.lock_time = lock_time
self.lock_time_disabled = lock_time_disabled
def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_nondefault_locktime(
ctx, self.lock_time, self.lock_time_disabled
)
__eq__ = utils.obj_eq __eq__ = utils.obj_eq
@ -106,8 +137,8 @@ def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore
return (yield UiConfirmForeignAddress(address_n)) return (yield UiConfirmForeignAddress(address_n))
def confirm_nondefault_locktime(lock_time: int) -> Awaitable[Any]: # type: ignore def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> Awaitable[Any]: # type: ignore
return (yield UiConfirmNonDefaultLocktime(lock_time)) return (yield UiConfirmNonDefaultLocktime(lock_time, lock_time_disabled))
def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes = None) -> Awaitable[Any]: # type: ignore def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes = None) -> Awaitable[Any]: # type: ignore

@ -101,13 +101,21 @@ async def confirm_change_count_over_threshold(
await require_confirm(ctx, text, ButtonRequestType.SignTx) await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def confirm_nondefault_locktime(ctx: wire.Context, lock_time: int) -> None: async def confirm_nondefault_locktime(
text = Text("Confirm locktime", ui.ICON_SEND, ui.GREEN) ctx: wire.Context, lock_time: int, lock_time_disabled: bool
text.normal("Locktime for this transaction is set to") ) -> None:
if lock_time < _LOCKTIME_TIMESTAMP_MIN_VALUE: if lock_time_disabled:
text.normal("blockheight:") text = Text("Warning", ui.ICON_SEND, ui.GREEN)
text.normal("Locktime is set but will", "have no effect.")
text.br_half()
else: else:
text.normal("timestamp:") text = Text("Confirm locktime", ui.ICON_SEND, ui.GREEN)
text.bold(str(lock_time)) text.normal("Locktime for this", "transaction is set to")
if lock_time < _LOCKTIME_TIMESTAMP_MIN_VALUE:
text.normal("blockheight:")
else:
text.normal("timestamp:")
text.bold(str(lock_time))
text.normal("Continue?") text.normal("Continue?")
await require_confirm(ctx, text, ButtonRequestType.SignTx) await require_confirm(ctx, text, ButtonRequestType.SignTx)

@ -10,6 +10,7 @@ from trezor.ui.passphrase import CANCELLED, PassphraseKeyboard
from trezor.ui.text import Text from trezor.ui.text import Text
from . import button_request from . import button_request
from .confirm import require_confirm
_MAX_PASSPHRASE_LEN = const(50) _MAX_PASSPHRASE_LEN = const(50)
@ -53,6 +54,22 @@ async def _request_on_host(ctx: wire.Context) -> str:
raise wire.DataError( raise wire.DataError(
"Passphrase not provided and on_device is False. Use empty string to set an empty passphrase." "Passphrase not provided and on_device is False. Use empty string to set an empty passphrase."
) )
# non-empty passphrase
if ack.passphrase:
text = Text("Hidden wallet", ICON_CONFIG)
text.normal("Access hidden wallet?")
text.br()
text.normal("Next screen will show")
text.normal("the passphrase!")
await require_confirm(ctx, text, ButtonRequestType.Other)
text = Text("Hidden wallet", ICON_CONFIG)
text.normal("Use this passphrase?")
text.br()
text.mono(ack.passphrase)
await require_confirm(ctx, text, ButtonRequestType.Other)
return ack.passphrase return ack.passphrase

@ -35,6 +35,7 @@ class TestApprover(unittest.TestCase):
TxInputType( TxInputType(
amount=denomination + 1000000 * (i + 1), amount=denomination + 1000000 * (i + 1),
script_type=InputScriptType.EXTERNAL, script_type=InputScriptType.EXTERNAL,
sequence=0xffffffff,
) for i in range(99) ) for i in range(99)
] ]
@ -45,6 +46,7 @@ class TestApprover(unittest.TestCase):
address_n=[H_(84), H_(0), H_(0), 0, 1], address_n=[H_(84), H_(0), H_(0), 0, 1],
amount=denomination + 1000000, amount=denomination + 1000000,
script_type=InputScriptType.SPENDWITNESS, script_type=InputScriptType.SPENDWITNESS,
sequence=0xffffffff,
) )
) )

@ -103,7 +103,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
helpers.UiConfirmOutput(out2, coin), helpers.UiConfirmOutput(out2, coin),
True, True,
helpers.UiConfirmNonDefaultLocktime(tx.lock_time), helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True, True,
helpers.UiConfirmTotal(12300000, 11000, coin), helpers.UiConfirmTotal(12300000, 11000, coin),
@ -225,7 +225,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out2])), TxAck(tx=TransactionType(outputs=[out2])),
helpers.UiConfirmNonDefaultLocktime(tx.lock_time), helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True, True,
helpers.UiConfirmTotal(5000000 + 11000, 11000, coin), helpers.UiConfirmTotal(5000000 + 11000, 11000, coin),

@ -103,7 +103,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
helpers.UiConfirmOutput(out2, coin), helpers.UiConfirmOutput(out2, coin),
True, True,
helpers.UiConfirmNonDefaultLocktime(tx.lock_time), helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True, True,
helpers.UiConfirmTotal(123445789 + 11000, 11000, coin), helpers.UiConfirmTotal(123445789 + 11000, 11000, coin),
@ -225,7 +225,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out2])), TxAck(tx=TransactionType(outputs=[out2])),
helpers.UiConfirmNonDefaultLocktime(tx.lock_time), helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True, True,
helpers.UiConfirmTotal(12300000 + 11000, 11000, coin), helpers.UiConfirmTotal(12300000 + 11000, 11000, coin),

@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- XVG support. [#1165] - XVG support. [#1165]
- Ask user to confirm custom nLockTime.
### Changed ### Changed
- Print inverted question mark for non-printable characters. - Print inverted question mark for non-printable characters.
@ -35,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
### Security ### Security
- Show non-empty passphrase on device when it was entered on host.
## 1.9.2 [5th August 2020] ## 1.9.2 [5th August 2020]

@ -601,6 +601,30 @@ const uint8_t *config_getSeed(void) {
memzero(passphrase, sizeof(passphrase)); memzero(passphrase, sizeof(passphrase));
return NULL; return NULL;
} }
// passphrase is used - confirm on the display
if (passphrase[0] != 0) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Access hidden wallet?"), NULL,
_("Next screen will show"), _("the passphrase!"), NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
memzero(mnemonic, sizeof(mnemonic));
memzero(passphrase, sizeof(passphrase));
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Passphrase dismissed"));
layoutHome();
return NULL;
}
layoutShowPassphrase(passphrase);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
memzero(mnemonic, sizeof(mnemonic));
memzero(passphrase, sizeof(passphrase));
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Passphrase dismissed"));
layoutHome();
return NULL;
}
}
// if storage was not imported (i.e. it was properly generated or recovered) // if storage was not imported (i.e. it was properly generated or recovered)
bool imported = false; bool imported = false;
config_get_bool(KEY_IMPORTED, &imported); config_get_bool(KEY_IMPORTED, &imported);

@ -37,6 +37,8 @@
#include "timer.h" #include "timer.h"
#include "util.h" #include "util.h"
#define LOCKTIME_TIMESTAMP_MIN_VALUE 500000000
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
static const char *slip44_extras(uint32_t coin_type) { static const char *slip44_extras(uint32_t coin_type) {
@ -450,6 +452,25 @@ void layoutChangeCountOverThreshold(uint32_t change_count) {
_("Continue?"), NULL); _("Continue?"), NULL);
} }
void layoutConfirmNondefaultLockTime(uint32_t lock_time,
bool lock_time_disabled) {
if (lock_time_disabled) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Warning!"), _("Locktime is set but"),
_("will have no effect."), NULL, _("Continue?"), NULL);
} else {
char str_locktime[11] = {0};
snprintf(str_locktime, sizeof(str_locktime), "%" PRIu32, lock_time);
char *str_type = (lock_time < LOCKTIME_TIMESTAMP_MIN_VALUE) ? "blockheight:"
: "timestamp:";
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Locktime for this"), _("transaction is set to"),
str_type, str_locktime, _("Continue?"), NULL);
}
}
void layoutSignMessage(const uint8_t *msg, uint32_t len) { void layoutSignMessage(const uint8_t *msg, uint32_t len) {
const char **str = NULL; const char **str = NULL;
if (!is_valid_ascii(msg, len)) { if (!is_valid_ascii(msg, len)) {
@ -823,6 +844,25 @@ void layoutU2FDialog(const char *verb, const char *appname) {
#endif #endif
void layoutShowPassphrase(const char *passphrase) {
if (layoutLast != layoutShowPassphrase) {
layoutSwipe();
} else {
oledClear();
}
const char **str =
split_message((const uint8_t *)passphrase, strlen(passphrase), 21);
for (int i = 0; i < 3; i++) {
oledDrawString(0, i * 9 + 4, str[i], FONT_FIXED);
}
oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1,
_("Use this passphrase?"), FONT_STANDARD);
oledHLine(OLED_HEIGHT - 21);
layoutButtonNo(_("Cancel"), &bmp_btn_cancel);
layoutButtonYes(_("Confirm"), &bmp_btn_confirm);
oledRefresh();
}
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,

@ -53,6 +53,8 @@ void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out,
uint64_t amount_fee); uint64_t amount_fee);
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee);
void layoutChangeCountOverThreshold(uint32_t change_count); void layoutChangeCountOverThreshold(uint32_t change_count);
void layoutConfirmNondefaultLockTime(uint32_t lock_time,
bool lock_time_disabled);
void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutSignMessage(const uint8_t *msg, uint32_t len);
void layoutVerifyAddress(const CoinInfo *coin, const char *address); void layoutVerifyAddress(const CoinInfo *coin, const char *address);
void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len);
@ -69,6 +71,7 @@ void layoutXPUB(const char *xpub, int index, int page, bool ours);
void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutSignIdentity(const IdentityType *identity, const char *challenge);
void layoutDecryptIdentity(const IdentityType *identity); void layoutDecryptIdentity(const IdentityType *identity);
void layoutU2FDialog(const char *verb, const char *appname); void layoutU2FDialog(const char *verb, const char *appname);
void layoutShowPassphrase(const char *passphrase);
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
const char *desc, const char *line1, const char *address); const char *desc, const char *line1, const char *address);

@ -75,6 +75,7 @@ static uint32_t lock_time = 0;
static uint32_t expiry = 0; static uint32_t expiry = 0;
static uint32_t version_group_id = 0; static uint32_t version_group_id = 0;
static uint32_t timestamp = 0; static uint32_t timestamp = 0;
static uint32_t min_sequence = 0;
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
static uint32_t branch_id = 0; static uint32_t branch_id = 0;
#endif #endif
@ -107,6 +108,10 @@ static uint32_t tx_weight;
/* The maximum number of change-outputs allowed without user confirmation. */ /* The maximum number of change-outputs allowed without user confirmation. */
#define MAX_SILENT_CHANGE_COUNT 2 #define MAX_SILENT_CHANGE_COUNT 2
/* Setting nSequence to this value for every input in a transaction disables
nLockTime. */
#define SEQUENCE_FINAL 0xffffffff
enum { enum {
SIGHASH_ALL = 1, SIGHASH_ALL = 1,
SIGHASH_FORKID = 0x40, SIGHASH_FORKID = 0x40,
@ -497,6 +502,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin,
memcpy(&root, _root, sizeof(HDNode)); memcpy(&root, _root, sizeof(HDNode));
version = msg->version; version = msg->version;
lock_time = msg->lock_time; lock_time = msg->lock_time;
min_sequence = SEQUENCE_FINAL;
if (!coin->overwintered) { if (!coin->overwintered) {
if (msg->has_version_group_id) { if (msg->has_version_group_id) {
@ -782,12 +788,18 @@ static bool signing_check_input(const TxInputType *txinput) {
} else { // single signature } else { // single signature
multisig_fp_mismatch = true; multisig_fp_mismatch = true;
} }
// remember the input bip32 path // remember the input bip32 path
// change addresses must use the same bip32 path as all inputs // change addresses must use the same bip32 path as all inputs
extract_input_bip32_path(txinput); extract_input_bip32_path(txinput);
// remember the minimum nSequence value
if (txinput->sequence < min_sequence) min_sequence = txinput->sequence;
// compute segwit hashPrevouts & hashSequence // compute segwit hashPrevouts & hashSequence
tx_prevout_hash(&hasher_prevouts, txinput); tx_prevout_hash(&hasher_prevouts, txinput);
tx_sequence_hash(&hasher_sequence, txinput); tx_sequence_hash(&hasher_sequence, txinput);
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
if (coin->decred) { if (coin->decred) {
// serialize Decred prefix in Phase 1 // serialize Decred prefix in Phase 1
@ -800,6 +812,7 @@ static bool signing_check_input(const TxInputType *txinput) {
tx_serialize_input_hash(&ti, txinput); tx_serialize_input_hash(&ti, txinput);
} }
#endif #endif
// hash prevout and script type to check it later (relevant for fee // hash prevout and script type to check it later (relevant for fee
// computation) // computation)
tx_prevout_hash(&hasher_check, txinput); tx_prevout_hash(&hasher_check, txinput);
@ -914,6 +927,7 @@ static bool signing_confirm_tx(void) {
return false; return false;
} }
} }
uint64_t fee = 0; uint64_t fee = 0;
if (spending <= to_spend) { if (spending <= to_spend) {
fee = to_spend - spending; fee = to_spend - spending;
@ -939,6 +953,16 @@ static bool signing_confirm_tx(void) {
} }
} }
if (lock_time != 0) {
bool lock_time_disabled = (min_sequence == SEQUENCE_FINAL);
layoutConfirmNondefaultLockTime(lock_time, lock_time_disabled);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
signing_abort();
return false;
}
}
// last confirmation // last confirmation
layoutConfirmTx(coin, to_spend - change_spend, fee); layoutConfirmTx(coin, to_spend - change_spend, fee);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {

@ -1,533 +0,0 @@
# This file is part of the Trezor project.
#
# Copyright (C) 2020 SatoshiLabs and contributors
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
import pytest
from trezorlib import btc, device, messages
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_meta, request_output
B = messages.ButtonRequestType
TX_CACHE_TESTNET = TxCache("Testnet")
TX_CACHE_MAINNET = TxCache("Bitcoin")
TXHASH_e5b7e2 = bytes.fromhex(
"e5b7e21b5ba720e81efd6bfa9f854ababdcddc75a43bfa60bf0fe069cfd1bb8a"
)
TXHASH_65b811 = bytes.fromhex(
"65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b"
)
PIN = "1234"
ROUND_ID_LEN = 32
pytestmark = pytest.mark.skip_t1
@pytest.mark.setup_client(pin=PIN)
def test_sign_tx(client):
with client:
client.use_pin_sequence([PIN])
btc.authorize_coinjoin(
client,
coordinator="www.example.com",
max_total_fee=10010,
fee_per_anonymity=5000000, # 0.005 %
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
client.call(messages.LockDevice())
with client:
client.set_expected_responses(
[messages.PreauthorizedRequest(), messages.OwnershipProof()]
)
btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
with client:
client.set_expected_responses(
[messages.PreauthorizedRequest(), messages.OwnershipProof()]
)
btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/5"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
inp1 = messages.TxInputType(
# seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
# 84'/1'/0'/0/0
# tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
amount=100000,
prev_hash=TXHASH_e5b7e2,
prev_index=0,
script_type=messages.InputScriptType.EXTERNAL,
ownership_proof=bytearray.fromhex(
"534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
),
)
inp2 = messages.TxInputType(
address_n=parse_path("84'/1'/0'/1/0"),
amount=7289000,
prev_hash=TXHASH_65b811,
prev_index=1,
script_type=messages.InputScriptType.SPENDWITNESS,
)
# Other's coinjoined output.
out1 = messages.TxOutputType(
address="tb1qk7j3ahs2v6hrv4v282cf0tvxh0vqq7rpt3zcml",
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our coinjoined output.
out2 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/1"),
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our change output.
out3 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/2"),
amount=7289000 - 50000 - 5 - 5000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Other's change output.
out4 = messages.TxOutputType(
address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
amount=100000 - 50000 - 5 - 5000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Coordinator's output.
out5 = messages.TxOutputType(
address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
amount=10,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
with client:
client.set_expected_responses(
[
messages.PreauthorizedRequest(),
request_input(0),
request_input(1),
request_meta(TXHASH_65b811),
request_input(0, TXHASH_65b811),
request_output(0, TXHASH_65b811),
request_output(1, TXHASH_65b811),
request_output(0),
request_output(1),
request_output(2),
request_output(3),
request_output(4),
request_input(0),
request_meta(TXHASH_e5b7e2),
request_input(0, TXHASH_e5b7e2),
request_output(0, TXHASH_e5b7e2),
request_output(1, TXHASH_e5b7e2),
request_input(0),
request_input(1),
request_output(0),
request_output(1),
request_output(2),
request_output(3),
request_output(4),
request_input(1),
request_finished(),
]
)
_, serialized_tx = btc.sign_tx(
client,
"Testnet",
[inp1, inp2],
[out1, out2, out3, out4, out5],
prev_txes=TX_CACHE_TESTNET,
preauthorized=True,
)
assert (
serialized_tx.hex()
== "010000000001028abbd1cf69e00fbf60fa3ba475dccdbdba4a859ffa6bfd1ee820a75b1be2b7e50000000000ffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff0550c3000000000000160014b7a51ede0a66ae36558a3ab097ad86bbd800786150c3000000000000160014167dae080bca35c9ea49c0c8335dcc4b252a1d70cb616e00000000001600141d03a4d2167961b853d6cadfeab08e4937c5dfe8c3af0000000000001600142e01768ca46e57210f0bd2c99e630e8168fa5fe50a000000000000001976a914a579388225827d9f2fe9014add644487808c695d88ac00024730440220694105071db8c6c8ba3d385d01694b6f7c17546327ab26d4c53a6503fee301e202202dd310c23a195a6cebc904b91ebd15d782e6dacd08670a72ade2795e7d3ff4ec012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f00000000"
)
# Test for a second time.
btc.sign_tx(
client,
"Testnet",
[inp1, inp2],
[out1, out2, out3, out4, out5],
prev_txes=TX_CACHE_TESTNET,
preauthorized=True,
)
# Test for a third time, fees should exceed max_total_fee.
with pytest.raises(TrezorFailure, match="Fees exceed authorized limit"):
btc.sign_tx(
client,
"Testnet",
[inp1, inp2],
[out1, out2, out3, out4, out5],
prev_txes=TX_CACHE_TESTNET,
preauthorized=True,
)
def test_unfair_fee(client):
# Test unfair mining fee distribution amongst participants.
with client:
btc.authorize_coinjoin(
client,
coordinator="www.example.com",
max_total_fee=10000,
fee_per_anonymity=5000000, # 0.005 %
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
inp1 = messages.TxInputType(
# seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
# 84'/1'/0'/0/0
# tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
amount=100000,
prev_hash=TXHASH_e5b7e2,
prev_index=0,
script_type=messages.InputScriptType.EXTERNAL,
ownership_proof=bytearray.fromhex(
"534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
),
)
inp2 = messages.TxInputType(
address_n=parse_path("84'/1'/0'/1/0"),
amount=7289000,
prev_hash=TXHASH_65b811,
prev_index=1,
script_type=messages.InputScriptType.SPENDWITNESS,
)
# Other's coinjoined output.
out1 = messages.TxOutputType(
address="tb1qk7j3ahs2v6hrv4v282cf0tvxh0vqq7rpt3zcml",
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our coinjoined output.
out2 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/1"),
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our change output.
out3 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/2"),
amount=7289000 - 50000 - 5 - 6000, # unfair mining fee
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Other's change output.
out4 = messages.TxOutputType(
address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
amount=100000 - 50000 - 5 - 4000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Coordinator's output.
out5 = messages.TxOutputType(
address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
amount=10,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
with pytest.raises(TrezorFailure, match="fee over threshold"):
btc.sign_tx(
client,
"Testnet",
[inp1, inp2],
[out1, out2, out3, out4, out5],
prev_txes=TX_CACHE_TESTNET,
preauthorized=True,
)
def test_no_anonymity(client):
# Test CoinJoin transaction giving the user's outputs no gain in anonymity.
with client:
btc.authorize_coinjoin(
client,
coordinator="www.example.com",
max_total_fee=5005,
fee_per_anonymity=5000000, # 0.005 %
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
inp1 = messages.TxInputType(
# seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
# 84'/1'/0'/0/0
# tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
amount=100000,
prev_hash=TXHASH_e5b7e2,
prev_index=0,
script_type=messages.InputScriptType.EXTERNAL,
ownership_proof=bytearray.fromhex(
"534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
),
)
inp2 = messages.TxInputType(
address_n=parse_path("84'/1'/0'/1/0"),
amount=7289000,
prev_hash=TXHASH_65b811,
prev_index=1,
script_type=messages.InputScriptType.SPENDWITNESS,
)
# Other's coinjoined output.
out1 = messages.TxOutputType(
address="tb1qk7j3ahs2v6hrv4v282cf0tvxh0vqq7rpt3zcml",
amount=30000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Other's coinjoined output.
out2 = messages.TxOutputType(
address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
amount=30000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our coinjoined output.
out3 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/1"),
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our coinjoined output.
out4 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/2"),
amount=50000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Our change output.
out5 = messages.TxOutputType(
address_n=parse_path("84'/1'/0'/1/2"),
amount=7289000 - 50000 - 50000 - 10 - 5000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Other's change output.
out6 = messages.TxOutputType(
address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
amount=100000 - 30000 - 30000 - 6 - 5000,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
# Coordinator's output.
out7 = messages.TxOutputType(
address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
amount=16,
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
with pytest.raises(TrezorFailure, match="No anonymity gain"):
btc.sign_tx(
client,
"Testnet",
[inp1, inp2],
[out1, out2, out3, out4, out5, out6, out7],
prev_txes=TX_CACHE_TESTNET,
preauthorized=True,
)
def test_wrong_coordinator(client):
# Ensure that a preauthorized GetOwnershipProof fails if the commitment_data doesn't match the coordinator.
btc.authorize_coinjoin(
client,
max_total_fee=50000,
coordinator="www.example.com",
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
with pytest.raises(TrezorFailure, match="Unauthorized operation"):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example.org" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
def test_cancel_authorization(client):
# Ensure that a preauthorized GetOwnershipProof fails if the commitment_data doesn't match the coordinator.
btc.authorize_coinjoin(
client,
max_total_fee=50000,
coordinator="www.example.com",
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
device.cancel_authorization(client)
with pytest.raises(TrezorFailure, match="No preauthorized operation"):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
@pytest.mark.skip_ui
def test_multisession_authorization(client):
# Authorize CoinJoin with www.example1.com in session 1.
btc.authorize_coinjoin(
client,
max_total_fee=50000,
coordinator="www.example1.com",
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
# Open a second session.
session_id1 = client.session_id
client.init_device(new_session=True)
# Authorize CoinJoin with www.example2.com in session 2.
btc.authorize_coinjoin(
client,
max_total_fee=50000,
coordinator="www.example2.com",
n=parse_path("m/84'/1'/0'"),
coin_name="Testnet",
script_type=messages.InputScriptType.SPENDWITNESS,
)
# Requesting a preauthorized ownership proof for www.example1.com should fail in session 2.
with pytest.raises(TrezorFailure, match="Unauthorized operation"):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example1.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
# Requesting a preauthorized ownership proof for www.example2.com should succeed in session 2.
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example2.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
assert (
ownership_proof.hex()
== "534c00190101f3ce2cb33599634353452b60b38e311282b6fca743eb6147d3d492066c8963de0002483045022100ff4df2485a3206642ce7053902da16f26f0084faa2eb6288a1c27e389f057f4f02202268e0f4e253bd1387230b1ff3de315794e0b426f9cc9624e9c34fa73451164c012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f"
)
# Switch back to the first session.
session_id2 = client.session_id
client.init_device(session_id=session_id1)
# Requesting a preauthorized ownership proof for www.example1.com should succeed in session 1.
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example1.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
assert (
ownership_proof.hex()
== "534c00190101f3ce2cb33599634353452b60b38e311282b6fca743eb6147d3d492066c8963de000247304402203b098674577c55c8d9151335c9e73ed74649fa01c461bd8390717bfca48167af02205ac35def1b0d7019fc492acb9bbd9914cf55e08e4f1a7e6d4f6f65cbc88b0bd2012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f"
)
# Requesting a preauthorized ownership proof for www.example2.com should fail in session 1.
with pytest.raises(TrezorFailure, match="Unauthorized operation"):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example2.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
# Cancel the authorization in session 1.
device.cancel_authorization(client)
# Requesting a preauthorized ownership proof should fail now.
with pytest.raises(TrezorFailure, match="No preauthorized operation"):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example1.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)
# Switch to the second session.
client.init_device(session_id=session_id2)
# Requesting a preauthorized ownership proof for www.example2.com should still succeed in session 2.
ownership_proof, _ = btc.get_ownership_proof(
client,
"Testnet",
parse_path("84'/1'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"www.example2.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
preauthorized=True,
)

@ -1,96 +0,0 @@
# This file is part of the Trezor project.
#
# Copyright (C) 2012-2019 SatoshiLabs and contributors
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
import pytest
from trezorlib import btc, messages
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
pytestmark = pytest.mark.skip_t1
@pytest.mark.skip_ui
def test_ownership_id(client):
ownership_id = btc.get_ownership_id(
client,
"Bitcoin",
parse_path("m/84'/0'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
)
assert (
ownership_id.hex()
== "a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad5707"
)
@pytest.mark.skip_ui
def test_p2wpkh_ownership_proof(client):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Bitcoin",
parse_path("m/84'/0'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
)
assert (
ownership_proof.hex()
== "534c00190001a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb50121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b"
)
@pytest.mark.skip_ui
def test_fake_ownership_id(client):
with pytest.raises(TrezorFailure, match="Invalid ownership identifier"):
btc.get_ownership_proof(
client,
"Bitcoin",
parse_path("m/84'/0'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
ownership_ids=[
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
],
)
def test_confirm_ownership_proof(client):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Bitcoin",
parse_path("m/84'/0'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
)
assert (
ownership_proof.hex()
== "534c00190101a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100fa4561d261464360f18af9668c19e1b07d58f76814623aa8e5c9b2d85bc211d002207f364096183f461be75f763d2f970df6ac9b30a5a39556a07cab9c6f4d7883a80121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b"
)
def test_confirm_ownership_proof_with_data(client):
ownership_proof, _ = btc.get_ownership_proof(
client,
"Bitcoin",
parse_path("m/84'/0'/0'/1/0"),
script_type=messages.InputScriptType.SPENDWITNESS,
user_confirmation=True,
commitment_data=b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
)
assert (
ownership_proof.hex()
== "534c00190101a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100ac67fde3f0c8443c2708b3e405b17c4c8a51e510132b4f35aa6d6782713a53280220616192365f6202ee3f050d4e0e13c38198156024ca978fbd2b8c89c8823bb3dd0121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b"
)

@ -1310,3 +1310,54 @@ class TestMsgSigntx:
btc.sign_tx( btc.sign_tx(
client, "Testnet", [inp1], [out1, out2], prev_txes=TX_CACHE_TESTNET client, "Testnet", [inp1], [out1, out2], prev_txes=TX_CACHE_TESTNET
) )
@pytest.mark.parametrize(
"lock_time, sequence",
((499999999, 0xFFFFFFFE), (500000000, 0xFFFFFFFE), (1, 0xFFFFFFFF)),
)
def test_lock_time(self, client, lock_time, sequence):
# tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
# input 0: 0.0039 BTC
inp1 = messages.TxInputType(
address_n=parse_path("44h/0h/0h/0/0"),
# amount=390000,
prev_hash=TXHASH_d5f65e,
prev_index=0,
sequence=sequence,
)
out1 = messages.TxOutputType(
address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
amount=390000 - 10000,
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
client.set_expected_responses(
[
request_input(0),
request_meta(TXHASH_d5f65e),
request_input(0, TXHASH_d5f65e),
request_input(1, TXHASH_d5f65e),
request_output(0, TXHASH_d5f65e),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
messages.ButtonRequest(code=B.SignTx),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
request_output(0),
request_finished(),
]
)
details = messages.SignTx(lock_time=lock_time)
btc.sign_tx(
client,
"Bitcoin",
[inp1],
[out1],
details=details,
prev_txes=TX_CACHE_MAINNET,
)

@ -60,7 +60,6 @@ class TestMsgSigntxKomodo:
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
trezor_core = client.features.model != "1"
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
@ -71,7 +70,7 @@ class TestMsgSigntxKomodo:
request_extra_data(0, 11, TXHASH_2807c), request_extra_data(0, 11, TXHASH_2807c),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
(trezor_core, proto.ButtonRequest(code=B.SignTx)), proto.ButtonRequest(code=B.SignTx),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
request_output(0), request_output(0),
@ -120,7 +119,6 @@ class TestMsgSigntxKomodo:
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
trezor_core = client.features.model != "1"
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
@ -133,7 +131,7 @@ class TestMsgSigntxKomodo:
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
(trezor_core, proto.ButtonRequest(code=B.SignTx)), proto.ButtonRequest(code=B.SignTx),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
request_output(0), request_output(0),

@ -137,7 +137,12 @@ def test_session_recycling(client):
session_id_orig = client.session_id session_id_orig = client.session_id
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[messages.PassphraseRequest(), messages.Address()] [
messages.PassphraseRequest(),
messages.ButtonRequest(),
messages.ButtonRequest(),
messages.Address(),
]
) )
client.use_passphrase("TREZOR") client.use_passphrase("TREZOR")
address = get_test_address(client) address = get_test_address(client)

@ -18,7 +18,7 @@ import random
import pytest import pytest
from trezorlib import messages from trezorlib import exceptions, messages
from trezorlib.messages import FailureType from trezorlib.messages import FailureType
from trezorlib.tools import parse_path from trezorlib.tools import parse_path
@ -53,12 +53,21 @@ def _init_session(client, session_id=None):
def _get_xpub(client, passphrase=None): def _get_xpub(client, passphrase=None):
"""Get XPUB and check that the appropriate passphrase flow has happened.""" """Get XPUB and check that the appropriate passphrase flow has happened."""
response = client.call_raw(XPUB_REQUEST)
if passphrase is not None: if passphrase is not None:
assert isinstance(response, messages.PassphraseRequest) expected_responses = [
response = client.call_raw(messages.PassphraseAck(passphrase=passphrase)) messages.PassphraseRequest(),
assert isinstance(response, messages.PublicKey) messages.ButtonRequest(),
return response.xpub messages.ButtonRequest(),
messages.PublicKey(),
]
else:
expected_responses = [messages.PublicKey()]
with client:
client.use_passphrase(passphrase or "")
client.set_expected_responses(expected_responses)
result = client.call(XPUB_REQUEST)
return result.xpub
@pytest.mark.skip_ui @pytest.mark.skip_ui
@ -239,7 +248,9 @@ def test_passphrase_on_device(client):
# try to get xpub with passphrase on host: # try to get xpub with passphrase on host:
response = client.call_raw(XPUB_REQUEST) response = client.call_raw(XPUB_REQUEST)
assert isinstance(response, messages.PassphraseRequest) assert isinstance(response, messages.PassphraseRequest)
response = client.call_raw(messages.PassphraseAck(passphrase="A", on_device=False)) # using `client.call` to auto-skip subsequent ButtonRequests for "show passphrase"
response = client.call(messages.PassphraseAck(passphrase="A", on_device=False))
assert isinstance(response, messages.PublicKey) assert isinstance(response, messages.PublicKey)
assert response.xpub == XPUB_PASSPHRASES["A"] assert response.xpub == XPUB_PASSPHRASES["A"]
@ -255,6 +266,7 @@ def test_passphrase_on_device(client):
response = client.call_raw(XPUB_REQUEST) response = client.call_raw(XPUB_REQUEST)
assert isinstance(response, messages.PassphraseRequest) assert isinstance(response, messages.PassphraseRequest)
response = client.call_raw(messages.PassphraseAck(on_device=True)) response = client.call_raw(messages.PassphraseAck(on_device=True))
# no "show passphrase" here
assert isinstance(response, messages.ButtonRequest) assert isinstance(response, messages.ButtonRequest)
client.debug.input("A") client.debug.input("A")
response = client.call_raw(messages.ButtonAck()) response = client.call_raw(messages.ButtonAck())
@ -352,12 +364,13 @@ def test_passphrase_length(client):
_init_session(client) _init_session(client)
response = client.call_raw(XPUB_REQUEST) response = client.call_raw(XPUB_REQUEST)
assert isinstance(response, messages.PassphraseRequest) assert isinstance(response, messages.PassphraseRequest)
response = client.call_raw(messages.PassphraseAck(passphrase)) try:
if expected_result: response = client.call(messages.PassphraseAck(passphrase))
assert expected_result is True, "Call should have failed"
assert isinstance(response, messages.PublicKey) assert isinstance(response, messages.PublicKey)
else: except exceptions.TrezorFailure as e:
assert isinstance(response, messages.Failure) assert expected_result is False, "Call should have succeeded"
assert response.code == FailureType.DataError assert e.code == FailureType.DataError
# 50 is ok # 50 is ok
call(passphrase="A" * 50, expected_result=True) call(passphrase="A" * 50, expected_result=True)
@ -374,7 +387,7 @@ def _get_xpub_cardano(client, passphrase):
response = client.call_raw(msg) response = client.call_raw(msg)
if passphrase is not None: if passphrase is not None:
assert isinstance(response, messages.PassphraseRequest) assert isinstance(response, messages.PassphraseRequest)
response = client.call_raw(messages.PassphraseAck(passphrase=passphrase)) response = client.call(messages.PassphraseAck(passphrase=passphrase))
assert isinstance(response, messages.CardanoPublicKey) assert isinstance(response, messages.CardanoPublicKey)
return response.xpub return response.xpub

@ -5,9 +5,9 @@
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters11-result11]": "c32706d1092edf9ac2504c88eddfe3e55b8a5b6c0e2d6fcd7fbf84232aabfcb8", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters11-result11]": "c32706d1092edf9ac2504c88eddfe3e55b8a5b6c0e2d6fcd7fbf84232aabfcb8",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters12-result12]": "39c495f6c8d1a046044b8d49569f51f615b163abeae98c0be8313761de828862", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters12-result12]": "39c495f6c8d1a046044b8d49569f51f615b163abeae98c0be8313761de828862",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters13-result13]": "f03f064e8829a27a49296c28755493983d86a235ddeac1c926c7195dd254940f", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters13-result13]": "f03f064e8829a27a49296c28755493983d86a235ddeac1c926c7195dd254940f",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters14-result14]": "6aa71de5007b0faf1eea4b1cfda1da6a739f852c0d875a1e59d83c03178c2f98", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters14-result14]": "623341dfed3aaca40284ec5b444fc768edc5af9c706d8c4e4f7a5e1e90343652",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters15-result15]": "7abf2e87a9b1e50afdf3502ba9480b07a59d59ccccf24915b46fb81285ae3fa8", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters15-result15]": "0f79d964628581aae91593f7a1e7bf9b4748b900d7973e1b48a78382cc8f6c4e",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters16-result16]": "d488a0f2c127a675a1c2e2d410b6c4f402cdb610e19886a8998aa5ad786a779e", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters16-result16]": "4597efa8c2d34df7ab70c626a244d14b783fa7be1f88f213c2f9a39d726976e2",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters2-result2]": "539936eee440830f64536228980a78b098a8e421e8b6c819fe49bc8efcac9b18", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters2-result2]": "539936eee440830f64536228980a78b098a8e421e8b6c819fe49bc8efcac9b18",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters3-result3]": "6aa71de5007b0faf1eea4b1cfda1da6a739f852c0d875a1e59d83c03178c2f98", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters3-result3]": "6aa71de5007b0faf1eea4b1cfda1da6a739f852c0d875a1e59d83c03178c2f98",
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters4-result4]": "68505427a1021dd3ef7dea03956d1ea3167c8fa3016e90328151618c45d7695e", "cardano-test_sign_tx.py::test_cardano_sign_tx[parameters4-result4]": "68505427a1021dd3ef7dea03956d1ea3167c8fa3016e90328151618c45d7695e",
@ -55,11 +55,6 @@
"test_msg_applysettings.py-test_apply_settings_passphrase": "5c1ed9a0be3d14475102d447da0b5d51bbb6dfaaeceff5ea9179064609db7870", "test_msg_applysettings.py-test_apply_settings_passphrase": "5c1ed9a0be3d14475102d447da0b5d51bbb6dfaaeceff5ea9179064609db7870",
"test_msg_applysettings.py-test_apply_settings_passphrase_on_device": "3e6527e227bdde54f51bc9c417b176d0d87fdb6c40c4761368f50eb201b4beed", "test_msg_applysettings.py-test_apply_settings_passphrase_on_device": "3e6527e227bdde54f51bc9c417b176d0d87fdb6c40c4761368f50eb201b4beed",
"test_msg_applysettings.py-test_safety_checks": "19bd500c3b791d51bbd1140085f306a838194593697529263f362acb0b1ab445", "test_msg_applysettings.py-test_safety_checks": "19bd500c3b791d51bbd1140085f306a838194593697529263f362acb0b1ab445",
"test_msg_authorize_coinjoin.py::test_cancel_authorization": "d8a608beb6165f5667cc44dcff6bdc17ebb4638ddd3bd09e7f0e1e75d1e21135",
"test_msg_authorize_coinjoin.py::test_no_anonymity": "fd09da284b650e893990b95047b63a35b6b695fc5301d595f17a6d2cf9d90bcb",
"test_msg_authorize_coinjoin.py::test_sign_tx": "2838d4062333c241b6bbef7e680ec8a5764fe7bcaa41419e4141e146d3586a5d",
"test_msg_authorize_coinjoin.py::test_unfair_fee": "62314e936de46a6caaf02c8eb20f6f471be6e79ca0c5450cad6f67f9cb823f2b",
"test_msg_authorize_coinjoin.py::test_wrong_coordinator": "d8a608beb6165f5667cc44dcff6bdc17ebb4638ddd3bd09e7f0e1e75d1e21135",
"test_msg_backup_device.py::test_backup_bip39": "42325cccfc0bd54db180a01a076437ec981022338307339bb5e0f6463d842e23", "test_msg_backup_device.py::test_backup_bip39": "42325cccfc0bd54db180a01a076437ec981022338307339bb5e0f6463d842e23",
"test_msg_backup_device.py::test_backup_slip39_advanced": "9a01aa5ecdafa52571ed2149575f86ffea6c2984a2541ea8e5f9a7c37cf4c9fe", "test_msg_backup_device.py::test_backup_slip39_advanced": "9a01aa5ecdafa52571ed2149575f86ffea6c2984a2541ea8e5f9a7c37cf4c9fe",
"test_msg_backup_device.py::test_backup_slip39_basic": "57d841257b10c4f67cf76487c8f0bc95947a93a8e0b8c03d7a11894da3c233da", "test_msg_backup_device.py::test_backup_slip39_basic": "57d841257b10c4f67cf76487c8f0bc95947a93a8e0b8c03d7a11894da3c233da",
@ -157,8 +152,6 @@
"test_msg_getentropy.py::test_entropy[65]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356", "test_msg_getentropy.py::test_entropy[65]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356",
"test_msg_getentropy.py::test_entropy[8]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356", "test_msg_getentropy.py::test_entropy[8]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356",
"test_msg_getentropy.py::test_entropy[9]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356", "test_msg_getentropy.py::test_entropy[9]": "a722fa2048fa3102889ec05558d25f837a364ef2a118e85975683e10a56f1356",
"test_msg_getownershipproof.py::test_confirm_ownership_proof": "7724ef59fee121da564b935b5880479c9518d97dc286e2949f13a8a8bdf6fa4a",
"test_msg_getownershipproof.py::test_confirm_ownership_proof_with_data": "1043f54be594bd3180c59c8474ef7ef46be35f99ad5f6890949c38680c097e52",
"test_msg_lisk_getaddress.py-test_lisk_getaddress": "0063ceb48d21aecd1ddabdb083c8afd2042cdf577e4751fa3f57b2b80f619084", "test_msg_lisk_getaddress.py-test_lisk_getaddress": "0063ceb48d21aecd1ddabdb083c8afd2042cdf577e4751fa3f57b2b80f619084",
"test_msg_lisk_getpublickey.py-test_lisk_get_public_key": "e4cb8c7430c240e27a2211391ab5eba848be4f50136cf9f693142c2677a939d7", "test_msg_lisk_getpublickey.py-test_lisk_get_public_key": "e4cb8c7430c240e27a2211391ab5eba848be4f50136cf9f693142c2677a939d7",
"test_msg_lisk_signmessage.py-test_sign": "c47a6ec147137c75903cff19da6607eaef5a1fc03ace1f840d2952744342b568", "test_msg_lisk_signmessage.py-test_sign": "c47a6ec147137c75903cff19da6607eaef5a1fc03ace1f840d2952744342b568",
@ -173,10 +166,10 @@
"test_msg_lisk_verifymessage.py-test_verify": "45df85077b20182803b5c4363386c555845e070f3a8a019add99e34dad510a07", "test_msg_lisk_verifymessage.py-test_verify": "45df85077b20182803b5c4363386c555845e070f3a8a019add99e34dad510a07",
"test_msg_lisk_verifymessage.py-test_verify_long": "d7d0ae3402b9ca6c7b0e61164fa483c4ba9549d306780c98ae15edd2dde51285", "test_msg_lisk_verifymessage.py-test_verify_long": "d7d0ae3402b9ca6c7b0e61164fa483c4ba9549d306780c98ae15edd2dde51285",
"test_msg_loaddevice.py-test_load_device_1": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605", "test_msg_loaddevice.py-test_load_device_1": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605",
"test_msg_loaddevice.py-test_load_device_2": "06426c64d246068fe80fea79b0afd06d3eac4545fbd711279b816c0fdbf1b794", "test_msg_loaddevice.py-test_load_device_2": "dc13c8486d8a59c5062e19139d8b3cea4ece1a3bc93592be7dc226f83ba54477",
"test_msg_loaddevice.py-test_load_device_slip39_advanced": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605", "test_msg_loaddevice.py-test_load_device_slip39_advanced": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605",
"test_msg_loaddevice.py-test_load_device_slip39_basic": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605", "test_msg_loaddevice.py-test_load_device_slip39_basic": "1c6db0d592b1d22b3c9fce3ddab8a9fd138f11d83e5d4e64431a02bf4ffed605",
"test_msg_loaddevice.py-test_load_device_utf": "dfac758aefbebd2594455986f86bb2c3b91c2428e15de6ed00f82145c0b54089", "test_msg_loaddevice.py-test_load_device_utf": "ad7c162c76a13a161166aba78c461ad5525a9a5da846e8d99854248d521e6979",
"test_msg_monero_getaddress.py-test_monero_getaddress": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586", "test_msg_monero_getaddress.py-test_monero_getaddress": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586",
"test_msg_monero_getwatchkey.py-test_monero_getwatchkey": "d77fa4d4322e145c41f1ce07526ff59f8b58d8854aeffaa5266e14cd572350e7", "test_msg_monero_getwatchkey.py-test_monero_getwatchkey": "d77fa4d4322e145c41f1ce07526ff59f8b58d8854aeffaa5266e14cd572350e7",
"test_msg_nem_getaddress.py-test_nem_getaddress": "e726f99401a20eb74c33d755cecea2a3f69b7ae5b541302677ee05f80f5aef19", "test_msg_nem_getaddress.py-test_nem_getaddress": "e726f99401a20eb74c33d755cecea2a3f69b7ae5b541302677ee05f80f5aef19",
@ -268,6 +261,9 @@
"test_msg_signtx.py-test_change_on_main_chain_allowed": "cfd5c83510c044c456622298138e222aee135a6df607bb6e5603228535f0762f", "test_msg_signtx.py-test_change_on_main_chain_allowed": "cfd5c83510c044c456622298138e222aee135a6df607bb6e5603228535f0762f",
"test_msg_signtx.py-test_fee_high_hardfail": "b450a59808fb20cbd01d34e8d24bf1a5814e9b2a10109710240c617b68e247b6", "test_msg_signtx.py-test_fee_high_hardfail": "b450a59808fb20cbd01d34e8d24bf1a5814e9b2a10109710240c617b68e247b6",
"test_msg_signtx.py-test_fee_high_warning": "8cb3b31dce25fa36cd5c8322c71611dc7bc9d2290579ffd88dd67d21058bde04", "test_msg_signtx.py-test_fee_high_warning": "8cb3b31dce25fa36cd5c8322c71611dc7bc9d2290579ffd88dd67d21058bde04",
"test_msg_signtx.py-test_lock_time[1-4294967295]": "d805244ea557c3695101a6f79f13045f22bc16d5608744e0321eab7f3a98d8b0",
"test_msg_signtx.py-test_lock_time[499999999-4294967294]": "23a154e7b40680161bb099cfc6702d75909c222056867515647123573eef1716",
"test_msg_signtx.py-test_lock_time[500000000-4294967294]": "2ac61446c20785e45223a20ae90660905fedf20d2a383a65fcbc1edd5fe87ad1",
"test_msg_signtx.py-test_lots_of_change": "9e143458b399d187b6a3060fc95b998822f5a7ed67d6915610fd02c0ccab791e", "test_msg_signtx.py-test_lots_of_change": "9e143458b399d187b6a3060fc95b998822f5a7ed67d6915610fd02c0ccab791e",
"test_msg_signtx.py-test_not_enough_funds": "dbaa027aa1f4b08b138a5965245593dab2a662b0f4d88dd28b82a64f88f5d7fe", "test_msg_signtx.py-test_not_enough_funds": "dbaa027aa1f4b08b138a5965245593dab2a662b0f4d88dd28b82a64f88f5d7fe",
"test_msg_signtx.py-test_one_one_fee": "f6b6662fa1384f20640522a169575f8ca26185fca8ca3bc2a3a5ccd1fa9d2f68", "test_msg_signtx.py-test_one_one_fee": "f6b6662fa1384f20640522a169575f8ca26185fca8ca3bc2a3a5ccd1fa9d2f68",
@ -311,14 +307,14 @@
"test_msg_signtx_external.py::test_p2wsh_external_presigned": "8374d50b803db0160de39ce7e5a4170112f4c99d703490920a2de735bd261bda", "test_msg_signtx_external.py::test_p2wsh_external_presigned": "8374d50b803db0160de39ce7e5a4170112f4c99d703490920a2de735bd261bda",
"test_msg_signtx_grs.py-test_legacy": "3a80ea724a93ed225d64f8def739d63b11f8c096455f971feabec8be6f7597fb", "test_msg_signtx_grs.py-test_legacy": "3a80ea724a93ed225d64f8def739d63b11f8c096455f971feabec8be6f7597fb",
"test_msg_signtx_grs.py-test_legacy_change": "8dfc140534bdaa08f6916831dc0d510f57b07617f30df748e4e0456d4dd93ece", "test_msg_signtx_grs.py-test_legacy_change": "8dfc140534bdaa08f6916831dc0d510f57b07617f30df748e4e0456d4dd93ece",
"test_msg_signtx_grs.py-test_send_segwit_native": "a1098f71dd6c197cb8a4a45806808fbacc130044585cb003e61110d8bda80114", "test_msg_signtx_grs.py-test_send_segwit_native": "82dfa15178d33e757da58943aff36dcc0eebb984e34832b71f6ca09b2a525cbc",
"test_msg_signtx_grs.py-test_send_segwit_native_change": "2b9119aea79b50a26bd86cc49fd5421aedee42245b83919bf142d2ca2e50dd16", "test_msg_signtx_grs.py-test_send_segwit_native_change": "d8ae74de3aada1d136c4119f2306a63bd109901ce15d00ae916ba5b4457e798e",
"test_msg_signtx_grs.py-test_send_segwit_p2sh": "e596ff7f2e10633d8de6bd5b98928020dfacf578ce71d6d6e0ca27011ed8bd53", "test_msg_signtx_grs.py-test_send_segwit_p2sh": "9ab885dd3b390813f8a47e1d1587abe07ab713e9f8696dc667b3a2925f23c103",
"test_msg_signtx_grs.py-test_send_segwit_p2sh_change": "65a33cc9ecf52bdab93d1066bfaff7f30c9908fc5ada8a672c39df57eb6129c2", "test_msg_signtx_grs.py-test_send_segwit_p2sh_change": "6c352ab975a75a150f7c3415a967fb8635395ff8db0de89ecb9c2011cb519509",
"test_msg_signtx_invalid_path.py-test_invalid_path_fail": "b0f22cba2dbab2cd21c15c002b66ed89b6c728b10daa8d0c0e78abd4164a3912", "test_msg_signtx_invalid_path.py-test_invalid_path_fail": "b0f22cba2dbab2cd21c15c002b66ed89b6c728b10daa8d0c0e78abd4164a3912",
"test_msg_signtx_invalid_path.py-test_invalid_path_pass_forkid": "667dcb09b569e5b4e091e6b1ac7e8e057c0c730c931b22f8c0ee64050f3f467b", "test_msg_signtx_invalid_path.py-test_invalid_path_pass_forkid": "667dcb09b569e5b4e091e6b1ac7e8e057c0c730c931b22f8c0ee64050f3f467b",
"test_msg_signtx_komodo.py-test_one_one_fee_sapling": "aa32424c04f65c0e2de57f6eb26830eb037c7b4daaf300ae61d30968affd9193", "test_msg_signtx_komodo.py-test_one_one_fee_sapling": "14bad8852ee51f6fec12677cced9ffafa0cbae91b4ba94e988a800544072ed21",
"test_msg_signtx_komodo.py-test_one_one_rewards_claim": "e53f221fda81469027e39e21877a81a8fafbffbece0a45aeda12aae8873b0464", "test_msg_signtx_komodo.py-test_one_one_rewards_claim": "751e83d63bf01c6c57047b5e004629d613df75342371cd43a7b4b80a07f4b88d",
"test_msg_signtx_peercoin.py::test_timestamp_included": "825b9bdf5238c5c6415a254a6bae4b2bd9df8fc5cb31f66f0c20145cb4e60bbb", "test_msg_signtx_peercoin.py::test_timestamp_included": "825b9bdf5238c5c6415a254a6bae4b2bd9df8fc5cb31f66f0c20145cb4e60bbb",
"test_msg_signtx_segwit.py-test_attack_change_input_address": "5ae71202c062ef7942626a80a4ceeb8d8c4ea5065a97f0de6a97505e9cb82c2c", "test_msg_signtx_segwit.py-test_attack_change_input_address": "5ae71202c062ef7942626a80a4ceeb8d8c4ea5065a97f0de6a97505e9cb82c2c",
"test_msg_signtx_segwit.py-test_attack_mixed_inputs": "ed4cf8ff26ca1abb0adf20e1020dad7861b5e63ead2a1a9c0c5e9080d37f6f1c", "test_msg_signtx_segwit.py-test_attack_mixed_inputs": "ed4cf8ff26ca1abb0adf20e1020dad7861b5e63ead2a1a9c0c5e9080d37f6f1c",
@ -396,10 +392,10 @@
"test_multisig_change.py-test_multisig_mismatch_change": "7cb243b20be31a587dced4aaaf782a2d8487595369dde66aacb1b9a76e89c4fe", "test_multisig_change.py-test_multisig_mismatch_change": "7cb243b20be31a587dced4aaaf782a2d8487595369dde66aacb1b9a76e89c4fe",
"test_multisig_change.py-test_multisig_mismatch_inputs": "64741bd84c5394e719125c1fbe8c34ef866ac63ca24ee1299e4268c59a199466", "test_multisig_change.py-test_multisig_mismatch_inputs": "64741bd84c5394e719125c1fbe8c34ef866ac63ca24ee1299e4268c59a199466",
"test_op_return.py-test_opreturn": "87907ef9c2f4ce30ac95ad7d0cb3eac66762756e4ace52147bc589d64277f3b1", "test_op_return.py-test_opreturn": "87907ef9c2f4ce30ac95ad7d0cb3eac66762756e4ace52147bc589d64277f3b1",
"test_passphrase_slip39_advanced.py::test_128bit_passphrase": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669", "test_passphrase_slip39_advanced.py::test_128bit_passphrase": "4d8c7eea0bd6786a070880d94fe288294e570b8d357dd9bc01865a8acc39d143",
"test_passphrase_slip39_advanced.py::test_256bit_passphrase": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669", "test_passphrase_slip39_advanced.py::test_256bit_passphrase": "4d8c7eea0bd6786a070880d94fe288294e570b8d357dd9bc01865a8acc39d143",
"test_passphrase_slip39_basic.py::test_2of5_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "test_passphrase_slip39_basic.py::test_2of5_passphrase": "54091a6faba4ecc4e40db591bb8861d00464de34b38a31925202f5bc44e4c41c",
"test_passphrase_slip39_basic.py::test_3of6_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0", "test_passphrase_slip39_basic.py::test_3of6_passphrase": "54091a6faba4ecc4e40db591bb8861d00464de34b38a31925202f5bc44e4c41c",
"test_reset_backup.py::test_skip_backup_manual[0-backup_flow_bip39]": "9c5cded50e6ebe51dc6ecdaa6b793da9ec5527df582acbdc189494b809ee9f47", "test_reset_backup.py::test_skip_backup_manual[0-backup_flow_bip39]": "9c5cded50e6ebe51dc6ecdaa6b793da9ec5527df582acbdc189494b809ee9f47",
"test_reset_backup.py::test_skip_backup_manual[1-backup_flow_slip39_basic]": "bf9ea5281234d622b39f388715dad86e95f0a0e1efbd3d4d6b60478a79edcc23", "test_reset_backup.py::test_skip_backup_manual[1-backup_flow_slip39_basic]": "bf9ea5281234d622b39f388715dad86e95f0a0e1efbd3d4d6b60478a79edcc23",
"test_reset_backup.py::test_skip_backup_manual[2-backup_flow_slip39_advanced]": "e3fb56f53d04edde94aa11e5eac1e2dc732bddcd39def3981e03cffcbef1a96c", "test_reset_backup.py::test_skip_backup_manual[2-backup_flow_slip39_advanced]": "e3fb56f53d04edde94aa11e5eac1e2dc732bddcd39def3981e03cffcbef1a96c",

@ -68,9 +68,20 @@ def test_passphrase_works(emulator):
messages.Deprecated_PassphraseStateRequest(), messages.Deprecated_PassphraseStateRequest(),
messages.Address(), messages.Address(),
] ]
elif (
emulator.client.features.model == "T" and emulator.client.version < (2, 3, 3)
) or (
emulator.client.features.model == "1" and emulator.client.version < (1, 9, 3)
):
expected_responses = [
messages.PassphraseRequest(),
messages.Address(),
]
else: else:
expected_responses = [ expected_responses = [
messages.PassphraseRequest(), messages.PassphraseRequest(),
messages.ButtonRequest(),
messages.ButtonRequest(),
messages.Address(), messages.Address(),
] ]
@ -96,9 +107,22 @@ def test_init_device(emulator):
messages.Features(), messages.Features(),
messages.Address(), messages.Address(),
] ]
elif (
emulator.client.features.model == "T" and emulator.client.version < (2, 3, 3)
) or (
emulator.client.features.model == "1" and emulator.client.version < (1, 9, 3)
):
expected_responses = [
messages.PassphraseRequest(),
messages.Address(),
messages.Features(),
messages.Address(),
]
else: else:
expected_responses = [ expected_responses = [
messages.PassphraseRequest(), messages.PassphraseRequest(),
messages.ButtonRequest(),
messages.ButtonRequest(),
messages.Address(), messages.Address(),
messages.Features(), messages.Features(),
messages.Address(), messages.Address(),

Loading…
Cancel
Save