feat(core): update most apps to use path schemas

pull/1328/head
matejcik 4 years ago committed by matejcik
parent 4ca8f7b0d6
commit f5c8138df6

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_BIP44
CURVE = "secp256k1"
SLIP44_ID = 714
PATTERN = PATTERN_BIP44
def boot() -> None:

@ -2,23 +2,21 @@ from trezor.messages.BinanceAddress import BinanceAddress
from trezor.messages.BinanceGetAddress import BinanceGetAddress
from apps.common import paths
from apps.common.keychain import Keychain, with_slip44_keychain
from apps.common.keychain import Keychain, auto_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, SLIP44_ID, helpers
from .helpers import address_from_public_key
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
HRP = "bnb"
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = node.public_key()
address = helpers.address_from_public_key(pubkey, HRP)
address = address_from_public_key(pubkey, HRP)
if msg.show_display:
desc = address_n_to_str(msg.address_n)
while True:

@ -2,16 +2,12 @@ from trezor.messages.BinanceGetPublicKey import BinanceGetPublicKey
from trezor.messages.BinancePublicKey import BinancePublicKey
from apps.common import layout, paths
from apps.common.keychain import Keychain, with_slip44_keychain
from apps.common.keychain import Keychain, auto_keychain
from . import CURVE, SLIP44_ID, helpers
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_public_key(ctx, msg: BinanceGetPublicKey, keychain: Keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = node.public_key()

@ -8,8 +8,6 @@ from trezor.messages.BinanceOrderMsg import BinanceOrderMsg
from trezor.messages.BinanceSignTx import BinanceSignTx
from trezor.messages.BinanceTransferMsg import BinanceTransferMsg
from apps.common import HARDENED
ENVELOPE_BLUEPRINT = '{{"account_number":"{account_number}","chain_id":"{chain_id}","data":null,"memo":"{memo}","msgs":[{msgs}],"sequence":"{sequence}","source":"{source}"}}'
MSG_TRANSFER_BLUEPRINT = '{{"inputs":[{inputs}],"outputs":[{outputs}]}}'
MSG_NEWORDER_BLUEPRINT = '{{"id":"{id}","ordertype":{ordertype},"price":{price},"quantity":{quantity},"sender":"{sender}","side":{side},"symbol":"{symbol}","timeinforce":{timeinforce}}}'
@ -91,25 +89,3 @@ def address_from_public_key(pubkey: bytes, hrp: str) -> str:
convertedbits = bech32.convertbits(h, 8, 5, False)
return bech32.bech32_encode(hrp, convertedbits)
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/714'/a'/0/0,
where `a` is an account index from 0 to 1 000 000.
Similar to Ethereum this should be 44'/714'/a', but for
compatibility with other HW vendors we use 44'/714'/a'/0/0.
"""
if len(path) != 5:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 714 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
if path[3] != 0:
return False
if path[4] != 0:
return False
return True

@ -9,20 +9,18 @@ from trezor.messages.BinanceTransferMsg import BinanceTransferMsg
from trezor.messages.BinanceTxRequest import BinanceTxRequest
from apps.common import paths
from apps.common.keychain import Keychain, with_slip44_keychain
from apps.common.keychain import Keychain, auto_keychain
from . import CURVE, SLIP44_ID, helpers, layout
from . import helpers, layout
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_tx(ctx, envelope, keychain: Keychain):
# create transaction message -> sign it -> create signature/pubkey message -> serialize all
if envelope.msg_count > 1:
raise wire.DataError("Multiple messages not supported.")
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, envelope.address_n, CURVE
)
await paths.validate_path(ctx, keychain, envelope.address_n)
node = keychain.derive(envelope.address_n)
tx_req = BinanceTxRequest()

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_BIP44
CURVE = "secp256k1"
SLIP44_ID = 194
PATTERN = PATTERN_BIP44
def boot() -> None:

@ -4,10 +4,9 @@ from trezor.messages.EosGetPublicKey import EosGetPublicKey
from trezor.messages.EosPublicKey import EosPublicKey
from apps.common import paths
from apps.common.keychain import Keychain, with_slip44_keychain
from apps.common.keychain import Keychain, auto_keychain
from . import CURVE, SLIP44_ID
from .helpers import public_key_to_wif, validate_full_path
from .helpers import public_key_to_wif
from .layout import require_get_public_key
if False:
@ -22,11 +21,11 @@ def _get_public_key(node: bip32.HDNode) -> Tuple[str, bytes]:
return wif, public_key
@with_slip44_keychain(SLIP44_ID, CURVE)
@auto_keychain(__name__)
async def get_public_key(
ctx: wire.Context, msg: EosGetPublicKey, keychain: Keychain
) -> EosPublicKey:
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
wif, public_key = _get_public_key(node)

@ -2,8 +2,6 @@ from trezor import wire
from trezor.crypto import base58
from trezor.messages.EosAsset import EosAsset
from apps.common import HARDENED
def base58_encode(prefix: str, sig_prefix: str, data: bytes) -> str:
b58 = base58.encode(data + base58.ripemd160_32(data + sig_prefix.encode()))
@ -42,28 +40,6 @@ def eos_asset_to_string(asset: EosAsset) -> str:
return "{} {}".format(amount_digits, symbol)
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/194'/a'/0/0,
where `a` is an account index from 0 to 1 000 000.
Similar to Ethereum this should be 44'/194'/a', but for
compatibility with other HW vendors we use 44'/194'/a'/0/0.
"""
if len(path) != 5:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 194 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
if path[3] != 0:
return False
if path[4] != 0:
return False
return True
def public_key_to_wif(pub_key: bytes) -> str:
if pub_key[0] == 0x04 and len(pub_key) == 65:
head = b"\x03" if pub_key[64] & 0x01 else b"\x02"

@ -8,15 +8,15 @@ from trezor.messages.EosTxActionRequest import EosTxActionRequest
from trezor.utils import HashWriter
from apps.common import paths
from apps.common.keychain import Keychain, with_slip44_keychain
from apps.common.keychain import Keychain, auto_keychain
from . import CURVE, SLIP44_ID, writers
from . import writers
from .actions import process_action
from .helpers import base58_encode, validate_full_path
from .helpers import base58_encode
from .layout import require_sign_tx
@with_slip44_keychain(SLIP44_ID, CURVE)
@auto_keychain(__name__)
async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx:
if msg.chain_id is None:
raise wire.DataError("No chain id")
@ -25,7 +25,7 @@ async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosS
if msg.num_actions is None or msg.num_actions == 0:
raise wire.DataError("No actions")
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
sha = HashWriter(sha256())

@ -2,59 +2,6 @@ from ubinascii import unhexlify
from trezor import wire
from apps.common import HARDENED, paths
from . import networks
"""
We believe Ethereum should use 44'/60'/a' for everything, because it is
account-based, rather than UTXO-based. Unfortunately, lot of Ethereum
tools (MEW, Metamask) do not use such scheme and set a = 0 and then
iterate the address index i. Therefore for compatibility reasons we use
the same scheme: 44'/60'/0'/0/i and only the i is being iterated.
"""
def validate_path_for_get_public_key(path: list) -> bool:
"""
This should be 44'/60'/0', but other non-hardened items are allowed.
"""
length = len(path)
if length < 3 or length > 5:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] not in networks.all_slip44_ids_hardened():
return False
if path[2] != 0 | HARDENED:
return False
if length > 3 and paths.is_hardened(path[3]):
return False
if length > 4 and paths.is_hardened(path[4]):
return False
return True
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/60'/0'/0/i,
where `i` is an address index from 0 to 1 000 000.
"""
if len(path) != 5:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] not in networks.all_slip44_ids_hardened():
return False
if path[2] != 0 | HARDENED:
return False
if path[3] != 0:
return False
if path[4] > 1000000:
return False
return True
def address_from_bytes(address_bytes: bytes, network=None) -> str:
"""

