mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 04:18:10 +00:00
feat(cardano): add support for 1854 and 1855 path roots
This commit is contained in:
parent
2687fd4ade
commit
54909681a8
@ -57,6 +57,78 @@
|
|||||||
"public_key": "be81ace1f63f4f0cae74dd274a72d7818f238bc764ab3e0dc0beb1945b756dca",
|
"public_key": "be81ace1f63f4f0cae74dd274a72d7818f238bc764ab3e0dc0beb1945b756dca",
|
||||||
"chain_code": "29034f036a162ac4f9f9f397b2d1f289754bb6633915f26b199e156f81d05c88"
|
"chain_code": "29034f036a162ac4f9f9f397b2d1f289754bb6633915f26b199e156f81d05c88"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1854'/1815'/0'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "99694f772a1cffa68ad4a8d911e649cfe990aee720d26893211a8818c4566a42",
|
||||||
|
"chain_code": "9c3372fcecd832bfe2418319e473b981cdd641e0e12bd878b5e94d93fa0b1552"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1854'/1815'/1'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "1b66eb903dc15131c0f39c1ac41ca659115ab790c3e2aef129e3095e406abffe",
|
||||||
|
"chain_code": "0fcb6522d3aa8ad78370c48e62c97eb1315f4234ded8d8fdd9b941c4e5fda0c0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1854'/1815'/2'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "29f3535b40978eda8038de3fe85cf08efecff5e565a3dc745660a43a172aaa0a",
|
||||||
|
"chain_code": "b82dbc91a252a93ec6d3f9e418a4e779c848162777367f729468ec23f409304e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1854'/1815'/3'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "bdc40afecb357a08538cd98878b11d0afa7a0a36a8c5f71be1b591ae09088149",
|
||||||
|
"chain_code": "c4e0b579c132de4204d19f12260ac6bede8ae67f0fe15b9098d4f32a42314924"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1855'/1815'/0'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872",
|
||||||
|
"chain_code": "9ad37dc23fe1cda7b0ac5574c6f16171cdb2bb723496954770a2bf0e08334e8f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1855'/1815'/1'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "a54627d6d16724032172541d4261e7aa87c06395724f1d18975a21d56650bda9",
|
||||||
|
"chain_code": "bccfd881a3bb7eefbfb885a80909c30892a9a2151f7530c10c68ec6e7a89b28a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1855'/1815'/2'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "5307953b17d4195e0b87d61731339dba2c7d543f621d87c1bd73466328372345",
|
||||||
|
"chain_code": "0e3314c9499b6efec4fa48cd5068dd549ed5ee524c300e754ebc0a63c3bc06ff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"path": "m/1855'/1815'/3'"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"public_key": "b404bb5bf674a38ebd6141416df8e1aea9ed04c2ebea659c29145d24db7e67db",
|
||||||
|
"chain_code": "2dc07d8eda29c2a806295ee42dc1f3bf63814d0c9ee978a24827575dcb5a53bb"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ from trezor.ui.layouts import show_pubkey
|
|||||||
from apps.common import paths
|
from apps.common import paths
|
||||||
|
|
||||||
from . import seed
|
from . import seed
|
||||||
from .helpers.paths import SCHEMA_PUBKEY
|
from .helpers.paths import SCHEMA_MINT, SCHEMA_PUBKEY
|
||||||
from .helpers.utils import derive_public_key
|
from .helpers.utils import derive_public_key
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
@ -23,7 +23,7 @@ async def get_public_key(
|
|||||||
keychain,
|
keychain,
|
||||||
msg.address_n,
|
msg.address_n,
|
||||||
# path must match the PUBKEY schema
|
# path must match the PUBKEY schema
|
||||||
SCHEMA_PUBKEY.match(msg.address_n),
|
SCHEMA_PUBKEY.match(msg.address_n) or SCHEMA_MINT.match(msg.address_n),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -6,13 +6,17 @@ SLIP44_ID = 1815
|
|||||||
|
|
||||||
BYRON_ROOT = [44 | HARDENED, SLIP44_ID | HARDENED]
|
BYRON_ROOT = [44 | HARDENED, SLIP44_ID | HARDENED]
|
||||||
SHELLEY_ROOT = [1852 | HARDENED, SLIP44_ID | HARDENED]
|
SHELLEY_ROOT = [1852 | HARDENED, SLIP44_ID | HARDENED]
|
||||||
|
MULTISIG_ROOT = [1854 | HARDENED, SLIP44_ID | HARDENED]
|
||||||
|
MINTING_ROOT = [1855 | HARDENED, SLIP44_ID | HARDENED]
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
SCHEMA_PUBKEY = PathSchema.parse("m/[44,1852]'/coin_type'/account'/*", SLIP44_ID)
|
SCHEMA_PUBKEY = PathSchema.parse("m/[44,1852,1854]'/coin_type'/account'/*", SLIP44_ID)
|
||||||
|
# minting has a specific schema for key derivation - see CIP-1855
|
||||||
|
SCHEMA_MINT = PathSchema.parse("m/1855'/coin_type'/[0-%s]'" % (HARDENED - 1), SLIP44_ID)
|
||||||
SCHEMA_PAYMENT = PathSchema.parse("m/[44,1852]'/coin_type'/account'/[0,1]/address_index", SLIP44_ID)
|
SCHEMA_PAYMENT = PathSchema.parse("m/[44,1852]'/coin_type'/account'/[0,1]/address_index", SLIP44_ID)
|
||||||
# staking is only allowed on Shelley paths with suffix /2/0
|
# staking is only allowed on Shelley paths with suffix /2/0
|
||||||
SCHEMA_STAKING = PathSchema.parse("m/1852'/coin_type'/account'/2/0", SLIP44_ID)
|
SCHEMA_STAKING = PathSchema.parse("m/[1852]'/coin_type'/account'/2/0", SLIP44_ID)
|
||||||
SCHEMA_STAKING_ANY_ACCOUNT = PathSchema.parse("m/1852'/coin_type'/[0-%s]'/2/0" % (HARDENED - 1), SLIP44_ID)
|
SCHEMA_STAKING_ANY_ACCOUNT = PathSchema.parse("m/[1852]'/coin_type'/[0-%s]'/2/0" % (HARDENED - 1), SLIP44_ID)
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
ACCOUNT_PATH_LENGTH = const(3)
|
ACCOUNT_PATH_LENGTH = const(3)
|
||||||
|
@ -18,15 +18,20 @@ if False:
|
|||||||
|
|
||||||
|
|
||||||
class Keychain:
|
class Keychain:
|
||||||
"""Cardano keychain hard-coded to Byron and Shelley seed namespaces."""
|
"""
|
||||||
|
Cardano keychain hard-coded to 44 (Byron), 1852 (Shelley), 1854 (multi-sig) and 1855 (token minting)
|
||||||
|
seed namespaces.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, root: bip32.HDNode) -> None:
|
def __init__(self, root: bip32.HDNode) -> None:
|
||||||
self.byron_root = derive_path_cardano(root, paths.BYRON_ROOT)
|
self.byron_root = derive_path_cardano(root, paths.BYRON_ROOT)
|
||||||
self.shelley_root = derive_path_cardano(root, paths.SHELLEY_ROOT)
|
self.shelley_root = derive_path_cardano(root, paths.SHELLEY_ROOT)
|
||||||
|
self.multisig_root = derive_path_cardano(root, paths.MULTISIG_ROOT)
|
||||||
|
self.minting_root = derive_path_cardano(root, paths.MINTING_ROOT)
|
||||||
root.__del__()
|
root.__del__()
|
||||||
|
|
||||||
def verify_path(self, path: Bip32Path) -> None:
|
def verify_path(self, path: Bip32Path) -> None:
|
||||||
if not is_byron_path(path) and not is_shelley_path(path):
|
if not self.is_in_keychain(path):
|
||||||
raise wire.DataError("Forbidden key path")
|
raise wire.DataError("Forbidden key path")
|
||||||
|
|
||||||
def _get_path_root(self, path: Bip32Path) -> bip32.HDNode:
|
def _get_path_root(self, path: Bip32Path) -> bip32.HDNode:
|
||||||
@ -34,18 +39,31 @@ class Keychain:
|
|||||||
return self.byron_root
|
return self.byron_root
|
||||||
elif is_shelley_path(path):
|
elif is_shelley_path(path):
|
||||||
return self.shelley_root
|
return self.shelley_root
|
||||||
|
elif is_multisig_path(path):
|
||||||
|
return self.multisig_root
|
||||||
|
elif is_minting_path(path):
|
||||||
|
return self.minting_root
|
||||||
else:
|
else:
|
||||||
raise wire.DataError("Forbidden key path")
|
raise wire.DataError("Forbidden key path")
|
||||||
|
|
||||||
def is_in_keychain(self, path: Bip32Path) -> bool:
|
def is_in_keychain(self, path: Bip32Path) -> bool:
|
||||||
return is_byron_path(path) or is_shelley_path(path)
|
return (
|
||||||
|
is_byron_path(path)
|
||||||
|
or is_shelley_path(path)
|
||||||
|
or is_multisig_path(path)
|
||||||
|
or is_minting_path(path)
|
||||||
|
)
|
||||||
|
|
||||||
def derive(self, node_path: Bip32Path) -> bip32.HDNode:
|
def derive(self, node_path: Bip32Path) -> bip32.HDNode:
|
||||||
self.verify_path(node_path)
|
self.verify_path(node_path)
|
||||||
path_root = self._get_path_root(node_path)
|
path_root = self._get_path_root(node_path)
|
||||||
|
|
||||||
# this is true now, so for simplicity we don't branch on path type
|
# this is true now, so for simplicity we don't branch on path type
|
||||||
assert len(paths.BYRON_ROOT) == len(paths.SHELLEY_ROOT)
|
assert (
|
||||||
|
len(paths.BYRON_ROOT) == len(paths.SHELLEY_ROOT)
|
||||||
|
and len(paths.MULTISIG_ROOT) == len(paths.SHELLEY_ROOT)
|
||||||
|
and len(paths.MINTING_ROOT) == len(paths.SHELLEY_ROOT)
|
||||||
|
)
|
||||||
suffix = node_path[len(paths.SHELLEY_ROOT) :]
|
suffix = node_path[len(paths.SHELLEY_ROOT) :]
|
||||||
|
|
||||||
# derive child node from the root
|
# derive child node from the root
|
||||||
@ -64,6 +82,14 @@ def is_shelley_path(path: Bip32Path) -> bool:
|
|||||||
return path[: len(paths.SHELLEY_ROOT)] == paths.SHELLEY_ROOT
|
return path[: len(paths.SHELLEY_ROOT)] == paths.SHELLEY_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
def is_multisig_path(path: Bip32Path) -> bool:
|
||||||
|
return path[: len(paths.MULTISIG_ROOT)] == paths.MULTISIG_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
def is_minting_path(path: Bip32Path) -> bool:
|
||||||
|
return path[: len(paths.MINTING_ROOT)] == paths.MINTING_ROOT
|
||||||
|
|
||||||
|
|
||||||
def derive_path_cardano(root: bip32.HDNode, path: Bip32Path) -> bip32.HDNode:
|
def derive_path_cardano(root: bip32.HDNode, path: Bip32Path) -> bip32.HDNode:
|
||||||
node = root.clone()
|
node = root.clone()
|
||||||
for i in path:
|
for i in path:
|
||||||
|
Loading…
Reference in New Issue
Block a user