1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-25 08:58:14 +00:00

core: rework cache and fix cardano caching

This commit is contained in:
Tomas Susanka 2020-01-27 13:58:32 +00:00 committed by Pavol Rusnak
parent aa6988a556
commit b96d7cafbb
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
4 changed files with 91 additions and 44 deletions

View File

@ -1,4 +1,5 @@
import storage
from storage import cache
from trezor import wire
from trezor.crypto import bip32
@ -6,11 +7,6 @@ from apps.cardano import CURVE, SEED_NAMESPACE
from apps.common import mnemonic
from apps.common.passphrase import get as get_passphrase
if False:
from typing import Optional
_cached_root = None # type: Optional[bytes]
class Keychain:
def __init__(self, path: list, root: bip32.HDNode):
@ -35,25 +31,30 @@ class Keychain:
async def get_keychain(ctx: wire.Context) -> Keychain:
global _cached_root
root = cache.get(cache.APP_CARDANO_ROOT)
if not storage.is_initialized():
raise wire.NotInitialized("Device is not initialized")
if _cached_root is None:
if root is None:
passphrase = await get_passphrase(ctx)
if mnemonic.is_bip39():
# derive the root node from mnemonic and passphrase
_cached_root = bip32.from_mnemonic_cardano(
root = bip32.from_mnemonic_cardano(
mnemonic.get_secret().decode(), passphrase
)
else:
seed = mnemonic.get_seed(passphrase)
_cached_root = bip32.from_seed(seed, "ed25519 cardano seed")
root = bip32.from_seed(seed, "ed25519 cardano seed")
storage.cache.set(cache.APP_CARDANO_ROOT, root)
# let's not modify the one in the cache
root = root.clone()
# derive the namespaced root node
for i in SEED_NAMESPACE:
_cached_root.derive_cardano(i)
root.derive_cardano(i)
keychain = Keychain(SEED_NAMESPACE, _cached_root)
keychain = Keychain(SEED_NAMESPACE, root)
return keychain

View File

@ -1,5 +1,5 @@
import storage
import storage.cache
from storage import cache
from trezor import wire
from trezor.crypto import bip32, hashlib, hmac
from trezor.crypto.curve import secp256k1
@ -112,11 +112,11 @@ class Keychain:
async def get_keychain(ctx: wire.Context, namespaces: list) -> Keychain:
if not storage.is_initialized():
raise wire.NotInitialized("Device is not initialized")
seed = storage.cache.get_seed()
seed = cache.get(cache.APP_COMMON_SEED)
if seed is None:
passphrase = await get_passphrase(ctx)
seed = mnemonic.get_seed(passphrase)
storage.cache.set_seed(seed)
cache.set(cache.APP_COMMON_SEED, seed)
keychain = Keychain(seed, namespaces)
return keychain
@ -126,10 +126,10 @@ def derive_node_without_passphrase(
) -> bip32.HDNode:
if not storage.is_initialized():
raise Exception("Device is not initialized")
seed = storage.cache.get_seed_without_passphrase()
seed = cache.get(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE)
if seed is None:
seed = mnemonic.get_seed(progress_bar=False)
storage.cache.set_seed_without_passphrase(seed)
cache.set(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE, seed)
node = bip32.from_seed(seed, curve_name)
node.derive_path(path)
return node
@ -138,10 +138,10 @@ def derive_node_without_passphrase(
def derive_slip21_node_without_passphrase(path: list) -> Slip21Node:
if not storage.is_initialized():
raise Exception("Device is not initialized")
seed = storage.cache.get_seed_without_passphrase()
seed = cache.get(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE)
if seed is None:
seed = mnemonic.get_seed(progress_bar=False)
storage.cache.set_seed_without_passphrase(seed)
cache.set(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE, seed)
node = Slip21Node(seed)
node.derive_path(path)
return node

View File

@ -3,39 +3,35 @@ from trezor.crypto import random
if False:
from typing import Optional
_cached_seed = None # type: Optional[bytes]
_cached_seed_without_passphrase = None # type: Optional[bytes] # Needed for SLIP-21
_cached_session_id = None # type: Optional[bytes]
APP_COMMON_SEED = 0
APP_COMMON_SEED_WITHOUT_PASSPHRASE = 1
APP_CARDANO_ROOT = 2
_cache_session_id = None # type: Optional[bytes]
_cache = {}
if False:
from typing import Any
def get_session_id() -> bytes:
global _cached_session_id
if not _cached_session_id:
_cached_session_id = random.bytes(32)
return _cached_session_id
global _cache_session_id
if not _cache_session_id:
_cache_session_id = random.bytes(32)
return _cache_session_id
def set_seed(seed: Optional[bytes]) -> None:
global _cached_seed
_cached_seed = seed
def set(key: int, value: Any) -> None:
global _cache
_cache[key] = value
def get_seed() -> Optional[bytes]:
return _cached_seed
def set_seed_without_passphrase(seed: Optional[bytes]) -> None:
global _cached_seed_without_passphrase
_cached_seed_without_passphrase = seed
def get_seed_without_passphrase() -> Optional[bytes]:
return _cached_seed_without_passphrase
def get(key: int) -> Any:
return _cache.get(key)
def clear() -> None:
global _cached_session_id
_cached_session_id = None
set_seed(None)
set_seed_without_passphrase(None)
global _cache_session_id
global _cache
_cache_session_id = None
_cache.clear()

View File

@ -22,6 +22,7 @@ from trezorlib.tools import parse_path
XPUB_PASSPHRASE_A = "xpub6CekxGcnqnJ6osfY4Rrq7W5ogFtR54KUvz4H16XzaQuukMFZCGebEpVznfq4yFcKEmYyShwj2UKjL7CazuNSuhdkofF4mHabHkLxCMVvsqG"
XPUB_PASSPHRASE_NONE = "xpub6BiVtCpG9fQPxnPmHXG8PhtzQdWC2Su4qWu6XW9tpWFYhxydCLJGrWBJZ5H6qTAHdPQ7pQhtpjiYZVZARo14qHiay2fvrX996oEP42u8wZy"
XPUB_CARDANO_PASSPHRASE_B = "d80e770f6dfc3edb58eaab68aa091b2c27b08a47583471e93437ac5f8baa61880c7af4938a941c084c19731e6e57a5710e6ad1196263291aea297ce0eec0f177"
def _get_xpub(client, passphrase):
@ -222,3 +223,52 @@ def test_passphrase_missing(client):
response = client.call_raw(messages.PassphraseAck(passphrase=None, on_device=False))
assert isinstance(response, messages.Failure)
assert response.code == FailureType.DataError
@pytest.mark.skip_ui
@pytest.mark.skip_t1
@pytest.mark.altcoin
@pytest.mark.setup_client(passphrase=True)
def test_cardano_passphrase(client):
# Cardano uses a variation of BIP-39 so we need to ask for the passphrase again.
response = client.call_raw(messages.Initialize())
assert isinstance(response, messages.Features)
session_id = response.session_id
assert len(session_id) == 32
# GetPublicKey requires passphrase and since it is not cached,
# Trezor will prompt for it.
xpub = _get_xpub(client, passphrase="A")
assert xpub == XPUB_PASSPHRASE_A
# The passphrase is now cached for non-Cardano coins.
xpub = _get_xpub(client, passphrase=None)
assert xpub == XPUB_PASSPHRASE_A
# Cardano will prompt for it again.
response = client.call_raw(
messages.CardanoGetPublicKey(address_n=parse_path("44'/1815'/0'/0/0"))
)
assert isinstance(response, messages.PassphraseRequest)
response = client.call_raw(messages.PassphraseAck(passphrase="B"))
assert response.xpub == XPUB_CARDANO_PASSPHRASE_B
# But now also Cardano has it cached.
response = client.call_raw(
messages.CardanoGetPublicKey(address_n=parse_path("44'/1815'/0'/0/0"))
)
assert response.xpub == XPUB_CARDANO_PASSPHRASE_B
# And others behaviour did not change.
xpub = _get_xpub(client, passphrase=None)
assert xpub == XPUB_PASSPHRASE_A
# Initialize with the session id does not destroy the state
client.call_raw(messages.Initialize(session_id=session_id))
xpub = _get_xpub(client, passphrase=None)
assert xpub == XPUB_PASSPHRASE_A
response = client.call_raw(
messages.CardanoGetPublicKey(address_n=parse_path("44'/1815'/0'/0/0"))
)
assert response.xpub == XPUB_CARDANO_PASSPHRASE_B