1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 07:28:10 +00:00

feat(core/cardano): Implement bech32 asset ids based on CIP-0014

This commit is contained in:
Rafael Korbas 2021-03-02 19:08:14 +01:00 committed by matejcik
parent bd4512b53a
commit 74ed5b7018
5 changed files with 48 additions and 43 deletions

View File

@ -663,7 +663,7 @@
"certificates": [], "certificates": [],
"withdrawals": [], "withdrawals": [],
"metadata": "", "metadata": "",
"input_flow": [["YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"]], "input_flow": [["YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"]],
"inputs": [ "inputs": [
{ {
"path": "m/1852'/1815'/0'/0/0", "path": "m/1852'/1815'/0'/0/0",
@ -711,7 +711,7 @@
"certificates": [], "certificates": [],
"withdrawals": [], "withdrawals": [],
"metadata": "", "metadata": "",
"input_flow": [["YES"], ["YES"], ["YES"], ["SWIPE", "YES"], ["YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["YES"]], "input_flow": [["YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "YES"], ["SWIPE", "SWIPE", "YES"], ["SWIPE", "YES"]],
"inputs": [ "inputs": [
{ {
"path": "m/1852'/1815'/0'/0/0", "path": "m/1852'/1815'/0'/0/0",

View File

@ -1,3 +1,5 @@
from trezor.crypto import hashlib
from apps.cardano.helpers.paths import ACCOUNT_PATH_INDEX, unharden from apps.cardano.helpers.paths import ACCOUNT_PATH_INDEX, unharden
from . import bech32 from . import bech32
@ -48,3 +50,14 @@ def format_optional_int(number: Optional[int]) -> str:
def format_stake_pool_id(pool_id_bytes: bytes) -> str: def format_stake_pool_id(pool_id_bytes: bytes) -> str:
return bech32.encode("pool", pool_id_bytes) return bech32.encode("pool", pool_id_bytes)
def format_asset_fingerprint(policy_id: bytes, asset_name_bytes: bytes) -> str:
fingerprint = hashlib.blake2b(
# bytearrays are being promoted to bytes: https://github.com/python/mypy/issues/654
# but bytearrays are not concatenable, this casting works around this limitation
data=bytes(policy_id) + bytes(asset_name_bytes),
outlen=20,
).digest()
return bech32.encode("asset", fingerprint)

View File

@ -25,6 +25,7 @@ from .address import (
from .helpers import protocol_magics from .helpers import protocol_magics
from .helpers.utils import ( from .helpers.utils import (
format_account_number, format_account_number,
format_asset_fingerprint,
format_optional_int, format_optional_int,
format_stake_pool_id, format_stake_pool_id,
to_account_path, to_account_path,
@ -42,7 +43,6 @@ if False:
from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType
from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
from trezor.messages.CardanoTokenType import CardanoTokenType
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
@ -79,8 +79,7 @@ async def confirm_sending(
token_bundle: List[CardanoAssetGroupType], token_bundle: List[CardanoAssetGroupType],
to: str, to: str,
) -> None: ) -> None:
for token_group in token_bundle: await confirm_sending_token_bundle(ctx, token_bundle)
await confirm_sending_token_group(ctx, token_group)
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Confirm sending:") page1.normal("Confirm sending:")
@ -96,42 +95,23 @@ async def confirm_sending(
await require_confirm(ctx, Paginated(pages)) await require_confirm(ctx, Paginated(pages))
async def confirm_sending_token_group( async def confirm_sending_token_bundle(
ctx: wire.Context, token_group: CardanoAssetGroupType ctx: wire.Context, token_bundle: List[CardanoAssetGroupType]
) -> None: ) -> None:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) for token_group in token_bundle:
page1.bold("Policy id: ") for token in token_group.tokens:
page1.mono(hexlify(token_group.policy_id).decode()) page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
await require_confirm(ctx, page1) page1.normal("Asset fingerprint:")
page1.bold(
for token_number, token in enumerate(token_group.tokens, 1): format_asset_fingerprint(
if is_printable_ascii_bytestring(token.asset_name_bytes): policy_id=token_group.policy_id,
await confirm_sending_token_ascii(ctx, token, token_number) asset_name_bytes=token.asset_name_bytes,
else: )
await confirm_sending_token_hex(ctx, token, token_number) )
page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page2.normal("Amount sent:")
async def confirm_sending_token_ascii( page2.bold(format_amount(token.amount, 0))
ctx: wire.Context, token: CardanoTokenType, token_number: int await require_confirm(ctx, Paginated([page1, page2]))
) -> None:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Asset #%s name (ASCII):" % (token_number))
page1.bold(token.asset_name_bytes.decode("ascii"))
page1.normal("Amount sent:")
page1.bold(format_amount(token.amount, 0))
await require_confirm(ctx, page1)
async def confirm_sending_token_hex(
ctx: wire.Context, token: CardanoTokenType, token_number: int
) -> None:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.bold("Asset #%s name (hex):" % (token_number))
page1.mono(hexlify(token.asset_name_bytes).decode())
page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page2.normal("Amount sent:")
page2.bold(format_amount(token.amount, 0))
await require_confirm(ctx, Paginated([page1, page2]))
async def show_warning_tx_output_contains_tokens(ctx: wire.Context) -> None: async def show_warning_tx_output_contains_tokens(ctx: wire.Context) -> None:

View File

@ -1,7 +1,7 @@
from common import * from common import *
if not utils.BITCOIN_ONLY: if not utils.BITCOIN_ONLY:
from apps.cardano.helpers.utils import variable_length_encode from apps.cardano.helpers.utils import variable_length_encode, format_asset_fingerprint
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin") @unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
@ -28,6 +28,18 @@ class TestCardanoUtils(unittest.TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
variable_length_encode(-1) variable_length_encode(-1)
def test_format_asset_fingerprint(self):
# source: https://github.com/cardano-foundation/CIPs/pull/64
test_vectors = [
(("7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", ""), "asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3"),
(("7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", "504154415445"), "asset13n25uv0yaf5kus35fm2k86cqy60z58d9xmde92"),
(("1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373"), "asset1aqrdypg669jgazruv5ah07nuyqe0wxjhe2el6f"),
]
for params, expected in test_vectors:
actual = format_asset_fingerprint(policy_id=unhexlify(params[0]), asset_name_bytes=unhexlify(params[1]))
self.assertEqual(actual, expected)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -5,8 +5,8 @@
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc", "cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_multiple_inputs]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc",
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc", "cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change0]": "5ba2589aeda7cb2b707b5dd0d40ac26a5abe6eb0c3ec3d47d834701ef07a42bc",
"cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "c57c4097446de48b1f79850854a83410816ac05c8a7476452771cdc71e0aeefa", "cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_without_change1]": "c57c4097446de48b1f79850854a83410816ac05c8a7476452771cdc71e0aeefa",
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "0f14d371c83adf4ceaa05530581df86eb653b9e8226be61fcd2bc1cc97e3581a", "cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_different_policies_-1dbb1bfb": "02f8517926fe8d38d96606929df43372d8949e917299199d37e648672fed9256",
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "a24edeaaefca10b45235836264b8385148048a23bd34c56570c3de69de4f3d06", "cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_multiasset_output]": "d0a58ab8b68fcd9f1191f309de52efb6be9157383357f5f9c0e0d116fccc08e4",
"cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "db76676358164a3b3dab5148f09ba5515d079212366b79c44f95e2ba613abc71", "cardano-test_sign_tx.py::test_cardano_sign_tx[mary_era_transaction_with_no_ttl-validity_start]": "db76676358164a3b3dab5148f09ba5515d079212366b79c44f95e2ba613abc71",
"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "f56482d4a0f2c07fe04291a7d9c29ed4aedfd31e6a80fed1563d80e3a4c4005c", "cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate]": "f56482d4a0f2c07fe04291a7d9c29ed4aedfd31e6a80fed1563d80e3a4c4005c",
"cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "629ccaa5b660247843b366582c1bc505831c1800e028474a784b0f8b35fc473a", "cardano-test_sign_tx.py::test_cardano_sign_tx[sample_stake_pool_registration_certificate_wi-d3427614": "629ccaa5b660247843b366582c1bc505831c1800e028474a784b0f8b35fc473a",