@ -5,14 +5,14 @@ from trezor.messages.EthereumAddress import EthereumAddress
from apps.common import paths
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, networks
from .address import address_from_bytes, validate_full_path
from .keychain import with_keychain_from_path
from . import networks
from .address import address_from_bytes
from .keychain import PATTERN_ADDRESS, with_keychain_from_path
@with_keychain_from_path
@with_keychain_from_path(PATTERN_ADDRESS)
async def get_address(ctx, msg, keychain):
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
seckey = node.private_key()

@ -3,15 +3,12 @@ from trezor.messages.HDNodeType import HDNodeType
from apps.common import coins, layout, paths
from . import CURVE, address
from .keychain import with_keychain_from_path
from .keychain import PATTERN_PUBKEY, with_keychain_from_path
@with_keychain_from_path
@with_keychain_from_path(PATTERN_PUBKEY)
async def get_public_key(ctx, msg, keychain):
await paths.validate_path(
ctx, address.validate_path_for_get_public_key, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
# we use the Bitcoin format for Ethereum xpubs

@ -1,12 +1,12 @@
from trezor import wire
from apps.common import HARDENED, seed
from apps.common import HARDENED, paths
from apps.common.keychain import get_keychain
from . import CURVE, networks
if False:
from typing import List
from typing import Callable
from typing_extensions import Protocol
from protobuf import MessageType
@ -16,48 +16,76 @@ if False:
from apps.common.keychain import MsgOut, Handler, HandlerWithKeychain
class MsgWithAddressN(MessageType, Protocol):
address_n = ... # type: List[int]
address_n = ... # type: paths.Bip32Path
async def from_address_n(ctx: wire.Context, address_n: List[int]) -> seed.Keychain:
# We believe Ethereum should use 44'/60'/a' for everything, because it is
# account-based, rather than UTXO-based. Unfortunately, lot of Ethereum
# tools (MEW, Metamask) do not use such scheme and set a = 0 and then
# iterate the address index i. Therefore for compatibility reasons we use
# the same scheme: 44'/60'/0'/0/i and only the i is being iterated.
PATTERN_ADDRESS = "m/44'/coin_type'/0'/0/address_index"
PATTERN_PUBKEY = "m/44'/coin_type'/0'/*"
def _schema_from_address_n(
pattern: str, address_n: paths.Bip32Path
) -> paths.PathSchema:
if len(address_n) < 2:
raise wire.DataError("Forbidden key path")
return paths.SCHEMA_NO_MATCH
slip44_hardened = address_n[1]
if slip44_hardened not in networks.all_slip44_ids_hardened():
raise wire.DataError("Forbidden key path")
namespace = [44 | HARDENED, slip44_hardened]
return await get_keychain(ctx, CURVE, [namespace])
return paths.SCHEMA_NO_MATCH
if not slip44_hardened & HARDENED:
return paths.SCHEMA_ANY_PATH
slip44_id = slip44_hardened - HARDENED
return paths.PathSchema(pattern, slip44_id)
def with_keychain_from_path(
func: HandlerWithKeychain[MsgWithAddressN, MsgOut]
) -> Handler[MsgWithAddressN, MsgOut]:
async def wrapper(ctx: wire.Context, msg: MsgWithAddressN) -> MsgOut:
keychain = await from_address_n(ctx, msg.address_n)
with keychain:
return await func(ctx, msg, keychain)
pattern: str,
) -> Callable[
[HandlerWithKeychain[MsgWithAddressN, MsgOut]], Handler[MsgWithAddressN, MsgOut]
]:
def decorator(
func: HandlerWithKeychain[MsgWithAddressN, MsgOut]
) -> Handler[MsgWithAddressN, MsgOut]:
async def wrapper(ctx: wire.Context, msg: MsgWithAddressN) -> MsgOut:
schema = _schema_from_address_n(pattern, msg.address_n)
keychain = await get_keychain(ctx, CURVE, [schema])
with keychain:
return await func(ctx, msg, keychain)
return wrapper
return wrapper
return decorator
def _schema_from_chain_id(msg: EthereumSignTx) -> paths.PathSchema:
if msg.chain_id is None:
return _schema_from_address_n(PATTERN_ADDRESS, msg.address_n)
info = networks.by_chain_id(msg.chain_id)
if info is None:
return paths.SCHEMA_NO_MATCH
slip44_id = info.slip44
if networks.is_wanchain(msg.chain_id, msg.tx_type):
slip44_id = networks.SLIP44_WANCHAIN
return paths.PathSchema(PATTERN_ADDRESS, slip44_id)
def with_keychain_from_chain_id(
func: HandlerWithKeychain[EthereumSignTx, MsgOut]
) -> Handler[EthereumSignTx, MsgOut]:
# this is only for SignTx, and only PATTERN_ADDRESS is allowed
async def wrapper(ctx: wire.Context, msg: EthereumSignTx) -> MsgOut:
if msg.chain_id is None:
keychain = await from_address_n(ctx, msg.address_n)
else:
info = networks.by_chain_id(msg.chain_id)
if info is None:
raise wire.DataError("Unsupported chain id")
slip44 = info.slip44
if networks.is_wanchain(msg.chain_id, msg.tx_type):
slip44 = networks.SLIP44_WANCHAIN
namespace = [44 | HARDENED, slip44 | HARDENED]
keychain = await get_keychain(ctx, CURVE, [namespace])
schema = _schema_from_chain_id(msg)
keychain = await get_keychain(ctx, CURVE, [schema])
with keychain:
return await func(ctx, msg, keychain)

