1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 15:38:11 +00:00

refactor(core): convert apps.common to layouts

This commit is contained in:
Martin Milata 2021-03-23 13:29:25 +01:00
parent 875cc0cb1a
commit 574dcbc8a3
37 changed files with 161 additions and 171 deletions

View File

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import Keychain, auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import address_from_public_key
@ -18,7 +17,7 @@ async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
pubkey = node.public_key()
address = address_from_public_key(pubkey, HRP)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return BinanceAddress(address=address)

View File

@ -3,8 +3,7 @@ from trezor.enums import InputScriptType
from trezor.messages import Address
from trezor.ui.layouts import show_address
from apps.common.layout import address_n_to_str
from apps.common.paths import validate_path
from apps.common.paths import address_n_to_str, validate_path
from . import addresses
from .keychain import validate_path_against_script_type, with_keychain

View File

@ -3,7 +3,6 @@ from trezor.messages import CardanoAddress
from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.layout import address_n_to_str
from . import seed
from .address import derive_human_readable_address, validate_address_parameters
@ -71,7 +70,7 @@ async def _display_address(
if not protocol_magics.is_mainnet(protocol_magic):
network_name = protocol_magics.to_ui_string(protocol_magic)
address_n = address_n_to_str(address_parameters.address_n)
address_n = paths.address_n_to_str(address_parameters.address_n)
await show_address(
ctx,
address=address,

View File

@ -1,7 +1,6 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import PathSchema
from apps.common.paths import HARDENED, PathSchema
SLIP44_ID = 1815

View File

@ -8,7 +8,7 @@ from trezor.ui.layouts import (
confirm_properties,
)
from apps.common.layout import address_n_to_str
from apps.common.paths import address_n_to_str
from . import seed
from .address import (

View File

@ -1,17 +0,0 @@
from micropython import const
from trezor import workflow
from trezor.enums import ButtonRequestType
from trezor.messages import ButtonAck, ButtonRequest
if False:
from trezor import wire
HARDENED = const(0x8000_0000)
async def button_request(
ctx: wire.GenericContext, code: ButtonRequestType = ButtonRequestType.Other
) -> None:
workflow.close_others()
await ctx.call(ButtonRequest(code=code), ButtonAck)

View File

@ -7,8 +7,7 @@ from trezor.ui.components.tt.confirm import (
HoldToConfirm,
InfoConfirm,
)
from . import button_request
from trezor.ui.layouts.common import button_request
if __debug__:
from trezor.ui.components.tt.scroll import Paginated

View File

@ -1,23 +0,0 @@
from trezor.utils import chunks
from apps.common import HARDENED
if False:
from typing import Iterable, Iterator
def split_address(address: str) -> Iterator[str]:
return chunks(address, 17)
def address_n_to_str(address_n: Iterable[int]) -> str:
def path_item(i: int) -> str:
if i & HARDENED:
return str(i ^ HARDENED) + "'"
else:
return str(i)
if not address_n:
return "m"
return "m/" + "/".join([path_item(i) for i in address_n])

View File

@ -3,7 +3,7 @@ from trezor import ui, utils, workflow
from trezor.enums import BackupType
def get() -> tuple[bytes | None, int]:
def get() -> tuple[bytes | None, BackupType]:
return get_secret(), get_type()
@ -54,13 +54,12 @@ def get_seed(passphrase: str = "", progress_bar: bool = True) -> bytes:
def _start_progress() -> None:
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import draw_simple_text
# Because we are drawing to the screen manually, without a layout, we
# should make sure that no other layout is running.
workflow.close_others()
t = Text("Please wait", ui.ICON_CONFIG)
ui.draw_simple(t)
draw_simple_text("Please wait")
def _render_progress(progress: int, total: int) -> None:

View File

@ -2,9 +2,6 @@ from micropython import const
import storage.device
from trezor import wire, workflow
from trezor.enums import ButtonRequestType
from . import button_request
_MAX_PASSPHRASE_LEN = const(50)
@ -23,7 +20,9 @@ async def get(ctx: wire.Context) -> str:
async def _request_from_user(ctx: wire.Context) -> str:
workflow.close_others() # request exclusive UI access
if storage.device.get_passphrase_always_on_device():
passphrase = await _request_on_device(ctx)
from trezor.ui.layouts import request_passphrase_on_device
passphrase = await request_passphrase_on_device(ctx, _MAX_PASSPHRASE_LEN)
else:
passphrase = await _request_on_host(ctx)
if len(passphrase.encode()) > _MAX_PASSPHRASE_LEN:
@ -36,19 +35,17 @@ async def _request_from_user(ctx: wire.Context) -> str:
async def _request_on_host(ctx: wire.Context) -> str:
from trezor.messages import PassphraseAck, PassphraseRequest
from trezor.ui import ICON_CONFIG
from trezor.ui.components.tt.text import Text
from .confirm import require_confirm
_entry_dialog()
request = PassphraseRequest()
ack = await ctx.call(request, PassphraseAck)
if ack.on_device:
from trezor.ui.layouts import request_passphrase_on_device
if ack.passphrase is not None:
raise wire.DataError("Passphrase provided when it should not be")
return await _request_on_device(ctx)
return await request_passphrase_on_device(ctx, _MAX_PASSPHRASE_LEN)
if ack.passphrase is None:
raise wire.DataError(
@ -57,41 +54,33 @@ async def _request_on_host(ctx: wire.Context) -> str:
# 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)
from trezor import ui
from trezor.ui.layouts import confirm_action, confirm_blob
text = Text("Hidden wallet", ICON_CONFIG, break_words=True)
text.normal("Use this passphrase?")
text.br()
text.mono(ack.passphrase)
await require_confirm(ctx, text, ButtonRequestType.Other)
await confirm_action(
ctx,
"passphrase_host1",
title="Hidden wallet",
description="Access hidden wallet?\n\nNext screen will show\nthe passphrase!",
icon=ui.ICON_CONFIG,
)
await confirm_blob(
ctx,
"passphrase_host2",
title="Hidden wallet",
description="Use this passphrase?\n",
data=ack.passphrase,
icon=ui.ICON_CONFIG,
icon_color=ui.ORANGE_ICON,
)
return ack.passphrase
async def _request_on_device(ctx: wire.Context) -> str:
from trezor.ui.components.tt.passphrase import CANCELLED, PassphraseKeyboard
await button_request(ctx, code=ButtonRequestType.PassphraseEntry)
keyboard = PassphraseKeyboard("Enter passphrase", _MAX_PASSPHRASE_LEN)
passphrase = await ctx.wait(keyboard)
if passphrase is CANCELLED:
raise wire.ActionCancelled("Passphrase entry cancelled")
assert isinstance(passphrase, str)
return passphrase
def _entry_dialog() -> None:
from trezor.ui import ICON_CONFIG, draw_simple
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import draw_simple_text
text = Text("Passphrase entry", ICON_CONFIG)
text.normal("Please type your", "passphrase on the", "connected host.")
draw_simple(text)
draw_simple_text(
"Passphrase entry", "Please type your\npassphrase on the\nconnected host."
)

View File

@ -1,4 +1,6 @@
from . import HARDENED
from micropython import const
HARDENED = const(0x8000_0000)
if False:
from typing import (
@ -325,7 +327,6 @@ async def validate_path(
async def show_path_warning(ctx: wire.Context, path: Bip32Path) -> None:
from trezor.ui.layouts import confirm_path_warning
from .layout import address_n_to_str
await confirm_path_warning(ctx, address_n_to_str(path))
@ -336,3 +337,16 @@ def is_hardened(i: int) -> bool:
def path_is_hardened(address_n: Bip32Path) -> bool:
return all(is_hardened(n) for n in address_n)
def address_n_to_str(address_n: Iterable[int]) -> str:
def path_item(i: int) -> str:
if i & HARDENED:
return str(i ^ HARDENED) + "'"
else:
return str(i)
if not address_n:
return "m"
return "m/" + "/".join(path_item(i) for i in address_n)

View File

@ -2,11 +2,8 @@ import utime
import storage.cache
import storage.sd_salt
from trezor import config, ui, wire
from trezor.enums import ButtonRequestType
from trezor.ui.popup import Popup
from trezor import config, wire
from . import button_request
from .sdcard import SdCardUnavailable, request_sd_salt
if False:
@ -24,25 +21,9 @@ async def request_pin(
attempts_remaining: int | None = None,
allow_cancel: bool = True,
) -> str:
from trezor.ui.components.tt.pin import CANCELLED, PinDialog
from trezor.ui.layouts import request_pin_on_device
await button_request(ctx, code=ButtonRequestType.PinEntry)
if attempts_remaining is None:
subprompt = None
elif attempts_remaining == 1:
subprompt = "This is your last attempt"
else:
subprompt = "%s attempts remaining" % attempts_remaining
dialog = PinDialog(prompt, subprompt, allow_cancel)
while True:
pin = await ctx.wait(dialog)
if pin is CANCELLED:
raise wire.PinCancelled
assert isinstance(pin, str)
return pin
return await request_pin_on_device(ctx, prompt, attempts_remaining, allow_cancel)
async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> str:
@ -55,14 +36,12 @@ async def request_pin_confirm(ctx: wire.Context, *args: Any, **kwargs: Any) -> s
async def pin_mismatch() -> None:
from trezor.ui.components.tt.text import Text
from trezor.ui.layouts import show_popup
text = Text("PIN mismatch", ui.ICON_WRONG, ui.RED)
text.normal("The PINs you entered", "do not match.")
text.normal("")
text.normal("Please try again.")
popup = Popup(text, 3000) # show for 3 seconds
await popup
await show_popup(
title="PIN mismatch",
description="The PINs you entered\ndo not match.\n\nPlease try again.",
)
async def request_pin_and_sd_salt(
@ -109,7 +88,11 @@ async def verify_user_pin(
return
if config.has_pin():
pin = await request_pin(ctx, prompt, config.get_pin_rem(), allow_cancel)
from trezor.ui.layouts import request_pin_on_device
pin = await request_pin_on_device(
ctx, prompt, config.get_pin_rem(), allow_cancel
)
config.ensure_not_wipe_code(pin)
else:
pin = ""
@ -125,7 +108,7 @@ async def verify_user_pin(
raise RuntimeError
while retry:
pin = await request_pin(
pin = await request_pin_on_device(
ctx, "Wrong PIN, enter again", config.get_pin_rem(), allow_cancel
)
if config.unlock(pin, salt):

View File

@ -4,7 +4,6 @@ from trezor.messages import EthereumAddress
from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.layout import address_n_to_str
from . import networks
from .address import address_from_bytes
@ -27,7 +26,7 @@ async def get_address(ctx, msg, keychain):
address = address_from_bytes(address_bytes, network)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return EthereumAddress(address=address)

View File

@ -1,6 +1,6 @@
from trezor import wire
from apps.common import HARDENED, paths
from apps.common import paths
from apps.common.keychain import get_keychain
from . import CURVE, networks
@ -37,10 +37,10 @@ def _schemas_from_address_n(
if slip44_hardened not in networks.all_slip44_ids_hardened():
return ()
if not slip44_hardened & HARDENED:
if not slip44_hardened & paths.HARDENED:
return ()
slip44_id = slip44_hardened - HARDENED
slip44_id = slip44_hardened - paths.HARDENED
schemas = [paths.PathSchema.parse(pattern, slip44_id) for pattern in patterns]
return [s.copy() for s in schemas]

View File

@ -3,7 +3,7 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import HARDENED
SLIP44_WANCHAIN = const(5718350)
SLIP44_ETHEREUM = const(60)

View File

@ -3,7 +3,7 @@
from micropython import const
from apps.common import HARDENED
from apps.common.paths import HARDENED
SLIP44_WANCHAIN = const(5718350)
SLIP44_ETHEREUM = const(60)

View File

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import get_address_from_public_key
@ -18,7 +17,7 @@ async def get_address(ctx, msg, keychain):
address = get_address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return LiskAddress(address=address)

View File

@ -6,8 +6,8 @@ from trezor.ui.components.tt.scroll import Paginated
from trezor.ui.components.tt.text import Text
from trezor.ui.components.tt.word_select import WordSelector
from trezor.ui.layouts import confirm_action, show_success, show_warning
from trezor.ui.layouts.common import button_request
from apps.common import button_request
from apps.common.confirm import confirm, info_confirm, require_confirm
from .. import backup_types

View File

@ -5,9 +5,8 @@ from trezor.crypto.hashlib import sha256
from trezor.messages import ECDHSessionKey
from trezor.ui.layouts import confirm_address
from apps.common import HARDENED
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from apps.common.paths import HARDENED, AlwaysMatchingSchema
from .sign_identity import serialize_identity, serialize_identity_without_proto

View File

@ -5,9 +5,9 @@ from trezor.crypto.hashlib import sha256
from trezor.messages import SignedIdentity
from trezor.ui.layouts import confirm_sign_identity
from apps.common import HARDENED, coininfo
from apps.common import coininfo
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from apps.common.paths import HARDENED, AlwaysMatchingSchema
if False:
from trezor.messages import IdentityType, SignIdentity

View File

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from apps.monero import misc
from apps.monero.xmr import addresses, crypto, monero
from apps.monero.xmr.networks import net_version
@ -41,7 +40,7 @@ async def get_address(ctx, msg, keychain):
)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(
ctx,
address=addr.decode(),

View File

@ -2,8 +2,7 @@ from trezor.messages import NEMAddress
from trezor.ui.layouts import show_address
from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str
from apps.common.paths import validate_path
from apps.common.paths import address_n_to_str, validate_path
from . import CURVE, PATTERNS, SLIP44_ID
from .helpers import check_path, get_network_str

View File

@ -1,6 +1,6 @@
from micropython import const
from apps.common import HARDENED, paths
from apps.common import paths
from . import SLIP44_ID
@ -45,7 +45,7 @@ def check_path(path: paths.Bip32Path, network: int) -> bool:
if len(path) < 2:
return False
coin_type = path[1] - HARDENED
coin_type = path[1] - paths.HARDENED
if network == NEM_NETWORK_TESTNET:
return coin_type == 1

View File

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from .helpers import address_from_public_key
@ -17,7 +16,7 @@ async def get_address(ctx, msg: RippleGetAddress, keychain):
address = address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return RippleAddress(address=address)

View File

@ -3,7 +3,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths, seed
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str
from . import helpers
@ -17,7 +16,7 @@ async def get_address(ctx, msg: StellarGetAddress, keychain):
address = helpers.address_from_public_key(pubkey)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(
ctx, address=address, address_qr=address.upper(), title=title
)

View File

@ -4,7 +4,6 @@ from trezor.ui.layouts import show_address
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str
from . import CURVE, PATTERNS, SLIP44_ID, helpers
@ -22,7 +21,7 @@ async def get_address(ctx, msg, keychain):
)
if msg.show_display:
title = address_n_to_str(msg.address_n)
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, address_qr=address, title=title)
return TezosAddress(address=address)

View File

@ -7,7 +7,8 @@ from trezor import log, utils
from trezor.crypto import bip32, chacha20poly1305, der, hashlib, hmac, random
from trezor.crypto.curve import ed25519, nist256p1
from apps.common import HARDENED, cbor, seed
from apps.common import cbor, seed
from apps.common.paths import HARDENED
from . import common

View File

@ -14,17 +14,25 @@ if __debug__:
from ..components.tt.scroll import Paginated
async def button_request(
ctx: wire.GenericContext,
br_type: str,
code: ButtonRequestType = ButtonRequestType.Other,
) -> None:
log.debug(__name__, "ButtonRequest.type={}".format(br_type))
workflow.close_others()
await ctx.call(ButtonRequest(code=code), ButtonAck)
async def interact(
ctx: wire.GenericContext,
layout: LayoutType,
brtype: str,
brcode: ButtonRequestType = ButtonRequestType.Other,
br_type: str,
br_code: ButtonRequestType = ButtonRequestType.Other,
) -> Any:
log.debug(__name__, "ButtonRequest.type={}".format(brtype))
if layout.__class__.__name__ == "Paginated":
assert isinstance(layout, Paginated)
return await layout.interact(ctx, code=brcode)
return await layout.interact(ctx, code=br_code)
else:
workflow.close_others()
await ctx.call(ButtonRequest(code=brcode), ButtonAck)
await button_request(ctx, br_type, br_code)
return await ctx.wait(layout)

View File

@ -12,6 +12,7 @@ from trezor.utils import chunks, chunks_intersperse
from ..components.common import break_path_to_lines
from ..components.common.confirm import is_confirmed, raise_if_cancelled
from ..components.common.webauthn import ConfirmInfo
from ..components.tt import passphrase, pin
from ..components.tt.button import ButtonCancel, ButtonDefault
from ..components.tt.confirm import Confirm, ConfirmPageable, HoldToConfirm, Pageable
from ..components.tt.scroll import (
@ -30,7 +31,7 @@ from ..constants.tt import (
QR_Y,
TEXT_MAX_LINES,
)
from .common import interact
from .common import button_request, interact
if False:
from typing import (
@ -78,6 +79,9 @@ __all__ = (
"show_popup",
"confirm_webauthn",
"confirm_webauthn_reset",
"draw_simple_text",
"request_passphrase_on_device",
"request_pin_on_device",
)
@ -1055,3 +1059,47 @@ async def confirm_webauthn_reset() -> bool:
text.normal("Do you really want to")
text.bold("erase all credentials?")
return is_confirmed(await Confirm(text))
def draw_simple_text(title: str, description: str = "") -> None:
text = Text(title, ui.ICON_CONFIG, new_lines=False)
text.normal(description)
ui.draw_simple(text)
async def request_passphrase_on_device(ctx: wire.GenericContext, max_len: int) -> str:
await button_request(
ctx, "passphrase_device", code=ButtonRequestType.PassphraseEntry
)
keyboard = passphrase.PassphraseKeyboard("Enter passphrase", max_len)
result = await ctx.wait(keyboard)
if result is passphrase.CANCELLED:
raise wire.ActionCancelled("Passphrase entry cancelled")
assert isinstance(result, str)
return result
async def request_pin_on_device(
ctx: wire.GenericContext,
prompt: str,
attempts_remaining: int,
allow_cancel: bool,
) -> str:
await button_request(ctx, "pin_device", code=ButtonRequestType.PinEntry)
if attempts_remaining is None:
subprompt = None
elif attempts_remaining == 1:
subprompt = "This is your last attempt"
else:
subprompt = "%s attempts remaining" % attempts_remaining
dialog = pin.PinDialog(prompt, subprompt, allow_cancel)
while True:
result = await ctx.wait(dialog)
if result is pin.CANCELLED:
raise wire.PinCancelled
assert isinstance(result, str)
return result

View File

@ -7,7 +7,7 @@ from ubinascii import hexlify, unhexlify # noqa: F401
import unittest # noqa: F401
from trezor import utils # noqa: F401
from apps.common import HARDENED
from apps.common.paths import HARDENED
def H_(x: int) -> int:

View File

@ -5,7 +5,8 @@ from trezor.enums import CardanoAddressType
from trezor.messages import CardanoAddressParametersType
from trezor.messages import CardanoBlockchainPointerType
from apps.common import HARDENED, seed
from apps.common import seed
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from apps.cardano.address import derive_human_readable_address, validate_address_parameters

View File

@ -2,7 +2,8 @@ from common import *
from trezor import wire
from trezor.crypto import bip32, slip39
from apps.common import HARDENED, seed
from apps.common import seed
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from apps.cardano.seed import Keychain

View File

@ -1,5 +1,5 @@
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
from trezor.messages import CardanoTxInputType
if not utils.BITCOIN_ONLY:

View File

@ -2,7 +2,7 @@ from ubinascii import unhexlify
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
from trezor.crypto import bip32
from trezor.enums import CardanoAddressType
from trezor.messages import CardanoAddressParametersType

View File

@ -1,6 +1,5 @@
from common import *
from trezor.utils import ensure
from apps.common.layout import address_n_to_str
from apps.common.paths import *

View File

@ -1,5 +1,5 @@
from common import *
from apps.common import HARDENED
from apps.common.paths import HARDENED
if not utils.BITCOIN_ONLY:
from trezor.crypto import nem

View File

@ -347,7 +347,7 @@
"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": "ad7c162c76a13a161166aba78c461ad5525a9a5da846e8d99854248d521e6979",
"test_msg_loaddevice.py-test_load_device_utf": "b51beeb07c60e8c803b5bf81e4470db785dc46006374b15df21a7810d659b2b6",
"test_msg_monero_getaddress.py-test_monero_getaddress": "0ba9bba02378d62c8f9f76aac5181ab94b25dcbed0f58d006c1f7d4eb1ecd03e",
"test_msg_monero_getwatchkey.py-test_monero_getwatchkey": "d77fa4d4322e145c41f1ce07526ff59f8b58d8854aeffaa5266e14cd572350e7",
"test_msg_nem_getaddress.py-test_nem_getaddress": "d3ac0e389d139c79abeff96cd05b9c9f94c3372086096d5eb85759ab3a37b0b8",
@ -714,7 +714,7 @@
"test_session_id_and_passphrase.py::test_multiple_sessions": "5a80508a71a9ef64f94762b07636f90e464832f0f4a3102af8fa1a8c69e94586",
"test_session_id_and_passphrase.py::test_passphrase_ack_mismatch": "612dad8ab8762162a186ec9279d7de0bdfc589c52b4e4f4eba0545a00f21c3f0",
"test_session_id_and_passphrase.py::test_passphrase_always_on_device": "524d90c68c6f091c2145f571a884a8a168e8af101513966f5e0fbb3859035129",
"test_session_id_and_passphrase.py::test_passphrase_length": "a8858d89288f2160148860fee8938d261c4960732db3b2c874b9899395b9ddc6",
"test_session_id_and_passphrase.py::test_passphrase_length": "6c9063e65e113d7c67624392b1bedae600ae02d4576375a11b399b3c3dd15987",
"test_session_id_and_passphrase.py::test_passphrase_missing": "3a92115b6bfb2d53f2445a67c9c5df6b6b5ff97769de98e3fac9e1bf424c5669",
"test_session_id_and_passphrase.py::test_passphrase_on_device": "c9ca2c9cf6dd416dad4de311266690ec2266b551d74f9d3619301305b3dbe81e",
"test_session_id_and_passphrase.py::test_session_enable_passphrase": "b27321ed372b8ade7c4941a80f1f945851046b039a1b43c43a6953106bd1619e",