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 import wire
from trezor.messages import MessageType from trezor.messages import MessageType
from apps.common.paths import PATTERN_BIP44
CURVE = "secp256k1" CURVE = "secp256k1"
SLIP44_ID = 714 SLIP44_ID = 714
PATTERN = PATTERN_BIP44
def boot() -> None: def boot() -> None:

@ -2,23 +2,21 @@ from trezor.messages.BinanceAddress import BinanceAddress
from trezor.messages.BinanceGetAddress import BinanceGetAddress from trezor.messages.BinanceGetAddress import BinanceGetAddress
from apps.common import paths 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 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): async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
HRP = "bnb" HRP = "bnb"
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
pubkey = node.public_key() pubkey = node.public_key()
address = helpers.address_from_public_key(pubkey, HRP) address = address_from_public_key(pubkey, HRP)
if msg.show_display: if msg.show_display:
desc = address_n_to_str(msg.address_n) desc = address_n_to_str(msg.address_n)
while True: while True:

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

@ -8,8 +8,6 @@ from trezor.messages.BinanceOrderMsg import BinanceOrderMsg
from trezor.messages.BinanceSignTx import BinanceSignTx from trezor.messages.BinanceSignTx import BinanceSignTx
from trezor.messages.BinanceTransferMsg import BinanceTransferMsg 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}"}}' 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_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}}}' 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) convertedbits = bech32.convertbits(h, 8, 5, False)
return bech32.bech32_encode(hrp, convertedbits) 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 trezor.messages.BinanceTxRequest import BinanceTxRequest
from apps.common import paths 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): async def sign_tx(ctx, envelope, keychain: Keychain):
# create transaction message -> sign it -> create signature/pubkey message -> serialize all # create transaction message -> sign it -> create signature/pubkey message -> serialize all
if envelope.msg_count > 1: if envelope.msg_count > 1:
raise wire.DataError("Multiple messages not supported.") 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) node = keychain.derive(envelope.address_n)
tx_req = BinanceTxRequest() tx_req = BinanceTxRequest()

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

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

@ -2,8 +2,6 @@ from trezor import wire
from trezor.crypto import base58 from trezor.crypto import base58
from trezor.messages.EosAsset import EosAsset from trezor.messages.EosAsset import EosAsset
from apps.common import HARDENED
def base58_encode(prefix: str, sig_prefix: str, data: bytes) -> str: def base58_encode(prefix: str, sig_prefix: str, data: bytes) -> str:
b58 = base58.encode(data + base58.ripemd160_32(data + sig_prefix.encode())) 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) 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: def public_key_to_wif(pub_key: bytes) -> str:
if pub_key[0] == 0x04 and len(pub_key) == 65: if pub_key[0] == 0x04 and len(pub_key) == 65:
head = b"\x03" if pub_key[64] & 0x01 else b"\x02" 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 trezor.utils import HashWriter
from apps.common import paths 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 .actions import process_action
from .helpers import base58_encode, validate_full_path from .helpers import base58_encode
from .layout import require_sign_tx 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: async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx:
if msg.chain_id is None: if msg.chain_id is None:
raise wire.DataError("No chain id") 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: if msg.num_actions is None or msg.num_actions == 0:
raise wire.DataError("No actions") 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) node = keychain.derive(msg.address_n)
sha = HashWriter(sha256()) sha = HashWriter(sha256())

@ -2,59 +2,6 @@ from ubinascii import unhexlify
from trezor import wire 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: 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 import paths
from apps.common.layout import address_n_to_str, show_address, show_qr from apps.common.layout import address_n_to_str, show_address, show_qr
from . import CURVE, networks from . import networks
from .address import address_from_bytes, validate_full_path from .address import address_from_bytes
from .keychain import with_keychain_from_path 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): 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) node = keychain.derive(msg.address_n)
seckey = node.private_key() seckey = node.private_key()

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