@ -6,8 +6,8 @@ from trezor.utils import HashWriter
from apps.common import paths
from apps.common.signverify import require_confirm_sign_message
from . import CURVE, address
from .keychain import with_keychain_from_path
from . import address
from .keychain import PATTERN_ADDRESS, with_keychain_from_path
def message_digest(message):
@ -19,11 +19,9 @@ def message_digest(message):
return h.get_digest()
@with_keychain_from_path
@with_keychain_from_path(PATTERN_ADDRESS)
async def sign_message(ctx, msg, keychain):
await paths.validate_path(
ctx, address.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
await require_confirm_sign_message(ctx, "ETH", msg.message)
node = keychain.derive(msg.address_n)

@ -9,8 +9,7 @@ from trezor.utils import HashWriter
from apps.common import paths
from . import CURVE, address, tokens
from .address import validate_full_path
from . import address, tokens
from .keychain import with_keychain_from_chain_id
from .layout import require_confirm_data, require_confirm_fee, require_confirm_tx
@ -22,7 +21,7 @@ MAX_CHAIN_ID = 2147483629
async def sign_tx(ctx, msg, keychain):
msg = sanitize(msg)
check(msg)
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
data_total = msg.data_length

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519"
SLIP44_ID = 134
PATTERN = PATTERN_SEP5
def boot() -> None:

@ -1,16 +1,15 @@
from trezor.messages.LiskAddress import LiskAddress
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, SLIP44_ID
from .helpers import get_address_from_public_key, validate_full_path
from .helpers import get_address_from_public_key
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_address(ctx, msg, keychain):
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = node.public_key()

@ -1,15 +1,12 @@
from trezor.messages.LiskPublicKey import LiskPublicKey
from apps.common import layout, paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from . import CURVE, SLIP44_ID
from .helpers import validate_full_path
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_public_key(ctx, msg, keychain):
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = node.public_key()

@ -1,7 +1,5 @@
from trezor.crypto.hashlib import sha256
from apps.common import HARDENED
def get_address_from_public_key(pubkey):
pubkeyhash = sha256(pubkey).digest()
@ -31,19 +29,3 @@ def get_vote_tx_text(votes):
def _text_with_plural(txt, value):
return "%s %s %s" % (txt, value, ("votes" if value != 1 else "vote"))
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/134'/a',
where `a` is an account index from 0 to 1 000 000.
"""
if len(path) != 3:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 134 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
return True

@ -4,13 +4,10 @@ from trezor.messages.LiskMessageSignature import LiskMessageSignature
from trezor.utils import HashWriter
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from apps.common.signverify import require_confirm_sign_message
from apps.common.writers import write_bitcoin_varint
from . import CURVE, SLIP44_ID
from .helpers import validate_full_path
def message_digest(message):
h = HashWriter(sha256())
@ -22,9 +19,9 @@ def message_digest(message):
return sha256(h.get_digest()).digest()
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_message(ctx, msg, keychain):
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
await require_confirm_sign_message(ctx, "Lisk", msg.message)
node = keychain.derive(msg.address_n)

@ -8,15 +8,15 @@ from trezor.messages.LiskSignedTx import LiskSignedTx
from trezor.utils import HashWriter
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from . import CURVE, SLIP44_ID, layout
from .helpers import get_address_from_public_key, validate_full_path
from . import layout
from .helpers import get_address_from_public_key
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_tx(ctx, msg, keychain):
await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)
await paths.validate_path(ctx, keychain, msg.address_n)
pubkey, seckey = _get_keys(keychain, msg)
transaction = _update_raw_tx(msg.transaction, pubkey)

@ -5,10 +5,11 @@ from trezor.ui.text import Text
from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
async def cipher_key_value(ctx, msg):
keychain = await get_keychain(ctx, "secp256k1", [[]])
keychain = await get_keychain(ctx, "secp256k1", [AlwaysMatchingSchema])
if len(msg.value) % 16 > 0:
raise wire.DataError("Value length must be a multiple of 16")

@ -9,6 +9,7 @@ from trezor.utils import chunks
from apps.common import HARDENED
from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from .sign_identity import serialize_identity, serialize_identity_without_proto
@ -17,7 +18,7 @@ async def get_ecdh_session_key(ctx, msg):
if msg.ecdsa_curve_name is None:
msg.ecdsa_curve_name = "secp256k1"
keychain = await get_keychain(ctx, msg.ecdsa_curve_name, [[]])
keychain = await get_keychain(ctx, msg.ecdsa_curve_name, [AlwaysMatchingSchema])
identity = serialize_identity(msg.identity)
await require_confirm_ecdh_session_key(ctx, msg.identity)

@ -9,13 +9,14 @@ from trezor.utils import chunks
from apps.common import HARDENED, coins
from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
async def sign_identity(ctx, msg):
if msg.ecdsa_curve_name is None:
msg.ecdsa_curve_name = "secp256k1"
keychain = await get_keychain(ctx, msg.ecdsa_curve_name, [[]])
keychain = await get_keychain(ctx, msg.ecdsa_curve_name, [AlwaysMatchingSchema])
identity = serialize_identity(msg.identity)
await require_confirm_sign_identity(ctx, msg.identity, msg.challenge_visual)

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519"
SLIP44_ID = 128
PATTERN = PATTERN_SEP5
def boot() -> None:

@ -1,19 +1,17 @@
from trezor.messages.MoneroAddress import MoneroAddress
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str, show_qr
from apps.monero import CURVE, SLIP44_ID, misc
from apps.monero import misc
from apps.monero.layout import confirms
from apps.monero.xmr import addresses, crypto, monero
from apps.monero.xmr.networks import net_version
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_address(ctx, msg, keychain):
await paths.validate_path(
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
creds = misc.get_creds(keychain, msg.address_n, msg.network_type)
addr = creds.address

@ -20,8 +20,8 @@ from trezor.messages.MoneroGetTxKeyAck import MoneroGetTxKeyAck
from trezor.messages.MoneroGetTxKeyRequest import MoneroGetTxKeyRequest
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.monero import CURVE, SLIP44_ID, misc
from apps.common.keychain import auto_keychain
from apps.monero import misc
from apps.monero.layout import confirms
from apps.monero.xmr import crypto
from apps.monero.xmr.crypto import chacha_poly
@ -30,11 +30,9 @@ _GET_TX_KEY_REASON_TX_KEY = 0
_GET_TX_KEY_REASON_TX_DERIVATION = 1
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_tx_keys(ctx, msg: MoneroGetTxKeyRequest, keychain):
await paths.validate_path(
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
do_deriv = msg.reason == _GET_TX_KEY_REASON_TX_DERIVATION
await confirms.require_confirm_tx_key(ctx, export_key=not do_deriv)

@ -2,17 +2,15 @@ from trezor.messages.MoneroGetWatchKey import MoneroGetWatchKey
from trezor.messages.MoneroWatchKey import MoneroWatchKey
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.monero import CURVE, SLIP44_ID, misc
from apps.common.keychain import auto_keychain
from apps.monero import misc
from apps.monero.layout import confirms
from apps.monero.xmr import crypto
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_watch_only(ctx, msg: MoneroGetWatchKey, keychain):
await paths.validate_path(
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
await confirms.require_confirm_watchkey(ctx)

@ -11,14 +11,14 @@ from trezor.messages.MoneroKeyImageSyncStepAck import MoneroKeyImageSyncStepAck
from trezor.messages.MoneroKeyImageSyncStepRequest import MoneroKeyImageSyncStepRequest
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.monero import CURVE, SLIP44_ID, misc
from apps.common.keychain import auto_keychain
from apps.monero import misc
from apps.monero.layout import confirms
from apps.monero.xmr import crypto, key_image, monero
from apps.monero.xmr.crypto import chacha_poly
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def key_image_sync(ctx, msg, keychain):
state = KeyImageSync()
@ -45,9 +45,7 @@ class KeyImageSync:
async def _init_step(s, ctx, msg, keychain):
await paths.validate_path(
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type)

@ -10,14 +10,14 @@ from trezor.messages.MoneroLiveRefreshStepAck import MoneroLiveRefreshStepAck
from trezor.messages.MoneroLiveRefreshStepRequest import MoneroLiveRefreshStepRequest
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.monero import CURVE, SLIP44_ID, misc
from apps.common.keychain import auto_keychain
from apps.monero import misc
from apps.monero.layout import confirms
from apps.monero.xmr import crypto, key_image, monero
from apps.monero.xmr.crypto import chacha_poly
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def live_refresh(ctx, msg: MoneroLiveRefreshStartRequest, keychain):
state = LiveRefreshState()
@ -47,9 +47,7 @@ class LiveRefreshState:
async def _init_step(
s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain
):
await paths.validate_path(
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
if not storage.cache.get(storage.cache.APP_MONERO_LIVE_REFRESH):
await confirms.require_confirm_live_refresh(ctx)

@ -1,5 +1,3 @@
from apps.common import HARDENED
if False:
from typing import Tuple
from apps.monero.xmr.types import Sc25519
@ -18,22 +16,6 @@ def get_creds(keychain, address_n=None, network_type=None):
return creds
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/128'/a',
where `a` is an account index from 0 to 1 000 000.
"""
if len(path) != 3:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 128 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
return True
def compute_tx_key(
spend_key_private: Sc25519,
tx_prefix_hash: bytes,

@ -3,12 +3,11 @@ import gc
from trezor import log, utils, wire
from trezor.messages import MessageType
from apps.common.keychain import with_slip44_keychain
from apps.monero import CURVE, SLIP44_ID
from apps.common.keychain import auto_keychain
from apps.monero.signing.state import State
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_tx(ctx, received_msg, keychain):
state = State(ctx)
mods = utils.unimport_begin()

@ -4,7 +4,7 @@ Initializes a new transaction.
import gc
from apps.monero import CURVE, misc, signing
from apps.monero import misc, signing
from apps.monero.layout import confirms
from apps.monero.signing.state import State
from apps.monero.xmr import crypto, monero
@ -31,9 +31,7 @@ async def init_transaction(
from apps.monero.signing import offloading_keys
from apps.common import paths
await paths.validate_path(
state.ctx, misc.validate_full_path, keychain, address_n, CURVE
)
await paths.validate_path(state.ctx, keychain, address_n)
state.creds = misc.get_creds(keychain, address_n, network_type)
state.client_version = tsx_data.client_version or 0

@ -1,9 +1,16 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519-keccak"
SLIP44_ID = 43
PATTERNS = (
PATTERN_SEP5,
"m/44'/coin_type'/account'/0'/0'", # NanoWallet compatibility
)
def boot() -> None:
wire.add(MessageType.NEMGetAddress, __name__, "get_address")

@ -4,16 +4,16 @@ from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from apps.common.paths import validate_path
from . import CURVE, SLIP44_ID
from . import CURVE, PATTERNS, SLIP44_ID
from .helpers import check_path, get_network_str
from .validators import validate_network
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def get_address(ctx, msg, keychain):
network = validate_network(msg.network)
await validate_path(
ctx, check_path, keychain, msg.address_n, CURVE, network=network
ctx, keychain, msg.address_n, check_path(msg.address_n, msg.network)
)
node = keychain.derive(msg.address_n)

@ -1,6 +1,8 @@
from micropython import const
from apps.common import HARDENED
from apps.common import HARDENED, paths
from . import SLIP44_ID
NEM_NETWORK_MAINNET = const(0x68)
NEM_NETWORK_TESTNET = const(0x98)
@ -38,26 +40,18 @@ def get_network_str(network: int) -> str:
return "Mijin"
def check_path(path: list, network=None) -> bool:
"""
Validates derivation path to fit 44'/43'/a' or 44'/43'/a'/0'/0',
where `a` is an account number. We believe the path should be
44'/43'/a', but for compatibility reasons with NEM's NanoWallet
we allow 44'/43'/a'/0'/0' as well.
Testnet is also allowed: 44'/1'/a'{/0'/0'}
"""
length = len(path)
if length != 3 and length != 5:
return False
if path[0] != 44 | HARDENED:
return False
if not (
path[1] == 43 | HARDENED
or (network == NEM_NETWORK_TESTNET and path[1] == 1 | HARDENED)
):
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
if length == 5 and (path[3] != 0 | HARDENED or path[4] != 0 | HARDENED):
def check_path(path: paths.Bip32Path, network: int) -> bool:
"""Validates that the appropriate coin_type is set for the given network."""
if len(path) < 2:
return False
return True
coin_type = path[1] - HARDENED
if network == NEM_NETWORK_TESTNET:
return coin_type == 1
if network in (NEM_NETWORK_MAINNET, NEM_NETWORK_MIJIN):
return coin_type == SLIP44_ID
# unknown network
return False

@ -7,22 +7,20 @@ from apps.common import seed
from apps.common.keychain import with_slip44_keychain
from apps.common.paths import validate_path
from . import CURVE, SLIP44_ID, mosaic, multisig, namespace, transfer
from . import CURVE, PATTERNS, SLIP44_ID, mosaic, multisig, namespace, transfer
from .helpers import NEM_HASH_ALG, check_path
from .validators import validate
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def sign_tx(ctx, msg: NEMSignTx, keychain):
validate(msg)
await validate_path(
ctx,
check_path,
keychain,
msg.transaction.address_n,
CURVE,
network=msg.transaction.network,
check_path(msg.transaction.address_n, msg.transaction.network),
)
node = keychain.derive(msg.transaction.address_n)

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_BIP44
CURVE = "secp256k1"
SLIP44_ID = 144
PATTERN = PATTERN_BIP44
def boot() -> None:

@ -2,21 +2,19 @@ from trezor.messages.RippleAddress import RippleAddress
from trezor.messages.RippleGetAddress import RippleGetAddress
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, SLIP44_ID, helpers
from .helpers import address_from_public_key
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_address(ctx, msg: RippleGetAddress, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = node.public_key()
address = helpers.address_from_public_key(pubkey)
address = address_from_public_key(pubkey)
if msg.show_display:
desc = address_n_to_str(msg.address_n)

@ -2,8 +2,6 @@ from micropython import const
from trezor.crypto.hashlib import ripemd160, sha256
from apps.common import HARDENED
from . import base58_ripple
# HASH_TX_ID = const(0x54584E00) # 'TXN'
@ -50,25 +48,3 @@ def decode_address(address: str):
"""Returns so called Account ID"""
adr = base58_ripple.decode_check(address)
return adr[1:]
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/144'/a'/0/0,
where `a` is an account index from 0 to 1 000 000.
Similar to Ethereum this should be 44'/144'/a', but for
compatibility with other HW vendors we use 44'/144'/a'/0/0.
"""
if len(path) != 5:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 144 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
if path[3] != 0:
return False
if path[4] != 0:
return False
return True

@ -6,19 +6,16 @@ from trezor.messages.RippleSignTx import RippleSignTx
from trezor.wire import ProcessError
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from . import CURVE, SLIP44_ID, helpers, layout
from . import helpers, layout
from .serialize import serialize
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_tx(ctx, msg: RippleSignTx, keychain):
validate(msg)
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
source_address = helpers.address_from_public_key(node.public_key())

@ -1,8 +1,11 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519"
SLIP44_ID = 148
PATTERN = PATTERN_SEP5
def boot() -> None:

@ -2,17 +2,15 @@ from trezor.messages.StellarAddress import StellarAddress
from trezor.messages.StellarGetAddress import StellarGetAddress
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, SLIP44_ID, helpers
from . import helpers
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def get_address(ctx, msg: StellarGetAddress, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = seed.remove_ed25519_prefix(node.public_key())

@ -3,8 +3,6 @@ import ustruct
from trezor.crypto import base32
from trezor.wire import ProcessError
from apps.common import HARDENED
def public_key_from_address(address: str) -> bytes:
"""Extracts public key from an address
@ -26,22 +24,6 @@ def address_from_public_key(pubkey: bytes):
return base32.encode(address)
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/148'/a',
where `a` is an account index from 0 to 1 000 000.
"""
if len(path) != 3:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 148 | HARDENED:
return False
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
return True
def _crc16_checksum_verify(data: bytes, checksum: bytes):
if _crc16_checksum(data) != checksum:
raise ProcessError("Invalid address checksum")

@ -8,17 +8,15 @@ from trezor.messages.StellarTxOpRequest import StellarTxOpRequest
from trezor.wire import ProcessError
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from apps.common.keychain import auto_keychain
from . import CURVE, SLIP44_ID, consts, helpers, layout, writers
from . import consts, helpers, layout, writers
from .operations import process_operation
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@auto_keychain(__name__)
async def sign_tx(ctx, msg: StellarSignTx, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pubkey = seed.remove_ed25519_prefix(node.public_key())

@ -1,8 +1,14 @@
from trezor import wire
from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519"
SLIP44_ID = 1729
PATTERNS = (
PATTERN_SEP5,
"m/44'/coin_type'/0'/account'", # Ledger compatibility
)
def boot() -> None:

@ -5,14 +5,12 @@ from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, SLIP44_ID, helpers
from . import CURVE, PATTERNS, SLIP44_ID, helpers
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def get_address(ctx, msg, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)

@ -8,14 +8,12 @@ from apps.common import paths, seed
from apps.common.confirm import require_confirm
from apps.common.keychain import with_slip44_keychain
from . import CURVE, SLIP44_ID, helpers
from . import CURVE, PATTERNS, SLIP44_ID, helpers
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def get_public_key(ctx, msg, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pk = seed.remove_ed25519_prefix(node.public_key())

@ -2,7 +2,6 @@ from micropython import const
from trezor.crypto import base58
from apps.common import HARDENED
from apps.common.writers import write_bytes_unchecked, write_uint8
TEZOS_AMOUNT_DECIMALS = const(6)
@ -66,31 +65,6 @@ def base58_decode_check(enc, prefix=None):
return decoded
def validate_full_path(path: list) -> bool:
"""
Validates derivation path to equal 44'/1729'/a',
where `a` is an account index from 0 to 1 000 000.
Additional component added to allow ledger migration
44'/1729'/0'/b' where `b` is an account index from 0 to 1 000 000
"""
length = len(path)
if length < 3 or length > 4:
return False
if path[0] != 44 | HARDENED:
return False
if path[1] != 1729 | HARDENED:
return False
if length == 3:
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
return False
if length == 4:
if path[2] != 0 | HARDENED:
return False
if path[3] < HARDENED or path[3] > 1000000 | HARDENED:
return False
return True
def write_bool(w: bytearray, boolean: bool):
if boolean:
write_uint8(w, 255)

@ -10,16 +10,14 @@ from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.writers import write_bytes_unchecked, write_uint8, write_uint32_be
from . import CURVE, SLIP44_ID, helpers, layout
from . import CURVE, PATTERNS, SLIP44_ID, helpers, layout
PROPOSAL_LENGTH = const(32)
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def sign_tx(ctx, msg, keychain):
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)

Loading…
Cancel
Save