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

pull/1531/head
Rafael Korbas 3 years ago committed by matejcik
parent bd4512b53a
commit 74ed5b7018

@ -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",

@ -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)

@ -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:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.bold("Policy id: ")
page1.mono(hexlify(token_group.policy_id).decode())
await require_confirm(ctx, page1)
for token_number, token in enumerate(token_group.tokens, 1):
if is_printable_ascii_bytestring(token.asset_name_bytes):
await confirm_sending_token_ascii(ctx, token, token_number)
else:
await confirm_sending_token_hex(ctx, token, token_number)
async def confirm_sending_token_ascii(
ctx: wire.Context, token: CardanoTokenType, token_number: int
) -> None: ) -> None:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) for token_group in token_bundle:
page1.normal("Asset #%s name (ASCII):" % (token_number)) for token in token_group.tokens:
page1.bold(token.asset_name_bytes.decode("ascii")) page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Amount sent:") page1.normal("Asset fingerprint:")
page1.bold(format_amount(token.amount, 0)) page1.bold(
await require_confirm(ctx, page1) format_asset_fingerprint(
policy_id=token_group.policy_id,
asset_name_bytes=token.asset_name_bytes,
async def confirm_sending_token_hex( )
ctx: wire.Context, token: CardanoTokenType, token_number: int )
) -> None: page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Amount sent:")
page1.bold("Asset #%s name (hex):" % (token_number)) page2.bold(format_amount(token.amount, 0))
page1.mono(hexlify(token.asset_name_bytes).decode()) await require_confirm(ctx, Paginated([page1, page2]))
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:

@ -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()

@ -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",

Loading…
Cancel
Save