@ -1,12 +1,12 @@
from trezor import wire from trezor import wire
from apps.common import HARDENED, seed from apps.common import HARDENED, paths
from apps.common.keychain import get_keychain from apps.common.keychain import get_keychain
from . import CURVE, networks from . import CURVE, networks
if False: if False:
from typing import List from typing import Callable
from typing_extensions import Protocol from typing_extensions import Protocol
from protobuf import MessageType from protobuf import MessageType
@ -16,48 +16,76 @@ if False:
from apps.common.keychain import MsgOut, Handler, HandlerWithKeychain from apps.common.keychain import MsgOut, Handler, HandlerWithKeychain
class MsgWithAddressN(MessageType, Protocol): 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: if len(address_n) < 2:
raise wire.DataError("Forbidden key path") return paths.SCHEMA_NO_MATCH
slip44_hardened = address_n[1] slip44_hardened = address_n[1]
if slip44_hardened not in networks.all_slip44_ids_hardened(): if slip44_hardened not in networks.all_slip44_ids_hardened():
raise wire.DataError("Forbidden key path") return paths.SCHEMA_NO_MATCH
namespace = [44 | HARDENED, slip44_hardened]
return await get_keychain(ctx, CURVE, [namespace]) 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( def with_keychain_from_path(
func: HandlerWithKeychain[MsgWithAddressN, MsgOut] pattern: str,
) -> Handler[MsgWithAddressN, MsgOut]: ) -> Callable[
async def wrapper(ctx: wire.Context, msg: MsgWithAddressN) -> MsgOut: [HandlerWithKeychain[MsgWithAddressN, MsgOut]], Handler[MsgWithAddressN, MsgOut]
keychain = await from_address_n(ctx, msg.address_n) ]:
with keychain: def decorator(
return await func(ctx, msg, keychain) 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( def with_keychain_from_chain_id(
func: HandlerWithKeychain[EthereumSignTx, MsgOut] func: HandlerWithKeychain[EthereumSignTx, MsgOut]
) -> Handler[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: async def wrapper(ctx: wire.Context, msg: EthereumSignTx) -> MsgOut:
if msg.chain_id is None: schema = _schema_from_chain_id(msg)
keychain = await from_address_n(ctx, msg.address_n) keychain = await get_keychain(ctx, CURVE, [schema])
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])
with keychain: with keychain:
return await func(ctx, msg, keychain) return await func(ctx, msg, keychain)

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

@ -9,8 +9,7 @@ from trezor.utils import HashWriter
from apps.common import paths from apps.common import paths
from . import CURVE, address, tokens from . import address, tokens
from .address import validate_full_path
from .keychain import with_keychain_from_chain_id from .keychain import with_keychain_from_chain_id
from .layout import require_confirm_data, require_confirm_fee, require_confirm_tx 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): async def sign_tx(ctx, msg, keychain):
msg = sanitize(msg) msg = sanitize(msg)
check(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 data_total = msg.data_length

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

@ -1,16 +1,15 @@
from trezor.messages.LiskAddress import LiskAddress from trezor.messages.LiskAddress import LiskAddress
from apps.common import paths 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 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
from .helpers import get_address_from_public_key, validate_full_path
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True) @auto_keychain(__name__)
async def get_address(ctx, msg, keychain): 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) node = keychain.derive(msg.address_n)
pubkey = node.public_key() pubkey = node.public_key()

@ -1,15 +1,12 @@
from trezor.messages.LiskPublicKey import LiskPublicKey from trezor.messages.LiskPublicKey import LiskPublicKey
from apps.common import layout, paths 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
@auto_keychain(__name__)
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True)
async def get_public_key(ctx, msg, keychain): 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) node = keychain.derive(msg.address_n)
pubkey = node.public_key() pubkey = node.public_key()

@ -1,7 +1,5 @@
from trezor.crypto.hashlib import sha256 from trezor.crypto.hashlib import sha256
from apps.common import HARDENED
def get_address_from_public_key(pubkey): def get_address_from_public_key(pubkey):
pubkeyhash = sha256(pubkey).digest() pubkeyhash = sha256(pubkey).digest()
@ -31,19 +29,3 @@ def get_vote_tx_text(votes):
def _text_with_plural(txt, value): def _text_with_plural(txt, value):
return "%s %s %s" % (txt, value, ("votes" if value != 1 else "vote")) 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 trezor.utils import HashWriter
from apps.common import paths 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.signverify import require_confirm_sign_message
from apps.common.writers import write_bitcoin_varint from apps.common.writers import write_bitcoin_varint
from . import CURVE, SLIP44_ID
from .helpers import validate_full_path
def message_digest(message): def message_digest(message):
h = HashWriter(sha256()) h = HashWriter(sha256())
@ -22,9 +19,9 @@ def message_digest(message):
return sha256(h.get_digest()).digest() 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): 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) await require_confirm_sign_message(ctx, "Lisk", msg.message)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)

