mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-22 13:21:03 +00:00
apps: introduce Keychain API
This commit is contained in:
parent
312c252bc1
commit
5bc47fc567
@ -1,8 +1,27 @@
|
|||||||
from trezor.crypto import base58, crc, hashlib
|
from trezor.crypto import base58, crc, hashlib
|
||||||
|
|
||||||
from . import cbor
|
from apps.cardano import cbor
|
||||||
|
from apps.common import HARDENED
|
||||||
|
from apps.common.seed import remove_ed25519_prefix
|
||||||
|
|
||||||
from apps.common import HARDENED, seed
|
|
||||||
|
def derive_address_and_node(keychain, path: list):
|
||||||
|
node = keychain.derive(path)
|
||||||
|
|
||||||
|
address_payload = None
|
||||||
|
address_attributes = {}
|
||||||
|
|
||||||
|
address_root = _get_address_root(node, address_payload)
|
||||||
|
address_type = 0
|
||||||
|
address_data = [address_root, address_attributes, address_type]
|
||||||
|
address_data_encoded = cbor.encode(address_data)
|
||||||
|
|
||||||
|
address = base58.encode(
|
||||||
|
cbor.encode(
|
||||||
|
[cbor.Tagged(24, address_data_encoded), crc.crc32(address_data_encoded)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return (address, node)
|
||||||
|
|
||||||
|
|
||||||
def validate_full_path(path: list) -> bool:
|
def validate_full_path(path: list) -> bool:
|
||||||
@ -36,31 +55,9 @@ def _address_hash(data) -> bytes:
|
|||||||
|
|
||||||
|
|
||||||
def _get_address_root(node, payload):
|
def _get_address_root(node, payload):
|
||||||
extpubkey = seed.remove_ed25519_prefix(node.public_key()) + node.chain_code()
|
extpubkey = remove_ed25519_prefix(node.public_key()) + node.chain_code()
|
||||||
if payload:
|
if payload:
|
||||||
payload = {1: cbor.encode(payload)}
|
payload = {1: cbor.encode(payload)}
|
||||||
else:
|
else:
|
||||||
payload = {}
|
payload = {}
|
||||||
return _address_hash([0, [0, extpubkey], payload])
|
return _address_hash([0, [0, extpubkey], payload])
|
||||||
|
|
||||||
|
|
||||||
def derive_address_and_node(root_node, path: list):
|
|
||||||
derived_node = root_node.clone()
|
|
||||||
|
|
||||||
address_payload = None
|
|
||||||
address_attributes = {}
|
|
||||||
|
|
||||||
for indice in path:
|
|
||||||
derived_node.derive_cardano(indice)
|
|
||||||
|
|
||||||
address_root = _get_address_root(derived_node, address_payload)
|
|
||||||
address_type = 0
|
|
||||||
address_data = [address_root, address_attributes, address_type]
|
|
||||||
address_data_encoded = cbor.encode(address_data)
|
|
||||||
|
|
||||||
address = base58.encode(
|
|
||||||
cbor.encode(
|
|
||||||
[cbor.Tagged(24, address_data_encoded), crc.crc32(address_data_encoded)]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return (address, derived_node)
|
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
from trezor import log, ui, wire
|
from trezor import log, ui, wire
|
||||||
from trezor.crypto import bip32
|
|
||||||
from trezor.messages.CardanoAddress import CardanoAddress
|
from trezor.messages.CardanoAddress import CardanoAddress
|
||||||
|
|
||||||
from .address import derive_address_and_node, validate_full_path
|
from apps.cardano import seed
|
||||||
from .layout import confirm_with_pagination
|
from apps.cardano.address import derive_address_and_node, validate_full_path
|
||||||
|
from apps.cardano.layout import confirm_with_pagination
|
||||||
from apps.common import paths, seed, storage
|
from apps.common import paths
|
||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
mnemonic = storage.get_mnemonic()
|
|
||||||
passphrase = await seed._get_cached_passphrase(ctx)
|
|
||||||
root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
address, _ = derive_address_and_node(root_node, msg.address_n)
|
address, _ = derive_address_and_node(keychain, msg.address_n)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
if __debug__:
|
if __debug__:
|
||||||
log.exception(__name__, e)
|
log.exception(__name__, e)
|
||||||
raise wire.ProcessError("Deriving address failed")
|
raise wire.ProcessError("Deriving address failed")
|
||||||
mnemonic = None
|
|
||||||
root_node = None
|
|
||||||
|
|
||||||
if msg.show_display:
|
if msg.show_display:
|
||||||
if not await confirm_with_pagination(
|
if not await confirm_with_pagination(
|
||||||
|
@ -1,42 +1,38 @@
|
|||||||
from ubinascii import hexlify
|
from ubinascii import hexlify
|
||||||
|
|
||||||
from trezor import log, wire
|
from trezor import log, wire
|
||||||
from trezor.crypto import bip32
|
|
||||||
from trezor.messages.CardanoPublicKey import CardanoPublicKey
|
from trezor.messages.CardanoPublicKey import CardanoPublicKey
|
||||||
from trezor.messages.HDNodeType import HDNodeType
|
from trezor.messages.HDNodeType import HDNodeType
|
||||||
|
|
||||||
from .address import derive_address_and_node
|
from apps.cardano import seed
|
||||||
|
from apps.cardano.address import derive_address_and_node
|
||||||
from apps.common import layout, paths, seed, storage
|
from apps.common import layout, paths
|
||||||
|
from apps.common.seed import remove_ed25519_prefix
|
||||||
|
|
||||||
|
|
||||||
async def get_public_key(ctx, msg):
|
async def get_public_key(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(
|
await paths.validate_path(
|
||||||
ctx, paths.validate_path_for_get_public_key, path=msg.address_n, slip44_id=1815
|
ctx, paths.validate_path_for_get_public_key, path=msg.address_n, slip44_id=1815
|
||||||
)
|
)
|
||||||
|
|
||||||
mnemonic = storage.get_mnemonic()
|
|
||||||
passphrase = await seed._get_cached_passphrase(ctx)
|
|
||||||
root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
key = _get_public_key(root_node, msg.address_n)
|
key = _get_public_key(keychain, msg.address_n)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
if __debug__:
|
if __debug__:
|
||||||
log.exception(__name__, e)
|
log.exception(__name__, e)
|
||||||
raise wire.ProcessError("Deriving public key failed")
|
raise wire.ProcessError("Deriving public key failed")
|
||||||
mnemonic = None
|
|
||||||
root_node = None
|
|
||||||
|
|
||||||
if msg.show_display:
|
if msg.show_display:
|
||||||
await layout.show_pubkey(ctx, key.node.public_key)
|
await layout.show_pubkey(ctx, key.node.public_key)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
def _get_public_key(root_node, derivation_path: list):
|
def _get_public_key(keychain, derivation_path: list):
|
||||||
_, node = derive_address_and_node(root_node, derivation_path)
|
_, node = derive_address_and_node(keychain, derivation_path)
|
||||||
|
|
||||||
public_key = hexlify(seed.remove_ed25519_prefix(node.public_key())).decode()
|
public_key = hexlify(remove_ed25519_prefix(node.public_key())).decode()
|
||||||
chain_code = hexlify(node.chain_code()).decode()
|
chain_code = hexlify(node.chain_code()).decode()
|
||||||
xpub_key = public_key + chain_code
|
xpub_key = public_key + chain_code
|
||||||
|
|
||||||
@ -45,7 +41,7 @@ def _get_public_key(root_node, derivation_path: list):
|
|||||||
child_num=node.child_num(),
|
child_num=node.child_num(),
|
||||||
fingerprint=node.fingerprint(),
|
fingerprint=node.fingerprint(),
|
||||||
chain_code=node.chain_code(),
|
chain_code=node.chain_code(),
|
||||||
public_key=seed.remove_ed25519_prefix(node.public_key()),
|
public_key=remove_ed25519_prefix(node.public_key()),
|
||||||
)
|
)
|
||||||
|
|
||||||
return CardanoPublicKey(node=node_type, xpub=xpub_key)
|
return CardanoPublicKey(node=node_type, xpub=xpub_key)
|
||||||
|
41
src/apps/cardano/seed.py
Normal file
41
src/apps/cardano/seed.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from trezor import wire
|
||||||
|
from trezor.crypto import bip32
|
||||||
|
|
||||||
|
from apps.common import HARDENED, cache, storage
|
||||||
|
from apps.common.request_passphrase import protect_by_passphrase
|
||||||
|
|
||||||
|
|
||||||
|
class Keychain:
|
||||||
|
def __init__(self, root: bip32.HDNode):
|
||||||
|
self.root = root
|
||||||
|
|
||||||
|
def derive(self, path: list) -> bip32.HDNode:
|
||||||
|
self.validate_path(path)
|
||||||
|
node = self.root.clone()
|
||||||
|
for i in path:
|
||||||
|
node.derive_cardano(i)
|
||||||
|
return node
|
||||||
|
|
||||||
|
def validate_path(self, path: list) -> None:
|
||||||
|
if len(path) < 2 or len(path) > 5:
|
||||||
|
raise wire.ProcessError("Derivation path must be composed from 2-5 indices")
|
||||||
|
if path[0] != HARDENED | 44 or path[1] != HARDENED | 1815:
|
||||||
|
raise wire.ProcessError("This is not cardano derivation path")
|
||||||
|
|
||||||
|
|
||||||
|
async def get_keychain(ctx: wire.Context) -> Keychain:
|
||||||
|
if not storage.is_initialized():
|
||||||
|
# device does not have any seed
|
||||||
|
raise wire.ProcessError("Device is not initialized")
|
||||||
|
|
||||||
|
# acquire passphrase
|
||||||
|
passphrase = cache.get_passphrase()
|
||||||
|
if passphrase is None:
|
||||||
|
passphrase = await protect_by_passphrase(ctx)
|
||||||
|
cache.set_passphrase(passphrase)
|
||||||
|
|
||||||
|
# compute the seed from mnemonic and passphrase
|
||||||
|
root = bip32.from_mnemonic_cardano(storage.get_mnemonic(), passphrase)
|
||||||
|
|
||||||
|
keychain = Keychain(root)
|
||||||
|
return keychain
|
@ -1,18 +1,17 @@
|
|||||||
from trezor import log, ui, wire
|
from trezor import log, ui, wire
|
||||||
from trezor.crypto import base58, bip32, hashlib
|
from trezor.crypto import base58, hashlib
|
||||||
from trezor.crypto.curve import ed25519
|
from trezor.crypto.curve import ed25519
|
||||||
from trezor.messages.CardanoSignedTx import CardanoSignedTx
|
from trezor.messages.CardanoSignedTx import CardanoSignedTx
|
||||||
from trezor.messages.CardanoTxRequest import CardanoTxRequest
|
from trezor.messages.CardanoTxRequest import CardanoTxRequest
|
||||||
from trezor.messages.MessageType import CardanoTxAck
|
from trezor.messages.MessageType import CardanoTxAck
|
||||||
from trezor.ui.text import BR
|
from trezor.ui.text import BR
|
||||||
|
|
||||||
from .address import derive_address_and_node, validate_full_path
|
from apps.cardano import cbor, seed
|
||||||
from .layout import confirm_with_pagination, progress
|
from apps.cardano.address import derive_address_and_node, validate_full_path
|
||||||
|
from apps.cardano.layout import confirm_with_pagination, progress
|
||||||
from apps.cardano import cbor
|
|
||||||
from apps.common import seed, storage
|
|
||||||
from apps.common.layout import address_n_to_str, split_address
|
from apps.common.layout import address_n_to_str, split_address
|
||||||
from apps.common.paths import validate_path
|
from apps.common.paths import validate_path
|
||||||
|
from apps.common.seed import remove_ed25519_prefix
|
||||||
from apps.homescreen.homescreen import display_homescreen
|
from apps.homescreen.homescreen import display_homescreen
|
||||||
|
|
||||||
|
|
||||||
@ -80,9 +79,7 @@ async def request_transaction(ctx, tx_req: CardanoTxRequest, index: int):
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg):
|
async def sign_tx(ctx, msg):
|
||||||
mnemonic = storage.get_mnemonic()
|
keychain = await seed.get_keychain(ctx)
|
||||||
passphrase = await seed._get_cached_passphrase(ctx)
|
|
||||||
root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase)
|
|
||||||
|
|
||||||
progress.init(msg.transactions_count, "Loading data")
|
progress.init(msg.transactions_count, "Loading data")
|
||||||
|
|
||||||
@ -103,7 +100,7 @@ async def sign_tx(ctx, msg):
|
|||||||
|
|
||||||
# sign the transaction bundle and prepare the result
|
# sign the transaction bundle and prepare the result
|
||||||
transaction = Transaction(
|
transaction = Transaction(
|
||||||
msg.inputs, msg.outputs, transactions, root_node, msg.network
|
msg.inputs, msg.outputs, transactions, keychain, msg.network
|
||||||
)
|
)
|
||||||
tx_body, tx_hash = transaction.serialise_tx()
|
tx_body, tx_hash = transaction.serialise_tx()
|
||||||
tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)
|
tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)
|
||||||
@ -135,12 +132,12 @@ def _micro_ada_to_ada(amount: float) -> float:
|
|||||||
|
|
||||||
class Transaction:
|
class Transaction:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, inputs: list, outputs: list, transactions: list, root_node, network: int
|
self, inputs: list, outputs: list, transactions: list, keychain, network: int
|
||||||
):
|
):
|
||||||
self.inputs = inputs
|
self.inputs = inputs
|
||||||
self.outputs = outputs
|
self.outputs = outputs
|
||||||
self.transactions = transactions
|
self.transactions = transactions
|
||||||
self.root_node = root_node
|
self.keychain = keychain
|
||||||
# attributes have to be always empty in current Cardano
|
# attributes have to be always empty in current Cardano
|
||||||
self.attributes = {}
|
self.attributes = {}
|
||||||
if network == 1:
|
if network == 1:
|
||||||
@ -170,7 +167,7 @@ class Transaction:
|
|||||||
|
|
||||||
nodes = []
|
nodes = []
|
||||||
for input in self.inputs:
|
for input in self.inputs:
|
||||||
_, node = derive_address_and_node(self.root_node, input.address_n)
|
_, node = derive_address_and_node(self.keychain, input.address_n)
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
|
|
||||||
for index, output_index in enumerate(output_indexes):
|
for index, output_index in enumerate(output_indexes):
|
||||||
@ -198,7 +195,7 @@ class Transaction:
|
|||||||
|
|
||||||
for output in self.outputs:
|
for output in self.outputs:
|
||||||
if output.address_n:
|
if output.address_n:
|
||||||
address, _ = derive_address_and_node(self.root_node, output.address_n)
|
address, _ = derive_address_and_node(self.keychain, output.address_n)
|
||||||
change_addresses.append(address)
|
change_addresses.append(address)
|
||||||
change_derivation_paths.append(output.address_n)
|
change_derivation_paths.append(output.address_n)
|
||||||
change_coins.append(output.amount)
|
change_coins.append(output.amount)
|
||||||
@ -225,7 +222,7 @@ class Transaction:
|
|||||||
node.private_key(), node.private_key_ext(), message
|
node.private_key(), node.private_key_ext(), message
|
||||||
)
|
)
|
||||||
extended_public_key = (
|
extended_public_key = (
|
||||||
seed.remove_ed25519_prefix(node.public_key()) + node.chain_code()
|
remove_ed25519_prefix(node.public_key()) + node.chain_code()
|
||||||
)
|
)
|
||||||
witnesses.append(
|
witnesses.append(
|
||||||
[
|
[
|
||||||
|
@ -7,38 +7,43 @@ from apps.common.request_passphrase import protect_by_passphrase
|
|||||||
_DEFAULT_CURVE = "secp256k1"
|
_DEFAULT_CURVE = "secp256k1"
|
||||||
|
|
||||||
|
|
||||||
async def derive_node(
|
class Keychain:
|
||||||
ctx: wire.Context, path: list, curve_name: str = _DEFAULT_CURVE
|
def __init__(self, seed: bytes):
|
||||||
) -> bip32.HDNode:
|
self.seed = seed
|
||||||
seed = await _get_cached_seed(ctx)
|
|
||||||
node = bip32.from_seed(seed, curve_name)
|
def derive(self, path: list, curve_name: str = _DEFAULT_CURVE) -> bip32.HDNode:
|
||||||
node.derive_path(path)
|
node = bip32.from_seed(self.seed, curve_name)
|
||||||
return node
|
node.derive_path(path)
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
async def _get_cached_seed(ctx: wire.Context) -> bytes:
|
async def get_keychain(ctx: wire.Context) -> Keychain:
|
||||||
if not storage.is_initialized():
|
if not storage.is_initialized():
|
||||||
|
# device does not have any seed
|
||||||
raise wire.ProcessError("Device is not initialized")
|
raise wire.ProcessError("Device is not initialized")
|
||||||
if cache.get_seed() is None:
|
|
||||||
passphrase = await _get_cached_passphrase(ctx)
|
seed = cache.get_seed()
|
||||||
|
if seed is None:
|
||||||
|
# acquire passphrase
|
||||||
|
passphrase = cache.get_passphrase()
|
||||||
|
if passphrase is None:
|
||||||
|
passphrase = await protect_by_passphrase(ctx)
|
||||||
|
cache.set_passphrase(passphrase)
|
||||||
|
|
||||||
|
# compute the seed from mnemonic and passphrase
|
||||||
seed = bip39.seed(storage.get_mnemonic(), passphrase)
|
seed = bip39.seed(storage.get_mnemonic(), passphrase)
|
||||||
cache.set_seed(seed)
|
cache.set_seed(seed)
|
||||||
return cache.get_seed()
|
|
||||||
|
|
||||||
|
keychain = Keychain(seed)
|
||||||
async def _get_cached_passphrase(ctx: wire.Context) -> str:
|
return keychain
|
||||||
if cache.get_passphrase() is None:
|
|
||||||
passphrase = await protect_by_passphrase(ctx)
|
|
||||||
cache.set_passphrase(passphrase)
|
|
||||||
return cache.get_passphrase()
|
|
||||||
|
|
||||||
|
|
||||||
def derive_node_without_passphrase(
|
def derive_node_without_passphrase(
|
||||||
path: list, curve_name: str = _DEFAULT_CURVE
|
path: list, curve_name: str = _DEFAULT_CURVE
|
||||||
) -> bip32.HDNode:
|
) -> bip32.HDNode:
|
||||||
if not storage.is_initialized():
|
if not storage.is_initialized():
|
||||||
|
# device does not have any seed
|
||||||
raise Exception("Device is not initialized")
|
raise Exception("Device is not initialized")
|
||||||
|
|
||||||
seed = bip39.seed(storage.get_mnemonic(), "")
|
seed = bip39.seed(storage.get_mnemonic(), "")
|
||||||
node = bip32.from_seed(seed, curve_name)
|
node = bip32.from_seed(seed, curve_name)
|
||||||
node.derive_path(path)
|
node.derive_path(path)
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
from .address import ethereum_address_hex, validate_full_path
|
from trezor.crypto.curve import secp256k1
|
||||||
|
from trezor.crypto.hashlib import sha3_256
|
||||||
|
from trezor.messages.EthereumAddress import EthereumAddress
|
||||||
|
|
||||||
from apps.common import paths
|
from apps.common import paths, seed
|
||||||
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.ethereum import networks
|
from apps.ethereum import networks
|
||||||
|
from apps.ethereum.address import ethereum_address_hex, validate_full_path
|
||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
from trezor.messages.EthereumAddress import EthereumAddress
|
keychain = await seed.get_keychain(ctx)
|
||||||
from trezor.crypto.curve import secp256k1
|
|
||||||
from trezor.crypto.hashlib import sha3_256
|
|
||||||
from apps.common import seed
|
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n)
|
node = keychain.derive(msg.address_n)
|
||||||
|
|
||||||
seckey = node.private_key()
|
seckey = node.private_key()
|
||||||
public_key = secp256k1.publickey(seckey, False) # uncompressed
|
public_key = secp256k1.publickey(seckey, False) # uncompressed
|
||||||
address = sha3_256(public_key[1:], keccak=True).digest()[12:]
|
address = sha3_256(public_key[1:], keccak=True).digest()[12:]
|
||||||
|
@ -21,11 +21,12 @@ def message_digest(message):
|
|||||||
|
|
||||||
|
|
||||||
async def sign_message(ctx, msg):
|
async def sign_message(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
await require_confirm_sign_message(ctx, msg.message)
|
await require_confirm_sign_message(ctx, msg.message)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n)
|
node = keychain.derive(msg.address_n)
|
||||||
|
|
||||||
signature = secp256k1.sign(
|
signature = secp256k1.sign(
|
||||||
node.private_key(),
|
node.private_key(),
|
||||||
message_digest(msg.message),
|
message_digest(msg.message),
|
||||||
|
@ -131,8 +131,9 @@ async def send_request_chunk(ctx, data_left: int):
|
|||||||
|
|
||||||
|
|
||||||
async def send_signature(ctx, msg: EthereumSignTx, digest):
|
async def send_signature(ctx, msg: EthereumSignTx, digest):
|
||||||
node = await seed.derive_node(ctx, msg.address_n)
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
|
node = keychain.derive(msg.address_n)
|
||||||
signature = secp256k1.sign(
|
signature = secp256k1.sign(
|
||||||
node.private_key(), digest, False, secp256k1.CANONICAL_SIG_ETHEREUM
|
node.private_key(), digest, False, secp256k1.CANONICAL_SIG_ETHEREUM
|
||||||
)
|
)
|
||||||
|
@ -7,9 +7,11 @@ from apps.common.layout import address_n_to_str, show_address, show_qr
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, LISK_CURVE)
|
node = keychain.derive(msg.address_n, LISK_CURVE)
|
||||||
pubkey = node.public_key()
|
pubkey = node.public_key()
|
||||||
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
||||||
address = get_address_from_public_key(pubkey)
|
address = get_address_from_public_key(pubkey)
|
||||||
|
@ -6,9 +6,11 @@ from apps.common import layout, paths, seed
|
|||||||
|
|
||||||
|
|
||||||
async def get_public_key(ctx, msg):
|
async def get_public_key(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, LISK_CURVE)
|
node = keychain.derive(msg.address_n, LISK_CURVE)
|
||||||
pubkey = node.public_key()
|
pubkey = node.public_key()
|
||||||
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
||||||
|
|
||||||
|
@ -23,10 +23,12 @@ def message_digest(message):
|
|||||||
|
|
||||||
|
|
||||||
async def sign_message(ctx, msg):
|
async def sign_message(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
await require_confirm_sign_message(ctx, msg.message)
|
await require_confirm_sign_message(ctx, msg.message)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, LISK_CURVE)
|
node = keychain.derive(msg.address_n, LISK_CURVE)
|
||||||
seckey = node.private_key()
|
seckey = node.private_key()
|
||||||
pubkey = node.public_key()
|
pubkey = node.public_key()
|
||||||
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
pubkey = pubkey[1:] # skip ed25519 pubkey marker
|
||||||
|
@ -14,9 +14,11 @@ from apps.common import paths, seed
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg):
|
async def sign_tx(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
pubkey, seckey = await _get_keys(ctx, msg)
|
pubkey, seckey = _get_keys(keychain, msg)
|
||||||
transaction = _update_raw_tx(msg.transaction, pubkey)
|
transaction = _update_raw_tx(msg.transaction, pubkey)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -37,8 +39,8 @@ async def sign_tx(ctx, msg):
|
|||||||
return LiskSignedTx(signature=signature)
|
return LiskSignedTx(signature=signature)
|
||||||
|
|
||||||
|
|
||||||
async def _get_keys(ctx, msg):
|
def _get_keys(keychain, msg):
|
||||||
node = await seed.derive_node(ctx, msg.address_n, LISK_CURVE)
|
node = keychain.derive(msg.address_n, LISK_CURVE)
|
||||||
|
|
||||||
seckey = node.private_key()
|
seckey = node.private_key()
|
||||||
pubkey = node.public_key()
|
pubkey = node.public_key()
|
||||||
|
@ -12,7 +12,9 @@ async def get_creds(ctx, address_n=None, network_type=None):
|
|||||||
curve = "ed25519"
|
curve = "ed25519"
|
||||||
else:
|
else:
|
||||||
curve = "secp256k1"
|
curve = "secp256k1"
|
||||||
node = await seed.derive_node(ctx, address_n, curve)
|
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
node = keychain.derive(address_n, curve)
|
||||||
|
|
||||||
if use_slip0010:
|
if use_slip0010:
|
||||||
key_seed = node.private_key()
|
key_seed = node.private_key()
|
||||||
|
@ -9,10 +9,12 @@ from apps.common.paths import validate_path
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
network = validate_network(msg.network)
|
keychain = await seed.get_keychain(ctx)
|
||||||
await validate_path(ctx, check_path, path=msg.address_n, network=msg.network)
|
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, NEM_CURVE)
|
network = validate_network(msg.network)
|
||||||
|
await validate_path(ctx, check_path, path=msg.address_n, network=network)
|
||||||
|
|
||||||
|
node = keychain.derive(msg.address_n, NEM_CURVE)
|
||||||
address = node.nem_address(network)
|
address = node.nem_address(network)
|
||||||
|
|
||||||
if msg.show_display:
|
if msg.show_display:
|
||||||
|
@ -11,12 +11,15 @@ from apps.common.paths import validate_path
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg: NEMSignTx):
|
async def sign_tx(ctx, msg: NEMSignTx):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
validate(msg)
|
validate(msg)
|
||||||
|
|
||||||
await validate_path(
|
await validate_path(
|
||||||
ctx, check_path, path=msg.transaction.address_n, network=msg.transaction.network
|
ctx, check_path, path=msg.transaction.address_n, network=msg.transaction.network
|
||||||
)
|
)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.transaction.address_n, NEM_CURVE)
|
node = keychain.derive(msg.transaction.address_n, NEM_CURVE)
|
||||||
|
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
public_key = msg.multisig.signer
|
public_key = msg.multisig.signer
|
||||||
|
@ -8,9 +8,11 @@ from apps.common.layout import address_n_to_str, show_address, show_qr
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg: RippleGetAddress):
|
async def get_address(ctx, msg: RippleGetAddress):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, 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 = helpers.address_from_public_key(pubkey)
|
||||||
|
|
||||||
|
@ -12,10 +12,13 @@ from apps.common import paths, seed
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg: RippleSignTx):
|
async def sign_tx(ctx, msg: RippleSignTx):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
validate(msg)
|
validate(msg)
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, 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())
|
||||||
|
|
||||||
set_canonical_flag(msg)
|
set_canonical_flag(msg)
|
||||||
|
@ -7,9 +7,11 @@ from apps.stellar import helpers
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg: StellarGetAddress):
|
async def get_address(ctx, msg: StellarGetAddress):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, helpers.STELLAR_CURVE)
|
node = keychain.derive(msg.address_n, helpers.STELLAR_CURVE)
|
||||||
pubkey = seed.remove_ed25519_prefix(node.public_key())
|
pubkey = seed.remove_ed25519_prefix(node.public_key())
|
||||||
address = helpers.address_from_public_key(pubkey)
|
address = helpers.address_from_public_key(pubkey)
|
||||||
|
|
||||||
|
@ -13,14 +13,16 @@ from apps.stellar.operations import process_operation
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg: StellarSignTx):
|
async def sign_tx(ctx, msg: StellarSignTx):
|
||||||
if msg.num_operations == 0:
|
keychain = await seed.get_keychain(ctx)
|
||||||
raise ProcessError("Stellar: At least one operation is required")
|
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, consts.STELLAR_CURVE)
|
node = keychain.derive(msg.address_n, consts.STELLAR_CURVE)
|
||||||
pubkey = seed.remove_ed25519_prefix(node.public_key())
|
pubkey = seed.remove_ed25519_prefix(node.public_key())
|
||||||
|
|
||||||
|
if msg.num_operations == 0:
|
||||||
|
raise ProcessError("Stellar: At least one operation is required")
|
||||||
|
|
||||||
w = bytearray()
|
w = bytearray()
|
||||||
await _init(ctx, w, pubkey, msg)
|
await _init(ctx, w, pubkey, msg)
|
||||||
_timebounds(w, msg.timebounds_start, msg.timebounds_end)
|
_timebounds(w, msg.timebounds_start, msg.timebounds_end)
|
||||||
|
@ -7,8 +7,11 @@ from apps.tezos import helpers
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
node = await seed.derive_node(ctx, msg.address_n, helpers.TEZOS_CURVE)
|
|
||||||
|
node = keychain.derive(msg.address_n, helpers.TEZOS_CURVE)
|
||||||
|
|
||||||
pk = seed.remove_ed25519_prefix(node.public_key())
|
pk = seed.remove_ed25519_prefix(node.public_key())
|
||||||
pkh = hashlib.blake2b(pk, outlen=20).digest()
|
pkh = hashlib.blake2b(pk, outlen=20).digest()
|
||||||
|
@ -10,9 +10,11 @@ from apps.tezos import helpers
|
|||||||
|
|
||||||
|
|
||||||
async def get_public_key(ctx, msg):
|
async def get_public_key(ctx, msg):
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
keychain = await seed.get_keychain(ctx)
|
||||||
node = await seed.derive_node(ctx, msg.address_n, helpers.TEZOS_CURVE)
|
|
||||||
|
|
||||||
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
|
|
||||||
|
node = keychain.derive(msg.address_n, helpers.TEZOS_CURVE)
|
||||||
pk = seed.remove_ed25519_prefix(node.public_key())
|
pk = seed.remove_ed25519_prefix(node.public_key())
|
||||||
pk_prefixed = helpers.base58_encode_check(pk, prefix=helpers.TEZOS_PUBLICKEY_PREFIX)
|
pk_prefixed = helpers.base58_encode_check(pk, prefix=helpers.TEZOS_PUBLICKEY_PREFIX)
|
||||||
|
|
||||||
|
@ -10,8 +10,11 @@ from apps.tezos import helpers, layout
|
|||||||
|
|
||||||
|
|
||||||
async def sign_tx(ctx, msg):
|
async def sign_tx(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
await paths.validate_path(ctx, helpers.validate_full_path, path=msg.address_n)
|
||||||
node = await seed.derive_node(ctx, msg.address_n, helpers.TEZOS_CURVE)
|
|
||||||
|
node = keychain.derive(msg.address_n, helpers.TEZOS_CURVE)
|
||||||
|
|
||||||
if msg.transaction is not None:
|
if msg.transaction is not None:
|
||||||
to = _get_address_from_contract(msg.transaction.destination)
|
to = _get_address_from_contract(msg.transaction.destination)
|
||||||
|
@ -9,6 +9,8 @@ from apps.common.confirm import require_confirm
|
|||||||
|
|
||||||
|
|
||||||
async def cipher_key_value(ctx, msg):
|
async def cipher_key_value(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
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")
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ async def cipher_key_value(ctx, msg):
|
|||||||
text.normal(msg.key)
|
text.normal(msg.key)
|
||||||
await require_confirm(ctx, text)
|
await require_confirm(ctx, text)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n)
|
node = keychain.derive(msg.address_n)
|
||||||
value = compute_cipher_key_value(msg, node.private_key())
|
value = compute_cipher_key_value(msg, node.private_key())
|
||||||
return CipheredKeyValue(value=value)
|
return CipheredKeyValue(value=value)
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ from apps.wallet.sign_tx import addresses
|
|||||||
|
|
||||||
|
|
||||||
async def get_address(ctx, msg):
|
async def get_address(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
coin_name = msg.coin_name or "Bitcoin"
|
coin_name = msg.coin_name or "Bitcoin"
|
||||||
coin = coins.by_name(coin_name)
|
coin = coins.by_name(coin_name)
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ async def get_address(ctx, msg):
|
|||||||
script_type=msg.script_type,
|
script_type=msg.script_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, curve_name=coin.curve_name)
|
node = keychain.derive(msg.address_n, coin.curve_name)
|
||||||
address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
|
address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
|
||||||
address_short = addresses.address_short(coin, address)
|
address_short = addresses.address_short(coin, address)
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ from apps.wallet.sign_identity import (
|
|||||||
|
|
||||||
|
|
||||||
async def get_ecdh_session_key(ctx, msg):
|
async def get_ecdh_session_key(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
if msg.ecdsa_curve_name is None:
|
if msg.ecdsa_curve_name is None:
|
||||||
msg.ecdsa_curve_name = "secp256k1"
|
msg.ecdsa_curve_name = "secp256k1"
|
||||||
|
|
||||||
@ -22,7 +24,7 @@ async def get_ecdh_session_key(ctx, msg):
|
|||||||
await require_confirm_ecdh_session_key(ctx, msg.identity)
|
await require_confirm_ecdh_session_key(ctx, msg.identity)
|
||||||
|
|
||||||
address_n = get_ecdh_path(identity, msg.identity.index or 0)
|
address_n = get_ecdh_path(identity, msg.identity.index or 0)
|
||||||
node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name)
|
node = keychain.derive(address_n, msg.ecdsa_curve_name)
|
||||||
|
|
||||||
session_key = ecdh(
|
session_key = ecdh(
|
||||||
seckey=node.private_key(),
|
seckey=node.private_key(),
|
||||||
|
@ -7,14 +7,14 @@ from apps.common import coins, layout, seed
|
|||||||
|
|
||||||
|
|
||||||
async def get_public_key(ctx, msg):
|
async def get_public_key(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
coin_name = msg.coin_name or "Bitcoin"
|
coin_name = msg.coin_name or "Bitcoin"
|
||||||
coin = coins.by_name(coin_name)
|
coin = coins.by_name(coin_name)
|
||||||
|
curve_name = msg.ecdsa_curve_name or coin.curve_name
|
||||||
script_type = msg.script_type or InputScriptType.SPENDADDRESS
|
script_type = msg.script_type or InputScriptType.SPENDADDRESS
|
||||||
|
|
||||||
curve_name = msg.ecdsa_curve_name
|
node = keychain.derive(msg.address_n, curve_name=curve_name)
|
||||||
if not curve_name:
|
|
||||||
curve_name = coin.curve_name
|
|
||||||
node = await seed.derive_node(ctx, msg.address_n, curve_name=curve_name)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
script_type in [InputScriptType.SPENDADDRESS, InputScriptType.SPENDMULTISIG]
|
script_type in [InputScriptType.SPENDADDRESS, InputScriptType.SPENDMULTISIG]
|
||||||
|
@ -11,6 +11,8 @@ from apps.common.confirm import require_confirm
|
|||||||
|
|
||||||
|
|
||||||
async def sign_identity(ctx, msg):
|
async def sign_identity(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
if msg.ecdsa_curve_name is None:
|
if msg.ecdsa_curve_name is None:
|
||||||
msg.ecdsa_curve_name = "secp256k1"
|
msg.ecdsa_curve_name = "secp256k1"
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ async def sign_identity(ctx, msg):
|
|||||||
await require_confirm_sign_identity(ctx, msg.identity, msg.challenge_visual)
|
await require_confirm_sign_identity(ctx, msg.identity, msg.challenge_visual)
|
||||||
|
|
||||||
address_n = get_identity_path(identity, msg.identity.index or 0)
|
address_n = get_identity_path(identity, msg.identity.index or 0)
|
||||||
node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name)
|
node = keychain.derive(address_n, msg.ecdsa_curve_name)
|
||||||
|
|
||||||
coin = coins.by_name("Bitcoin")
|
coin = coins.by_name("Bitcoin")
|
||||||
if msg.ecdsa_curve_name == "secp256k1":
|
if msg.ecdsa_curve_name == "secp256k1":
|
||||||
|
@ -12,6 +12,8 @@ from apps.wallet.sign_tx.addresses import get_address, validate_full_path
|
|||||||
|
|
||||||
|
|
||||||
async def sign_message(ctx, msg):
|
async def sign_message(ctx, msg):
|
||||||
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
|
||||||
message = msg.message
|
message = msg.message
|
||||||
address_n = msg.address_n
|
address_n = msg.address_n
|
||||||
coin_name = msg.coin_name or "Bitcoin"
|
coin_name = msg.coin_name or "Bitcoin"
|
||||||
@ -19,7 +21,6 @@ async def sign_message(ctx, msg):
|
|||||||
coin = coins.by_name(coin_name)
|
coin = coins.by_name(coin_name)
|
||||||
|
|
||||||
await require_confirm_sign_message(ctx, message)
|
await require_confirm_sign_message(ctx, message)
|
||||||
|
|
||||||
await validate_path(
|
await validate_path(
|
||||||
ctx,
|
ctx,
|
||||||
validate_full_path,
|
validate_full_path,
|
||||||
@ -29,7 +30,7 @@ async def sign_message(ctx, msg):
|
|||||||
validate_script_type=False,
|
validate_script_type=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
node = await seed.derive_node(ctx, address_n, curve_name=coin.curve_name)
|
node = keychain.derive(address_n, coin.curve_name)
|
||||||
seckey = node.private_key()
|
seckey = node.private_key()
|
||||||
|
|
||||||
address = get_address(script_type, coin, node)
|
address = get_address(script_type, coin, node)
|
||||||
|
@ -19,7 +19,8 @@ async def sign_tx(ctx, msg):
|
|||||||
coin_name = msg.coin_name or "Bitcoin"
|
coin_name = msg.coin_name or "Bitcoin"
|
||||||
coin = coins.by_name(coin_name)
|
coin = coins.by_name(coin_name)
|
||||||
# TODO: rework this so we don't have to pass root to signing.sign_tx
|
# TODO: rework this so we don't have to pass root to signing.sign_tx
|
||||||
root = await seed.derive_node(ctx, [], curve_name=coin.curve_name)
|
keychain = await seed.get_keychain(ctx)
|
||||||
|
root = keychain.derive([], coin.curve_name)
|
||||||
|
|
||||||
signer = signing.sign_tx(msg, root)
|
signer = signing.sign_tx(msg, root)
|
||||||
res = None
|
res = None
|
||||||
|
Loading…
Reference in New Issue
Block a user