mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-25 00:48:19 +00:00
Merge remote-tracking branch 'origin/release/2020-09'
This commit is contained in:
commit
b99b8b3df3
@ -18,7 +18,7 @@
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["SWIPE", "YES"], ["SWIPE", "YES"]],
|
||||
"input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/44'/1815'/0'/0/1",
|
||||
@ -48,7 +48,7 @@
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
|
||||
"input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"path": "m/44'/1815'/0'/0/1",
|
||||
@ -83,7 +83,7 @@
|
||||
"certificates": [],
|
||||
"withdrawals": [],
|
||||
"metadata": "",
|
||||
"input_flow": [["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
|
||||
"input_flow": [["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"]],
|
||||
"inputs": [
|
||||
{
|
||||
"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
|
||||
|
||||
### Removed
|
||||
- ETP, GIN, PTC, ZEL support
|
||||
- Remove ETP, GIN, PTC, ZEL support.
|
||||
- Drop support for signing Zcash v3 transactions. [#982]
|
||||
|
||||
### Fixed
|
||||
- CRW addresses are properly generated. [#1139]
|
||||
- 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
|
||||
- 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]
|
||||
|
||||
@ -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
|
||||
[#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
|
||||
[#1030]: https://github.com/trezor/trezor-firmware/issues/1030
|
||||
[#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
|
||||
[#1087]: https://github.com/trezor/trezor-firmware/issues/1087
|
||||
[#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
|
||||
[#1115]: https://github.com/trezor/trezor-firmware/issues/1115
|
||||
[#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
|
||||
[#1173]: https://github.com/trezor/trezor-firmware/pull/1173
|
||||
[#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:
|
||||
wire.add(MessageType.AuthorizeCoinJoin, __name__, "authorize_coinjoin")
|
||||
wire.add(MessageType.GetPublicKey, __name__, "get_public_key")
|
||||
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.SignMessage, __name__, "sign_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.TxRequest import TxRequest
|
||||
|
||||
from apps.common import coininfo, paths
|
||||
from apps.common import coininfo
|
||||
|
||||
from ..common import BITCOIN_NAMES
|
||||
from ..keychain import with_keychain
|
||||
from . import approvers, bitcoin, helpers, layout, progress
|
||||
from . import approvers, bitcoin, helpers, progress
|
||||
|
||||
if not utils.BITCOIN_ONLY:
|
||||
from . import bitcoinlike, decred, zcash
|
||||
@ -52,30 +52,8 @@ async def sign_tx(
|
||||
if req.request_type == TXFINISHED:
|
||||
break
|
||||
res = await ctx.call(req, TxAck, field_cache)
|
||||
elif isinstance(req, helpers.UiConfirmOutput):
|
||||
res = await layout.confirm_output(ctx, req.output, req.coin)
|
||||
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)
|
||||
elif isinstance(req, helpers.UiConfirm):
|
||||
res = await req.confirm_dialog(ctx)
|
||||
progress.report_init()
|
||||
else:
|
||||
raise TypeError("Invalid signing instruction")
|
||||
|
@ -15,6 +15,9 @@ from . import helpers, tx_weight
|
||||
if False:
|
||||
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
|
||||
# to confirm transaction parameters (output addresses, amounts and fees) or uses
|
||||
@ -25,6 +28,7 @@ class Approver:
|
||||
self.tx = tx
|
||||
self.coin = coin
|
||||
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
||||
self.min_sequence = _SEQUENCE_FINAL # the minimum nSequence of all inputs
|
||||
|
||||
# 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:
|
||||
self.weight.add_input(txi)
|
||||
self.total_in += amount
|
||||
self.min_sequence = min(self.min_sequence, txi.sequence)
|
||||
|
||||
def add_external_input(self, txi: TxInputType) -> None:
|
||||
self.weight.add_input(txi)
|
||||
self.total_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:
|
||||
self.weight.add_output(script_pubkey)
|
||||
@ -100,7 +106,10 @@ class BasicApprover(Approver):
|
||||
if self.change_count > self.MAX_SILENT_CHANGE_COUNT:
|
||||
await helpers.confirm_change_count_over_threshold(self.change_count)
|
||||
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:
|
||||
await helpers.confirm_total(total, fee, self.coin)
|
||||
else:
|
||||
|
@ -14,10 +14,12 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||
from trezor.messages.TxOutputType import TxOutputType
|
||||
from trezor.messages.TxRequest import TxRequest
|
||||
|
||||
from apps.common import paths
|
||||
from apps.common.coininfo import CoinInfo
|
||||
|
||||
from .. import common
|
||||
from ..writers import TX_HASH_SIZE
|
||||
from . import layout
|
||||
|
||||
if False:
|
||||
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):
|
||||
self.output = output
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmTotal:
|
||||
class UiConfirmTotal(UiConfirm):
|
||||
def __init__(self, spending: int, fee: int, coin: CoinInfo):
|
||||
self.spending = spending
|
||||
self.fee = fee
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmJointTotal:
|
||||
class UiConfirmJointTotal(UiConfirm):
|
||||
def __init__(self, spending: int, total: int, coin: CoinInfo):
|
||||
self.spending = spending
|
||||
self.total = total
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmFeeOverThreshold:
|
||||
class UiConfirmFeeOverThreshold(UiConfirm):
|
||||
def __init__(self, fee: int, coin: CoinInfo):
|
||||
self.fee = fee
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmChangeCountOverThreshold:
|
||||
class UiConfirmChangeCountOverThreshold(UiConfirm):
|
||||
def __init__(self, change_count: int):
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmForeignAddress:
|
||||
class UiConfirmForeignAddress(UiConfirm):
|
||||
def __init__(self, address_n: list):
|
||||
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
|
||||
|
||||
|
||||
class UiConfirmNonDefaultLocktime:
|
||||
def __init__(self, lock_time: int):
|
||||
class UiConfirmNonDefaultLocktime(UiConfirm):
|
||||
def __init__(self, lock_time: int, lock_time_disabled: bool):
|
||||
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
|
||||
|
||||
@ -106,8 +137,8 @@ def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore
|
||||
return (yield UiConfirmForeignAddress(address_n))
|
||||
|
||||
|
||||
def confirm_nondefault_locktime(lock_time: int) -> Awaitable[Any]: # type: ignore
|
||||
return (yield UiConfirmNonDefaultLocktime(lock_time))
|
||||
def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> Awaitable[Any]: # type: ignore
|
||||
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
|
||||
|
@ -101,13 +101,21 @@ async def confirm_change_count_over_threshold(
|
||||
await require_confirm(ctx, text, ButtonRequestType.SignTx)
|
||||
|
||||
|
||||
async def confirm_nondefault_locktime(ctx: wire.Context, lock_time: int) -> None:
|
||||
async def confirm_nondefault_locktime(
|
||||
ctx: wire.Context, lock_time: int, lock_time_disabled: bool
|
||||
) -> None:
|
||||
if lock_time_disabled:
|
||||
text = Text("Warning", ui.ICON_SEND, ui.GREEN)
|
||||
text.normal("Locktime is set but will", "have no effect.")
|
||||
text.br_half()
|
||||
else:
|
||||
text = Text("Confirm locktime", ui.ICON_SEND, ui.GREEN)
|
||||
text.normal("Locktime for this transaction is set to")
|
||||
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?")
|
||||
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 . import button_request
|
||||
from .confirm import require_confirm
|
||||
|
||||
_MAX_PASSPHRASE_LEN = const(50)
|
||||
|
||||
@ -53,6 +54,22 @@ async def _request_on_host(ctx: wire.Context) -> str:
|
||||
raise wire.DataError(
|
||||
"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
|
||||
|
||||
|
||||
|
@ -35,6 +35,7 @@ class TestApprover(unittest.TestCase):
|
||||
TxInputType(
|
||||
amount=denomination + 1000000 * (i + 1),
|
||||
script_type=InputScriptType.EXTERNAL,
|
||||
sequence=0xffffffff,
|
||||
) for i in range(99)
|
||||
]
|
||||
|
||||
@ -45,6 +46,7 @@ class TestApprover(unittest.TestCase):
|
||||
address_n=[H_(84), H_(0), H_(0), 0, 1],
|
||||
amount=denomination + 1000000,
|
||||
script_type=InputScriptType.SPENDWITNESS,
|
||||
sequence=0xffffffff,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -103,7 +103,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
|
||||
helpers.UiConfirmOutput(out2, coin),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time),
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
True,
|
||||
|
||||
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),
|
||||
TxAck(tx=TransactionType(outputs=[out2])),
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time),
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmTotal(5000000 + 11000, 11000, coin),
|
||||
|
@ -103,7 +103,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
|
||||
helpers.UiConfirmOutput(out2, coin),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time),
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
True,
|
||||
|
||||
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),
|
||||
TxAck(tx=TransactionType(outputs=[out2])),
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time),
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
True,
|
||||
|
||||
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
|
||||
- XVG support. [#1165]
|
||||
- Ask user to confirm custom nLockTime.
|
||||
|
||||
### Changed
|
||||
- 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
|
||||
|
||||
### Security
|
||||
- Show non-empty passphrase on device when it was entered on host.
|
||||
|
||||
## 1.9.2 [5th August 2020]
|
||||
|
||||
|
@ -601,6 +601,30 @@ const uint8_t *config_getSeed(void) {
|
||||
memzero(passphrase, sizeof(passphrase));
|
||||
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)
|
||||
bool imported = false;
|
||||
config_get_bool(KEY_IMPORTED, &imported);
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
#define LOCKTIME_TIMESTAMP_MIN_VALUE 500000000
|
||||
|
||||
#if !BITCOIN_ONLY
|
||||
|
||||
static const char *slip44_extras(uint32_t coin_type) {
|
||||
@ -450,6 +452,25 @@ void layoutChangeCountOverThreshold(uint32_t change_count) {
|
||||
_("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) {
|
||||
const char **str = NULL;
|
||||
if (!is_valid_ascii(msg, len)) {
|
||||
@ -823,6 +844,25 @@ void layoutU2FDialog(const char *verb, const char *appname) {
|
||||
|
||||
#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
|
||||
|
||||
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);
|
||||
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee);
|
||||
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 layoutVerifyAddress(const CoinInfo *coin, const char *address);
|
||||
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 layoutDecryptIdentity(const IdentityType *identity);
|
||||
void layoutU2FDialog(const char *verb, const char *appname);
|
||||
void layoutShowPassphrase(const char *passphrase);
|
||||
|
||||
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
|
||||
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 version_group_id = 0;
|
||||
static uint32_t timestamp = 0;
|
||||
static uint32_t min_sequence = 0;
|
||||
#if !BITCOIN_ONLY
|
||||
static uint32_t branch_id = 0;
|
||||
#endif
|
||||
@ -107,6 +108,10 @@ static uint32_t tx_weight;
|
||||
/* The maximum number of change-outputs allowed without user confirmation. */
|
||||
#define MAX_SILENT_CHANGE_COUNT 2
|
||||
|
||||
/* Setting nSequence to this value for every input in a transaction disables
|
||||
nLockTime. */
|
||||
#define SEQUENCE_FINAL 0xffffffff
|
||||
|
||||
enum {
|
||||
SIGHASH_ALL = 1,
|
||||
SIGHASH_FORKID = 0x40,
|
||||
@ -497,6 +502,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin,
|
||||
memcpy(&root, _root, sizeof(HDNode));
|
||||
version = msg->version;
|
||||
lock_time = msg->lock_time;
|
||||
min_sequence = SEQUENCE_FINAL;
|
||||
|
||||
if (!coin->overwintered) {
|
||||
if (msg->has_version_group_id) {
|
||||
@ -782,12 +788,18 @@ static bool signing_check_input(const TxInputType *txinput) {
|
||||
} else { // single signature
|
||||
multisig_fp_mismatch = true;
|
||||
}
|
||||
|
||||
// remember the input bip32 path
|
||||
// change addresses must use the same bip32 path as all inputs
|
||||
extract_input_bip32_path(txinput);
|
||||
|
||||
// remember the minimum nSequence value
|
||||
if (txinput->sequence < min_sequence) min_sequence = txinput->sequence;
|
||||
|
||||
// compute segwit hashPrevouts & hashSequence
|
||||
tx_prevout_hash(&hasher_prevouts, txinput);
|
||||
tx_sequence_hash(&hasher_sequence, txinput);
|
||||
|
||||
#if !BITCOIN_ONLY
|
||||
if (coin->decred) {
|
||||
// serialize Decred prefix in Phase 1
|
||||
@ -800,6 +812,7 @@ static bool signing_check_input(const TxInputType *txinput) {
|
||||
tx_serialize_input_hash(&ti, txinput);
|
||||
}
|
||||
#endif
|
||||
|
||||
// hash prevout and script type to check it later (relevant for fee
|
||||
// computation)
|
||||
tx_prevout_hash(&hasher_check, txinput);
|
||||
@ -914,6 +927,7 @@ static bool signing_confirm_tx(void) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t fee = 0;
|
||||
if (spending <= to_spend) {
|
||||
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
|
||||
layoutConfirmTx(coin, to_spend - change_spend, fee);
|
||||
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(
|
||||
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,
|
||||
)
|
||||
|
||||
trezor_core = client.features.model != "1"
|
||||
with client:
|
||||
client.set_expected_responses(
|
||||
[
|
||||
@ -71,7 +70,7 @@ class TestMsgSigntxKomodo:
|
||||
request_extra_data(0, 11, TXHASH_2807c),
|
||||
request_output(0),
|
||||
proto.ButtonRequest(code=B.ConfirmOutput),
|
||||
(trezor_core, proto.ButtonRequest(code=B.SignTx)),
|
||||
proto.ButtonRequest(code=B.SignTx),
|
||||
proto.ButtonRequest(code=B.SignTx),
|
||||
request_input(0),
|
||||
request_output(0),
|
||||
@ -120,7 +119,6 @@ class TestMsgSigntxKomodo:
|
||||
script_type=proto.OutputScriptType.PAYTOADDRESS,
|
||||
)
|
||||
|
||||
trezor_core = client.features.model != "1"
|
||||
with client:
|
||||
client.set_expected_responses(
|
||||
[
|
||||
@ -133,7 +131,7 @@ class TestMsgSigntxKomodo:
|
||||
proto.ButtonRequest(code=B.ConfirmOutput),
|
||||
request_output(1),
|
||||
proto.ButtonRequest(code=B.ConfirmOutput),
|
||||
(trezor_core, proto.ButtonRequest(code=B.SignTx)),
|
||||
proto.ButtonRequest(code=B.SignTx),
|
||||
proto.ButtonRequest(code=B.SignTx),
|
||||
request_input(0),
|
||||
request_output(0),
|
||||
|
@ -137,7 +137,12 @@ def test_session_recycling(client):
|
||||
session_id_orig = client.session_id
|
||||
with client:
|
||||
client.set_expected_responses(
|
||||
[messages.PassphraseRequest(), messages.Address()]
|
||||
[
|
||||
messages.PassphraseRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.Address(),
|
||||
]
|
||||
)
|
||||
client.use_passphrase("TREZOR")
|
||||
address = get_test_address(client)
|
||||
|
@ -18,7 +18,7 @@ import random
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import messages
|
||||
from trezorlib import exceptions, messages
|
||||
from trezorlib.messages import FailureType
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
@ -53,12 +53,21 @@ def _init_session(client, session_id=None):
|
||||
|
||||
def _get_xpub(client, passphrase=None):
|
||||
"""Get XPUB and check that the appropriate passphrase flow has happened."""
|
||||
response = client.call_raw(XPUB_REQUEST)
|
||||
if passphrase is not None:
|
||||
assert isinstance(response, messages.PassphraseRequest)
|
||||
response = client.call_raw(messages.PassphraseAck(passphrase=passphrase))
|
||||
assert isinstance(response, messages.PublicKey)
|
||||
return response.xpub
|
||||
expected_responses = [
|
||||
messages.PassphraseRequest(),
|
||||
messages.ButtonRequest(),
|
||||
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
|
||||
@ -239,7 +248,9 @@ def test_passphrase_on_device(client):
|
||||
# try to get xpub with passphrase on host:
|
||||
response = client.call_raw(XPUB_REQUEST)
|
||||
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 response.xpub == XPUB_PASSPHRASES["A"]
|
||||
|
||||
@ -255,6 +266,7 @@ def test_passphrase_on_device(client):
|
||||
response = client.call_raw(XPUB_REQUEST)
|
||||
assert isinstance(response, messages.PassphraseRequest)
|
||||
response = client.call_raw(messages.PassphraseAck(on_device=True))
|
||||
# no "show passphrase" here
|
||||
assert isinstance(response, messages.ButtonRequest)
|
||||
client.debug.input("A")
|
||||
response = client.call_raw(messages.ButtonAck())
|
||||
@ -352,12 +364,13 @@ def test_passphrase_length(client):
|
||||
_init_session(client)
|
||||
response = client.call_raw(XPUB_REQUEST)
|
||||
assert isinstance(response, messages.PassphraseRequest)
|
||||
response = client.call_raw(messages.PassphraseAck(passphrase))
|
||||
if expected_result:
|
||||
try:
|
||||
response = client.call(messages.PassphraseAck(passphrase))
|
||||
assert expected_result is True, "Call should have failed"
|
||||
assert isinstance(response, messages.PublicKey)
|
||||
else:
|
||||
assert isinstance(response, messages.Failure)
|
||||
assert response.code == FailureType.DataError
|
||||
except exceptions.TrezorFailure as e:
|
||||
assert expected_result is False, "Call should have succeeded"
|
||||
assert e.code == FailureType.DataError
|
||||
|
||||
# 50 is ok
|
||||
call(passphrase="A" * 50, expected_result=True)
|
||||
@ -374,7 +387,7 @@ def _get_xpub_cardano(client, passphrase):
|
||||
response = client.call_raw(msg)
|
||||
if passphrase is not None:
|
||||
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)
|
||||
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[parameters12-result12]": "39c495f6c8d1a046044b8d49569f51f615b163abeae98c0be8313761de828862",
|
||||
"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[parameters15-result15]": "7abf2e87a9b1e50afdf3502ba9480b07a59d59ccccf24915b46fb81285ae3fa8",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters16-result16]": "d488a0f2c127a675a1c2e2d410b6c4f402cdb610e19886a8998aa5ad786a779e",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters14-result14]": "623341dfed3aaca40284ec5b444fc768edc5af9c706d8c4e4f7a5e1e90343652",
|
||||
"cardano-test_sign_tx.py::test_cardano_sign_tx[parameters15-result15]": "0f79d964628581aae91593f7a1e7bf9b4748b900d7973e1b48a78382cc8f6c4e",
|
||||
"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[parameters3-result3]": "6aa71de5007b0faf1eea4b1cfda1da6a739f852c0d875a1e59d83c03178c2f98",
|
||||
"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_on_device": "3e6527e227bdde54f51bc9c417b176d0d87fdb6c40c4761368f50eb201b4beed",
|
||||
"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_slip39_advanced": "9a01aa5ecdafa52571ed2149575f86ffea6c2984a2541ea8e5f9a7c37cf4c9fe",
|
||||
"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[8]": "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_getpublickey.py-test_lisk_get_public_key": "e4cb8c7430c240e27a2211391ab5eba848be4f50136cf9f693142c2677a939d7",
|
||||
"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_long": "d7d0ae3402b9ca6c7b0e61164fa483c4ba9549d306780c98ae15edd2dde51285",
|
||||
"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_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_getwatchkey.py-test_monero_getwatchkey": "d77fa4d4322e145c41f1ce07526ff59f8b58d8854aeffaa5266e14cd572350e7",
|
||||
"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_fee_high_hardfail": "b450a59808fb20cbd01d34e8d24bf1a5814e9b2a10109710240c617b68e247b6",
|
||||
"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_not_enough_funds": "dbaa027aa1f4b08b138a5965245593dab2a662b0f4d88dd28b82a64f88f5d7fe",
|
||||
"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_grs.py-test_legacy": "3a80ea724a93ed225d64f8def739d63b11f8c096455f971feabec8be6f7597fb",
|
||||
"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_change": "2b9119aea79b50a26bd86cc49fd5421aedee42245b83919bf142d2ca2e50dd16",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_p2sh": "e596ff7f2e10633d8de6bd5b98928020dfacf578ce71d6d6e0ca27011ed8bd53",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_p2sh_change": "65a33cc9ecf52bdab93d1066bfaff7f30c9908fc5ada8a672c39df57eb6129c2",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_native": "82dfa15178d33e757da58943aff36dcc0eebb984e34832b71f6ca09b2a525cbc",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_native_change": "d8ae74de3aada1d136c4119f2306a63bd109901ce15d00ae916ba5b4457e798e",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_p2sh": "9ab885dd3b390813f8a47e1d1587abe07ab713e9f8696dc667b3a2925f23c103",
|
||||
"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_pass_forkid": "667dcb09b569e5b4e091e6b1ac7e8e057c0c730c931b22f8c0ee64050f3f467b",
|
||||
"test_msg_signtx_komodo.py-test_one_one_fee_sapling": "aa32424c04f65c0e2de57f6eb26830eb037c7b4daaf300ae61d30968affd9193",
|
||||
"test_msg_signtx_komodo.py-test_one_one_rewards_claim": "e53f221fda81469027e39e21877a81a8fafbffbece0a45aeda12aae8873b0464",
|
||||
"test_msg_signtx_komodo.py-test_one_one_fee_sapling": "14bad8852ee51f6fec12677cced9ffafa0cbae91b4ba94e988a800544072ed21",
|
||||
"test_msg_signtx_komodo.py-test_one_one_rewards_claim": "751e83d63bf01c6c57047b5e004629d613df75342371cd43a7b4b80a07f4b88d",
|
||||
"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_mixed_inputs": "ed4cf8ff26ca1abb0adf20e1020dad7861b5e63ead2a1a9c0c5e9080d37f6f1c",
|
||||
@ -396,10 +392,10 @@
|
||||
"test_multisig_change.py-test_multisig_mismatch_change": "7cb243b20be31a587dced4aaaf782a2d8487595369dde66aacb1b9a76e89c4fe",
|
||||
"test_multisig_change.py-test_multisig_mismatch_inputs": "64741bd84c5394e719125c1fbe8c34ef866ac63ca24ee1299e4268c59a199466",
|
||||
"test_op_return.py-test_opreturn": "87907ef9c2f4ce30ac95ad7d0cb3eac66762756e4ace52147bc589d64277f3b1",
|
||||
"test_passphrase_slip39_advanced.py::test_128bit_passphrase": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669",
|
||||
"test_passphrase_slip39_advanced.py::test_256bit_passphrase": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669",
|
||||
"test_passphrase_slip39_basic.py::test_2of5_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"test_passphrase_slip39_basic.py::test_3of6_passphrase": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
|
||||
"test_passphrase_slip39_advanced.py::test_128bit_passphrase": "4d8c7eea0bd6786a070880d94fe288294e570b8d357dd9bc01865a8acc39d143",
|
||||
"test_passphrase_slip39_advanced.py::test_256bit_passphrase": "4d8c7eea0bd6786a070880d94fe288294e570b8d357dd9bc01865a8acc39d143",
|
||||
"test_passphrase_slip39_basic.py::test_2of5_passphrase": "54091a6faba4ecc4e40db591bb8861d00464de34b38a31925202f5bc44e4c41c",
|
||||
"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[1-backup_flow_slip39_basic]": "bf9ea5281234d622b39f388715dad86e95f0a0e1efbd3d4d6b60478a79edcc23",
|
||||
"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.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:
|
||||
expected_responses = [
|
||||
messages.PassphraseRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.Address(),
|
||||
]
|
||||
|
||||
@ -96,9 +107,22 @@ def test_init_device(emulator):
|
||||
messages.Features(),
|
||||
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:
|
||||
expected_responses = [
|
||||
messages.PassphraseRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.ButtonRequest(),
|
||||
messages.Address(),
|
||||
messages.Features(),
|
||||
messages.Address(),
|
||||
|
Loading…
Reference in New Issue
Block a user