@ -8,15 +8,15 @@ from trezor.messages.LiskSignedTx import LiskSignedTx
from trezor.utils import HashWriter from trezor.utils import HashWriter
from apps.common import paths 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 . import layout
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 sign_tx(ctx, msg, keychain): 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) pubkey, seckey = _get_keys(keychain, msg)
transaction = _update_raw_tx(msg.transaction, pubkey) 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.confirm import require_confirm
from apps.common.keychain import get_keychain from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
async def cipher_key_value(ctx, msg): 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: if len(msg.value) % 16 > 0:
raise wire.DataError("Value length must be a multiple of 16") 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 import HARDENED
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from .sign_identity import serialize_identity, serialize_identity_without_proto 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: if msg.ecdsa_curve_name is None:
msg.ecdsa_curve_name = "secp256k1" 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) identity = serialize_identity(msg.identity)
await require_confirm_ecdh_session_key(ctx, 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 import HARDENED, coins
from apps.common.confirm import require_confirm from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
async def sign_identity(ctx, msg): async def sign_identity(ctx, msg):
if msg.ecdsa_curve_name is None: if msg.ecdsa_curve_name is None:
msg.ecdsa_curve_name = "secp256k1" 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) identity = serialize_identity(msg.identity)
await require_confirm_sign_identity(ctx, msg.identity, msg.challenge_visual) await require_confirm_sign_identity(ctx, msg.identity, msg.challenge_visual)

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

@ -1,19 +1,17 @@
from trezor.messages.MoneroAddress import MoneroAddress from trezor.messages.MoneroAddress import MoneroAddress
from apps.common import paths 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.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.layout import confirms
from apps.monero.xmr import addresses, crypto, monero from apps.monero.xmr import addresses, crypto, monero
from apps.monero.xmr.networks import net_version 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): async def get_address(ctx, msg, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
creds = misc.get_creds(keychain, msg.address_n, msg.network_type) creds = misc.get_creds(keychain, msg.address_n, msg.network_type)
addr = creds.address addr = creds.address

@ -20,8 +20,8 @@ from trezor.messages.MoneroGetTxKeyAck import MoneroGetTxKeyAck
from trezor.messages.MoneroGetTxKeyRequest import MoneroGetTxKeyRequest from trezor.messages.MoneroGetTxKeyRequest import MoneroGetTxKeyRequest
from apps.common import paths from apps.common import paths
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import auto_keychain
from apps.monero import CURVE, SLIP44_ID, misc from apps.monero import misc
from apps.monero.layout import confirms from apps.monero.layout import confirms
from apps.monero.xmr import crypto from apps.monero.xmr import crypto
from apps.monero.xmr.crypto import chacha_poly 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 _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): async def get_tx_keys(ctx, msg: MoneroGetTxKeyRequest, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
do_deriv = msg.reason == _GET_TX_KEY_REASON_TX_DERIVATION do_deriv = msg.reason == _GET_TX_KEY_REASON_TX_DERIVATION
await confirms.require_confirm_tx_key(ctx, export_key=not do_deriv) 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 trezor.messages.MoneroWatchKey import MoneroWatchKey
from apps.common import paths from apps.common import paths
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import auto_keychain
from apps.monero import CURVE, SLIP44_ID, misc from apps.monero import misc
from apps.monero.layout import confirms from apps.monero.layout import confirms
from apps.monero.xmr import crypto 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): async def get_watch_only(ctx, msg: MoneroGetWatchKey, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
await confirms.require_confirm_watchkey(ctx) await confirms.require_confirm_watchkey(ctx)

@ -11,14 +11,14 @@ from trezor.messages.MoneroKeyImageSyncStepAck import MoneroKeyImageSyncStepAck
from trezor.messages.MoneroKeyImageSyncStepRequest import MoneroKeyImageSyncStepRequest from trezor.messages.MoneroKeyImageSyncStepRequest import MoneroKeyImageSyncStepRequest
from apps.common import paths from apps.common import paths
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import auto_keychain
from apps.monero import CURVE, SLIP44_ID, misc from apps.monero import misc
from apps.monero.layout import confirms from apps.monero.layout import confirms
from apps.monero.xmr import crypto, key_image, monero from apps.monero.xmr import crypto, key_image, monero
from apps.monero.xmr.crypto import chacha_poly 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): async def key_image_sync(ctx, msg, keychain):
state = KeyImageSync() state = KeyImageSync()
@ -45,9 +45,7 @@ class KeyImageSync:
async def _init_step(s, ctx, msg, keychain): async def _init_step(s, ctx, msg, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
s.creds = misc.get_creds(keychain, msg.address_n, msg.network_type) 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 trezor.messages.MoneroLiveRefreshStepRequest import MoneroLiveRefreshStepRequest
from apps.common import paths from apps.common import paths
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import auto_keychain
from apps.monero import CURVE, SLIP44_ID, misc from apps.monero import misc
from apps.monero.layout import confirms from apps.monero.layout import confirms
from apps.monero.xmr import crypto, key_image, monero from apps.monero.xmr import crypto, key_image, monero
from apps.monero.xmr.crypto import chacha_poly 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): async def live_refresh(ctx, msg: MoneroLiveRefreshStartRequest, keychain):
state = LiveRefreshState() state = LiveRefreshState()
@ -47,9 +47,7 @@ class LiveRefreshState:
async def _init_step( async def _init_step(
s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain s: LiveRefreshState, ctx, msg: MoneroLiveRefreshStartRequest, keychain
): ):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, misc.validate_full_path, keychain, msg.address_n, CURVE
)
if not storage.cache.get(storage.cache.APP_MONERO_LIVE_REFRESH): if not storage.cache.get(storage.cache.APP_MONERO_LIVE_REFRESH):
await confirms.require_confirm_live_refresh(ctx) await confirms.require_confirm_live_refresh(ctx)

@ -1,5 +1,3 @@
from apps.common import HARDENED
if False: if False:
from typing import Tuple from typing import Tuple
from apps.monero.xmr.types import Sc25519 from apps.monero.xmr.types import Sc25519
@ -18,22 +16,6 @@ def get_creds(keychain, address_n=None, network_type=None):
return creds 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( def compute_tx_key(
spend_key_private: Sc25519, spend_key_private: Sc25519,
tx_prefix_hash: bytes, tx_prefix_hash: bytes,

@ -3,12 +3,11 @@ import gc
from trezor import log, utils, wire from trezor import log, utils, wire
from trezor.messages import MessageType from trezor.messages import MessageType
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import auto_keychain
from apps.monero import CURVE, SLIP44_ID
from apps.monero.signing.state import State 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): async def sign_tx(ctx, received_msg, keychain):
state = State(ctx) state = State(ctx)
mods = utils.unimport_begin() mods = utils.unimport_begin()

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

@ -1,9 +1,16 @@
from trezor import wire from trezor import wire
from trezor.messages import MessageType from trezor.messages import MessageType
from apps.common.paths import PATTERN_SEP5
CURVE = "ed25519-keccak" CURVE = "ed25519-keccak"
SLIP44_ID = 43 SLIP44_ID = 43
PATTERNS = (
PATTERN_SEP5,
"m/44'/coin_type'/account'/0'/0'", # NanoWallet compatibility
)
def boot() -> None: def boot() -> None:
wire.add(MessageType.NEMGetAddress, __name__, "get_address") 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.layout import address_n_to_str, show_address, show_qr
from apps.common.paths import validate_path 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 .helpers import check_path, get_network_str
from .validators import validate_network 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): async def get_address(ctx, msg, keychain):
network = validate_network(msg.network) network = validate_network(msg.network)
await validate_path( 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) node = keychain.derive(msg.address_n)

@ -1,6 +1,8 @@
from micropython import const 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_MAINNET = const(0x68)
NEM_NETWORK_TESTNET = const(0x98) NEM_NETWORK_TESTNET = const(0x98)
@ -38,26 +40,18 @@ def get_network_str(network: int) -> str:
return "Mijin" return "Mijin"
def check_path(path: list, network=None) -> bool: def check_path(path: paths.Bip32Path, network: int) -> bool:
""" """Validates that the appropriate coin_type is set for the given network."""
Validates derivation path to fit 44'/43'/a' or 44'/43'/a'/0'/0', if len(path) < 2:
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):
return False 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.keychain import with_slip44_keychain
from apps.common.paths import validate_path 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 .helpers import NEM_HASH_ALG, check_path
from .validators import validate 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): async def sign_tx(ctx, msg: NEMSignTx, keychain):
validate(msg) validate(msg)
await validate_path( await validate_path(
ctx, ctx,
check_path,
keychain, keychain,
msg.transaction.address_n, msg.transaction.address_n,
CURVE, check_path(msg.transaction.address_n, msg.transaction.network),
network=msg.transaction.network,
) )
node = keychain.derive(msg.transaction.address_n) node = keychain.derive(msg.transaction.address_n)

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

@ -2,21 +2,19 @@ from trezor.messages.RippleAddress import RippleAddress
from trezor.messages.RippleGetAddress import RippleGetAddress from trezor.messages.RippleGetAddress import RippleGetAddress
from apps.common import paths 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 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): async def get_address(ctx, msg: RippleGetAddress, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
pubkey = node.public_key() pubkey = node.public_key()
address = helpers.address_from_public_key(pubkey) address = address_from_public_key(pubkey)
if msg.show_display: if msg.show_display:
desc = address_n_to_str(msg.address_n) desc = address_n_to_str(msg.address_n)

@ -2,8 +2,6 @@ from micropython import const
from trezor.crypto.hashlib import ripemd160, sha256 from trezor.crypto.hashlib import ripemd160, sha256
from apps.common import HARDENED
from . import base58_ripple from . import base58_ripple
# HASH_TX_ID = const(0x54584E00) # 'TXN' # HASH_TX_ID = const(0x54584E00) # 'TXN'
@ -50,25 +48,3 @@ def decode_address(address: str):
"""Returns so called Account ID""" """Returns so called Account ID"""
adr = base58_ripple.decode_check(address) adr = base58_ripple.decode_check(address)
return adr[1:] 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 trezor.wire import ProcessError
from apps.common import paths 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 from .serialize import serialize
@with_slip44_keychain(SLIP44_ID, CURVE, allow_testnet=True) @auto_keychain(__name__)
async def sign_tx(ctx, msg: RippleSignTx, keychain): async def sign_tx(ctx, msg: RippleSignTx, keychain):
validate(msg) validate(msg)
await paths.validate_path(ctx, keychain, msg.address_n)
await paths.validate_path(
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
source_address = helpers.address_from_public_key(node.public_key()) source_address = helpers.address_from_public_key(node.public_key())

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

@ -2,17 +2,15 @@ from trezor.messages.StellarAddress import StellarAddress
from trezor.messages.StellarGetAddress import StellarGetAddress from trezor.messages.StellarGetAddress import StellarGetAddress
from apps.common import paths, seed 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 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): async def get_address(ctx, msg: StellarGetAddress, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
pubkey = seed.remove_ed25519_prefix(node.public_key()) pubkey = seed.remove_ed25519_prefix(node.public_key())

@ -3,8 +3,6 @@ import ustruct
from trezor.crypto import base32 from trezor.crypto import base32
from trezor.wire import ProcessError from trezor.wire import ProcessError
from apps.common import HARDENED
def public_key_from_address(address: str) -> bytes: def public_key_from_address(address: str) -> bytes:
"""Extracts public key from an address """Extracts public key from an address
@ -26,22 +24,6 @@ def address_from_public_key(pubkey: bytes):
return base32.encode(address) 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): def _crc16_checksum_verify(data: bytes, checksum: bytes):
if _crc16_checksum(data) != checksum: if _crc16_checksum(data) != checksum:
raise ProcessError("Invalid address checksum") raise ProcessError("Invalid address checksum")

@ -8,17 +8,15 @@ from trezor.messages.StellarTxOpRequest import StellarTxOpRequest
from trezor.wire import ProcessError from trezor.wire import ProcessError
from apps.common import paths, seed 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 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): async def sign_tx(ctx, msg: StellarSignTx, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
pubkey = seed.remove_ed25519_prefix(node.public_key()) pubkey = seed.remove_ed25519_prefix(node.public_key())

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

@ -5,14 +5,12 @@ from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import with_slip44_keychain
from apps.common.layout import address_n_to_str, show_address, show_qr 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): async def get_address(ctx, msg, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(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.confirm import require_confirm
from apps.common.keychain import with_slip44_keychain 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): async def get_public_key(ctx, msg, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)
pk = seed.remove_ed25519_prefix(node.public_key()) pk = seed.remove_ed25519_prefix(node.public_key())

@ -2,7 +2,6 @@ from micropython import const
from trezor.crypto import base58 from trezor.crypto import base58
from apps.common import HARDENED
from apps.common.writers import write_bytes_unchecked, write_uint8 from apps.common.writers import write_bytes_unchecked, write_uint8
TEZOS_AMOUNT_DECIMALS = const(6) TEZOS_AMOUNT_DECIMALS = const(6)
@ -66,31 +65,6 @@ def base58_decode_check(enc, prefix=None):
return decoded 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): def write_bool(w: bytearray, boolean: bool):
if boolean: if boolean:
write_uint8(w, 255) write_uint8(w, 255)

@ -10,16 +10,14 @@ from apps.common import paths
from apps.common.keychain import with_slip44_keychain from apps.common.keychain import with_slip44_keychain
from apps.common.writers import write_bytes_unchecked, write_uint8, write_uint32_be 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) 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): async def sign_tx(ctx, msg, keychain):
await paths.validate_path( await paths.validate_path(ctx, keychain, msg.address_n)
ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE
)
node = keychain.derive(msg.address_n) node = keychain.derive(msg.address_n)

Loading…
Cancel
Save