From 021f6ff6c969f251a64a55cc69e9a1f5ee58dc3c Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 13:00:47 +0100 Subject: [PATCH 01/33] refactor: move the rust tests to a new folder --- tests/{ => old_to_delete}/.gitignore | 0 tests/{ => old_to_delete}/Cargo.lock | 0 tests/{ => old_to_delete}/Cargo.toml | 0 tests/{ => old_to_delete}/src/main.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => old_to_delete}/.gitignore (100%) rename tests/{ => old_to_delete}/Cargo.lock (100%) rename tests/{ => old_to_delete}/Cargo.toml (100%) rename tests/{ => old_to_delete}/src/main.rs (100%) diff --git a/tests/.gitignore b/tests/old_to_delete/.gitignore similarity index 100% rename from tests/.gitignore rename to tests/old_to_delete/.gitignore diff --git a/tests/Cargo.lock b/tests/old_to_delete/Cargo.lock similarity index 100% rename from tests/Cargo.lock rename to tests/old_to_delete/Cargo.lock diff --git a/tests/Cargo.toml b/tests/old_to_delete/Cargo.toml similarity index 100% rename from tests/Cargo.toml rename to tests/old_to_delete/Cargo.toml diff --git a/tests/src/main.rs b/tests/old_to_delete/src/main.rs similarity index 100% rename from tests/src/main.rs rename to tests/old_to_delete/src/main.rs From 0255d23b63b094a6668670d66556881458d1b035 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 13:02:46 +0100 Subject: [PATCH 02/33] test: add the ragger test structure from the latest boilerplate --- tests/application_client/__init__.py | 0 .../boilerplate_command_sender.py | 127 +++++++++++++++ .../boilerplate_response_unpacker.py | 70 +++++++++ .../boilerplate_transaction.py | 50 ++++++ tests/application_client/boilerplate_utils.py | 61 ++++++++ tests/application_client/py.typed | 0 tests/conftest.py | 14 ++ tests/requirements.txt | 4 + tests/setup.cfg | 23 +++ tests/test_app_mainmenu.py | 54 +++++++ tests/test_appname_cmd.py | 16 ++ tests/test_error_cmd.py | 59 +++++++ tests/test_name_version.py | 18 +++ tests/test_pubkey_cmd.py | 57 +++++++ tests/test_sign_cmd.py | 145 ++++++++++++++++++ tests/test_version_cmd.py | 16 ++ tests/usage.md | 78 ++++++++++ tests/utils.py | 76 +++++++++ 18 files changed, 868 insertions(+) create mode 100644 tests/application_client/__init__.py create mode 100644 tests/application_client/boilerplate_command_sender.py create mode 100644 tests/application_client/boilerplate_response_unpacker.py create mode 100644 tests/application_client/boilerplate_transaction.py create mode 100644 tests/application_client/boilerplate_utils.py create mode 100644 tests/application_client/py.typed create mode 100644 tests/conftest.py create mode 100644 tests/requirements.txt create mode 100644 tests/setup.cfg create mode 100644 tests/test_app_mainmenu.py create mode 100644 tests/test_appname_cmd.py create mode 100644 tests/test_error_cmd.py create mode 100644 tests/test_name_version.py create mode 100644 tests/test_pubkey_cmd.py create mode 100644 tests/test_sign_cmd.py create mode 100644 tests/test_version_cmd.py create mode 100644 tests/usage.md create mode 100644 tests/utils.py diff --git a/tests/application_client/__init__.py b/tests/application_client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py new file mode 100644 index 0000000..cb83ce7 --- /dev/null +++ b/tests/application_client/boilerplate_command_sender.py @@ -0,0 +1,127 @@ +from enum import IntEnum +from typing import Generator, List, Optional +from contextlib import contextmanager + +from ragger.backend.interface import BackendInterface, RAPDU +from ragger.bip import pack_derivation_path + + +MAX_APDU_LEN: int = 255 + +CLA: int = 0xE0 + +class P1(IntEnum): + # Parameter 1 for first APDU number. + P1_START = 0x00 + # Parameter 1 for maximum APDU number. + P1_MAX = 0x03 + # Parameter 1 for screen confirmation for GET_PUBLIC_KEY. + P1_CONFIRM = 0x01 + +class P2(IntEnum): + # Parameter 2 for last APDU to receive. + P2_LAST = 0x00 + # Parameter 2 for more APDU to receive. + P2_MORE = 0x80 + +class InsType(IntEnum): + GET_VERSION = 0x03 + GET_APP_NAME = 0x04 + GET_PUBLIC_KEY = 0x05 + SIGN_TX = 0x06 + +class Errors(IntEnum): + SW_DENY = 0x6985 + SW_WRONG_P1P2 = 0x6A86 + SW_WRONG_DATA_LENGTH = 0x6A87 + SW_INS_NOT_SUPPORTED = 0x6D00 + SW_CLA_NOT_SUPPORTED = 0x6E00 + SW_WRONG_RESPONSE_LENGTH = 0xB000 + SW_DISPLAY_BIP32_PATH_FAIL = 0xB001 + SW_DISPLAY_ADDRESS_FAIL = 0xB002 + SW_DISPLAY_AMOUNT_FAIL = 0xB003 + SW_WRONG_TX_LENGTH = 0xB004 + SW_TX_PARSING_FAIL = 0xB005 + SW_TX_HASH_FAIL = 0xB006 + SW_BAD_STATE = 0xB007 + SW_SIGNATURE_FAIL = 0xB008 + + +def split_message(message: bytes, max_size: int) -> List[bytes]: + return [message[x:x + max_size] for x in range(0, len(message), max_size)] + + +class BoilerplateCommandSender: + def __init__(self, backend: BackendInterface) -> None: + self.backend = backend + + + def get_app_and_version(self) -> RAPDU: + return self.backend.exchange(cla=0xB0, # specific CLA for BOLOS + ins=0x01, # specific INS for get_app_and_version + p1=P1.P1_START, + p2=P2.P2_LAST, + data=b"") + + + def get_version(self) -> RAPDU: + return self.backend.exchange(cla=CLA, + ins=InsType.GET_VERSION, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=b"") + + + def get_app_name(self) -> RAPDU: + return self.backend.exchange(cla=CLA, + ins=InsType.GET_APP_NAME, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=b"") + + + def get_public_key(self, path: str) -> RAPDU: + return self.backend.exchange(cla=CLA, + ins=InsType.GET_PUBLIC_KEY, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=pack_derivation_path(path)) + + + @contextmanager + def get_public_key_with_confirmation(self, path: str) -> Generator[None, None, None]: + with self.backend.exchange_async(cla=CLA, + ins=InsType.GET_PUBLIC_KEY, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=pack_derivation_path(path)) as response: + yield response + + + @contextmanager + def sign_tx(self, path: str, transaction: bytes) -> Generator[None, None, None]: + self.backend.exchange(cla=CLA, + ins=InsType.SIGN_TX, + p1=P1.P1_START, + p2=P2.P2_MORE, + data=pack_derivation_path(path)) + messages = split_message(transaction, MAX_APDU_LEN) + idx: int = P1.P1_START + 1 + + for msg in messages[:-1]: + self.backend.exchange(cla=CLA, + ins=InsType.SIGN_TX, + p1=idx, + p2=P2.P2_MORE, + data=msg) + idx += 1 + + with self.backend.exchange_async(cla=CLA, + ins=InsType.SIGN_TX, + p1=idx, + p2=P2.P2_LAST, + data=messages[-1]) as response: + yield response + + def get_async_response(self) -> Optional[RAPDU]: + return self.backend.last_async_response diff --git a/tests/application_client/boilerplate_response_unpacker.py b/tests/application_client/boilerplate_response_unpacker.py new file mode 100644 index 0000000..5d1f748 --- /dev/null +++ b/tests/application_client/boilerplate_response_unpacker.py @@ -0,0 +1,70 @@ +from typing import Tuple +from struct import unpack + +# remainder, data_len, data +def pop_sized_buf_from_buffer(buffer:bytes, size:int) -> Tuple[bytes, bytes]: + return buffer[size:], buffer[0:size] + +# remainder, data_len, data +def pop_size_prefixed_buf_from_buf(buffer:bytes) -> Tuple[bytes, int, bytes]: + data_len = buffer[0] + return buffer[1+data_len:], data_len, buffer[1:data_len+1] + +# Unpack from response: +# response = app_name (var) +def unpack_get_app_name_response(response: bytes) -> str: + return response.decode("ascii") + +# Unpack from response: +# response = MAJOR (1) +# MINOR (1) +# PATCH (1) +def unpack_get_version_response(response: bytes) -> Tuple[int, int, int]: + assert len(response) == 3 + major, minor, patch = unpack("BBB", response) + return (major, minor, patch) + +# Unpack from response: +# response = format_id (1) +# app_name_raw_len (1) +# app_name_raw (var) +# version_raw_len (1) +# version_raw (var) +# unused_len (1) +# unused (var) +def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]: + response, _ = pop_sized_buf_from_buffer(response, 1) + response, _, app_name_raw = pop_size_prefixed_buf_from_buf(response) + response, _, version_raw = pop_size_prefixed_buf_from_buf(response) + response, _, _ = pop_size_prefixed_buf_from_buf(response) + + assert len(response) == 0 + + return app_name_raw.decode("ascii"), version_raw.decode("ascii") + +# Unpack from response: +# response = pub_key_len (1) +# pub_key (var) +# chain_code_len (1) +# chain_code (var) +def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, bytes]: + response, pub_key_len, pub_key = pop_size_prefixed_buf_from_buf(response) + response, chain_code_len, chain_code = pop_size_prefixed_buf_from_buf(response) + + assert pub_key_len == 65 + assert chain_code_len == 32 + assert len(response) == 0 + + return pub_key_len, pub_key, chain_code_len, chain_code + +# Unpack from response: +# response = der_sig_len (1) +# der_sig (var) +# v (1) +def unpack_sign_tx_response(response: bytes) -> Tuple[int, bytes, int]: + response, der_sig_len, der_sig = pop_size_prefixed_buf_from_buf(response) + response, v = pop_sized_buf_from_buffer(response, 1) + + assert len(response) == 0 + + return der_sig_len, der_sig, int.from_bytes(v, byteorder='big') diff --git a/tests/application_client/boilerplate_transaction.py b/tests/application_client/boilerplate_transaction.py new file mode 100644 index 0000000..19f0625 --- /dev/null +++ b/tests/application_client/boilerplate_transaction.py @@ -0,0 +1,50 @@ +from io import BytesIO +from typing import Union + +from .boilerplate_utils import read, read_uint, read_varint, write_varint, UINT64_MAX + + +class TransactionError(Exception): + pass + + +class Transaction: + def __init__(self, + nonce: int, + to: Union[str, bytes], + value: int, + memo: str) -> None: + self.nonce: int = nonce + self.to: bytes = bytes.fromhex(to[2:]) if isinstance(to, str) else to + self.value: int = value + self.memo: bytes = memo.encode("ascii") + + if not 0 <= self.nonce <= UINT64_MAX: + raise TransactionError(f"Bad nonce: '{self.nonce}'!") + + if not 0 <= self.value <= UINT64_MAX: + raise TransactionError(f"Bad value: '{self.value}'!") + + if len(self.to) != 20: + raise TransactionError(f"Bad address: '{self.to.hex()}'!") + + def serialize(self) -> bytes: + return b"".join([ + self.nonce.to_bytes(8, byteorder="big"), + self.to, + self.value.to_bytes(8, byteorder="big"), + write_varint(len(self.memo)), + self.memo + ]) + + @classmethod + def from_bytes(cls, hexa: Union[bytes, BytesIO]): + buf: BytesIO = BytesIO(hexa) if isinstance(hexa, bytes) else hexa + + nonce: int = read_uint(buf, 64, byteorder="big") + to: bytes = read(buf, 20) + value: int = read_uint(buf, 64, byteorder="big") + memo_len: int = read_varint(buf) + memo: str = read(buf, memo_len).decode("ascii") + + return cls(nonce=nonce, to=to, value=value, memo=memo) diff --git a/tests/application_client/boilerplate_utils.py b/tests/application_client/boilerplate_utils.py new file mode 100644 index 0000000..fd96e62 --- /dev/null +++ b/tests/application_client/boilerplate_utils.py @@ -0,0 +1,61 @@ +from io import BytesIO +from typing import Optional, Literal + + +UINT64_MAX: int = 2**64-1 +UINT32_MAX: int = 2**32-1 +UINT16_MAX: int = 2**16-1 + + +def write_varint(n: int) -> bytes: + if n < 0xFC: + return n.to_bytes(1, byteorder="little") + + if n <= UINT16_MAX: + return b"\xFD" + n.to_bytes(2, byteorder="little") + + if n <= UINT32_MAX: + return b"\xFE" + n.to_bytes(4, byteorder="little") + + if n <= UINT64_MAX: + return b"\xFF" + n.to_bytes(8, byteorder="little") + + raise ValueError(f"Can't write to varint: '{n}'!") + + +def read_varint(buf: BytesIO, + prefix: Optional[bytes] = None) -> int: + b: bytes = prefix if prefix else buf.read(1) + + if not b: + raise ValueError(f"Can't read prefix: '{b.hex()}'!") + + n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1 + + b = buf.read(n) if n > 1 else b + + if len(b) != n: + raise ValueError("Can't read varint!") + + return int.from_bytes(b, byteorder="little") + + +def read(buf: BytesIO, size: int) -> bytes: + b: bytes = buf.read(size) + + if len(b) < size: + raise ValueError(f"Can't read {size} bytes in buffer!") + + return b + + +def read_uint(buf: BytesIO, + bit_len: int, + byteorder: Literal['big', 'little'] = 'little') -> int: + size: int = bit_len // 8 + b: bytes = buf.read(size) + + if len(b) < size: + raise ValueError(f"Can't read u{bit_len} in buffer!") + + return int.from_bytes(b, byteorder) diff --git a/tests/application_client/py.typed b/tests/application_client/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..a9ea72c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ + +########################### +### CONFIGURATION START ### +########################### + +# You can configure optional parameters by overriding the value of ragger.configuration.OPTIONAL_CONFIGURATION +# Please refer to ragger/conftest/configuration.py for their descriptions and accepted values + +######################### +### CONFIGURATION END ### +######################### + +# Pull all features from the base ragger conftest using the overridden configuration +pytest_plugins = ("ragger.conftest.base_conftest", ) diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..dd07dfb --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,4 @@ +pytest +ragger[speculos,ledgerwallet]>=1.11.4 +ecdsa>=0.16.1,<0.17.0 +pycryptodome diff --git a/tests/setup.cfg b/tests/setup.cfg new file mode 100644 index 0000000..2398a52 --- /dev/null +++ b/tests/setup.cfg @@ -0,0 +1,23 @@ +[tool:pytest] +addopts = --strict-markers + +[pylint] +disable = C0114, # missing-module-docstring + C0115, # missing-class-docstring + C0116, # missing-function-docstring + C0103, # invalid-name + R0801, # duplicate-code + R0913, # too-many-arguments + R0917 # too-many-positional-arguments + +max-line-length=120 +extension-pkg-whitelist=hid + +[pycodestyle] +max-line-length = 100 + +[mypy-hid.*] +ignore_missing_imports = True + +[mypy-pytest.*] +ignore_missing_imports = True diff --git a/tests/test_app_mainmenu.py b/tests/test_app_mainmenu.py new file mode 100644 index 0000000..d5ee01f --- /dev/null +++ b/tests/test_app_mainmenu.py @@ -0,0 +1,54 @@ +from ragger.firmware import Firmware +from ragger.navigator import Navigator, NavInsID, NavIns + + +# In this test we check the behavior of the device main menu +def test_app_mainmenu(firmware: Firmware, + navigator: Navigator, + test_name: str, + default_screenshot_path: str) -> None: + # Navigate in the main menu + instructions = [] + if firmware.is_nano: + instructions += [ + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, + NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, + ] + elif firmware is Firmware.STAX: + instructions += [ + NavInsID.USE_CASE_HOME_SETTINGS, + NavIns(NavInsID.TOUCH, (200, 113)), + NavIns(NavInsID.TOUCH, (200, 261)), + NavInsID.USE_CASE_CHOICE_CONFIRM, + NavIns(NavInsID.TOUCH, (200, 261)), + NavInsID.USE_CASE_SETTINGS_NEXT, + NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT + ] + elif firmware is Firmware.FLEX: + instructions += [ + NavInsID.USE_CASE_HOME_SETTINGS, + NavIns(NavInsID.TOUCH, (200, 113)), + NavIns(NavInsID.TOUCH, (200, 300)), + NavInsID.USE_CASE_CHOICE_CONFIRM, + NavIns(NavInsID.TOUCH, (200, 300)), + NavInsID.USE_CASE_SETTINGS_NEXT, + NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT + ] + + assert len(instructions) > 0 + navigator.navigate_and_compare(default_screenshot_path, test_name, instructions, + screen_change_before_first_instruction=False) diff --git a/tests/test_appname_cmd.py b/tests/test_appname_cmd.py new file mode 100644 index 0000000..f1eefb8 --- /dev/null +++ b/tests/test_appname_cmd.py @@ -0,0 +1,16 @@ +from ragger.backend.interface import BackendInterface + +from application_client.boilerplate_command_sender import BoilerplateCommandSender +from application_client.boilerplate_response_unpacker import unpack_get_app_name_response + +from utils import verify_name + + +# In this test we check that the GET_APP_NAME replies the application name +def test_app_name(backend: BackendInterface) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + # Send the GET_APP_NAME instruction to the app + response = client.get_app_name() + # Assert that we have received the correct appname + verify_name(unpack_get_app_name_response(response.data)) diff --git a/tests/test_error_cmd.py b/tests/test_error_cmd.py new file mode 100644 index 0000000..3d89a57 --- /dev/null +++ b/tests/test_error_cmd.py @@ -0,0 +1,59 @@ +import pytest + +from ragger.error import ExceptionRAPDU +from ragger.backend.interface import BackendInterface + +from application_client.boilerplate_command_sender import CLA, InsType, P1, P2, Errors + + +# Ensure the app returns an error when a bad CLA is used +def test_bad_cla(backend: BackendInterface) -> None: + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA + 1, ins=InsType.GET_VERSION) + assert e.value.status == Errors.SW_CLA_NOT_SUPPORTED + + +# Ensure the app returns an error when a bad INS is used +def test_bad_ins(backend: BackendInterface) -> None: + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=0xff) + assert e.value.status == Errors.SW_INS_NOT_SUPPORTED + + +# Ensure the app returns an error when a bad P1 or P2 is used +def test_wrong_p1p2(backend: BackendInterface) -> None: + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START + 1, p2=P2.P2_LAST) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START, p2=P2.P2_MORE) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START + 1, p2=P2.P2_LAST) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_MORE) + assert e.value.status == Errors.SW_WRONG_P1P2 + + +# Ensure the app returns an error when a bad data length is used +def test_wrong_data_length(backend: BackendInterface) -> None: + # APDUs must be at least 4 bytes: CLA, INS, P1, P2. + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange_raw(bytes.fromhex("E00300")) + assert e.value.status == Errors.SW_WRONG_DATA_LENGTH + # APDUs advertises a too long length + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange_raw(bytes.fromhex("E003000005")) + assert e.value.status == Errors.SW_WRONG_DATA_LENGTH + + +# Ensure there is no state confusion when trying wrong APDU sequences +def test_invalid_state(backend: BackendInterface) -> None: + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, + ins=InsType.SIGN_TX, + p1=P1.P1_START + 1, # Try to continue a flow instead of start a new one + p2=P2.P2_MORE, + data=b"abcde") # data is not parsed in this case + assert e.value.status == Errors.SW_BAD_STATE diff --git a/tests/test_name_version.py b/tests/test_name_version.py new file mode 100644 index 0000000..68e9c5e --- /dev/null +++ b/tests/test_name_version.py @@ -0,0 +1,18 @@ +from ragger.backend.interface import BackendInterface + +from application_client.boilerplate_command_sender import BoilerplateCommandSender +from application_client.boilerplate_response_unpacker import unpack_get_app_and_version_response + +from utils import verify_version, verify_name + +# Test a specific APDU asking BOLOS (and not the app) the name and version of the current app +def test_get_app_and_version(backend: BackendInterface) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + # Send the special instruction to BOLOS + response = client.get_app_and_version() + # Use an helper to parse the response, assert the values + app_name, version = unpack_get_app_and_version_response(response.data) + + verify_name(app_name) + verify_version(version) diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py new file mode 100644 index 0000000..92966db --- /dev/null +++ b/tests/test_pubkey_cmd.py @@ -0,0 +1,57 @@ +import pytest + +from ragger.bip import calculate_public_key_and_chaincode, CurveChoice +from ragger.error import ExceptionRAPDU +from ragger.backend.interface import BackendInterface +from ragger.navigator.navigation_scenario import NavigateWithScenario + +from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors +from application_client.boilerplate_response_unpacker import unpack_get_public_key_response + + +# In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode +def test_get_public_key_no_confirm(backend: BackendInterface) -> None: + path_list = [ + "m/44'/1'/0'/0/0", + "m/44'/1'/0/0/0", + "m/44'/1'/911'/0/0", + "m/44'/1'/255/255/255", + "m/44'/1'/2147483647/0/0/0/0/0/0/0" + ] + for path in path_list: + client = BoilerplateCommandSender(backend) + response = client.get_public_key(path=path).data + _, public_key, _, chain_code = unpack_get_public_key_response(response) + + ref_public_key, ref_chain_code = calculate_public_key_and_chaincode(CurveChoice.Secp256k1, path=path) + assert public_key.hex() == ref_public_key + assert chain_code.hex() == ref_chain_code + + +# In this test we check that the GET_PUBLIC_KEY works in confirmation mode +def test_get_public_key_confirm_accepted(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + client = BoilerplateCommandSender(backend) + path = "m/44'/1'/0'/0/0" + with client.get_public_key_with_confirmation(path=path): + scenario_navigator.address_review_approve() + + response = client.get_async_response().data + _, public_key, _, chain_code = unpack_get_public_key_response(response) + + ref_public_key, ref_chain_code = calculate_public_key_and_chaincode(CurveChoice.Secp256k1, path=path) + assert public_key.hex() == ref_public_key + assert chain_code.hex() == ref_chain_code + + +# In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses +def test_get_public_key_confirm_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + client = BoilerplateCommandSender(backend) + path = "m/44'/1'/0'/0/0" + + with pytest.raises(ExceptionRAPDU) as e: + with client.get_public_key_with_confirmation(path=path): + scenario_navigator.address_review_reject() + + # Assert that we have received a refusal + assert e.value.status == Errors.SW_DENY + assert len(e.value.data) == 0 diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py new file mode 100644 index 0000000..81ed8eb --- /dev/null +++ b/tests/test_sign_cmd.py @@ -0,0 +1,145 @@ +import pytest + +from ragger.backend.interface import BackendInterface +from ragger.error import ExceptionRAPDU +from ragger.firmware import Firmware +from ragger.navigator import Navigator, NavInsID +from ragger.navigator.navigation_scenario import NavigateWithScenario + +from application_client.boilerplate_transaction import Transaction +from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors +from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response +from utils import check_signature_validity + +# In this tests we check the behavior of the device when asked to sign a transaction + + +# In this test we send to the device a transaction to sign and validate it on screen +# The transaction is short and will be sent in one chunk +# We will ensure that the displayed information is correct by using screenshots comparison +def test_sign_tx_short_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + # The path used for this entire test + path: str = "m/44'/1'/0'/0/0" + + # First we need to get the public key of the device in order to build the transaction + rapdu = client.get_public_key(path=path) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + # Create the transaction that will be sent to the device for signing + transaction = Transaction( + nonce=1, + to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", + value=666, + memo="For u EthDev" + ).serialize() + + # Send the sign device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + with client.sign_tx(path=path, transaction=transaction): + # Validate the on-screen request by performing the navigation appropriate for this device + scenario_navigator.review_approve() + + # The device as yielded the result, parse it and ensure that the signature is correct + response = client.get_async_response().data + _, der_sig, _ = unpack_sign_tx_response(response) + assert check_signature_validity(public_key, der_sig, transaction) + + +# In this test we send to the device a transaction to trig a blind-signing flow +# The transaction is short and will be sent in one chunk +# We will ensure that the displayed information is correct by using screenshots comparison +def test_sign_tx_short_tx_blind_sign(firmware: Firmware, + backend: BackendInterface, + navigator: Navigator, + scenario_navigator: NavigateWithScenario, + test_name: str, + default_screenshot_path: str) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + # The path used for this entire test + path: str = "m/44'/1'/0'/0/0" + + # First we need to get the public key of the device in order to build the transaction + rapdu = client.get_public_key(path=path) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + # Create the transaction that will be sent to the device for signing + transaction = Transaction( + nonce=1, + to="0x0000000000000000000000000000000000000000", + value=0, + memo="Blind-sign" + ).serialize() + + # Send the sign device instruction. + valid_instruction = [NavInsID.RIGHT_CLICK] if firmware.is_nano else [NavInsID.USE_CASE_CHOICE_REJECT] + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + with client.sign_tx(path=path, transaction=transaction): + navigator.navigate_and_compare(default_screenshot_path, + test_name+"/part1", + valid_instruction, + screen_change_after_last_instruction=False) + + # Validate the on-screen request by performing the navigation appropriate for this device + scenario_navigator.review_approve() + + # The device as yielded the result, parse it and ensure that the signature is correct + response = client.get_async_response().data + _, der_sig, _ = unpack_sign_tx_response(response) + assert check_signature_validity(public_key, der_sig, transaction) + +# In this test se send to the device a transaction to sign and validate it on screen +# This test is mostly the same as the previous one but with different values. +# In particular the long memo will force the transaction to be sent in multiple chunks +def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + path: str = "m/44'/1'/0'/0/0" + + rapdu = client.get_public_key(path=path) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + transaction = Transaction( + nonce=1, + to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", + value=666, + memo=("This is a very long memo. " + "It will force the app client to send the serialized transaction to be sent in chunk. " + "As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. " + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, " + "dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.") + ).serialize() + + with client.sign_tx(path=path, transaction=transaction): + scenario_navigator.review_approve() + + response = client.get_async_response().data + _, der_sig, _ = unpack_sign_tx_response(response) + assert check_signature_validity(public_key, der_sig, transaction) + + +# Transaction signature refused test +# The test will ask for a transaction signature that will be refused on screen +def test_sign_tx_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + path: str = "m/44'/1'/0'/0/0" + + transaction = Transaction( + nonce=1, + to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", + value=666, + memo="This transaction will be refused by the user" + ).serialize() + + with pytest.raises(ExceptionRAPDU) as e: + with client.sign_tx(path=path, transaction=transaction): + scenario_navigator.review_reject() + + # Assert that we have received a refusal + assert e.value.status == Errors.SW_DENY + assert len(e.value.data) == 0 diff --git a/tests/test_version_cmd.py b/tests/test_version_cmd.py new file mode 100644 index 0000000..0f1d4be --- /dev/null +++ b/tests/test_version_cmd.py @@ -0,0 +1,16 @@ +from ragger.backend.interface import BackendInterface + +from application_client.boilerplate_command_sender import BoilerplateCommandSender +from application_client.boilerplate_response_unpacker import unpack_get_version_response + +from utils import verify_version + +# In this test we check the behavior of the device when asked to provide the app version +def test_version(backend: BackendInterface) -> None: + # Use the app interface instead of raw interface + client = BoilerplateCommandSender(backend) + # Send the GET_VERSION instruction + rapdu = client.get_version() + # Use an helper to parse the response, assert the values + MAJOR, MINOR, PATCH = unpack_get_version_response(rapdu.data) + verify_version(f"{MAJOR}.{MINOR}.{PATCH}") diff --git a/tests/usage.md b/tests/usage.md new file mode 100644 index 0000000..dc2fbfa --- /dev/null +++ b/tests/usage.md @@ -0,0 +1,78 @@ +# How to use the Ragger test framework + +This framework allows testing the application on the Speculos emulator or on a real device using LedgerComm or LedgerWallet + +## Quickly get started with Ragger and Speculos + +### Install ragger and dependencies + +```shell +pip install --extra-index-url https://test.pypi.org/simple/ -r requirements.txt +sudo apt-get update && sudo apt-get install qemu-user-static +``` + +### Compile the application + +The application to test must be compiled for all required devices. +You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`: + +```shell +docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest +cd # replace with the name of your app, (eg boilerplate) +docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest +make clean && make BOLOS_SDK=$_SDK # replace with one of [NANOX, NANOSP, STAX, FLEX] +exit +``` + +### Run a simple test using the Speculos emulator + +You can use the following command to get your first experience with Ragger and Speculos + +```shell +pytest -v --tb=short --device nanox --display +``` + +Or you can refer to the section `Available pytest options` to configure the options you want to use + +### Run a simple test using a real device + +The application to test must be loaded and started on a Ledger device plugged in USB. +You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`: + +```shell +docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest +cd app-/ # replace with the name of your app, (eg boilerplate) +docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest +make clean && make BOLOS_SDK=$_SDK load # replace with one of [NANOX, NANOSP, STAX, FLEX] +exit +``` + +You can use the following command to get your first experience with Ragger and Ledgerwallet on a NANOX. +Make sure that the device is plugged, unlocked, and that the tested application is open. + +```shell +pytest -v --tb=short --device nanox --backend ledgerwallet +``` + +Or you can refer to the section `Available pytest options` to configure the options you want to use + +## Available pytest options + +Standard useful pytest options + +```shell + -v formats the test summary in a readable way + -s enable logs for successful tests, on Speculos it will enable app logs if compiled with DEBUG=1 + -k only run the tests that contain in their names + --tb=short in case of errors, formats the test traceback in a readable way +``` + +Custom pytest options + +```shell + --device run the test on the specified device [nanox,nanosp,stax,flex,all]. This parameter is mandatory + --backend run the tests against the backend [speculos, ledgercomm, ledgerwallet]. Speculos is the default + --display on Speculos, enables the display of the app screen using QT + --golden_run on Speculos, screen comparison functions will save the current screen instead of comparing + --log_apdu_file log all apdu exchanges to the file in parameter. The previous file content is erased +``` diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..b342855 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,76 @@ +from pathlib import Path +from typing import List +import re +from Crypto.Hash import keccak + +from ecdsa.curves import SECP256k1 +from ecdsa.keys import VerifyingKey +from ecdsa.util import sigdecode_der + + +# Check if a signature of a given message is valid +def check_signature_validity(public_key: bytes, signature: bytes, message: bytes) -> bool: + pk: VerifyingKey = VerifyingKey.from_string( + public_key, + curve=SECP256k1, + hashfunc=None + ) + # Compute message hash (keccak_256) + k = keccak.new(digest_bits=256) + k.update(message) + message_hash = k.digest() + + return pk.verify_digest(signature=signature, + digest=message_hash, + sigdecode=sigdecode_der) + + +def verify_name(name: str) -> None: + """Verify the app name, based on defines in Makefile + + Args: + name (str): Name to be checked + """ + + name_str = "" + lines = _read_makefile() + name_re = re.compile(r"^APPNAME\s?=\s?\"?(?P\w+)\"?", re.I) + for line in lines: + info = name_re.match(line) + if info: + dinfo = info.groupdict() + name_str = dinfo["val"] + assert name == name_str + + +def verify_version(version: str) -> None: + """Verify the app version, based on defines in Makefile + + Args: + Version (str): Version to be checked + """ + + vers_dict = {} + vers_str = "" + lines = _read_makefile() + version_re = re.compile(r"^APPVERSION_(?P\w)\s?=\s?(?P\d*)", re.I) + for line in lines: + info = version_re.match(line) + if info: + dinfo = info.groupdict() + vers_dict[dinfo["part"]] = dinfo["val"] + try: + vers_str = f"{vers_dict['M']}.{vers_dict['N']}.{vers_dict['P']}" + except KeyError: + pass + assert version == vers_str + + +def _read_makefile() -> List[str]: + """Read lines from the parent Makefile """ + + parent = Path(__file__).parent.parent.resolve() + makefile = f"{parent}/Makefile" + with open(makefile, "r", encoding="utf-8") as f_p: + lines = f_p.readlines() + return lines From 81281227a658dbbc293b42f0c181c27789cc2dc6 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 13:20:45 +0100 Subject: [PATCH 03/33] refactor: update instruction types and error codes to match with the current app --- .../boilerplate_command_sender.py | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py index cb83ce7..84c3ca3 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/boilerplate_command_sender.py @@ -25,26 +25,46 @@ class P2(IntEnum): P2_MORE = 0x80 class InsType(IntEnum): - GET_VERSION = 0x03 - GET_APP_NAME = 0x04 - GET_PUBLIC_KEY = 0x05 - SIGN_TX = 0x06 + GET_APP_CONFIGURATION = 0x01 + GET_PUBLIC_KEY = 0x02 + SIGN_MESSAGE = 0x03 + GET_ADDRESS = 0X04 + SIGN_TRANSACTION = 0x05 class Errors(IntEnum): - SW_DENY = 0x6985 - SW_WRONG_P1P2 = 0x6A86 - SW_WRONG_DATA_LENGTH = 0x6A87 - SW_INS_NOT_SUPPORTED = 0x6D00 - SW_CLA_NOT_SUPPORTED = 0x6E00 - SW_WRONG_RESPONSE_LENGTH = 0xB000 - SW_DISPLAY_BIP32_PATH_FAIL = 0xB001 - SW_DISPLAY_ADDRESS_FAIL = 0xB002 - SW_DISPLAY_AMOUNT_FAIL = 0xB003 - SW_WRONG_TX_LENGTH = 0xB004 - SW_TX_PARSING_FAIL = 0xB005 - SW_TX_HASH_FAIL = 0xB006 - SW_BAD_STATE = 0xB007 - SW_SIGNATURE_FAIL = 0xB008 + SW_INVALID_DATA = 0x6B00, + SW_CELL_UNDERFLOW = 0x6B01, + SW_RANGE_CHECK_FAIL = 0x6B02, + SW_WRONG_LABEL = 0x6B03, + SW_INVALID_FLAG = 0x6B04, + SW_END_OF_STREAM = 0x6B05, + SW_SLICE_IS_EMPTY = 0x6B06, + SW_INVALID_KEY = 0x6B07, + SW_CELL_IS_EMPTY = 0x6B08, + SW_INVALID_HASH = 0x6B09, + SW_INVALID_CELL_INDEX = 0x6B10, + SW_INVALID_REQUEST = 0x6B11, + SW_INVALID_FUNCTION_ID = 0x6B12, + SW_INVALID_SRC_ADDRESS = 0x6B13, + SW_INVALID_WALLET_ID = 0x6B14, + SW_INVALID_WALLET_TYPE = 0x6B15, + SW_INVALID_TICKER_LENGTH = 0x6B16 + + # Status Word from boilerplate app + # SW_DENY = 0x6985 + # SW_WRONG_P1P2 = 0x6A86 + # SW_WRONG_DATA_LENGTH = 0x6A87 + # SW_INS_NOT_SUPPORTED = 0x6D00 + # SW_CLA_NOT_SUPPORTED = 0x6E00 + # SW_WRONG_RESPONSE_LENGTH = 0xB000 + # SW_DISPLAY_BIP32_PATH_FAIL = 0xB001 + # SW_DISPLAY_ADDRESS_FAIL = 0xB002 + # SW_DISPLAY_AMOUNT_FAIL = 0xB003 + # SW_WRONG_TX_LENGTH = 0xB004 + # SW_TX_PARSING_FAIL = 0xB005 + # SW_TX_HASH_FAIL = 0xB006 + # SW_BAD_STATE = 0xB007 + # SW_SIGNATURE_FAIL = 0xB008 def split_message(message: bytes, max_size: int) -> List[bytes]: From 9d16f284d3ebb083beda802b7643d6f9d7f76b43 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 13:31:30 +0100 Subject: [PATCH 04/33] refactor: rename all instances of 'boilerplate' to 'everscale' --- ...mmand_sender.py => everscale_command_sender.py} | 4 ++-- ..._unpacker.py => everscale_response_unpacker.py} | 0 ...ate_transaction.py => everscale_transaction.py} | 2 +- .../{boilerplate_utils.py => everscale_utils.py} | 0 tests/test_appname_cmd.py | 6 +++--- tests/test_error_cmd.py | 2 +- ...t_version_cmd.py => test_get_app_config_cmd.py} | 10 +++++----- tests/test_name_version.py | 6 +++--- tests/test_pubkey_cmd.py | 10 +++++----- tests/test_sign_cmd.py | 14 +++++++------- 10 files changed, 27 insertions(+), 27 deletions(-) rename tests/application_client/{boilerplate_command_sender.py => everscale_command_sender.py} (98%) rename tests/application_client/{boilerplate_response_unpacker.py => everscale_response_unpacker.py} (100%) rename tests/application_client/{boilerplate_transaction.py => everscale_transaction.py} (94%) rename tests/application_client/{boilerplate_utils.py => everscale_utils.py} (100%) rename tests/{test_version_cmd.py => test_get_app_config_cmd.py} (59%) diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/everscale_command_sender.py similarity index 98% rename from tests/application_client/boilerplate_command_sender.py rename to tests/application_client/everscale_command_sender.py index 84c3ca3..73093b5 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -50,7 +50,7 @@ class Errors(IntEnum): SW_INVALID_WALLET_TYPE = 0x6B15, SW_INVALID_TICKER_LENGTH = 0x6B16 - # Status Word from boilerplate app + # Status Word from everscale app # SW_DENY = 0x6985 # SW_WRONG_P1P2 = 0x6A86 # SW_WRONG_DATA_LENGTH = 0x6A87 @@ -71,7 +71,7 @@ def split_message(message: bytes, max_size: int) -> List[bytes]: return [message[x:x + max_size] for x in range(0, len(message), max_size)] -class BoilerplateCommandSender: +class EverscaleCommandSender: def __init__(self, backend: BackendInterface) -> None: self.backend = backend diff --git a/tests/application_client/boilerplate_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py similarity index 100% rename from tests/application_client/boilerplate_response_unpacker.py rename to tests/application_client/everscale_response_unpacker.py diff --git a/tests/application_client/boilerplate_transaction.py b/tests/application_client/everscale_transaction.py similarity index 94% rename from tests/application_client/boilerplate_transaction.py rename to tests/application_client/everscale_transaction.py index 19f0625..9ef3d17 100644 --- a/tests/application_client/boilerplate_transaction.py +++ b/tests/application_client/everscale_transaction.py @@ -1,7 +1,7 @@ from io import BytesIO from typing import Union -from .boilerplate_utils import read, read_uint, read_varint, write_varint, UINT64_MAX +from .everscale_utils import read, read_uint, read_varint, write_varint, UINT64_MAX class TransactionError(Exception): diff --git a/tests/application_client/boilerplate_utils.py b/tests/application_client/everscale_utils.py similarity index 100% rename from tests/application_client/boilerplate_utils.py rename to tests/application_client/everscale_utils.py diff --git a/tests/test_appname_cmd.py b/tests/test_appname_cmd.py index f1eefb8..277c58a 100644 --- a/tests/test_appname_cmd.py +++ b/tests/test_appname_cmd.py @@ -1,7 +1,7 @@ from ragger.backend.interface import BackendInterface -from application_client.boilerplate_command_sender import BoilerplateCommandSender -from application_client.boilerplate_response_unpacker import unpack_get_app_name_response +from application_client.everscale_command_sender import EverscaleCommandSender +from application_client.everscale_response_unpacker import unpack_get_app_name_response from utils import verify_name @@ -9,7 +9,7 @@ # In this test we check that the GET_APP_NAME replies the application name def test_app_name(backend: BackendInterface) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) # Send the GET_APP_NAME instruction to the app response = client.get_app_name() # Assert that we have received the correct appname diff --git a/tests/test_error_cmd.py b/tests/test_error_cmd.py index 3d89a57..12e3166 100644 --- a/tests/test_error_cmd.py +++ b/tests/test_error_cmd.py @@ -3,7 +3,7 @@ from ragger.error import ExceptionRAPDU from ragger.backend.interface import BackendInterface -from application_client.boilerplate_command_sender import CLA, InsType, P1, P2, Errors +from application_client.everscale_command_sender import CLA, InsType, P1, P2, Errors # Ensure the app returns an error when a bad CLA is used diff --git a/tests/test_version_cmd.py b/tests/test_get_app_config_cmd.py similarity index 59% rename from tests/test_version_cmd.py rename to tests/test_get_app_config_cmd.py index 0f1d4be..733d1ee 100644 --- a/tests/test_version_cmd.py +++ b/tests/test_get_app_config_cmd.py @@ -1,16 +1,16 @@ from ragger.backend.interface import BackendInterface -from application_client.boilerplate_command_sender import BoilerplateCommandSender -from application_client.boilerplate_response_unpacker import unpack_get_version_response +from application_client.everscale_command_sender import EverscaleCommandSender +from application_client.everscale_response_unpacker import unpack_get_version_response from utils import verify_version # In this test we check the behavior of the device when asked to provide the app version -def test_version(backend: BackendInterface) -> None: +def test_get_app_config(backend: BackendInterface) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) # Send the GET_VERSION instruction - rapdu = client.get_version() + rapdu = client.get_app_config() # Use an helper to parse the response, assert the values MAJOR, MINOR, PATCH = unpack_get_version_response(rapdu.data) verify_version(f"{MAJOR}.{MINOR}.{PATCH}") diff --git a/tests/test_name_version.py b/tests/test_name_version.py index 68e9c5e..ce3e067 100644 --- a/tests/test_name_version.py +++ b/tests/test_name_version.py @@ -1,14 +1,14 @@ from ragger.backend.interface import BackendInterface -from application_client.boilerplate_command_sender import BoilerplateCommandSender -from application_client.boilerplate_response_unpacker import unpack_get_app_and_version_response +from application_client.everscale_command_sender import EverscaleCommandSender +from application_client.everscale_response_unpacker import unpack_get_app_and_version_response from utils import verify_version, verify_name # Test a specific APDU asking BOLOS (and not the app) the name and version of the current app def test_get_app_and_version(backend: BackendInterface) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) # Send the special instruction to BOLOS response = client.get_app_and_version() # Use an helper to parse the response, assert the values diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py index 92966db..de3fade 100644 --- a/tests/test_pubkey_cmd.py +++ b/tests/test_pubkey_cmd.py @@ -5,8 +5,8 @@ from ragger.backend.interface import BackendInterface from ragger.navigator.navigation_scenario import NavigateWithScenario -from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors -from application_client.boilerplate_response_unpacker import unpack_get_public_key_response +from application_client.everscale_command_sender import EverscaleCommandSender, Errors +from application_client.everscale_response_unpacker import unpack_get_public_key_response # In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode @@ -19,7 +19,7 @@ def test_get_public_key_no_confirm(backend: BackendInterface) -> None: "m/44'/1'/2147483647/0/0/0/0/0/0/0" ] for path in path_list: - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) response = client.get_public_key(path=path).data _, public_key, _, chain_code = unpack_get_public_key_response(response) @@ -30,7 +30,7 @@ def test_get_public_key_no_confirm(backend: BackendInterface) -> None: # In this test we check that the GET_PUBLIC_KEY works in confirmation mode def test_get_public_key_confirm_accepted(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) path = "m/44'/1'/0'/0/0" with client.get_public_key_with_confirmation(path=path): scenario_navigator.address_review_approve() @@ -45,7 +45,7 @@ def test_get_public_key_confirm_accepted(backend: BackendInterface, scenario_nav # In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses def test_get_public_key_confirm_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) path = "m/44'/1'/0'/0/0" with pytest.raises(ExceptionRAPDU) as e: diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py index 81ed8eb..ebc3127 100644 --- a/tests/test_sign_cmd.py +++ b/tests/test_sign_cmd.py @@ -6,9 +6,9 @@ from ragger.navigator import Navigator, NavInsID from ragger.navigator.navigation_scenario import NavigateWithScenario -from application_client.boilerplate_transaction import Transaction -from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors -from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response +from application_client.everscale_transaction import Transaction +from application_client.everscale_command_sender import EverscaleCommandSender, Errors +from application_client.everscale_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response from utils import check_signature_validity # In this tests we check the behavior of the device when asked to sign a transaction @@ -19,7 +19,7 @@ # We will ensure that the displayed information is correct by using screenshots comparison def test_sign_tx_short_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) # The path used for this entire test path: str = "m/44'/1'/0'/0/0" @@ -58,7 +58,7 @@ def test_sign_tx_short_tx_blind_sign(firmware: Firmware, test_name: str, default_screenshot_path: str) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) # The path used for this entire test path: str = "m/44'/1'/0'/0/0" @@ -97,7 +97,7 @@ def test_sign_tx_short_tx_blind_sign(firmware: Firmware, # In particular the long memo will force the transaction to be sent in multiple chunks def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) path: str = "m/44'/1'/0'/0/0" rapdu = client.get_public_key(path=path) @@ -126,7 +126,7 @@ def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: Navigate # The test will ask for a transaction signature that will be refused on screen def test_sign_tx_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) + client = EverscaleCommandSender(backend) path: str = "m/44'/1'/0'/0/0" transaction = Transaction( From dd8b75c5491688624d4771ae2c637b7be67f727a Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 12:19:11 +0100 Subject: [PATCH 05/33] ops: add the ci workflow from the boilerplate app --- .../workflows/build_and_functional_tests.yml | 43 +++++++++++++ .github/workflows/cflite_cron.yml | 40 ++++++++++++ .github/workflows/cflite_pr.yml | 43 +++++++++++++ .github/workflows/codeql_checks.yml | 45 ++++++++++++++ .github/workflows/coding_style_checks.yml | 25 ++++++++ .../workflows/documentation_generation.yml | 29 +++++++++ .github/workflows/misspellings_checks.yml | 28 +++++++++ .github/workflows/python_client_checks.yml | 41 +++++++++++++ .github/workflows/unit_tests.yml | 61 +++++++++++++++++++ 9 files changed, 355 insertions(+) create mode 100644 .github/workflows/build_and_functional_tests.yml create mode 100644 .github/workflows/cflite_cron.yml create mode 100644 .github/workflows/cflite_pr.yml create mode 100644 .github/workflows/codeql_checks.yml create mode 100644 .github/workflows/coding_style_checks.yml create mode 100644 .github/workflows/documentation_generation.yml create mode 100644 .github/workflows/misspellings_checks.yml create mode 100644 .github/workflows/python_client_checks.yml create mode 100644 .github/workflows/unit_tests.yml diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml new file mode 100644 index 0000000..696f27c --- /dev/null +++ b/.github/workflows/build_and_functional_tests.yml @@ -0,0 +1,43 @@ +name: Build and run functional tests using ragger through reusable workflow + +# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation. +# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the +# resulting binaries. +# It then calls another reusable workflow to run the Ragger tests on the compiled application binary. +# +# The build part of this workflow is mandatory, this ensures that the app will be deployable in the Ledger App Store. +# While the test part of this workflow is optional, having functional testing on your application is mandatory and this workflow and +# tooling environment is meant to be easy to use and adapt after forking your application + +on: + workflow_dispatch: + inputs: + golden_run: + type: choice + required: true + default: 'Raise an error (default)' + description: CI behavior if the test snapshots are different than expected. + options: + - 'Raise an error (default)' + - 'Open a PR' + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + build_application: + name: Build application using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "compiled_app_binaries" + + ragger_tests: + name: Run ragger tests using the reusable workflow + needs: build_application + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1 + with: + download_app_binaries_artifact: "compiled_app_binaries" + regenerate_snapshots: ${{ inputs.golden_run == 'Open a PR' }} diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml new file mode 100644 index 0000000..17c1e65 --- /dev/null +++ b/.github/workflows/cflite_cron.yml @@ -0,0 +1,40 @@ +name: ClusterFuzzLite cron tasks +on: + workflow_dispatch: + push: + branches: + - main # Use your actual default branch here. + schedule: + - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday +permissions: read-all +jobs: + Fuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - mode: batch + sanitizer: address + - mode: batch + sanitizer: memory + - mode: prune + sanitizer: address + - mode: coverage + sanitizer: coverage + steps: + - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + language: c # Change this to the language you are fuzzing. + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: ${{ matrix.mode }} + sanitizer: ${{ matrix.sanitizer }} diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 0000000..09f91da --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,43 @@ +name: ClusterFuzzLite PR fuzzing +on: + pull_request: + paths: + - '**' +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] # Override this with the sanitizers you want. + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c # Change this to the language you are fuzzing. + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml new file mode 100644 index 0000000..cc2aae4 --- /dev/null +++ b/.github/workflows/codeql_checks.yml @@ -0,0 +1,45 @@ +name: "CodeQL" + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + # Excluded path: add the paths you want to ignore instead of deleting the workflow + paths-ignore: + - '.github/workflows/*.yml' + - 'tests/*' + +jobs: + analyse: + name: Analyse + strategy: + fail-fast: false + matrix: + sdk: ["$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK"] + # 'cpp' covers C and C++ + language: ['cpp'] + runs-on: ubuntu-latest + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: security-and-quality + + # CodeQL will create the database during the compilation + - name: Build + run: | + make BOLOS_SDK=${{ matrix.sdk }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml new file mode 100644 index 0000000..7927239 --- /dev/null +++ b/.github/workflows/coding_style_checks.yml @@ -0,0 +1,25 @@ +name: Run coding style check through reusable workflow + +# This workflow will run linting checks to ensure a level of uniformization among all Ledger applications. +# +# The presence of this workflow is mandatory as a minimal level of linting is required. +# You are however free to modify the content of the .clang-format file and thus the coding style of your application. +# We simply ask you to not diverge too much from the linting of the everscale application. + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + check_linting: + name: Check linting using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1 + with: + source: './src' + extensions: 'h,c' + version: 12 diff --git a/.github/workflows/documentation_generation.yml b/.github/workflows/documentation_generation.yml new file mode 100644 index 0000000..31b1efb --- /dev/null +++ b/.github/workflows/documentation_generation.yml @@ -0,0 +1,29 @@ +name: Generate project documentation + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + job_generate_doc: + name: Generate project documentation + runs-on: ubuntu-latest + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: HTML documentation + run: doxygen .doxygen/Doxyfile + + - uses: actions/upload-artifact@v4 + with: + name: documentation + path: doc/html diff --git a/.github/workflows/misspellings_checks.yml b/.github/workflows/misspellings_checks.yml new file mode 100644 index 0000000..f38799e --- /dev/null +++ b/.github/workflows/misspellings_checks.yml @@ -0,0 +1,28 @@ +name: Misspellings checks + +# This workflow performs some misspelling checks on the repository +# It is there to help us maintain a level of quality in our codebase and does not have to be kept on forked +# applications. + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + misspell: + name: Check misspellings + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Check misspellings + uses: codespell-project/actions-codespell@v2 + with: + builtin: clear,rare + check_filenames: true diff --git a/.github/workflows/python_client_checks.yml b/.github/workflows/python_client_checks.yml new file mode 100644 index 0000000..db60fd7 --- /dev/null +++ b/.github/workflows/python_client_checks.yml @@ -0,0 +1,41 @@ +name: Checks on the Python client + +# This workflow performs some checks on the Python client used by the everscale tests +# It is there to help us maintain a level of quality in our codebase and does not have to be kept on forked +# applications. + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + lint: + name: everscale client linting + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Installing PIP dependencies + run: | + pip install pylint + pip install -r tests/requirements.txt + - name: Lint Python code + run: pylint --rc tests/setup.cfg tests/application_client/ + + mypy: + name: Type checking + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Installing PIP dependencies + run: | + pip install mypy + pip install -r tests/requirements.txt + - name: Mypy type checking + run: mypy tests/application_client/ diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml new file mode 100644 index 0000000..4eec9af --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,61 @@ +name: Unit testing with Codecov coverage checking + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + job_unit_test: + name: Unit test + runs-on: ubuntu-latest + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest + + steps: + - name: Clone + uses: actions/checkout@v4 + + - name: Clone SDK + uses: actions/checkout@v4 + with: + repository: ledgerHQ/ledger-secure-sdk + path: sdk + + - name: Build unit tests + run: | + cd unit-tests/ + export BOLOS_SDK=../sdk + cmake -Bbuild -H. && make -C build && make -C build test + + - name: Generate code coverage + run: | + cd unit-tests/ + lcov --directory . -b "$(realpath build/)" --capture --initial -o coverage.base && \ + lcov --rc lcov_branch_coverage=1 --directory . -b "$(realpath build/)" --capture -o coverage.capture && \ + lcov --directory . -b "$(realpath build/)" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info && \ + lcov --directory . -b "$(realpath build/)" --remove coverage.info '*/unit-tests/*' -o coverage.info && \ + genhtml coverage.info -o coverage + + - uses: actions/upload-artifact@v4 + with: + name: code-coverage + path: unit-tests/coverage + + - name: Install codecov dependencies + run: apk update && apk add curl gpg + + - name: Upload to codecov.io + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: ./unit-tests/coverage.info + flags: unittests + name: codecov-app-everscale + fail_ci_if_error: true + verbose: true From 26087f55a22e1e9804e71c00927f8bb9288cc024 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 14:25:11 +0100 Subject: [PATCH 06/33] build: remove "Pending review" --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a679a22..85b9957 100644 --- a/Makefile +++ b/Makefile @@ -28,9 +28,9 @@ else endif APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) -# Pending review parameters -APP_LOAD_PARAMS += --tlvraw 9F:01 -DEFINES += HAVE_PENDING_REVIEW_SCREEN +# # Pending review parameters +# APP_LOAD_PARAMS += --tlvraw 9F:01 +# DEFINES += HAVE_PENDING_REVIEW_SCREEN ################## # Define Version # From e819bcac429c0d7aed9d8d375c641c43f57228be Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 14:29:14 +0100 Subject: [PATCH 07/33] chore: update .gitignore and ledger_app.toml --- .gitignore | 2 ++ ledger_app.toml | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0666ff3..97e91e5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ dist *.spec *.DS_Store client/target + +__pycache__ \ No newline at end of file diff --git a/ledger_app.toml b/ledger_app.toml index 8f4c403..e6634a3 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -1,4 +1,7 @@ [app] build_directory = "./" sdk = "C" -devices = ["nanos", "nanox", "nanos+"] +devices = ["nanos+", "nanox"] + +[tests] +pytest_directory = "./tests/" From a507a330dc1e516a2644bc6fbbc3222c7e595ad2 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 16:12:40 +0100 Subject: [PATCH 08/33] test: add active_test_scope marker for pytest --- tests/conftest.py | 10 ++++++++++ tests/setup.cfg | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index a9ea72c..76b5e0c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,4 @@ +from ragger.conftest import configuration ########################### ### CONFIGURATION START ### @@ -6,6 +7,15 @@ # You can configure optional parameters by overriding the value of ragger.configuration.OPTIONAL_CONFIGURATION # Please refer to ragger/conftest/configuration.py for their descriptions and accepted values +# Define pytest markers +def pytest_configure(config): + config.addinivalue_line( + "markers", + "active_test_scope: marks tests related to application name functionality", + ) + # Add more markers here as needed + + ######################### ### CONFIGURATION END ### ######################### diff --git a/tests/setup.cfg b/tests/setup.cfg index 2398a52..2d024b3 100644 --- a/tests/setup.cfg +++ b/tests/setup.cfg @@ -1,5 +1,5 @@ [tool:pytest] -addopts = --strict-markers +addopts = --strict-markers -m active_test_scope [pylint] disable = C0114, # missing-module-docstring From 4a94604478332d891013633c559879c59cee0337 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 16:13:08 +0100 Subject: [PATCH 09/33] test: add test for app configuration command --- tests/application_client/everscale_command_sender.py | 4 ++-- tests/{test_get_app_config_cmd.py => test_app_config_cmd.py} | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) rename tests/{test_get_app_config_cmd.py => test_app_config_cmd.py} (94%) diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 73093b5..011fecd 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -84,9 +84,9 @@ def get_app_and_version(self) -> RAPDU: data=b"") - def get_version(self) -> RAPDU: + def get_app_config(self) -> RAPDU: return self.backend.exchange(cla=CLA, - ins=InsType.GET_VERSION, + ins=InsType.GET_APP_CONFIGURATION, p1=P1.P1_START, p2=P2.P2_LAST, data=b"") diff --git a/tests/test_get_app_config_cmd.py b/tests/test_app_config_cmd.py similarity index 94% rename from tests/test_get_app_config_cmd.py rename to tests/test_app_config_cmd.py index 733d1ee..b272b86 100644 --- a/tests/test_get_app_config_cmd.py +++ b/tests/test_app_config_cmd.py @@ -1,3 +1,4 @@ +import pytest from ragger.backend.interface import BackendInterface from application_client.everscale_command_sender import EverscaleCommandSender @@ -6,6 +7,7 @@ from utils import verify_version # In this test we check the behavior of the device when asked to provide the app version +@pytest.mark.active_test_scope def test_get_app_config(backend: BackendInterface) -> None: # Use the app interface instead of raw interface client = EverscaleCommandSender(backend) From 25dcc40a1b9e8460af616293bfadda437c6ff001 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 18:34:02 +0100 Subject: [PATCH 10/33] chore: enhance .gitignore with more comprehensive file exclusions --- .gitignore | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 97e91e5..581399e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,34 @@ +# Build and compilation directories (Répertoires de compilation) bin debug dep obj dev-env + +# Generated source files src/glyphs.c src/glyphs.h + +# IDE/editor specific files .idea .vscode gitignore + +# Dependency directories node_modules + +# Log files and test specifications *.log* +*.spec + +# Build output and distribution directories build dist -*.spec -*.DS_Store client/target -__pycache__ \ No newline at end of file +# Operating system files +*.DS_Store + +# Python cache and temporary files +__pycache__ +snapshots-tmp \ No newline at end of file From 9f90c9b43823c55c09ca8d318afb6950a9b3c7f6 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 6 Feb 2025 18:37:00 +0100 Subject: [PATCH 11/33] test: update public key retrieval tests for Everscale app - Modify public key tests to use account number instead of derivation path - Switch to Ed25519Slip curve for public key calculation - Update response unpacking to handle 32-byte public keys - Add snapshot images for confirmation tests - Add active test scope markers --- .../everscale_command_sender.py | 13 +++--- .../everscale_response_unpacker.py | 6 +-- .../00000.png | Bin 0 -> 904 bytes .../00001.png | Bin 0 -> 556 bytes .../00002.png | Bin 0 -> 369 bytes .../00003.png | Bin 0 -> 356 bytes .../00004.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 904 bytes .../00001.png | Bin 0 -> 556 bytes .../00002.png | Bin 0 -> 369 bytes .../00003.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 904 bytes .../00001.png | Bin 0 -> 556 bytes .../00002.png | Bin 0 -> 369 bytes .../00003.png | Bin 0 -> 356 bytes .../00004.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 904 bytes .../00001.png | Bin 0 -> 556 bytes .../00002.png | Bin 0 -> 369 bytes .../00003.png | Bin 0 -> 382 bytes tests/test_pubkey_cmd.py | 44 ++++++++++-------- 21 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00004.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 011fecd..1510b60 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -48,10 +48,9 @@ class Errors(IntEnum): SW_INVALID_SRC_ADDRESS = 0x6B13, SW_INVALID_WALLET_ID = 0x6B14, SW_INVALID_WALLET_TYPE = 0x6B15, - SW_INVALID_TICKER_LENGTH = 0x6B16 - + SW_INVALID_TICKER_LENGTH = 0x6B16, + SW_DENY = 0x6985, # Status Word from everscale app - # SW_DENY = 0x6985 # SW_WRONG_P1P2 = 0x6A86 # SW_WRONG_DATA_LENGTH = 0x6A87 # SW_INS_NOT_SUPPORTED = 0x6D00 @@ -100,21 +99,21 @@ def get_app_name(self) -> RAPDU: data=b"") - def get_public_key(self, path: str) -> RAPDU: + def get_public_key(self, account_number: int) -> RAPDU: return self.backend.exchange(cla=CLA, ins=InsType.GET_PUBLIC_KEY, p1=P1.P1_START, p2=P2.P2_LAST, - data=pack_derivation_path(path)) + data=account_number.to_bytes(4, "big")) @contextmanager - def get_public_key_with_confirmation(self, path: str) -> Generator[None, None, None]: + def get_public_key_with_confirmation(self, account_number: int) -> Generator[None, None, None]: with self.backend.exchange_async(cla=CLA, ins=InsType.GET_PUBLIC_KEY, p1=P1.P1_CONFIRM, p2=P2.P2_LAST, - data=pack_derivation_path(path)) as response: + data=account_number.to_bytes(4, "big")) as response: yield response diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py index 5d1f748..9cc096a 100644 --- a/tests/application_client/everscale_response_unpacker.py +++ b/tests/application_client/everscale_response_unpacker.py @@ -49,13 +49,11 @@ def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]: # chain_code (var) def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, bytes]: response, pub_key_len, pub_key = pop_size_prefixed_buf_from_buf(response) - response, chain_code_len, chain_code = pop_size_prefixed_buf_from_buf(response) - assert pub_key_len == 65 - assert chain_code_len == 32 + assert pub_key_len == 32 assert len(response) == 0 - return pub_key_len, pub_key, chain_code_len, chain_code + return pub_key_len, pub_key # Unpack from response: # response = der_sig_len (1) diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..a63f85f1db8b849a5dcbea69fdefdc20a1688f58 GIT binary patch literal 904 zcmV;319$w1P)8GLwKmkH`Ak$EC#E_E*H^E)Hz+84Xmjkj19-@3^!2iC3w87M$~`iC%H8O9Meo1) zhFE2f0|FL+CVX#V{;joSK$y+IZp*VL1Raju7Q&1kh<35Jw-2X7PzU&oaVMWRW%jJv zYVU4)&;e?SMsA|MzHU?z$q65YaQL3f)j*ezNZE714+kV&*N)}O_wZT>I*GMFyN)lJ z=D+z4z}vqlilRWz05yhUy-+Pt6;qHujQOjo#_)xgoekq7E>?k53-NqYh_pBSL3C*8 zUs!8YGkq)lR|lF48Jo$mtl=!)NkgqoLCWg~4yYFS7XSiB3)-$d;jysr`PSQljjvy3 z90v$>R|TBf)sodYgy-DN{-|p)kkg&Auf zc_S9U&09vu#O7K_oWd3+_ewSm1smTrktq+Sp>Con#&YMyTL{w7C!Qk38nFOa?4*3~ zKIMZqsnvgzTKzYfSKmxSmqb3RGLtwi9px+=m~42omeg*+prZdJfp!g7g2h?yYZK3CM9LFiusIpEP7)|%%-BU)M}Da<{$4yFUn%SLDX{q#U1%s_q`dT}Bj zE&;uf`5%*pVw1*8c{P{MvqfQ16h%=KMRB=*9{_|vH|Jwsi?1e&mz{c&@-0Xo`Ep(% z&Ssyy(y3~t^JyNJjF&7WfN8sGJZ=kGxy@ZIWP=(?IvJ=s0_FhuYtA)4<%d}vYxQGV zW6}~a;;sGjg(SWM0_W*b>e?l|tPb73iXIq!RE*e$A8&~d*b-(G-vP1Z-&-Y)kY!1H2u=wA0002sIA4*$Ip_N8bzQb) zV^Cid4V-?a$vGES(~sN-u@9kk-;J*(7s!> zE=yf&*H0xD#K8$qG=3HoVB+@1 z5WlzP;d9PGHSo-vwTn<%B0-0>TcZi12$2(yaj?K5M2>t9T zfVe+%c2LRhP*s|piC=|!`6?gkl|u}^zDrz@LjMEa9And!7O8pM$!jF&BwBV>DM`@J zpPd1A`vU+#+OY=o=O@~ssdk<-JQ3>mxWl6)F$UwJwsCs*6-C^Mi)V-Z2hm>hVEeRx zdTL*;e8xZFckhuY_Vxby<7kmyUc~ciZLDphxoQS_Hm2Gs`p0yYI7uH#kW;~)y3z*L zXs!%higRcNI1yJ@alM^zCE|PuTGwFhY}oQfY%av7DcjMH#_iG`Eouu8yvMDf_J*>y zOx+VU1C7{j5BG~O&vN1^n15xOW02l6J@wB~lT7xHA*7n@ABGyd5>)7w43bO@wnBOV u0000000000000000000000000w($$(`{Y7*AFC$-0000ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd127e517c190a1684db420b839a65dd8776a10 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`htba4!+nDh2#AYZeBfa}G~ z%X2sUSKT3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o8GLwKmkH`Ak$EC#E_E*H^E)Hz+84Xmjkj19-@3^!2iC3w87M$~`iC%H8O9Meo1) zhFE2f0|FL+CVX#V{;joSK$y+IZp*VL1Raju7Q&1kh<35Jw-2X7PzU&oaVMWRW%jJv zYVU4)&;e?SMsA|MzHU?z$q65YaQL3f)j*ezNZE714+kV&*N)}O_wZT>I*GMFyN)lJ z=D+z4z}vqlilRWz05yhUy-+Pt6;qHujQOjo#_)xgoekq7E>?k53-NqYh_pBSL3C*8 zUs!8YGkq)lR|lF48Jo$mtl=!)NkgqoLCWg~4yYFS7XSiB3)-$d;jysr`PSQljjvy3 z90v$>R|TBf)sodYgy-DN{-|p)kkg&Auf zc_S9U&09vu#O7K_oWd3+_ewSm1smTrktq+Sp>Con#&YMyTL{w7C!Qk38nFOa?4*3~ zKIMZqsnvgzTKzYfSKmxSmqb3RGLtwi9px+=m~42omeg*+prZdJfp!g7g2h?yYZK3CM9LFiusIpEP7)|%%-BU)M}Da<{$4yFUn%SLDX{q#U1%s_q`dT}Bj zE&;uf`5%*pVw1*8c{P{MvqfQ16h%=KMRB=*9{_|vH|Jwsi?1e&mz{c&@-0Xo`Ep(% z&Ssyy(y3~t^JyNJjF&7WfN8sGJZ=kGxy@ZIWP=(?IvJ=s0_FhuYtA)4<%d}vYxQGV zW6}~a;;sGjg(SWM0_W*b>e?l|tPb73iXIq!RE*e$A8&~d*b-(G-vP1Z-&-Y)kY!1H2u=wA0002sIA4*$Ip_N8bzQb) zV^Cid4V-?a$vGES(~sN-u@9kk-;J*(7s!> zE=yf&*H0xD#K8$qG=3HoVB+@1 z5WlzP;d9PGHSo-vwTn<%B0-0>TcZi12$2(yaj?K5M2>t9T zfVe+%c2LRhP*s|piC=|!`6?gkl|u}^zDrz@LjMEa9And!7O8pM$!jF&BwBV>DM`@J zpPd1A`vU+#+OY=o=O@~ssdk<-JQ3>mxWl6)F$UwJwsCs*6-C^Mi)V-Z2hm>hVEeRx zdTL*;e8xZFckhuY_Vxby<7kmyUc~ciZLDphxoQS_Hm2Gs`p0yYI7uH#kW;~)y3z*L zXs!%higRcNI1yJ@alM^zCE|PuTGwFhY}oQfY%av7DcjMH#_iG`Eouu8yvMDf_J*>y zOx+VU1C7{j5BG~O&vN1^n15xOW02l6J@wB~lT7xHA*7n@ABGyd5>)7w43bO@wnBOV u0000000000000000000000000w($$(`{Y7*AFC$-0000ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..a58590b988714545e7960f7f400f360ffc5de41f GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9hba4!+nDh2#bl+hG9*4k? zQuR0Wo;SViCn%lTo!KM1sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o8GLwKmkH`Ak$EC#E_E*H^E)Hz+84Xmjkj19-@3^!2iC3w87M$~`iC%H8O9Meo1) zhFE2f0|FL+CVX#V{;joSK$y+IZp*VL1Raju7Q&1kh<35Jw-2X7PzU&oaVMWRW%jJv zYVU4)&;e?SMsA|MzHU?z$q65YaQL3f)j*ezNZE714+kV&*N)}O_wZT>I*GMFyN)lJ z=D+z4z}vqlilRWz05yhUy-+Pt6;qHujQOjo#_)xgoekq7E>?k53-NqYh_pBSL3C*8 zUs!8YGkq)lR|lF48Jo$mtl=!)NkgqoLCWg~4yYFS7XSiB3)-$d;jysr`PSQljjvy3 z90v$>R|TBf)sodYgy-DN{-|p)kkg&Auf zc_S9U&09vu#O7K_oWd3+_ewSm1smTrktq+Sp>Con#&YMyTL{w7C!Qk38nFOa?4*3~ zKIMZqsnvgzTKzYfSKmxSmqb3RGLtwi9px+=m~42omeg*+prZdJfp!g7g2h?yYZK3CM9LFiusIpEP7)|%%-BU)M}Da<{$4yFUn%SLDX{q#U1%s_q`dT}Bj zE&;uf`5%*pVw1*8c{P{MvqfQ16h%=KMRB=*9{_|vH|Jwsi?1e&mz{c&@-0Xo`Ep(% z&Ssyy(y3~t^JyNJjF&7WfN8sGJZ=kGxy@ZIWP=(?IvJ=s0_FhuYtA)4<%d}vYxQGV zW6}~a;;sGjg(SWM0_W*b>e?l|tPb73iXIq!RE*e$A8&~d*b-(G-vP1Z-&-Y)kY!1H2u=wA0002sIA4*$Ip_N8bzQb) zV^Cid4V-?a$vGES(~sN-u@9kk-;J*(7s!> zE=yf&*H0xD#K8$qG=3HoVB+@1 z5WlzP;d9PGHSo-vwTn<%B0-0>TcZi12$2(yaj?K5M2>t9T zfVe+%c2LRhP*s|piC=|!`6?gkl|u}^zDrz@LjMEa9And!7O8pM$!jF&BwBV>DM`@J zpPd1A`vU+#+OY=o=O@~ssdk<-JQ3>mxWl6)F$UwJwsCs*6-C^Mi)V-Z2hm>hVEeRx zdTL*;e8xZFckhuY_Vxby<7kmyUc~ciZLDphxoQS_Hm2Gs`p0yYI7uH#kW;~)y3z*L zXs!%higRcNI1yJ@alM^zCE|PuTGwFhY}oQfY%av7DcjMH#_iG`Eouu8yvMDf_J*>y zOx+VU1C7{j5BG~O&vN1^n15xOW02l6J@wB~lT7xHA*7n@ABGyd5>)7w43bO@wnBOV u0000000000000000000000000w($$(`{Y7*AFC$-0000ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd127e517c190a1684db420b839a65dd8776a10 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`htba4!+nDh2#AYZeBfa}G~ z%X2sUSKT3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o8GLwKmkH`Ak$EC#E_E*H^E)Hz+84Xmjkj19-@3^!2iC3w87M$~`iC%H8O9Meo1) zhFE2f0|FL+CVX#V{;joSK$y+IZp*VL1Raju7Q&1kh<35Jw-2X7PzU&oaVMWRW%jJv zYVU4)&;e?SMsA|MzHU?z$q65YaQL3f)j*ezNZE714+kV&*N)}O_wZT>I*GMFyN)lJ z=D+z4z}vqlilRWz05yhUy-+Pt6;qHujQOjo#_)xgoekq7E>?k53-NqYh_pBSL3C*8 zUs!8YGkq)lR|lF48Jo$mtl=!)NkgqoLCWg~4yYFS7XSiB3)-$d;jysr`PSQljjvy3 z90v$>R|TBf)sodYgy-DN{-|p)kkg&Auf zc_S9U&09vu#O7K_oWd3+_ewSm1smTrktq+Sp>Con#&YMyTL{w7C!Qk38nFOa?4*3~ zKIMZqsnvgzTKzYfSKmxSmqb3RGLtwi9px+=m~42omeg*+prZdJfp!g7g2h?yYZK3CM9LFiusIpEP7)|%%-BU)M}Da<{$4yFUn%SLDX{q#U1%s_q`dT}Bj zE&;uf`5%*pVw1*8c{P{MvqfQ16h%=KMRB=*9{_|vH|Jwsi?1e&mz{c&@-0Xo`Ep(% z&Ssyy(y3~t^JyNJjF&7WfN8sGJZ=kGxy@ZIWP=(?IvJ=s0_FhuYtA)4<%d}vYxQGV zW6}~a;;sGjg(SWM0_W*b>e?l|tPb73iXIq!RE*e$A8&~d*b-(G-vP1Z-&-Y)kY!1H2u=wA0002sIA4*$Ip_N8bzQb) zV^Cid4V-?a$vGES(~sN-u@9kk-;J*(7s!> zE=yf&*H0xD#K8$qG=3HoVB+@1 z5WlzP;d9PGHSo-vwTn<%B0-0>TcZi12$2(yaj?K5M2>t9T zfVe+%c2LRhP*s|piC=|!`6?gkl|u}^zDrz@LjMEa9And!7O8pM$!jF&BwBV>DM`@J zpPd1A`vU+#+OY=o=O@~ssdk<-JQ3>mxWl6)F$UwJwsCs*6-C^Mi)V-Z2hm>hVEeRx zdTL*;e8xZFckhuY_Vxby<7kmyUc~ciZLDphxoQS_Hm2Gs`p0yYI7uH#kW;~)y3z*L zXs!%higRcNI1yJ@alM^zCE|PuTGwFhY}oQfY%av7DcjMH#_iG`Eouu8yvMDf_J*>y zOx+VU1C7{j5BG~O&vN1^n15xOW02l6J@wB~lT7xHA*7n@ABGyd5>)7w43bO@wnBOV u0000000000000000000000000w($$(`{Y7*AFC$-0000ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..a58590b988714545e7960f7f400f360ffc5de41f GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9hba4!+nDh2#bl+hG9*4k? zQuR0Wo;SViCn%lTo!KM1sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o None: - path_list = [ - "m/44'/1'/0'/0/0", - "m/44'/1'/0/0/0", - "m/44'/1'/911'/0/0", - "m/44'/1'/255/255/255", - "m/44'/1'/2147483647/0/0/0/0/0/0/0" + account_number_list = [ + 0, + 1, + 911, + 255, + 2147483647 ] - for path in path_list: + for account_number in account_number_list: client = EverscaleCommandSender(backend) - response = client.get_public_key(path=path).data - _, public_key, _, chain_code = unpack_get_public_key_response(response) + response = client.get_public_key(account_number=account_number).data + _, public_key = unpack_get_public_key_response(response) - ref_public_key, ref_chain_code = calculate_public_key_and_chaincode(CurveChoice.Secp256k1, path=path) - assert public_key.hex() == ref_public_key - assert chain_code.hex() == ref_chain_code + ref_public_key, _ = calculate_public_key_and_chaincode(CurveChoice.Ed25519Slip, path=PATH_PREFIX + str(account_number | HARDENED_OFFSET) + PATH_SUFFIX) + assert "00" + public_key.hex() == ref_public_key # In this test we check that the GET_PUBLIC_KEY works in confirmation mode +@pytest.mark.active_test_scope def test_get_public_key_confirm_accepted(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: client = EverscaleCommandSender(backend) - path = "m/44'/1'/0'/0/0" - with client.get_public_key_with_confirmation(path=path): + account_number = 0 + with client.get_public_key_with_confirmation(account_number=account_number): scenario_navigator.address_review_approve() response = client.get_async_response().data - _, public_key, _, chain_code = unpack_get_public_key_response(response) + _, public_key = unpack_get_public_key_response(response) - ref_public_key, ref_chain_code = calculate_public_key_and_chaincode(CurveChoice.Secp256k1, path=path) - assert public_key.hex() == ref_public_key - assert chain_code.hex() == ref_chain_code + ref_public_key, _ = calculate_public_key_and_chaincode(CurveChoice.Ed25519Slip, path=PATH_PREFIX + str(account_number | HARDENED_OFFSET) + PATH_SUFFIX) + assert "00" + public_key.hex() == ref_public_key # In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses +@pytest.mark.active_test_scope def test_get_public_key_confirm_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: client = EverscaleCommandSender(backend) - path = "m/44'/1'/0'/0/0" + account_number = 0 with pytest.raises(ExceptionRAPDU) as e: - with client.get_public_key_with_confirmation(path=path): + with client.get_public_key_with_confirmation(account_number=account_number): scenario_navigator.address_review_reject() # Assert that we have received a refusal From fa65f97641e22b4e96fcb4699cfcddf410561219 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Mon, 10 Feb 2025 12:25:55 +0100 Subject: [PATCH 12/33] test: add tests for Everscale address retrieval functionality - Implement test cases for address retrieval across different wallet types - Add support for non-confirmation and confirmation modes of address retrieval - Create test scenarios for address review acceptance and rejection - Extend command sender and response unpacker to handle address-related operations - Add snapshot images for address confirmation tests --- .../everscale_command_sender.py | 27 ++++++++ .../everscale_response_unpacker.py | 13 +++- .../00000.png | Bin 0 -> 400 bytes .../00001.png | Bin 0 -> 889 bytes .../00002.png | Bin 0 -> 498 bytes .../00003.png | Bin 0 -> 369 bytes .../00004.png | Bin 0 -> 356 bytes .../00005.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 400 bytes .../00001.png | Bin 0 -> 889 bytes .../00002.png | Bin 0 -> 498 bytes .../00003.png | Bin 0 -> 369 bytes .../00004.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 400 bytes .../00001.png | Bin 0 -> 889 bytes .../00002.png | Bin 0 -> 498 bytes .../00003.png | Bin 0 -> 369 bytes .../00004.png | Bin 0 -> 356 bytes .../00005.png | Bin 0 -> 382 bytes .../00000.png | Bin 0 -> 400 bytes .../00001.png | Bin 0 -> 889 bytes .../00002.png | Bin 0 -> 498 bytes .../00003.png | Bin 0 -> 369 bytes .../00004.png | Bin 0 -> 382 bytes tests/test_address_cmd.py | 64 ++++++++++++++++++ 25 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00005.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png create mode 100644 tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png create mode 100644 tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png create mode 100644 tests/test_address_cmd.py diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 1510b60..921f339 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -31,6 +31,17 @@ class InsType(IntEnum): GET_ADDRESS = 0X04 SIGN_TRANSACTION = 0x05 +class WalletType(IntEnum): + WALLET_V3 = 0 + EVER_WALLET = 1 + SAFE_MULTISIG_WALLET = 2 + SAFE_MULTISIG_WALLET_24H = 3 + SETCODE_MULTISIG_WALLET = 4 + BRIDGE_MULTISIG_WALLET = 5 + SURF_WALLET = 6 + MULTISIG_2 = 7 + MULTISIG_2_1 = 8 + class Errors(IntEnum): SW_INVALID_DATA = 0x6B00, SW_CELL_UNDERFLOW = 0x6B01, @@ -116,6 +127,22 @@ def get_public_key_with_confirmation(self, account_number: int) -> Generator[Non data=account_number.to_bytes(4, "big")) as response: yield response + def get_address(self, account_number: int, wallet_type: WalletType) -> RAPDU: + return self.backend.exchange(cla=CLA, + ins=InsType.GET_ADDRESS, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big")) + + @contextmanager + def get_address_with_confirmation(self, account_number: int, wallet_type: WalletType) -> Generator[None, None, None]: + with self.backend.exchange_async(cla=CLA, + ins=InsType.GET_ADDRESS, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big")) as response: + yield response + @contextmanager def sign_tx(self, path: str, transaction: bytes) -> Generator[None, None, None]: diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py index 9cc096a..24e626d 100644 --- a/tests/application_client/everscale_response_unpacker.py +++ b/tests/application_client/everscale_response_unpacker.py @@ -45,8 +45,6 @@ def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]: # Unpack from response: # response = pub_key_len (1) # pub_key (var) -# chain_code_len (1) -# chain_code (var) def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, bytes]: response, pub_key_len, pub_key = pop_size_prefixed_buf_from_buf(response) @@ -55,6 +53,17 @@ def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, by return pub_key_len, pub_key +# Unpack from response: +# response = address_len (1) +# address (var) +def unpack_get_address_response(response: bytes) -> Tuple[int, bytes]: + response, address_len, address = pop_size_prefixed_buf_from_buf(response) + + assert address_len == 32 + assert len(response) == 0 + + return address_len, address + # Unpack from response: # response = der_sig_len (1) # der_sig (var) diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..a487005a859c0e4cfa0212a67f75a4794d81978c GIT binary patch literal 400 zcmV;B0dM|^P)CI7!~g&QfPa@`!PrJQ5_gtexv+u#;<7n?ZA>=8WP3sS)E3>Z zE!xY!9dS=7B}gQ@x;^0FVDIF?`GpenfZ9e>)xCO*lgBykAKe#*G9mk>o6EkWtAGi$ zGexMpHiozruqDn$Y{#w$*~F;G!$#0S7$x##_JEJys@+nJ)BK}UfHaSYH}BKlb~|vz<*qUayO&UL-bn@O u0WKrm9KB3jyJN~A3;+NC0000$MC1WGrw>UKISsS`00007f41`H4H{t$A@?G-a3Pqu<#o}@1@9$}fku0%ThPF!~gb+dqA>^C5uIsuk{4d9T zS3Z8YzUBId<-UvGCoWpLbdQcHjvQ;%tk&B8?SK1TEBx7hMIW^f>fKOlwFUxjnajcP z-OiCaz*=tofDZr4KFg(7YgGq&@Rcn?2x)*ILvP{W9WZ1JuKl?y^aE32<+#>o0|Y>@f`GM(Ncr|y8h;0}$$;zDX`v$1xH z(jbi6P`3bmh`#a3=kr&wUJp+nQ@)@7<*7gjA>^m<%lczldl|NC>ZWrDgdC~V3l3>G zLH*?Y>#KPpJq`N~f#{lpjin%}J8sng`H@OBZ1D}8ex-s+HXp>Y3JlLRff%ROhZ5bJ z@*)#n&Bf7qth$G%;TS)&I1*~8RqRrZVXtImXeC>fH~N;|MwasF0d1GPR|EK_0enT_ zO#nDv6CE2$YTv`&V1gA8gLAv4ytCBjcS>aE$58=3`2o)E}u|pZ5;eCtMSf* zF0KY1O(Q2oIOV0}&xF!N6=4t^)Q_%usk+U?;dYTgjBCH8SmtPx1z2BFzeE^}5s3zu zaa85ivUJ>2coVR$-!6I`(&;QM7DS!V=~VZtq3>5Wvu~3QY4SId&j7U%ugmMgs}U1!Bc zH4Dp>pX&T@fwwSXfV<;$N&TJ5e>&o#V^92bwA!LdiGHNeJr(Fx>dH#0!36k{)^PQd zIv*xyS-x%b%i5=|<^;&W#mijHe?Xaf8|7>bk!L_Ejk#Ea5JCtcguI%+Tt#N5f~LHY P00000NkvXXu0mjfn=Q4X literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79ec8e7d5f4668017394572679a188b792d1ef70 GIT binary patch literal 498 zcmV*S6;srWKHAi^h!zFxUtJDqm8Ea z9rNzALm^q>xitNU(YR64UP|5nWF1Akk1LaR!Q5YZ9KACV#eURt_~q%TbGA$6H3u%p zJogO1o_6;ql!phhj?8JYj+0y%l1`fs-7^3av|+f|n&x?zb}dPI8$MPx#07*qoM6N<$g6k6JrvLx| literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..78530ed78893e8cde716b8c31d30c1cb56cec73a GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WHba4!+nDh2VG~Xcwk(P&x z3)S!bpLC;}UuDU|MO!+Jod3P|R5r6{pX~zF0|gT%26<`T{T*_-xRm|fi)A_DwP|4u zk1alRYrXrl&7>ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd127e517c190a1684db420b839a65dd8776a10 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`htba4!+nDh2#AYZeBfa}G~ z%X2sUSKT3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~oCI7!~g&QfPa@`!PrJQ5_gtexv+u#;<7n?ZA>=8WP3sS)E3>Z zE!xY!9dS=7B}gQ@x;^0FVDIF?`GpenfZ9e>)xCO*lgBykAKe#*G9mk>o6EkWtAGi$ zGexMpHiozruqDn$Y{#w$*~F;G!$#0S7$x##_JEJys@+nJ)BK}UfHaSYH}BKlb~|vz<*qUayO&UL-bn@O u0WKrm9KB3jyJN~A3;+NC0000$MC1WGrw>UKISsS`00007f41`H4H{t$A@?G-a3Pqu<#o}@1@9$}fku0%ThPF!~gb+dqA>^C5uIsuk{4d9T zS3Z8YzUBId<-UvGCoWpLbdQcHjvQ;%tk&B8?SK1TEBx7hMIW^f>fKOlwFUxjnajcP z-OiCaz*=tofDZr4KFg(7YgGq&@Rcn?2x)*ILvP{W9WZ1JuKl?y^aE32<+#>o0|Y>@f`GM(Ncr|y8h;0}$$;zDX`v$1xH z(jbi6P`3bmh`#a3=kr&wUJp+nQ@)@7<*7gjA>^m<%lczldl|NC>ZWrDgdC~V3l3>G zLH*?Y>#KPpJq`N~f#{lpjin%}J8sng`H@OBZ1D}8ex-s+HXp>Y3JlLRff%ROhZ5bJ z@*)#n&Bf7qth$G%;TS)&I1*~8RqRrZVXtImXeC>fH~N;|MwasF0d1GPR|EK_0enT_ zO#nDv6CE2$YTv`&V1gA8gLAv4ytCBjcS>aE$58=3`2o)E}u|pZ5;eCtMSf* zF0KY1O(Q2oIOV0}&xF!N6=4t^)Q_%usk+U?;dYTgjBCH8SmtPx1z2BFzeE^}5s3zu zaa85ivUJ>2coVR$-!6I`(&;QM7DS!V=~VZtq3>5Wvu~3QY4SId&j7U%ugmMgs}U1!Bc zH4Dp>pX&T@fwwSXfV<;$N&TJ5e>&o#V^92bwA!LdiGHNeJr(Fx>dH#0!36k{)^PQd zIv*xyS-x%b%i5=|<^;&W#mijHe?Xaf8|7>bk!L_Ejk#Ea5JCtcguI%+Tt#N5f~LHY P00000NkvXXu0mjfn=Q4X literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79ec8e7d5f4668017394572679a188b792d1ef70 GIT binary patch literal 498 zcmV*S6;srWKHAi^h!zFxUtJDqm8Ea z9rNzALm^q>xitNU(YR64UP|5nWF1Akk1LaR!Q5YZ9KACV#eURt_~q%TbGA$6H3u%p zJogO1o_6;ql!phhj?8JYj+0y%l1`fs-7^3av|+f|n&x?zb}dPI8$MPx#07*qoM6N<$g6k6JrvLx| literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..78530ed78893e8cde716b8c31d30c1cb56cec73a GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WHba4!+nDh2VG~Xcwk(P&x z3)S!bpLC;}UuDU|MO!+Jod3P|R5r6{pX~zF0|gT%26<`T{T*_-xRm|fi)A_DwP|4u zk1alRYrXrl&7>ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..a58590b988714545e7960f7f400f360ffc5de41f GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9hba4!+nDh2#bl+hG9*4k? zQuR0Wo;SViCn%lTo!KM1sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~oCI7!~g&QfPa@`!PrJQ5_gtexv+u#;<7n?ZA>=8WP3sS)E3>Z zE!xY!9dS=7B}gQ@x;^0FVDIF?`GpenfZ9e>)xCO*lgBykAKe#*G9mk>o6EkWtAGi$ zGexMpHiozruqDn$Y{#w$*~F;G!$#0S7$x##_JEJys@+nJ)BK}UfHaSYH}BKlb~|vz<*qUayO&UL-bn@O u0WKrm9KB3jyJN~A3;+NC0000$MC1WGrw>UKISsS`00007f41`H4H{t$A@?G-a3Pqu<#o}@1@9$}fku0%ThPF!~gb+dqA>^C5uIsuk{4d9T zS3Z8YzUBId<-UvGCoWpLbdQcHjvQ;%tk&B8?SK1TEBx7hMIW^f>fKOlwFUxjnajcP z-OiCaz*=tofDZr4KFg(7YgGq&@Rcn?2x)*ILvP{W9WZ1JuKl?y^aE32<+#>o0|Y>@f`GM(Ncr|y8h;0}$$;zDX`v$1xH z(jbi6P`3bmh`#a3=kr&wUJp+nQ@)@7<*7gjA>^m<%lczldl|NC>ZWrDgdC~V3l3>G zLH*?Y>#KPpJq`N~f#{lpjin%}J8sng`H@OBZ1D}8ex-s+HXp>Y3JlLRff%ROhZ5bJ z@*)#n&Bf7qth$G%;TS)&I1*~8RqRrZVXtImXeC>fH~N;|MwasF0d1GPR|EK_0enT_ zO#nDv6CE2$YTv`&V1gA8gLAv4ytCBjcS>aE$58=3`2o)E}u|pZ5;eCtMSf* zF0KY1O(Q2oIOV0}&xF!N6=4t^)Q_%usk+U?;dYTgjBCH8SmtPx1z2BFzeE^}5s3zu zaa85ivUJ>2coVR$-!6I`(&;QM7DS!V=~VZtq3>5Wvu~3QY4SId&j7U%ugmMgs}U1!Bc zH4Dp>pX&T@fwwSXfV<;$N&TJ5e>&o#V^92bwA!LdiGHNeJr(Fx>dH#0!36k{)^PQd zIv*xyS-x%b%i5=|<^;&W#mijHe?Xaf8|7>bk!L_Ejk#Ea5JCtcguI%+Tt#N5f~LHY P00000NkvXXu0mjfn=Q4X literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79ec8e7d5f4668017394572679a188b792d1ef70 GIT binary patch literal 498 zcmV*S6;srWKHAi^h!zFxUtJDqm8Ea z9rNzALm^q>xitNU(YR64UP|5nWF1Akk1LaR!Q5YZ9KACV#eURt_~q%TbGA$6H3u%p zJogO1o_6;ql!phhj?8JYj+0y%l1`fs-7^3av|+f|n&x?zb}dPI8$MPx#07*qoM6N<$g6k6JrvLx| literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..78530ed78893e8cde716b8c31d30c1cb56cec73a GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WHba4!+nDh2VG~Xcwk(P&x z3)S!bpLC;}UuDU|MO!+Jod3P|R5r6{pX~zF0|gT%26<`T{T*_-xRm|fi)A_DwP|4u zk1alRYrXrl&7>ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd127e517c190a1684db420b839a65dd8776a10 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`htba4!+nDh2#AYZeBfa}G~ z%X2sUSKT3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~oCI7!~g&QfPa@`!PrJQ5_gtexv+u#;<7n?ZA>=8WP3sS)E3>Z zE!xY!9dS=7B}gQ@x;^0FVDIF?`GpenfZ9e>)xCO*lgBykAKe#*G9mk>o6EkWtAGi$ zGexMpHiozruqDn$Y{#w$*~F;G!$#0S7$x##_JEJys@+nJ)BK}UfHaSYH}BKlb~|vz<*qUayO&UL-bn@O u0WKrm9KB3jyJN~A3;+NC0000$MC1WGrw>UKISsS`00007f41`H4H{t$A@?G-a3Pqu<#o}@1@9$}fku0%ThPF!~gb+dqA>^C5uIsuk{4d9T zS3Z8YzUBId<-UvGCoWpLbdQcHjvQ;%tk&B8?SK1TEBx7hMIW^f>fKOlwFUxjnajcP z-OiCaz*=tofDZr4KFg(7YgGq&@Rcn?2x)*ILvP{W9WZ1JuKl?y^aE32<+#>o0|Y>@f`GM(Ncr|y8h;0}$$;zDX`v$1xH z(jbi6P`3bmh`#a3=kr&wUJp+nQ@)@7<*7gjA>^m<%lczldl|NC>ZWrDgdC~V3l3>G zLH*?Y>#KPpJq`N~f#{lpjin%}J8sng`H@OBZ1D}8ex-s+HXp>Y3JlLRff%ROhZ5bJ z@*)#n&Bf7qth$G%;TS)&I1*~8RqRrZVXtImXeC>fH~N;|MwasF0d1GPR|EK_0enT_ zO#nDv6CE2$YTv`&V1gA8gLAv4ytCBjcS>aE$58=3`2o)E}u|pZ5;eCtMSf* zF0KY1O(Q2oIOV0}&xF!N6=4t^)Q_%usk+U?;dYTgjBCH8SmtPx1z2BFzeE^}5s3zu zaa85ivUJ>2coVR$-!6I`(&;QM7DS!V=~VZtq3>5Wvu~3QY4SId&j7U%ugmMgs}U1!Bc zH4Dp>pX&T@fwwSXfV<;$N&TJ5e>&o#V^92bwA!LdiGHNeJr(Fx>dH#0!36k{)^PQd zIv*xyS-x%b%i5=|<^;&W#mijHe?Xaf8|7>bk!L_Ejk#Ea5JCtcguI%+Tt#N5f~LHY P00000NkvXXu0mjfn=Q4X literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79ec8e7d5f4668017394572679a188b792d1ef70 GIT binary patch literal 498 zcmV*S6;srWKHAi^h!zFxUtJDqm8Ea z9rNzALm^q>xitNU(YR64UP|5nWF1Akk1LaR!Q5YZ9KACV#eURt_~q%TbGA$6H3u%p zJogO1o_6;ql!phhj?8JYj+0y%l1`fs-7^3av|+f|n&x?zb}dPI8$MPx#07*qoM6N<$g6k6JrvLx| literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..78530ed78893e8cde716b8c31d30c1cb56cec73a GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WHba4!+nDh2VG~Xcwk(P&x z3)S!bpLC;}UuDU|MO!+Jod3P|R5r6{pX~zF0|gT%26<`T{T*_-xRm|fi)A_DwP|4u zk1alRYrXrl&7>ePtl`Dg1Ll7_D%QL^;QO}e@r*i)a}8^{Zkzo5pnJe9hTGs)%i9RC z2YX)kopaUu!*yX^<(ljOafd(VJ$`faOn+Rm{dn)VSh(O}xmV@2(sNgM{y)Fspw}8F z?VIlpU+W0(yO8^$vgAz6x~JdvT`wp)rTMS?c;!KRuJu=CXIz>qbCu`Eg=N1@Caz2l zXef@WjPbS{x`#dx8HeXrotLqoTi}!zV zWi2{>VN>7nJ8ahbIp@!pu@k+dTCr@8V=d>cc^8CC`cqk8A;56?-sZ_S(sh?ur-Fn$ MUHx3vIVCg!0MAmW;Q#;t literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..a58590b988714545e7960f7f400f360ffc5de41f GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9hba4!+nDh2#bl+hG9*4k? zQuR0Wo;SViCn%lTo!KM1sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o None: + temp = [] + for wallet_type in range(9): + client = EverscaleCommandSender(backend) + response = client.get_address(account_number=0, wallet_type=wallet_type).data + _, address = unpack_get_address_response(response) + + assert address.hex() == EXPECTED_ADDRESSES[wallet_type], f"Error with wallet_type: {wallet_type}, expected: {EXPECTED_ADDRESSES[wallet_type]}, but got {address.hex()}" + + +# In this test we check that the GET_ADDRESS works in confirmation mode +@pytest.mark.active_test_scope +def test_get_address_wallet_v3_confirm_accepted(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + client = EverscaleCommandSender(backend) + account_number = 0 + wallet_type = WalletType.WALLET_V3 + with client.get_address_with_confirmation(account_number=account_number, wallet_type=wallet_type): + scenario_navigator.address_review_approve() + + response = client.get_async_response().data + _, address = unpack_get_address_response(response) + + assert address.hex() == EXPECTED_ADDRESSES[wallet_type], f"Error with wallet_type: {wallet_type}, expected: {EXPECTED_ADDRESSES[wallet_type]}, but got {address.hex()}" + + +# In this test we check that the GET_ADDRESS in confirmation mode replies an error if the user refuses +@pytest.mark.active_test_scope +def test_get_address_wallet_v3_confirm_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + client = EverscaleCommandSender(backend) + account_number = 0 + wallet_type = WalletType.WALLET_V3 + + with pytest.raises(ExceptionRAPDU) as e: + with client.get_address_with_confirmation(account_number=account_number, wallet_type=wallet_type): + scenario_navigator.address_review_reject() + + # Assert that we have received a refusal + assert e.value.status == Errors.SW_DENY + assert len(e.value.data) == 0 + + + + + From dea39ec4a5d2d4f573f9f9fd72475cf44f51daf0 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Mon, 10 Feb 2025 16:39:49 +0100 Subject: [PATCH 13/33] test: add message and transaction signing tests for Everscale app (incomplete) - Implement test cases for signing transactions and messages - Update transaction and command sender classes to support new signing methods - Add placeholder tests with TODO comments for future implementation - Modify response unpacking and transaction serialization logic - Simplify signing methods with account number and wallet type parameters --- .../everscale_command_sender.py | 29 +-- .../everscale_response_unpacker.py | 3 +- .../everscale_transaction.py | 210 ++++++++++++++--- tests/test_sign_cmd.py | 218 +++++++++--------- tests/test_sign_message_cmd.py | 44 ++++ 5 files changed, 338 insertions(+), 166 deletions(-) create mode 100644 tests/test_sign_message_cmd.py diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 921f339..90a16c0 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -145,28 +145,21 @@ def get_address_with_confirmation(self, account_number: int, wallet_type: Wallet @contextmanager - def sign_tx(self, path: str, transaction: bytes) -> Generator[None, None, None]: - self.backend.exchange(cla=CLA, - ins=InsType.SIGN_TX, - p1=P1.P1_START, - p2=P2.P2_MORE, - data=pack_derivation_path(path)) - messages = split_message(transaction, MAX_APDU_LEN) - idx: int = P1.P1_START + 1 - - for msg in messages[:-1]: - self.backend.exchange(cla=CLA, - ins=InsType.SIGN_TX, - p1=idx, - p2=P2.P2_MORE, - data=msg) - idx += 1 + def sign_message(self, account_number: int, wallet_type: WalletType, message: bytes) -> Generator[None, None, None]: + with self.backend.exchange_async(cla=CLA, + ins=InsType.SIGN_MESSAGE, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big") + message) as response: + yield response + @contextmanager + def sign_tx(self, account_number: int, wallet_type: WalletType, transaction: bytes) -> Generator[None, None, None]: with self.backend.exchange_async(cla=CLA, ins=InsType.SIGN_TX, - p1=idx, + p1=P1.P1_START, p2=P2.P2_LAST, - data=messages[-1]) as response: + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big") + transaction) as response: yield response def get_async_response(self) -> Optional[RAPDU]: diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py index 24e626d..b08e690 100644 --- a/tests/application_client/everscale_response_unpacker.py +++ b/tests/application_client/everscale_response_unpacker.py @@ -45,7 +45,7 @@ def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]: # Unpack from response: # response = pub_key_len (1) # pub_key (var) -def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, bytes]: +def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes]: response, pub_key_len, pub_key = pop_size_prefixed_buf_from_buf(response) assert pub_key_len == 32 @@ -68,6 +68,7 @@ def unpack_get_address_response(response: bytes) -> Tuple[int, bytes]: # response = der_sig_len (1) # der_sig (var) # v (1) +# TODO: check if this needs to be edited def unpack_sign_tx_response(response: bytes) -> Tuple[int, bytes, int]: response, der_sig_len, der_sig = pop_size_prefixed_buf_from_buf(response) response, v = pop_sized_buf_from_buffer(response, 1) diff --git a/tests/application_client/everscale_transaction.py b/tests/application_client/everscale_transaction.py index 9ef3d17..5094dfc 100644 --- a/tests/application_client/everscale_transaction.py +++ b/tests/application_client/everscale_transaction.py @@ -1,50 +1,188 @@ -from io import BytesIO -from typing import Union +from application_client.everscale_command_sender import WalletType -from .everscale_utils import read, read_uint, read_varint, write_varint, UINT64_MAX +class Transaction: + ADDRESS_LENGTH = 32 + CHAIN_ID_LENGTH = 4 + FLAG_WITH_WALLET_ID = 0x01 + FLAG_WITH_WORKCHAIN_ID = 0x02 + FLAG_WITH_ADDRESS = 0x04 + FLAG_WITH_CHAIN_ID = 0x08 -class TransactionError(Exception): - pass + def __init__(self, + decimals: int, + ticker: str, + message: bytes, + current_wallet_type: WalletType, + workchain_id: int | None = None, + prepend_address: bytes | None = None, + chain_id: bytes | None = None) -> None: + """ + Construct a Transaction. + + The metadata byte is deduced as follows: + - FLAG_WITH_WALLET_ID is set if a current_wallet_type is provided and + it differs from the origin_wallet_type. + - FLAG_WITH_WORKCHAIN_ID is set if workchain_id is provided. + - FLAG_WITH_ADDRESS is set if prepend_address is provided. + - FLAG_WITH_CHAIN_ID is set if chain_id is provided. + + If current_wallet_type is None or equals origin_wallet_type, then that field is omitted + and on deserialization the origin_wallet_type will be used. + """ + self.decimals = decimals + self.ticker = ticker + self.message = message + self.workchain_id = workchain_id + self.prepend_address = prepend_address + self.chain_id = chain_id + # Deduce metadata flags based on optional inputs. + metadata = 0 + if current_wallet_type is not None: + metadata |= self.FLAG_WITH_WALLET_ID + self.current_wallet_type = current_wallet_type + else: + # Do not include the field; on the device, it will be set to origin_wallet_type. + self.current_wallet_type = None -class Transaction: - def __init__(self, - nonce: int, - to: Union[str, bytes], - value: int, - memo: str) -> None: - self.nonce: int = nonce - self.to: bytes = bytes.fromhex(to[2:]) if isinstance(to, str) else to - self.value: int = value - self.memo: bytes = memo.encode("ascii") + if workchain_id is not None: + metadata |= self.FLAG_WITH_WORKCHAIN_ID + + if prepend_address is not None: + if len(prepend_address) != self.ADDRESS_LENGTH: + raise ValueError(f"prepend_address must be {self.ADDRESS_LENGTH} bytes") + metadata |= self.FLAG_WITH_ADDRESS - if not 0 <= self.nonce <= UINT64_MAX: - raise TransactionError(f"Bad nonce: '{self.nonce}'!") + if chain_id is not None: + if len(chain_id) != self.CHAIN_ID_LENGTH: + raise ValueError(f"chain_id must be {self.CHAIN_ID_LENGTH} bytes") + metadata |= self.FLAG_WITH_CHAIN_ID - if not 0 <= self.value <= UINT64_MAX: - raise TransactionError(f"Bad value: '{self.value}'!") + self.metadata = metadata - if len(self.to) != 20: - raise TransactionError(f"Bad address: '{self.to.hex()}'!") + # Nice-to-haves: check ticker length constraints. + ticker_len = len(ticker) + if ticker_len == 0 or ticker_len > 10: + raise ValueError("Ticker length must be between 1 and 10 bytes.") def serialize(self) -> bytes: - return b"".join([ - self.nonce.to_bytes(8, byteorder="big"), - self.to, - self.value.to_bytes(8, byteorder="big"), - write_varint(len(self.memo)), - self.memo - ]) + """ + Serialize the transaction into a byte-buffer with the following structure: + + [decimals:1] [ticker_length:1] [ticker:N] [metadata:1] + [optional fields (if flagged)...] [message:remaining bytes] + """ + result = bytearray() + # 1. Decimals (1 byte) + result.append(self.decimals) + + # 2. Ticker: length (1 byte) followed by its ASCII bytes + ticker_bytes = self.ticker.encode("ascii") + ticker_len = len(ticker_bytes) + result.append(ticker_len) + result.extend(ticker_bytes) + + # 3. Metadata (1 byte; deduced from optional parameters) + result.append(self.metadata) + + # 4. Conditionally append optional fields based on metadata flags. + if self.metadata & self.FLAG_WITH_WALLET_ID: + # current_wallet_type is provided and differs from origin_wallet_type. + result.append(self.current_wallet_type) + # Workchain id. + if self.metadata & self.FLAG_WITH_WORKCHAIN_ID: + result.append(self.workchain_id) + # Prepend address. + if self.metadata & self.FLAG_WITH_ADDRESS: + result.extend(self.prepend_address) + # Chain id. + if self.metadata & self.FLAG_WITH_CHAIN_ID: + result.extend(self.chain_id) + + # 5. Append the message (payload). + result.extend(self.message) + + return bytes(result) @classmethod - def from_bytes(cls, hexa: Union[bytes, BytesIO]): - buf: BytesIO = BytesIO(hexa) if isinstance(hexa, bytes) else hexa + def from_bytes(cls, data: bytes) -> "Transaction": + """ + Deserialize a byte-buffer into a Transaction object. + + The parsing order in the buffer is: + decimals (1 byte) -> + ticker_length (1 byte) -> + ticker -> + metadata (1 byte) -> + [optional fields... based on metadata] -> + message (remaining bytes) + + If the metadata does NOT include FLAG_WITH_WALLET_ID, then current_wallet_type + defaults to origin_wallet_type. + """ + offset = 0 + + # Read decimals (1 byte) + if len(data) < offset + 1: + raise ValueError("Data too short for decimals") + decimals = data[offset] + offset += 1 + + # Read ticker: first its length (1 byte) then the ticker string + if len(data) < offset + 1: + raise ValueError("Data too short for ticker length") + ticker_len = data[offset] + offset += 1 + if len(data) < offset + ticker_len: + raise ValueError("Data too short for ticker") + ticker = data[offset:offset+ticker_len].decode("ascii") + offset += ticker_len + + # Read metadata (1 byte) + if len(data) < offset + 1: + raise ValueError("Data too short for metadata") + metadata = data[offset] + offset += 1 + + # Read optional fields based on metadata flags. + current_wallet_type = None + if metadata & cls.FLAG_WITH_WALLET_ID: + if len(data) < offset + 1: + raise ValueError("Data too short for current_wallet_type") + current_wallet_type = data[offset] + offset += 1 + + workchain_id = None + if metadata & cls.FLAG_WITH_WORKCHAIN_ID: + if len(data) < offset + 1: + raise ValueError("Data too short for workchain_id") + workchain_id = data[offset] + offset += 1 + + prepend_address = None + if metadata & cls.FLAG_WITH_ADDRESS: + if len(data) < offset + cls.ADDRESS_LENGTH: + raise ValueError("Data too short for prepend_address") + prepend_address = data[offset:offset+cls.ADDRESS_LENGTH] + offset += cls.ADDRESS_LENGTH + + chain_id = None + if metadata & cls.FLAG_WITH_CHAIN_ID: + if len(data) < offset + cls.CHAIN_ID_LENGTH: + raise ValueError("Data too short for chain_id") + chain_id = data[offset:offset+cls.CHAIN_ID_LENGTH] + offset += cls.CHAIN_ID_LENGTH - nonce: int = read_uint(buf, 64, byteorder="big") - to: bytes = read(buf, 20) - value: int = read_uint(buf, 64, byteorder="big") - memo_len: int = read_varint(buf) - memo: str = read(buf, memo_len).decode("ascii") + # The remaining bytes are the message. + message = data[offset:] - return cls(nonce=nonce, to=to, value=value, memo=memo) + return cls( + decimals=decimals, + ticker=ticker, + message=message, + current_wallet_type=current_wallet_type, + workchain_id=workchain_id, + prepend_address=prepend_address, + chain_id=chain_id + ) \ No newline at end of file diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py index ebc3127..9147a3a 100644 --- a/tests/test_sign_cmd.py +++ b/tests/test_sign_cmd.py @@ -7,7 +7,7 @@ from ragger.navigator.navigation_scenario import NavigateWithScenario from application_client.everscale_transaction import Transaction -from application_client.everscale_command_sender import EverscaleCommandSender, Errors +from application_client.everscale_command_sender import EverscaleCommandSender, Errors, WalletType from application_client.everscale_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response from utils import check_signature_validity @@ -17,129 +17,125 @@ # In this test we send to the device a transaction to sign and validate it on screen # The transaction is short and will be sent in one chunk # We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_tx_short_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: - # Use the app interface instead of raw interface - client = EverscaleCommandSender(backend) - # The path used for this entire test - path: str = "m/44'/1'/0'/0/0" - - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) - _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) - - # Create the transaction that will be sent to the device for signing - transaction = Transaction( - nonce=1, - to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", - value=666, - memo="For u EthDev" - ).serialize() - # Send the sign device instruction. - # As it requires on-screen validation, the function is asynchronous. - # It will yield the result when the navigation is done - with client.sign_tx(path=path, transaction=transaction): - # Validate the on-screen request by performing the navigation appropriate for this device - scenario_navigator.review_approve() - - # The device as yielded the result, parse it and ensure that the signature is correct - response = client.get_async_response().data - _, der_sig, _ = unpack_sign_tx_response(response) - assert check_signature_validity(public_key, der_sig, transaction) - - -# In this test we send to the device a transaction to trig a blind-signing flow -# The transaction is short and will be sent in one chunk -# We will ensure that the displayed information is correct by using screenshots comparison -def test_sign_tx_short_tx_blind_sign(firmware: Firmware, - backend: BackendInterface, - navigator: Navigator, - scenario_navigator: NavigateWithScenario, - test_name: str, - default_screenshot_path: str) -> None: +# TODO: Add a valid raw transaction and a valid expected signature +def test_sign_tx_short_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: # Use the app interface instead of raw interface client = EverscaleCommandSender(backend) - # The path used for this entire test - path: str = "m/44'/1'/0'/0/0" - + account_number = 0 + wallet_type = WalletType.WALLET_V3 # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(path=path) + rapdu = client.get_public_key(account_number=account_number) _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) - # Create the transaction that will be sent to the device for signing - transaction = Transaction( - nonce=1, - to="0x0000000000000000000000000000000000000000", - value=0, - memo="Blind-sign" - ).serialize() + # Raw transaction + transaction = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000") # Send the sign device instruction. - valid_instruction = [NavInsID.RIGHT_CLICK] if firmware.is_nano else [NavInsID.USE_CASE_CHOICE_REJECT] # As it requires on-screen validation, the function is asynchronous. # It will yield the result when the navigation is done - with client.sign_tx(path=path, transaction=transaction): - navigator.navigate_and_compare(default_screenshot_path, - test_name+"/part1", - valid_instruction, - screen_change_after_last_instruction=False) - + with client.sign_tx(account_number=account_number, wallet_type=wallet_type, transaction=transaction): # Validate the on-screen request by performing the navigation appropriate for this device scenario_navigator.review_approve() # The device as yielded the result, parse it and ensure that the signature is correct response = client.get_async_response().data _, der_sig, _ = unpack_sign_tx_response(response) - assert check_signature_validity(public_key, der_sig, transaction) - -# In this test se send to the device a transaction to sign and validate it on screen -# This test is mostly the same as the previous one but with different values. -# In particular the long memo will force the transaction to be sent in multiple chunks -def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: - # Use the app interface instead of raw interface - client = EverscaleCommandSender(backend) - path: str = "m/44'/1'/0'/0/0" - - rapdu = client.get_public_key(path=path) - _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) - - transaction = Transaction( - nonce=1, - to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", - value=666, - memo=("This is a very long memo. " - "It will force the app client to send the serialized transaction to be sent in chunk. " - "As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. " - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, " - "dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.") - ).serialize() - - with client.sign_tx(path=path, transaction=transaction): - scenario_navigator.review_approve() - - response = client.get_async_response().data - _, der_sig, _ = unpack_sign_tx_response(response) - assert check_signature_validity(public_key, der_sig, transaction) - - -# Transaction signature refused test -# The test will ask for a transaction signature that will be refused on screen -def test_sign_tx_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: - # Use the app interface instead of raw interface - client = EverscaleCommandSender(backend) - path: str = "m/44'/1'/0'/0/0" - - transaction = Transaction( - nonce=1, - to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", - value=666, - memo="This transaction will be refused by the user" - ).serialize() - - with pytest.raises(ExceptionRAPDU) as e: - with client.sign_tx(path=path, transaction=transaction): - scenario_navigator.review_reject() - - # Assert that we have received a refusal - assert e.value.status == Errors.SW_DENY - assert len(e.value.data) == 0 + assert der_sig.hex() == "0000000000000000000000000000000000000000000000000000000000000000" + + +# # In this test we send to the device a transaction to trig a blind-signing flow +# # The transaction is short and will be sent in one chunk +# # We will ensure that the displayed information is correct by using screenshots comparison +# def test_sign_tx_short_tx_blind_sign(firmware: Firmware, +# backend: BackendInterface, +# navigator: Navigator, +# scenario_navigator: NavigateWithScenario, +# test_name: str, +# default_screenshot_path: str) -> None: +# # Use the app interface instead of raw interface +# client = EverscaleCommandSender(backend) +# # The path used for this entire test +# path: str = "m/44'/1'/0'/0/0" + +# # First we need to get the public key of the device in order to build the transaction +# rapdu = client.get_public_key(path=path) +# _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + +# # Create the transaction that will be sent to the device for signing +# transaction = Transaction( +# nonce=1, +# to="0x0000000000000000000000000000000000000000", +# value=0, +# memo="Blind-sign" +# ).serialize() + +# # Send the sign device instruction. +# valid_instruction = [NavInsID.RIGHT_CLICK] if firmware.is_nano else [NavInsID.USE_CASE_CHOICE_REJECT] +# # As it requires on-screen validation, the function is asynchronous. +# # It will yield the result when the navigation is done +# with client.sign_tx(path=path, transaction=transaction): +# navigator.navigate_and_compare(default_screenshot_path, +# test_name+"/part1", +# valid_instruction, +# screen_change_after_last_instruction=False) + +# # Validate the on-screen request by performing the navigation appropriate for this device +# scenario_navigator.review_approve() + +# # The device as yielded the result, parse it and ensure that the signature is correct +# response = client.get_async_response().data +# _, der_sig, _ = unpack_sign_tx_response(response) +# assert check_signature_validity(public_key, der_sig, transaction) + +# # In this test se send to the device a transaction to sign and validate it on screen +# # This test is mostly the same as the previous one but with different values. +# # In particular the long memo will force the transaction to be sent in multiple chunks +# def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: +# # Use the app interface instead of raw interface +# client = EverscaleCommandSender(backend) +# path: str = "m/44'/1'/0'/0/0" + +# rapdu = client.get_public_key(path=path) +# _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + +# transaction = Transaction( +# nonce=1, +# to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", +# value=666, +# memo=("This is a very long memo. " +# "It will force the app client to send the serialized transaction to be sent in chunk. " +# "As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. " +# "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, " +# "dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.") +# ).serialize() + +# with client.sign_tx(path=path, transaction=transaction): +# scenario_navigator.review_approve() + +# response = client.get_async_response().data +# _, der_sig, _ = unpack_sign_tx_response(response) +# assert check_signature_validity(public_key, der_sig, transaction) + + +# # Transaction signature refused test +# # The test will ask for a transaction signature that will be refused on screen +# def test_sign_tx_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: +# # Use the app interface instead of raw interface +# client = EverscaleCommandSender(backend) +# path: str = "m/44'/1'/0'/0/0" + +# transaction = Transaction( +# nonce=1, +# to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", +# value=666, +# memo="This transaction will be refused by the user" +# ).serialize() + +# with pytest.raises(ExceptionRAPDU) as e: +# with client.sign_tx(path=path, transaction=transaction): +# scenario_navigator.review_reject() + +# # Assert that we have received a refusal +# assert e.value.status == Errors.SW_DENY +# assert len(e.value.data) == 0 diff --git a/tests/test_sign_message_cmd.py b/tests/test_sign_message_cmd.py new file mode 100644 index 0000000..befb48a --- /dev/null +++ b/tests/test_sign_message_cmd.py @@ -0,0 +1,44 @@ +import pytest + +from ragger.backend.interface import BackendInterface +from ragger.error import ExceptionRAPDU +from ragger.firmware import Firmware +from ragger.navigator import Navigator, NavInsID +from ragger.navigator.navigation_scenario import NavigateWithScenario + +from application_client.everscale_transaction import Transaction +from application_client.everscale_command_sender import EverscaleCommandSender, Errors, WalletType +from application_client.everscale_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response +from utils import check_signature_validity + +# In this tests we check the behavior of the device when asked to sign a transaction + + +# In this test we send to the device a transaction to sign and validate it on screen +# The transaction is short and will be sent in one chunk +# We will ensure that the displayed information is correct by using screenshots comparison + +# TODO: Add a valid raw message and a valid expected signature +def test_sign_message(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None: + # Use the app interface instead of raw interface + client = EverscaleCommandSender(backend) + account_number = 0 + wallet_type = WalletType.WALLET_V3 + # First we need to get the public key of the device in order to build the transaction + rapdu = client.get_public_key(account_number=account_number) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + # Message to sign + message = b"Hello, world!" + + # Send the sign device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + with client.sign_message(account_number=account_number, wallet_type=wallet_type, message=message): + # Validate the on-screen request by performing the navigation appropriate for this device + scenario_navigator.review_approve() + + # The device as yielded the result, parse it and ensure that the signature is correct + response = client.get_async_response().data + _, der_sig, _ = unpack_sign_tx_response(response) + assert der_sig.hex() == "0000000000000000000000000000000000000000000000000000000000000000" \ No newline at end of file From f7c0a65f0f2ffdfaff649d57250e8006f1e7227e Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 16:39:52 +0100 Subject: [PATCH 14/33] test: update transaction signing test - Refactor test_sign_tx_short_tx to test_sign_tx_transfer - Update transaction signing method to remove account number and wallet type - Add navigation utility function for cross-device screenshot comparison - Update command sender to use new SIGN_TRANSACTION instruction - Add snapshot images for NanoSP and NanoX devices --- .../everscale_command_sender.py | 8 +-- .../nanosp/test_sign_tx_transfer/00000.png | Bin 0 -> 414 bytes .../nanosp/test_sign_tx_transfer/00001.png | Bin 0 -> 374 bytes .../nanosp/test_sign_tx_transfer/00002.png | Bin 0 -> 517 bytes .../nanosp/test_sign_tx_transfer/00003.png | Bin 0 -> 872 bytes .../nanosp/test_sign_tx_transfer/00004.png | Bin 0 -> 518 bytes .../nanosp/test_sign_tx_transfer/00005.png | Bin 0 -> 472 bytes .../nanosp/test_sign_tx_transfer/00006.png | Bin 0 -> 382 bytes .../nanox/test_sign_tx_transfer/00000.png | Bin 0 -> 414 bytes .../nanox/test_sign_tx_transfer/00001.png | Bin 0 -> 374 bytes .../nanox/test_sign_tx_transfer/00002.png | Bin 0 -> 517 bytes .../nanox/test_sign_tx_transfer/00003.png | Bin 0 -> 872 bytes .../nanox/test_sign_tx_transfer/00004.png | Bin 0 -> 518 bytes .../nanox/test_sign_tx_transfer/00005.png | Bin 0 -> 472 bytes .../nanox/test_sign_tx_transfer/00006.png | Bin 0 -> 382 bytes tests/test_sign_cmd.py | 30 +++++----- tests/test_sign_message_cmd.py | 1 - tests/utils.py | 55 +++++++++++++++++- 18 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00004.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00005.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_transfer/00006.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00000.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00001.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00002.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00003.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00004.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00005.png create mode 100644 tests/snapshots/nanox/test_sign_tx_transfer/00006.png diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 90a16c0..5312ca6 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -154,12 +154,12 @@ def sign_message(self, account_number: int, wallet_type: WalletType, message: by yield response @contextmanager - def sign_tx(self, account_number: int, wallet_type: WalletType, transaction: bytes) -> Generator[None, None, None]: + def sign_tx(self, transaction: bytes) -> Generator[None, None, None]: with self.backend.exchange_async(cla=CLA, - ins=InsType.SIGN_TX, - p1=P1.P1_START, + ins=InsType.SIGN_TRANSACTION, + p1=P1.P1_CONFIRM, p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big") + transaction) as response: + data=transaction) as response: yield response def get_async_response(self) -> Optional[RAPDU]: diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..487ea10fcfeb2f3e6b79239459672251d49addd7 GIT binary patch literal 414 zcmV;P0b%}$P)vpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*(jh-fK3T23(Y4`gbm7ef>$a^q?R-l&=-{~*9?`WIUM+ZC z_-)R@Icl3+UCJHS*$2HnHqqnATuz~ct*0)}*gTc_Y>@Kxp5GI9r@#1Y?eKYXpuf*; z^U#U!Ct5$8`})?*D`^ut|K(~eRQqMF%&r{R>UN9M$a06sLsn1#AOXG4Y$@BX2_4!m QwFD&U>FVdQ&MBb@0PMM>*Z=?k literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79a77673d7bd10a263a1a333e44005aaf77d60a9 GIT binary patch literal 517 zcmV+g0{Z=lP)Jzp^b!$W#V8|MH30DxnK5JCvry-@J2-2vyE zOH;pX4eYG(0KjumI7exhQAcNIY3!B?Nu$4Bn)?1M<*Z2KSb7uc$|oWhO#U9+WRtseX%= zUl^V0$L>4;003QIGlj%yZze4xs#nkWt?HdJ{dQU%HZp`ov90QPc_t+w&f1r<2xXRZ zCU4p*tUH93@q^f%1)O;%+Q9M<9?Jz)cYSL+$BX{<&#Q|JbElTsAw1K${vC0%A1;Pb zWwNQxolb-MhtRT^3mUF%3cH>7d#C;Tj0|BV1kGo=E_G!mJ428QF!@QXQ`fL=S+W}6 zg|bXF3dif22KNs^baK!%-qW09W`CQ?R5SaVu?CumLYfAX%o@C^oZhKy=w_`Wok%g3 zN4oI$B{=s+Zt~w-%R0wO07Gy+w>U2Jc1%mN zBFKGbec)?(g&BYnfHj}-t5M#;`h=-O; zeY!y~XE^=_!6nq)@j@lb*@cQ-YDFnutcBs~wK#i<3zosz^x zEB>XOWAp*+2~dmVpd39*dJM1ou;O`t0>-w+K-t=)Lybw8iDDakPncl}{E*-chw09{ zU4o^O-t++OBy08`!Gl?^IOAwzr6lzzS;Q_ z=DRG!1JVl`EAkxU*lZV5&UEbq_ZZLF1@NRkpip*@lG$PwKx&YncW}+@RsB9t3-Fjk zHIA^mCyoksrVbWX@!TU_jThiukrD^AjgBoU;prCG6VUcY>XEpSw9ReMCLW#!iSZsvkqjvbGmoeLSx3idvD0fGtC)Pt>jVpMI!c~XH*x!*UvedO{Wg$KL%}cUVHz3+ yWsru>mYD6E|CtAbrc+_tI0000008hY#u#Ia{Gp)!u6V?? z;uv(DqVT>e8l7*WqW!yc9((W23U4mgbt-P>XM2kQ^9IbG*n9V~kS{TLhmxmnxBm?g z2^DXHxHq$~Iepelv^ZCnc$c`#dubl3dILnb$-ckV!kpY>x<$2Honx<(IiM9xs(sR~ zk{(|=6WFoYYx4tm#XS!Ne`C6?oatQgXnr~VpCr5q&D@Xl3e4O z7dkE2DliY}Lh(m_!_GTo)`_d>&FXvr4^?eNEGX?q!6v9abh1Yu+K$$5tN97)op?7R z`7OD8%bD@;4ZNYi`yC?~g3Nz2jn6W%#TAkpd6_XVqvQ>^)w7;AzIH7!<&?%8DEUF= zWcKqXijvFy?K9*ubm0!YwPW))Ak7nX0P&*p)wsF$*=m-d3qSq@7cvg#+rk<*$z=Z+ zBh_U8FrL9XF$%rYMUr_2rARLT0000000000000000026P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*(jh-fK3T23(Y4`gbm7ef>$a^q?R-l&=-{~*9?`WIUM+ZC z_-)R@Icl3+UCJHS*$2HnHqqnATuz~ct*0)}*gTc_Y>@Kxp5GI9r@#1Y?eKYXpuf*; z^U#U!Ct5$8`})?*D`^ut|K(~eRQqMF%&r{R>UN9M$a06sLsn1#AOXG4Y$@BX2_4!m QwFD&U>FVdQ&MBb@0PMM>*Z=?k literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00002.png b/tests/snapshots/nanox/test_sign_tx_transfer/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..79a77673d7bd10a263a1a333e44005aaf77d60a9 GIT binary patch literal 517 zcmV+g0{Z=lP)Jzp^b!$W#V8|MH30DxnK5JCvry-@J2-2vyE zOH;pX4eYG(0KjumI7exhQAcNIY3!B?Nu$4Bn)?1M<*Z2KSb7uc$|oWhO#U9+WRtseX%= zUl^V0$L>4;003QIGlj%yZze4xs#nkWt?HdJ{dQU%HZp`ov90QPc_t+w&f1r<2xXRZ zCU4p*tUH93@q^f%1)O;%+Q9M<9?Jz)cYSL+$BX{<&#Q|JbElTsAw1K${vC0%A1;Pb zWwNQxolb-MhtRT^3mUF%3cH>7d#C;Tj0|BV1kGo=E_G!mJ428QF!@QXQ`fL=S+W}6 zg|bXF3dif22KNs^baK!%-qW09W`CQ?R5SaVu?CumLYfAX%o@C^oZhKy=w_`Wok%g3 zN4oI$B{=s+Zt~w-%R0wO07Gy+w>U2Jc1%mN zBFKGbec)?(g&BYnfHj}-t5M#;`h=-O; zeY!y~XE^=_!6nq)@j@lb*@cQ-YDFnutcBs~wK#i<3zosz^x zEB>XOWAp*+2~dmVpd39*dJM1ou;O`t0>-w+K-t=)Lybw8iDDakPncl}{E*-chw09{ zU4o^O-t++OBy08`!Gl?^IOAwzr6lzzS;Q_ z=DRG!1JVl`EAkxU*lZV5&UEbq_ZZLF1@NRkpip*@lG$PwKx&YncW}+@RsB9t3-Fjk zHIA^mCyoksrVbWX@!TU_jThiukrD^AjgBoU;prCG6VUcY>XEpSw9ReMCLW#!iSZsvkqjvbGmoeLSx3idvD0fGtC)Pt>jVpMI!c~XH*x!*UvedO{Wg$KL%}cUVHz3+ yWsru>mYD6E|CtAbrc+_tI0000008hY#u#Ia{Gp)!u6V?? z;uv(DqVT>e8l7*WqW!yc9((W23U4mgbt-P>XM2kQ^9IbG*n9V~kS{TLhmxmnxBm?g z2^DXHxHq$~Iepelv^ZCnc$c`#dubl3dILnb$-ckV!kpY>x<$2Honx<(IiM9xs(sR~ zk{(|=6WFoYYx4tm#XS!Ne`C6?oatQgXnr~VpCr5q&D@Xl3e4O z7dkE2DliY}Lh(m_!_GTo)`_d>&FXvr4^?eNEGX?q!6v9abh1Yu+K$$5tN97)op?7R z`7OD8%bD@;4ZNYi`yC?~g3Nz2jn6W%#TAkpd6_XVqvQ>^)w7;AzIH7!<&?%8DEUF= zWcKqXijvFy?K9*ubm0!YwPW))Ak7nX0P&*p)wsF$*=m-d3qSq@7cvg#+rk<*$z=Z+ zBh_U8FrL9XF$%rYMUr_2rARLT0000000000000000026P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o None: +@pytest.mark.active_test_scope +def test_sign_tx_transfer(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str) -> None: # Use the app interface instead of raw interface client = EverscaleCommandSender(backend) - account_number = 0 - wallet_type = WalletType.WALLET_V3 - # First we need to get the public key of the device in order to build the transaction - rapdu = client.get_public_key(account_number=account_number) - _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) # Raw transaction - transaction = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000") + transaction = bytes.fromhex("00000000010904455645520001010301006c000161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7cfb9642b3d6449ea677323640010165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d038020000") + # Send the sign device instruction. # As it requires on-screen validation, the function is asynchronous. # It will yield the result when the navigation is done - with client.sign_tx(account_number=account_number, wallet_type=wallet_type, transaction=transaction): + with client.sign_tx(transaction): # Validate the on-screen request by performing the navigation appropriate for this device - scenario_navigator.review_approve() + navigate_until_text_and_compare( + backend.firmware, + navigator, + "Accept", + default_screenshot_path, + test_name + ) # The device as yielded the result, parse it and ensure that the signature is correct response = client.get_async_response().data _, der_sig, _ = unpack_sign_tx_response(response) - assert der_sig.hex() == "0000000000000000000000000000000000000000000000000000000000000000" + assert der_sig.hex() == "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808" # # In this test we send to the device a transaction to trig a blind-signing flow diff --git a/tests/test_sign_message_cmd.py b/tests/test_sign_message_cmd.py index befb48a..9bcd3ac 100644 --- a/tests/test_sign_message_cmd.py +++ b/tests/test_sign_message_cmd.py @@ -6,7 +6,6 @@ from ragger.navigator import Navigator, NavInsID from ragger.navigator.navigation_scenario import NavigateWithScenario -from application_client.everscale_transaction import Transaction from application_client.everscale_command_sender import EverscaleCommandSender, Errors, WalletType from application_client.everscale_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response from utils import check_signature_validity diff --git a/tests/utils.py b/tests/utils.py index b342855..000024b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,7 @@ from ecdsa.curves import SECP256k1 from ecdsa.keys import VerifyingKey from ecdsa.util import sigdecode_der - +from ragger.navigator import NavInsID # Check if a signature of a given message is valid def check_signature_validity(public_key: bytes, signature: bytes, message: bytes) -> bool: @@ -74,3 +74,56 @@ def _read_makefile() -> List[str]: with open(makefile, "r", encoding="utf-8") as f_p: lines = f_p.readlines() return lines + + +def navigate_until_text_and_compare( + firmware, + navigator, + text: str, + screenshot_path: str, + test_name: str, + screen_change_before_first_instruction: bool = True, + screen_change_after_last_instruction: bool = True, + nav_ins_confirm_instruction: NavInsID = NavInsID.USE_CASE_REVIEW_CONFIRM, +): + """Navigate through device screens until specified text is found and compare screenshots. + + This function handles navigation through device screens differently based on the device type (Stax/Flex vs others). + It will navigate through screens until the specified text is found, taking screenshots for comparison along the way. + + Args: + firmware: The firmware object containing device information + navigator: The navigator object used to control device navigation + text: The text string to search for on device screens + screenshot_path: Path where screenshot comparison files will be saved + test_name: The name of the test that is being run + screen_change_before_first_instruction: Whether to wait for screen change before first instruction + screen_change_after_last_instruction: Whether to wait for screen change after last instruction + Returns: + None + + Note: + For Stax/Flex devices: + - Uses swipe left gesture for navigation + - Uses review confirm for confirmation + For other devices: + - Uses right click for navigation + - Uses both click for confirmation + """ + if firmware.device.startswith(("stax", "flex")): + go_right_instruction = NavInsID.SWIPE_CENTER_TO_LEFT + confirm_instructions = [nav_ins_confirm_instruction] + else: + go_right_instruction = NavInsID.RIGHT_CLICK + confirm_instructions = [NavInsID.BOTH_CLICK] + + navigator.navigate_until_text_and_compare( + go_right_instruction, + confirm_instructions, + text, + screenshot_path, + test_name, + 300, + screen_change_before_first_instruction, + screen_change_after_last_instruction, + ) From 75152ddf804eafd8c03680321a4835044e1a151b Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:07:59 +0100 Subject: [PATCH 15/33] refactor: update sign flow message display text Minor UI text adjustment in the sign flow to add a period at the end of the "message" text to create a difference between first screen and validation screen --- src/sign.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sign.c b/src/sign.c index d6b0740..7788dd6 100644 --- a/src/sign.c +++ b/src/sign.c @@ -58,7 +58,7 @@ UX_STEP_CB( { &C_icon_validate_14, "Sign", - "message", + "message.", }); UX_FLOW(ux_sign_flow, From 8f7908aee971978dce000a0a9a672baf4dcec883 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:09:14 +0100 Subject: [PATCH 16/33] test: implement message signing test - Update sign_message test with new payload and signature - Modify command sender to simplify message signing method - Add screenshot navigation for cross-device testing - Remove account number and wallet type from signing flow - Add snapshot images for NanoSP and NanoX devices --- .../everscale_command_sender.py | 4 ++-- .../nanosp/test_sign_message/00000.png | Bin 0 -> 415 bytes .../nanosp/test_sign_message/00001.png | Bin 0 -> 495 bytes .../nanosp/test_sign_message/00002.png | Bin 0 -> 443 bytes .../nanosp/test_sign_message/00003.png | Bin 0 -> 503 bytes .../nanosp/test_sign_message/00004.png | Bin 0 -> 451 bytes .../nanosp/test_sign_message/00005.png | Bin 0 -> 382 bytes .../nanox/test_sign_message/00000.png | Bin 0 -> 415 bytes .../nanox/test_sign_message/00001.png | Bin 0 -> 495 bytes .../nanox/test_sign_message/00002.png | Bin 0 -> 443 bytes .../nanox/test_sign_message/00003.png | Bin 0 -> 503 bytes .../nanox/test_sign_message/00004.png | Bin 0 -> 451 bytes .../nanox/test_sign_message/00005.png | Bin 0 -> 382 bytes tests/test_sign_message_cmd.py | 20 ++++++++++++------ 14 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 tests/snapshots/nanosp/test_sign_message/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_message/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_message/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_message/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_message/00004.png create mode 100644 tests/snapshots/nanosp/test_sign_message/00005.png create mode 100644 tests/snapshots/nanox/test_sign_message/00000.png create mode 100644 tests/snapshots/nanox/test_sign_message/00001.png create mode 100644 tests/snapshots/nanox/test_sign_message/00002.png create mode 100644 tests/snapshots/nanox/test_sign_message/00003.png create mode 100644 tests/snapshots/nanox/test_sign_message/00004.png create mode 100644 tests/snapshots/nanox/test_sign_message/00005.png diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 5312ca6..86a3aab 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -145,12 +145,12 @@ def get_address_with_confirmation(self, account_number: int, wallet_type: Wallet @contextmanager - def sign_message(self, account_number: int, wallet_type: WalletType, message: bytes) -> Generator[None, None, None]: + def sign_message(self, payload: bytes) -> Generator[None, None, None]: with self.backend.exchange_async(cla=CLA, ins=InsType.SIGN_MESSAGE, p1=P1.P1_CONFIRM, p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big") + message) as response: + data=payload) as response: yield response @contextmanager diff --git a/tests/snapshots/nanosp/test_sign_message/00000.png b/tests/snapshots/nanosp/test_sign_message/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1b271542d4bdb2b420bf296e4efb75129bcde20b GIT binary patch literal 415 zcmV;Q0bu@#P)5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message/00001.png b/tests/snapshots/nanosp/test_sign_message/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..db58d4271e08ae84259d65e743b146b6eeb34040 GIT binary patch literal 495 zcmVCRas>u{W-+tmB-kpkV8Dl<-x{vwMKau1!vxGfGVdp z7D#u;oH<2zl&7kD)I2wmyS@QsMm2jX9PLTZk!n#_)XS(&VQ3{+x19&w%Q>(GwKiy# zz5m#%oyuR~Q07OnIfI6&E$BL5UeSlPy%>?!lBu$(r|_2~(+(xE@A)z!x7lac&<9ns zW^^c|o)2Zxdx-Xp#vQsPNC7!3$U l1A@_jU^D;#008)ZegSnO17HlDNRj{m002ovPDHLkV1o5L-%9`h literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message/00002.png b/tests/snapshots/nanosp/test_sign_message/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..464ffaaead3e4412e784f03312a4bf44e4a813a8 GIT binary patch literal 443 zcmV;s0Yv_ZP)oH7i0AUiSYB=>x^#1=w49H$fj003aSFaP7#+VMxN)oRIg z?30 z1|Ne&_O$iUGO?v+cR-(Zb>ve{V@v&0MBT@0{4V4zk>K)TXI$pUW1O51(H)@bah;tZ z*V;0tco)mNB3YdcJ8dcFkq{Bu0b@8dbR87C=)GlH)Dv|KQx^^^xO(iwMQ*te_QVln z9ndQO{P9gERXoE}kuOJZ{&gBHPaQ!=XMIH%?Raroto1TQQ@e<#B*UHxGUea5mlI!} zw69%8cbTf@%uq@`HwEE6!1StR>&IEV32$b79|ZusGx=>{XUnHM${~M2+|z;w|JCX4 zmMpvnBx3@SF#*Y#fMoLo{GX@OTUwNt>Th5cnd)z&l$z>q#vEkg6w1VNI1}Xs00000 l00000000000001P^9z5Ghd}eiv=IOR002ovPDHLkV1h{_#5({0 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message/00003.png b/tests/snapshots/nanosp/test_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..e52854f5ba2364e90179f67a78c28752a8349b4c GIT binary patch literal 503 zcmVK70z}J!-{_0Tk97eKYAYO%(HD!#`&@lUi0Y3 z!mVF%)6EA9u=BuEo(YY40^~c?OWrl-K&C8fIou5)w4>toWc6}$sql4qX82zWF1Y7y zb?5jcR+J||dTFsX7_9cRcENHIRgjnR*lamSv1==nUFP{YqE+?vWZYE69oH6n&L7g2 zYOY23^;WdnncLxAjc|1d0002~uNkHXa1D34G#H4j502E=p4I8kkx`pEWGnAxK51(9 zUQqc~p?b91XlGHvhcx5c^_$Cg#PhW$C!LO2wokdo`6+>uk*dONRdE?4psY-KldqfU zxn!cWD%JU$9AHxgZB`MRCtO&P2fk&6!4ojj;`Ls_EiY6%Jmvo066X4?%u`~iimAIk tH~`B(DjZZpw2C0ssKJtyu-Nf#oo{^!u-4&!p|! z==N;!POxkrV1cDiF0C=cO8ML3+B9_dSIH%&lS7;=TomE&y7j+pdoaH|aNrOp3)cYS zXL?(>I(fJ5k@l4xCZ-WKZsDScNm1tKpSSsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message/00001.png b/tests/snapshots/nanox/test_sign_message/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..db58d4271e08ae84259d65e743b146b6eeb34040 GIT binary patch literal 495 zcmVCRas>u{W-+tmB-kpkV8Dl<-x{vwMKau1!vxGfGVdp z7D#u;oH<2zl&7kD)I2wmyS@QsMm2jX9PLTZk!n#_)XS(&VQ3{+x19&w%Q>(GwKiy# zz5m#%oyuR~Q07OnIfI6&E$BL5UeSlPy%>?!lBu$(r|_2~(+(xE@A)z!x7lac&<9ns zW^^c|o)2Zxdx-Xp#vQsPNC7!3$U l1A@_jU^D;#008)ZegSnO17HlDNRj{m002ovPDHLkV1o5L-%9`h literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message/00002.png b/tests/snapshots/nanox/test_sign_message/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..464ffaaead3e4412e784f03312a4bf44e4a813a8 GIT binary patch literal 443 zcmV;s0Yv_ZP)oH7i0AUiSYB=>x^#1=w49H$fj003aSFaP7#+VMxN)oRIg z?30 z1|Ne&_O$iUGO?v+cR-(Zb>ve{V@v&0MBT@0{4V4zk>K)TXI$pUW1O51(H)@bah;tZ z*V;0tco)mNB3YdcJ8dcFkq{Bu0b@8dbR87C=)GlH)Dv|KQx^^^xO(iwMQ*te_QVln z9ndQO{P9gERXoE}kuOJZ{&gBHPaQ!=XMIH%?Raroto1TQQ@e<#B*UHxGUea5mlI!} zw69%8cbTf@%uq@`HwEE6!1StR>&IEV32$b79|ZusGx=>{XUnHM${~M2+|z;w|JCX4 zmMpvnBx3@SF#*Y#fMoLo{GX@OTUwNt>Th5cnd)z&l$z>q#vEkg6w1VNI1}Xs00000 l00000000000001P^9z5Ghd}eiv=IOR002ovPDHLkV1h{_#5({0 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message/00003.png b/tests/snapshots/nanox/test_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..e52854f5ba2364e90179f67a78c28752a8349b4c GIT binary patch literal 503 zcmVK70z}J!-{_0Tk97eKYAYO%(HD!#`&@lUi0Y3 z!mVF%)6EA9u=BuEo(YY40^~c?OWrl-K&C8fIou5)w4>toWc6}$sql4qX82zWF1Y7y zb?5jcR+J||dTFsX7_9cRcENHIRgjnR*lamSv1==nUFP{YqE+?vWZYE69oH6n&L7g2 zYOY23^;WdnncLxAjc|1d0002~uNkHXa1D34G#H4j502E=p4I8kkx`pEWGnAxK51(9 zUQqc~p?b91XlGHvhcx5c^_$Cg#PhW$C!LO2wokdo`6+>uk*dONRdE?4psY-KldqfU zxn!cWD%JU$9AHxgZB`MRCtO&P2fk&6!4ojj;`Ls_EiY6%Jmvo066X4?%u`~iimAIk tH~`B(DjZZpw2C0ssKJtyu-Nf#oo{^!u-4&!p|! z==N;!POxkrV1cDiF0C=cO8ML3+B9_dSIH%&lS7;=TomE&y7j+pdoaH|aNrOp3)cYS zXL?(>I(fJ5k@l4xCZ-WKZsDScNm1tKpSSsAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o None: +@pytest.mark.active_test_scope +def test_sign_message(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str) -> None: # Use the app interface instead of raw interface client = EverscaleCommandSender(backend) account_number = 0 wallet_type = WalletType.WALLET_V3 # First we need to get the public key of the device in order to build the transaction rapdu = client.get_public_key(account_number=account_number) - _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) # Message to sign - message = b"Hello, world!" + payload = bytes.fromhex("00000000001111111111111111111111111111111111111111111111111111111111111111") # Send the sign device instruction. # As it requires on-screen validation, the function is asynchronous. # It will yield the result when the navigation is done - with client.sign_message(account_number=account_number, wallet_type=wallet_type, message=message): + with client.sign_message(payload=payload): # Validate the on-screen request by performing the navigation appropriate for this device - scenario_navigator.review_approve() + navigate_until_text_and_compare( + backend.firmware, + navigator, + "message.", + default_screenshot_path, + test_name + ) # The device as yielded the result, parse it and ensure that the signature is correct response = client.get_async_response().data _, der_sig, _ = unpack_sign_tx_response(response) - assert der_sig.hex() == "0000000000000000000000000000000000000000000000000000000000000000" \ No newline at end of file + assert der_sig.hex() == "d2edfcb178abad8df455f605d2887e6fed24ed1d2462e1fc216fad55f2e60fa372239ce950b7ab944a2eb80a2bcfaadfa02f870c6b3ed6df29fa9bc7419a730f" \ No newline at end of file From c1747e58f0800ad31e327eec7dfcb19abc2254b8 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:16:19 +0100 Subject: [PATCH 17/33] test: delete useless tests --- tests/test_app_mainmenu.py | 54 ---------------------------------- tests/test_appname_cmd.py | 16 ----------- tests/test_error_cmd.py | 59 -------------------------------------- tests/test_name_version.py | 18 ------------ 4 files changed, 147 deletions(-) delete mode 100644 tests/test_app_mainmenu.py delete mode 100644 tests/test_appname_cmd.py delete mode 100644 tests/test_error_cmd.py delete mode 100644 tests/test_name_version.py diff --git a/tests/test_app_mainmenu.py b/tests/test_app_mainmenu.py deleted file mode 100644 index d5ee01f..0000000 --- a/tests/test_app_mainmenu.py +++ /dev/null @@ -1,54 +0,0 @@ -from ragger.firmware import Firmware -from ragger.navigator import Navigator, NavInsID, NavIns - - -# In this test we check the behavior of the device main menu -def test_app_mainmenu(firmware: Firmware, - navigator: Navigator, - test_name: str, - default_screenshot_path: str) -> None: - # Navigate in the main menu - instructions = [] - if firmware.is_nano: - instructions += [ - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.RIGHT_CLICK, - NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, - ] - elif firmware is Firmware.STAX: - instructions += [ - NavInsID.USE_CASE_HOME_SETTINGS, - NavIns(NavInsID.TOUCH, (200, 113)), - NavIns(NavInsID.TOUCH, (200, 261)), - NavInsID.USE_CASE_CHOICE_CONFIRM, - NavIns(NavInsID.TOUCH, (200, 261)), - NavInsID.USE_CASE_SETTINGS_NEXT, - NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT - ] - elif firmware is Firmware.FLEX: - instructions += [ - NavInsID.USE_CASE_HOME_SETTINGS, - NavIns(NavInsID.TOUCH, (200, 113)), - NavIns(NavInsID.TOUCH, (200, 300)), - NavInsID.USE_CASE_CHOICE_CONFIRM, - NavIns(NavInsID.TOUCH, (200, 300)), - NavInsID.USE_CASE_SETTINGS_NEXT, - NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT - ] - - assert len(instructions) > 0 - navigator.navigate_and_compare(default_screenshot_path, test_name, instructions, - screen_change_before_first_instruction=False) diff --git a/tests/test_appname_cmd.py b/tests/test_appname_cmd.py deleted file mode 100644 index 277c58a..0000000 --- a/tests/test_appname_cmd.py +++ /dev/null @@ -1,16 +0,0 @@ -from ragger.backend.interface import BackendInterface - -from application_client.everscale_command_sender import EverscaleCommandSender -from application_client.everscale_response_unpacker import unpack_get_app_name_response - -from utils import verify_name - - -# In this test we check that the GET_APP_NAME replies the application name -def test_app_name(backend: BackendInterface) -> None: - # Use the app interface instead of raw interface - client = EverscaleCommandSender(backend) - # Send the GET_APP_NAME instruction to the app - response = client.get_app_name() - # Assert that we have received the correct appname - verify_name(unpack_get_app_name_response(response.data)) diff --git a/tests/test_error_cmd.py b/tests/test_error_cmd.py deleted file mode 100644 index 12e3166..0000000 --- a/tests/test_error_cmd.py +++ /dev/null @@ -1,59 +0,0 @@ -import pytest - -from ragger.error import ExceptionRAPDU -from ragger.backend.interface import BackendInterface - -from application_client.everscale_command_sender import CLA, InsType, P1, P2, Errors - - -# Ensure the app returns an error when a bad CLA is used -def test_bad_cla(backend: BackendInterface) -> None: - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA + 1, ins=InsType.GET_VERSION) - assert e.value.status == Errors.SW_CLA_NOT_SUPPORTED - - -# Ensure the app returns an error when a bad INS is used -def test_bad_ins(backend: BackendInterface) -> None: - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, ins=0xff) - assert e.value.status == Errors.SW_INS_NOT_SUPPORTED - - -# Ensure the app returns an error when a bad P1 or P2 is used -def test_wrong_p1p2(backend: BackendInterface) -> None: - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START + 1, p2=P2.P2_LAST) - assert e.value.status == Errors.SW_WRONG_P1P2 - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START, p2=P2.P2_MORE) - assert e.value.status == Errors.SW_WRONG_P1P2 - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START + 1, p2=P2.P2_LAST) - assert e.value.status == Errors.SW_WRONG_P1P2 - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_MORE) - assert e.value.status == Errors.SW_WRONG_P1P2 - - -# Ensure the app returns an error when a bad data length is used -def test_wrong_data_length(backend: BackendInterface) -> None: - # APDUs must be at least 4 bytes: CLA, INS, P1, P2. - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange_raw(bytes.fromhex("E00300")) - assert e.value.status == Errors.SW_WRONG_DATA_LENGTH - # APDUs advertises a too long length - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange_raw(bytes.fromhex("E003000005")) - assert e.value.status == Errors.SW_WRONG_DATA_LENGTH - - -# Ensure there is no state confusion when trying wrong APDU sequences -def test_invalid_state(backend: BackendInterface) -> None: - with pytest.raises(ExceptionRAPDU) as e: - backend.exchange(cla=CLA, - ins=InsType.SIGN_TX, - p1=P1.P1_START + 1, # Try to continue a flow instead of start a new one - p2=P2.P2_MORE, - data=b"abcde") # data is not parsed in this case - assert e.value.status == Errors.SW_BAD_STATE diff --git a/tests/test_name_version.py b/tests/test_name_version.py deleted file mode 100644 index ce3e067..0000000 --- a/tests/test_name_version.py +++ /dev/null @@ -1,18 +0,0 @@ -from ragger.backend.interface import BackendInterface - -from application_client.everscale_command_sender import EverscaleCommandSender -from application_client.everscale_response_unpacker import unpack_get_app_and_version_response - -from utils import verify_version, verify_name - -# Test a specific APDU asking BOLOS (and not the app) the name and version of the current app -def test_get_app_and_version(backend: BackendInterface) -> None: - # Use the app interface instead of raw interface - client = EverscaleCommandSender(backend) - # Send the special instruction to BOLOS - response = client.get_app_and_version() - # Use an helper to parse the response, assert the values - app_name, version = unpack_get_app_and_version_response(response.data) - - verify_name(app_name) - verify_version(version) From e3b548a4fa2b30c07b57b635b2289f397ed4fbde Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:26:44 +0100 Subject: [PATCH 18/33] test: update transaction signing test with TODO comments - Remove TODO comment for raw transaction and signature - Add TODO comment for testing other transaction types --- tests/test_sign_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py index 9f68a04..5e36c3a 100644 --- a/tests/test_sign_cmd.py +++ b/tests/test_sign_cmd.py @@ -17,7 +17,6 @@ # The transaction is short and will be sent in one chunk # We will ensure that the displayed information is correct by using screenshots comparison -# TODO: Add a valid raw transaction and a valid expected signature @pytest.mark.active_test_scope def test_sign_tx_transfer(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str) -> None: # Use the app interface instead of raw interface @@ -45,6 +44,7 @@ def test_sign_tx_transfer(backend: BackendInterface, navigator: Navigator, defau _, der_sig, _ = unpack_sign_tx_response(response) assert der_sig.hex() == "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808" +# TODO: Add tests for the other transaction types # # In this test we send to the device a transaction to trig a blind-signing flow # # The transaction is short and will be sent in one chunk From dc5e9999eccff81e9e1ae0b057770f8163fef5fb Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:46:10 +0100 Subject: [PATCH 19/33] ops: remove ClusterFuzzLite and documentation workflows - Delete cflite_cron.yml GitHub workflow for periodic fuzzing - Remove cflite_pr.yml GitHub workflow for PR-based fuzzing - Delete documentation_generation.yml workflow for generating project docs --- .github/workflows/cflite_cron.yml | 40 ----------------- .github/workflows/cflite_pr.yml | 43 ------------------- .../workflows/documentation_generation.yml | 29 ------------- 3 files changed, 112 deletions(-) delete mode 100644 .github/workflows/cflite_cron.yml delete mode 100644 .github/workflows/cflite_pr.yml delete mode 100644 .github/workflows/documentation_generation.yml diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml deleted file mode 100644 index 17c1e65..0000000 --- a/.github/workflows/cflite_cron.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: ClusterFuzzLite cron tasks -on: - workflow_dispatch: - push: - branches: - - main # Use your actual default branch here. - schedule: - - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday -permissions: read-all -jobs: - Fuzzing: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - mode: batch - sanitizer: address - - mode: batch - sanitizer: memory - - mode: prune - sanitizer: address - - mode: coverage - sanitizer: coverage - steps: - - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) - id: build - uses: google/clusterfuzzlite/actions/build_fuzzers@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - language: c # Change this to the language you are fuzzing. - sanitizer: ${{ matrix.sanitizer }} - - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) - id: run - uses: google/clusterfuzzlite/actions/run_fuzzers@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - fuzz-seconds: 300 # 5 minutes - mode: ${{ matrix.mode }} - sanitizer: ${{ matrix.sanitizer }} diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml deleted file mode 100644 index 09f91da..0000000 --- a/.github/workflows/cflite_pr.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: ClusterFuzzLite PR fuzzing -on: - pull_request: - paths: - - '**' -permissions: read-all -jobs: - PR: - runs-on: ubuntu-latest - concurrency: - group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} - cancel-in-progress: true - strategy: - fail-fast: false - matrix: - sanitizer: [address, undefined, memory] # Override this with the sanitizers you want. - steps: - - name: Build Fuzzers (${{ matrix.sanitizer }}) - id: build - uses: google/clusterfuzzlite/actions/build_fuzzers@v1 - with: - language: c # Change this to the language you are fuzzing. - github-token: ${{ secrets.GITHUB_TOKEN }} - sanitizer: ${{ matrix.sanitizer }} - # Optional but recommended: used to only run fuzzers that are affected - # by the PR. - # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git - # storage-repo-branch: main # Optional. Defaults to "main" - # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". - - name: Run Fuzzers (${{ matrix.sanitizer }}) - id: run - uses: google/clusterfuzzlite/actions/run_fuzzers@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - fuzz-seconds: 300 # 5 minutes - mode: 'code-change' - sanitizer: ${{ matrix.sanitizer }} - output-sarif: true - # Optional but recommended: used to download the corpus produced by - # batch fuzzing. - # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git - # storage-repo-branch: main # Optional. Defaults to "main" - # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". diff --git a/.github/workflows/documentation_generation.yml b/.github/workflows/documentation_generation.yml deleted file mode 100644 index 31b1efb..0000000 --- a/.github/workflows/documentation_generation.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Generate project documentation - -on: - workflow_dispatch: - push: - branches: - - master - - main - - develop - pull_request: - -jobs: - job_generate_doc: - name: Generate project documentation - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - name: Clone - uses: actions/checkout@v4 - - - name: HTML documentation - run: doxygen .doxygen/Doxyfile - - - uses: actions/upload-artifact@v4 - with: - name: documentation - path: doc/html From 8045bd652ef2954170c723f40e1cac71f0c63be3 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:50:04 +0100 Subject: [PATCH 20/33] style: format the C codebase --- src/byte_stream.c | 77 ++-- src/cell.c | 243 ++++++----- src/contract.c | 763 ++++++++++++++++---------------- src/get_address.c | 124 +++--- src/get_app_configuration.c | 29 +- src/get_public_key.c | 100 ++--- src/hashmap_label.c | 128 +++--- src/main.c | 508 +++++++++++----------- src/menu.c | 55 +-- src/message.c | 841 +++++++++++++++++++----------------- src/sign.c | 162 ++++--- src/sign_transaction.c | 406 ++++++++--------- src/slice_data.c | 330 +++++++------- src/utils.c | 316 +++++++------- 14 files changed, 2016 insertions(+), 2066 deletions(-) diff --git a/src/byte_stream.c b/src/byte_stream.c index cc5d518..7d785ff 100644 --- a/src/byte_stream.c +++ b/src/byte_stream.c @@ -2,58 +2,59 @@ #include "errors.h" #include "utils.h" -void ByteStream_init(struct ByteStream_t* self, uint8_t* data, uint16_t data_size) { - VALIDATE(self && data && data_size, ERR_INVALID_DATA); - self->data_size = data_size; - self->offset = 0; - self->data = data; +void ByteStream_init(struct ByteStream_t *self, uint8_t *data, + uint16_t data_size) { + VALIDATE(self && data && data_size, ERR_INVALID_DATA); + self->data_size = data_size; + self->offset = 0; + self->data = data; } -void ByteStream_move_by(struct ByteStream_t* self, uint16_t data_size) { - VALIDATE(data_size <= self->data_size - self->offset, ERR_END_OF_STREAM); - self->offset += data_size; +void ByteStream_move_by(struct ByteStream_t *self, uint16_t data_size) { + VALIDATE(data_size <= self->data_size - self->offset, ERR_END_OF_STREAM); + self->offset += data_size; } -uint8_t* ByteStream_read_data(struct ByteStream_t* self, uint32_t data_size) { - uint8_t* data = self->data + self->offset; - ByteStream_move_by(self, data_size); - return data; +uint8_t *ByteStream_read_data(struct ByteStream_t *self, uint32_t data_size) { + uint8_t *data = self->data + self->offset; + ByteStream_move_by(self, data_size); + return data; } -uint8_t ByteStream_read_byte(struct ByteStream_t* self) { - uint8_t byte = self->data[self->offset]; - ByteStream_move_by(self, 1); - return byte; +uint8_t ByteStream_read_byte(struct ByteStream_t *self) { + uint8_t byte = self->data[self->offset]; + ByteStream_move_by(self, 1); + return byte; } -uint32_t ByteStream_read_u32(struct ByteStream_t* self) { - uint32_t u32 = readUint32BE(self->data + self->offset); - ByteStream_move_by(self, sizeof(uint32_t)); - return u32; +uint32_t ByteStream_read_u32(struct ByteStream_t *self) { + uint32_t u32 = readUint32BE(self->data + self->offset); + ByteStream_move_by(self, sizeof(uint32_t)); + return u32; } -uint8_t* ByteStream_get_cursor(struct ByteStream_t* self) { - return self->data + self->offset; +uint8_t *ByteStream_get_cursor(struct ByteStream_t *self) { + return self->data + self->offset; } -uint64_t ByteStream_read_uint(struct ByteStream_t* self, uint16_t bytes) { - VALIDATE(bytes > 0 && bytes <= 8, ERR_INVALID_DATA); +uint64_t ByteStream_read_uint(struct ByteStream_t *self, uint16_t bytes) { + VALIDATE(bytes > 0 && bytes <= 8, ERR_INVALID_DATA); - uint64_t val; + uint64_t val; - if (bytes == 1) { - val = self->data[self->offset]; - } else if (bytes == 2) { - val = readUint16BE(self->data + self->offset); - } else if (bytes >= 3 && bytes <= 4) { - val = readUint32BE(self->data + self->offset); - } else if (bytes >= 5 && bytes <= 8) { - val = readUint64BE(self->data + self->offset); - } else { - THROW(ERR_INVALID_DATA); - } + if (bytes == 1) { + val = self->data[self->offset]; + } else if (bytes == 2) { + val = readUint16BE(self->data + self->offset); + } else if (bytes >= 3 && bytes <= 4) { + val = readUint32BE(self->data + self->offset); + } else if (bytes >= 5 && bytes <= 8) { + val = readUint64BE(self->data + self->offset); + } else { + THROW(ERR_INVALID_DATA); + } - ByteStream_move_by(self, bytes); + ByteStream_move_by(self, bytes); - return val; + return val; } diff --git a/src/cell.c b/src/cell.c index 59aa6a8..aa20ac0 100644 --- a/src/cell.c +++ b/src/cell.c @@ -1,141 +1,148 @@ #include "cell.h" #include "utils.h" -void Cell_init(struct Cell_t* self, uint8_t* cell_begin) { - VALIDATE(self && cell_begin, ERR_CELL_IS_EMPTY); - self->cell_begin = cell_begin; +void Cell_init(struct Cell_t *self, uint8_t *cell_begin) { + VALIDATE(self && cell_begin, ERR_CELL_IS_EMPTY); + self->cell_begin = cell_begin; } -uint8_t Cell_get_d1(const struct Cell_t* self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin[0]; +uint8_t Cell_get_d1(const struct Cell_t *self) { + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin[0]; } -uint8_t Cell_get_d2(const struct Cell_t* self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin[1]; +uint8_t Cell_get_d2(const struct Cell_t *self) { + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin[1]; } -uint8_t Cell_get_data_size(const struct Cell_t* self) { - uint8_t d2 = Cell_get_d2(self); - return (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); +uint8_t Cell_get_data_size(const struct Cell_t *self) { + uint8_t d2 = Cell_get_d2(self); + return (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); } -uint8_t* Cell_get_data(const struct Cell_t* self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin + CELL_DATA_OFFSET; +uint8_t *Cell_get_data(const struct Cell_t *self) { + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin + CELL_DATA_OFFSET; } -uint8_t* Cell_get_refs(const struct Cell_t* self, uint8_t* refs_count) { - uint8_t d1 = Cell_get_d1(self); - *refs_count = d1 & 7; - uint8_t data_size = Cell_get_data_size(self); - return self->cell_begin + CELL_DATA_OFFSET + data_size; +uint8_t *Cell_get_refs(const struct Cell_t *self, uint8_t *refs_count) { + uint8_t d1 = Cell_get_d1(self); + *refs_count = d1 & 7; + uint8_t data_size = Cell_get_data_size(self); + return self->cell_begin + CELL_DATA_OFFSET + data_size; } -uint16_t Cell_bit_len(struct Cell_t* self) { - uint8_t data_size = Cell_get_data_size(self); +uint16_t Cell_bit_len(struct Cell_t *self) { + uint8_t data_size = Cell_get_data_size(self); - uint16_t bit_len = data_size * 8; - if ((Cell_get_d2(self) & 0b1) == 0) { - return bit_len; - } - - uint8_t* data = Cell_get_data(self); - for (uint8_t i = data_size - 1; i >= 0; --i) { - if (data[i] == 0) { - bit_len -= 8; - } else { - uint8_t skip = 1; - uint8_t mask = 1; - while ((data[i] & mask) == 0) { - skip += 1; - mask <<= 1; - } - bit_len -= skip; - break; - } - } + uint16_t bit_len = data_size * 8; + if ((Cell_get_d2(self) & 0b1) == 0) { return bit_len; -} - -uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const uint8_t cells_count) { - uint8_t d1 = Cell_get_d1(cell); - uint8_t level = d1 >> 5; // level - uint8_t hashes = (d1 & 16) == 16; // with hashes - uint8_t exotic = (d1 & 8) == 8; // exotic - uint8_t refs_count = d1 & 7; // refs count - uint8_t absent = refs_count == 7 && hashes; - uint8_t pruned = d1 == PRUNED_BRANCH_D1; - UNUSED(level); - - VALIDATE(!hashes, ERR_INVALID_DATA); - VALIDATE(!exotic || pruned, ERR_INVALID_DATA); // only ordinary or pruned cells are valid - VALIDATE(refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - VALIDATE(!absent, ERR_INVALID_DATA); - - uint8_t data_size = Cell_get_data_size(cell); - VALIDATE(!pruned || pruned && (data_size == PRUNED_BRANCH_DATA_SIZE), ERR_INVALID_DATA); - - uint8_t* refs = Cell_get_refs(cell, &refs_count); - for (uint8_t i = 0; i < refs_count; ++i) { - uint8_t ref = refs[i]; - VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_DATA); - } - - return CELL_DATA_OFFSET + data_size + refs_count; // cell size -} + } -void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) { - BocContext_t* bc = &boc_context; - - uint8_t d1 = Cell_get_d1(cell); - if (d1 == PRUNED_BRANCH_D1) { - // handle pruned branch case - // 1 byte - cell type - // 1 byte - level mask - // 32 bytes - hash - // 2 bytes - cell depth (BE) - uint8_t* cell_data = Cell_get_data(cell); - memcpy(bc->hashes + cell_index * HASH_SIZE, cell_data + 2, HASH_SIZE); - bc->cell_depth[cell_index] = *(cell_data + 2 + HASH_SIZE + 1); - return; - } - - uint8_t hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32)) - - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = d1 & 0b00011111; - hash_buffer[1] = Cell_get_d2(cell); - hash_buffer_offset += 2; - uint8_t data_size = Cell_get_data_size(cell); - if (bc->public_key_cell_index && cell_index == bc->public_key_cell_index) { - memcpy(hash_buffer + hash_buffer_offset, bc->public_key_cell_data, data_size); + uint8_t *data = Cell_get_data(self); + for (uint8_t i = data_size - 1; i >= 0; --i) { + if (data[i] == 0) { + bit_len -= 8; } else { - memcpy(hash_buffer + hash_buffer_offset, Cell_get_data(cell), data_size); - } - hash_buffer_offset += data_size; - - uint8_t refs_count = 0; - uint8_t* refs = Cell_get_refs(cell, &refs_count); - VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t* depth = &bc->cell_depth[cell_index]; - uint8_t child_depth = bc->cell_depth[refs[child]]; - *depth = (*depth > child_depth + 1) ? *depth : (child_depth + 1); - uint8_t buf[2]; - buf[0] = 0; - buf[1] = child_depth; - memcpy(hash_buffer + hash_buffer_offset, buf, sizeof(buf)); - hash_buffer_offset += sizeof(buf); + uint8_t skip = 1; + uint8_t mask = 1; + while ((data[i] & mask) == 0) { + skip += 1; + mask <<= 1; + } + bit_len -= skip; + break; } + } + return bit_len; +} - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t* cell_hash = bc->hashes + refs[child] * HASH_SIZE; - memcpy(hash_buffer + hash_buffer_offset, cell_hash, HASH_SIZE); - hash_buffer_offset += HASH_SIZE; - } +uint16_t deserialize_cell(struct Cell_t *cell, const uint8_t cell_index, + const uint8_t cells_count) { + uint8_t d1 = Cell_get_d1(cell); + uint8_t level = d1 >> 5; // level + uint8_t hashes = (d1 & 16) == 16; // with hashes + uint8_t exotic = (d1 & 8) == 8; // exotic + uint8_t refs_count = d1 & 7; // refs count + uint8_t absent = refs_count == 7 && hashes; + uint8_t pruned = d1 == PRUNED_BRANCH_D1; + UNUSED(level); + + VALIDATE(!hashes, ERR_INVALID_DATA); + VALIDATE(!exotic || pruned, + ERR_INVALID_DATA); // only ordinary or pruned cells are valid + VALIDATE(refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + VALIDATE(!absent, ERR_INVALID_DATA); + + uint8_t data_size = Cell_get_data_size(cell); + VALIDATE(!pruned || pruned && (data_size == PRUNED_BRANCH_DATA_SIZE), + ERR_INVALID_DATA); + + uint8_t *refs = Cell_get_refs(cell, &refs_count); + for (uint8_t i = 0; i < refs_count; ++i) { + uint8_t ref = refs[i]; + VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_DATA); + } + + return CELL_DATA_OFFSET + data_size + refs_count; // cell size +} - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, bc->hashes + cell_index * HASH_SIZE, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); +void calc_cell_hash(Cell_t *cell, const uint8_t cell_index) { + BocContext_t *bc = &boc_context; + + uint8_t d1 = Cell_get_d1(cell); + if (d1 == PRUNED_BRANCH_D1) { + // handle pruned branch case + // 1 byte - cell type + // 1 byte - level mask + // 32 bytes - hash + // 2 bytes - cell depth (BE) + uint8_t *cell_data = Cell_get_data(cell); + memcpy(bc->hashes + cell_index * HASH_SIZE, cell_data + 2, HASH_SIZE); + bc->cell_depth[cell_index] = *(cell_data + 2 + HASH_SIZE + 1); + return; + } + + uint8_t + hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32)) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = d1 & 0b00011111; + hash_buffer[1] = Cell_get_d2(cell); + hash_buffer_offset += 2; + uint8_t data_size = Cell_get_data_size(cell); + if (bc->public_key_cell_index && cell_index == bc->public_key_cell_index) { + memcpy(hash_buffer + hash_buffer_offset, bc->public_key_cell_data, + data_size); + } else { + memcpy(hash_buffer + hash_buffer_offset, Cell_get_data(cell), data_size); + } + hash_buffer_offset += data_size; + + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(cell, &refs_count); + VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, + ERR_INVALID_DATA); + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t *depth = &bc->cell_depth[cell_index]; + uint8_t child_depth = bc->cell_depth[refs[child]]; + *depth = (*depth > child_depth + 1) ? *depth : (child_depth + 1); + uint8_t buf[2]; + buf[0] = 0; + buf[1] = child_depth; + memcpy(hash_buffer + hash_buffer_offset, buf, sizeof(buf)); + hash_buffer_offset += sizeof(buf); + } + + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t *cell_hash = bc->hashes + refs[child] * HASH_SIZE; + memcpy(hash_buffer + hash_buffer_offset, cell_hash, HASH_SIZE); + hash_buffer_offset += HASH_SIZE; + } + + int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, + bc->hashes + cell_index * HASH_SIZE, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); } diff --git a/src/contract.c b/src/contract.c index c2e107f..f675f0b 100644 --- a/src/contract.c +++ b/src/contract.c @@ -1,123 +1,109 @@ #include "contract.h" -#include "slice_data.h" #include "byte_stream.h" #include "cell.h" -#include "utils.h" #include "errors.h" #include "hashmap_label.h" +#include "slice_data.h" +#include "utils.h" // Wallets code -const uint8_t safe_multisig_wallet[] = { 0x01, 0x02, 0x49, 0x01, - 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, 0x06, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, - 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, - 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }; - -const uint8_t safe_multisig_wallet_24h[] = { 0x01, 0x02, 0x49, 0x01, - 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, 0x06, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, - 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, - 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }; - -const uint8_t setcode_multisig_wallet[] = { 0x01, 0x02, 0x65, 0x01, - 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, 0x06, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, - 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, - 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }; - -const uint8_t bridge_multisig_wallet[] = { 0x01, 0x02, 0x45, 0x01, - 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, 0x03, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20 }; - -const uint8_t multisig_2_wallet[] = { 0x01, 0x02, 0x56, 0x01, - 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, 0x03, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20 }; - -const uint8_t multisig_2_1_wallet[] = { 0x01, 0x02, 0x4D, 0x01, - 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, 0x03, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20 }; - -const uint8_t surf_wallet[] = { 0x01, 0x02, 0x4D, 0x01, - 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34, 0x03, - 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20 }; +const uint8_t safe_multisig_wallet[] = { + 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, + 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, + 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, + 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + +const uint8_t safe_multisig_wallet_24h[] = { + 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, + 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, + 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, + 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + +const uint8_t setcode_multisig_wallet[] = { + 0x01, 0x02, 0x65, 0x01, 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, + 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, + 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, + 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + +const uint8_t bridge_multisig_wallet[] = { + 0x01, 0x02, 0x45, 0x01, 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, + 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + +const uint8_t multisig_2_wallet[] = { + 0x01, 0x02, 0x56, 0x01, 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, + 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + +const uint8_t multisig_2_1_wallet[] = { + 0x01, 0x02, 0x4D, 0x01, 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, + 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + +const uint8_t surf_wallet[] = { + 0x01, 0x02, 0x4D, 0x01, 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34, + 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; // Wallets code hash -const uint8_t wallet_v3_code_hash[] = { 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98, - 0x77, 0x89, 0xBA, 0x23, 0x23, 0x58, 0x07, 0x2B, - 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, 0x02, 0xA5, - 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99 }; - -const uint8_t ever_wallet_code_hash[] = { 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11, - 0x81, 0x80, 0xAA, 0x3B, 0xD1, 0x0D, 0xD1, 0x9F, - 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, 0xCF, 0x58, - 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6 }; - -const uint8_t safe_multisig_wallet_code_hash[] = { 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c, - 0x9b, 0x39, 0x7b, 0x71, 0x71, 0x6f, 0x3f, 0xae, - 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, 0xc5, 0x2e, - 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05 }; - -const uint8_t safe_multisig_wallet_24h_code_hash[] = { 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6, - 0x2a, 0x4f, 0xf2, 0x91, 0xb1, 0x22, 0x8b, 0xf0, - 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, 0x43, 0x6c, - 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2 }; - -const uint8_t setcode_multisig_wallet_code_hash[] = { 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce, - 0xd7, 0xea, 0x8e, 0xde, 0x4b, 0xdf, 0x96, 0x34, - 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, 0x06, 0x6f, - 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08 }; - -const uint8_t bridge_multisig_wallet_code_hash[] = { 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25, - 0x9D, 0x7F, 0xA4, 0x84, 0x7B, 0x86, 0x33, 0x5B, - 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, 0xBA, 0x4B, - 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18 }; - -const uint8_t multisig_2_wallet_code_hash[] = { 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05, - 0xc5, 0xa1, 0xb8, 0xd8, 0xfd, 0x75, 0xcb, 0x72, - 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, 0x53, 0x32, - 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90 }; - -const uint8_t multisig_2_1_wallet_code_hash[] = { 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1, - 0x25, 0x3f, 0x34, 0x15, 0x82, 0x6c, 0x94, 0x6c, - 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, 0x08, 0x62, - 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3, }; - - -const uint8_t surf_wallet_code_hash[] = { 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1, - 0xa2, 0xc1, 0x47, 0x93, 0x56, 0xf8, 0xf3, 0xee, - 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, 0xf4, 0x78, - 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82 }; +const uint8_t wallet_v3_code_hash[] = { + 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98, 0x77, 0x89, 0xBA, + 0x23, 0x23, 0x58, 0x07, 0x2B, 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, + 0x02, 0xA5, 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99}; + +const uint8_t ever_wallet_code_hash[] = { + 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11, 0x81, 0x80, 0xAA, + 0x3B, 0xD1, 0x0D, 0xD1, 0x9F, 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, + 0xCF, 0x58, 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6}; + +const uint8_t safe_multisig_wallet_code_hash[] = { + 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c, 0x9b, 0x39, 0x7b, + 0x71, 0x71, 0x6f, 0x3f, 0xae, 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, + 0xc5, 0x2e, 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05}; + +const uint8_t safe_multisig_wallet_24h_code_hash[] = { + 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6, 0x2a, 0x4f, 0xf2, + 0x91, 0xb1, 0x22, 0x8b, 0xf0, 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, + 0x43, 0x6c, 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2}; + +const uint8_t setcode_multisig_wallet_code_hash[] = { + 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce, 0xd7, 0xea, 0x8e, + 0xde, 0x4b, 0xdf, 0x96, 0x34, 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, + 0x06, 0x6f, 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08}; + +const uint8_t bridge_multisig_wallet_code_hash[] = { + 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25, 0x9D, 0x7F, 0xA4, + 0x84, 0x7B, 0x86, 0x33, 0x5B, 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, + 0xBA, 0x4B, 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18}; + +const uint8_t multisig_2_wallet_code_hash[] = { + 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05, 0xc5, 0xa1, 0xb8, + 0xd8, 0xfd, 0x75, 0xcb, 0x72, 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, + 0x53, 0x32, 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90}; + +const uint8_t multisig_2_1_wallet_code_hash[] = { + 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1, 0x25, 0x3f, 0x34, + 0x15, 0x82, 0x6c, 0x94, 0x6c, 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, + 0x08, 0x62, 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3, +}; + +const uint8_t surf_wallet_code_hash[] = { + 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1, 0xa2, 0xc1, 0x47, + 0x93, 0x56, 0xf8, 0xf3, 0xee, 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, + 0xf4, 0x78, 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82}; // Cell depths const uint32_t safe_multisig_wallet_cell_depth = 0x0C; @@ -128,303 +114,304 @@ const uint32_t multisig_2_wallet_cell_depth = 0x0C; const uint32_t multisig_2_1_wallet_cell_depth = 0x0A; const uint32_t surf_wallet_cell_depth = 0x0C; -void deserialize_cells_tree(struct ByteStream_t* src) { - uint8_t first_byte = ByteStream_read_byte(src); - { - bool index_included = (first_byte & 0x80) != 0; - bool has_crc = (first_byte & 0x40) != 0; - bool has_cache_bits = (first_byte & 0x20) != 0; - uint8_t flags = (first_byte & 0x18) >> 3; - UNUSED(flags); - VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_DATA); - } - - uint8_t ref_size = first_byte & 0x7; // size in bytes - VALIDATE(ref_size == 1, ERR_INVALID_DATA); - - uint8_t offset_size = ByteStream_read_byte(src); - VALIDATE(offset_size != 0 && offset_size <= 8, ERR_INVALID_DATA); - - uint8_t cells_count = ByteStream_read_uint(src, ref_size); - uint8_t roots_count = ByteStream_read_uint(src, ref_size); - VALIDATE(roots_count == MAX_ROOTS_COUNT, ERR_INVALID_DATA); - boc_context.cells_count = cells_count; - - { - uint8_t absent_count = ByteStream_read_uint(src, ref_size); - UNUSED(absent_count); - uint8_t* total_cells_size = ByteStream_read_data(src, offset_size); - UNUSED(total_cells_size); - uint8_t* buf = ByteStream_read_data(src, roots_count * ref_size); - UNUSED(buf); - } - - Cell_t cell; - for (uint8_t i = 0; i < cells_count; ++i) { - uint8_t* cell_begin = ByteStream_get_cursor(src); - Cell_init(&cell, cell_begin); - uint16_t offset = deserialize_cell(&cell, i, cells_count); - boc_context.cells[i] = cell; - ByteStream_read_data(src, offset); - - if (src->offset >= src->data_size) { - break; - } +void deserialize_cells_tree(struct ByteStream_t *src) { + uint8_t first_byte = ByteStream_read_byte(src); + { + bool index_included = (first_byte & 0x80) != 0; + bool has_crc = (first_byte & 0x40) != 0; + bool has_cache_bits = (first_byte & 0x20) != 0; + uint8_t flags = (first_byte & 0x18) >> 3; + UNUSED(flags); + VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_DATA); + } + + uint8_t ref_size = first_byte & 0x7; // size in bytes + VALIDATE(ref_size == 1, ERR_INVALID_DATA); + + uint8_t offset_size = ByteStream_read_byte(src); + VALIDATE(offset_size != 0 && offset_size <= 8, ERR_INVALID_DATA); + + uint8_t cells_count = ByteStream_read_uint(src, ref_size); + uint8_t roots_count = ByteStream_read_uint(src, ref_size); + VALIDATE(roots_count == MAX_ROOTS_COUNT, ERR_INVALID_DATA); + boc_context.cells_count = cells_count; + + { + uint8_t absent_count = ByteStream_read_uint(src, ref_size); + UNUSED(absent_count); + uint8_t *total_cells_size = ByteStream_read_data(src, offset_size); + UNUSED(total_cells_size); + uint8_t *buf = ByteStream_read_data(src, roots_count * ref_size); + UNUSED(buf); + } + + Cell_t cell; + for (uint8_t i = 0; i < cells_count; ++i) { + uint8_t *cell_begin = ByteStream_get_cursor(src); + Cell_init(&cell, cell_begin); + uint16_t offset = deserialize_cell(&cell, i, cells_count); + boc_context.cells[i] = cell; + ByteStream_read_data(src, offset); + + if (src->offset >= src->data_size) { + break; } + } } void find_public_key_cell() { - BocContext_t* bc = &boc_context; - VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, ERR_INVALID_DATA); // has data branch - - uint8_t refs_count = 0; - uint8_t* refs = Cell_get_refs(&bc->cells[0], &refs_count); - VALIDATE(refs_count > 0 && refs_count <= 2, ERR_INVALID_DATA); - - uint8_t data_root = refs[refs_count - 1]; - VALIDATE(data_root != 0 && data_root <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); - refs = Cell_get_refs(&bc->cells[data_root], &refs_count); - VALIDATE(refs_count != 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - - uint8_t key_buffer[8]; - SliceData_t key; - memset(key_buffer, 0, sizeof(key_buffer)); - SliceData_init(&key, key_buffer, sizeof(key_buffer)); - - uint16_t bit_len = SliceData_remaining_bits(&key); - put_to_node(refs[0], bit_len, &key); -} - -void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) { - uint8_t data_hash[HASH_SIZE]; - - // Compute data hash - { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32) - - uint16_t hash_buffer_offset = 0; - - hash_buffer[0] = 0x00; // d1(1) - hash_buffer[1] = 0x50; // d2(1) - hash_buffer_offset += 2; - - // Data - writeUint64BE(WALLET_ID, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint64_t); - - // Pubkey - uint8_t public_key[PUBLIC_KEY_LENGTH]; - get_public_key(account_number, public_key); - - memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); - hash_buffer_offset += PUBLIC_KEY_LENGTH; - - // Calculate data hash - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } - - // Compute address - { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32) - - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x02; // d1(1) - hash_buffer[1] = 0x01; // d2(1) - hash_buffer_offset += 2; - - // Data - hash_buffer[2] = 0x34; - hash_buffer_offset += 1; - - writeUint32BE(0x00, hash_buffer + hash_buffer_offset); - hash_buffer_offset += 4; - - // Code hash - memcpy(hash_buffer + hash_buffer_offset, wallet_v3_code_hash, sizeof(wallet_v3_code_hash)); - hash_buffer_offset += sizeof(wallet_v3_code_hash); - - // Data hash - memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); - hash_buffer_offset += sizeof(data_hash); - - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } + BocContext_t *bc = &boc_context; + VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, + ERR_INVALID_DATA); // has data branch + + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(&bc->cells[0], &refs_count); + VALIDATE(refs_count > 0 && refs_count <= 2, ERR_INVALID_DATA); + + uint8_t data_root = refs[refs_count - 1]; + VALIDATE(data_root != 0 && data_root <= MAX_CONTRACT_CELLS_COUNT, + ERR_INVALID_DATA); + refs = Cell_get_refs(&bc->cells[data_root], &refs_count); + VALIDATE(refs_count != 0 && refs_count <= MAX_REFERENCES_COUNT, + ERR_INVALID_DATA); + + uint8_t key_buffer[8]; + SliceData_t key; + memset(key_buffer, 0, sizeof(key_buffer)); + SliceData_init(&key, key_buffer, sizeof(key_buffer)); + + uint16_t bit_len = SliceData_remaining_bits(&key); + put_to_node(refs[0], bit_len, &key); } -void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) { - uint8_t data_hash[HASH_SIZE]; - - // Compute data hash - { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) - - uint16_t hash_buffer_offset = 0; +void compute_wallet_v3_address(uint32_t account_number, uint8_t *address) { + uint8_t data_hash[HASH_SIZE]; - hash_buffer[0] = 0x00; // d1(1) - hash_buffer[1] = 0x50; // d2(1) - hash_buffer_offset += 2; + // Compute data hash + { + uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32) - // Pubkey - uint8_t public_key[PUBLIC_KEY_LENGTH]; - get_public_key(account_number, public_key); + uint16_t hash_buffer_offset = 0; - memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); - hash_buffer_offset += PUBLIC_KEY_LENGTH; - - // Data - writeUint64BE(0, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint64_t); - - // Calculate data hash - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } + hash_buffer[0] = 0x00; // d1(1) + hash_buffer[1] = 0x50; // d2(1) + hash_buffer_offset += 2; - // Compute address - { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32) + // Data + writeUint64BE(WALLET_ID, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint64_t); - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x02; // d1(1) - hash_buffer[1] = 0x01; // d2(1) - hash_buffer_offset += 2; - - // Data - hash_buffer[2] = 0x34; - hash_buffer_offset += 1; - - writeUint32BE(0x30000, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint32_t); - - // Code hash - memcpy(hash_buffer + hash_buffer_offset, ever_wallet_code_hash, sizeof(ever_wallet_code_hash)); - hash_buffer_offset += sizeof(ever_wallet_code_hash); - - // Data hash - memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); - hash_buffer_offset += sizeof(data_hash); + // Pubkey + uint8_t public_key[PUBLIC_KEY_LENGTH]; + get_public_key(account_number, public_key); - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } + memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); + hash_buffer_offset += PUBLIC_KEY_LENGTH; + + // Calculate data hash + int result = + cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } + + // Compute address + { + uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + + // data_hash(32) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) + hash_buffer_offset += 2; + + // Data + hash_buffer[2] = 0x34; + hash_buffer_offset += 1; + + writeUint32BE(0x00, hash_buffer + hash_buffer_offset); + hash_buffer_offset += 4; + + // Code hash + memcpy(hash_buffer + hash_buffer_offset, wallet_v3_code_hash, + sizeof(wallet_v3_code_hash)); + hash_buffer_offset += sizeof(wallet_v3_code_hash); + + // Data hash + memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); + hash_buffer_offset += sizeof(data_hash); + + int result = + cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } } -void compute_multisig_address(uint32_t account_number, const uint8_t* wallet, uint16_t wallet_size, const uint8_t* code_hash, uint32_t cell_depth, uint8_t* address) { - { - ByteStream_t src; - ByteStream_init(&src, (uint8_t*)wallet, wallet_size); - deserialize_cells_tree(&src); - } - - BocContext_t* bc = &boc_context; +void compute_ever_wallet_address(uint32_t account_number, uint8_t *address) { + uint8_t data_hash[HASH_SIZE]; - VALIDATE(bc->cells_count != 0, ERR_INVALID_DATA); - find_public_key_cell(); // sets public key cell index to boc_context + // Compute data hash + { + uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) - // Set code hash - memcpy(bc->hashes + (bc->public_key_cell_index + 1) * HASH_SIZE, code_hash, HASH_SIZE); - bc->cell_depth[bc->public_key_cell_index + 1] = cell_depth; + uint16_t hash_buffer_offset = 0; - VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, ERR_CELL_IS_EMPTY); - Cell_t* cell = &bc->cells[bc->public_key_cell_index]; - uint8_t cell_data_size = Cell_get_data_size(cell); - VALIDATE(cell_data_size != 0 && cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, ERR_INVALID_DATA); - uint8_t* cell_data = Cell_get_data(cell); + hash_buffer[0] = 0x00; // d1(1) + hash_buffer[1] = 0x50; // d2(1) + hash_buffer_offset += 2; - memcpy(bc->public_key_cell_data, cell_data, cell_data_size); - uint8_t* public_key = data_context.pk_context.public_key; + // Pubkey + uint8_t public_key[PUBLIC_KEY_LENGTH]; get_public_key(account_number, public_key); - uint8_t* data = bc->public_key_cell_data; - SliceData_t slice; - SliceData_init(&slice, data, sizeof(bc->public_key_cell_data)); - SliceData_move_by(&slice, bc->public_key_label_size_bits); - SliceData_append(&slice, public_key, PUBLIC_KEY_LENGTH * 8, true); - - for (int16_t i = bc->public_key_cell_index; i >= 0; --i) { - Cell_t* cell = &bc->cells[i]; - calc_cell_hash(cell, i); - } + memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); + hash_buffer_offset += PUBLIC_KEY_LENGTH; + + // Data + writeUint64BE(0, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint64_t); + + // Calculate data hash + int result = + cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } + + // Compute address + { + uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + + // data_hash(32) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) + hash_buffer_offset += 2; + + // Data + hash_buffer[2] = 0x34; + hash_buffer_offset += 1; + + writeUint32BE(0x30000, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint32_t); + + // Code hash + memcpy(hash_buffer + hash_buffer_offset, ever_wallet_code_hash, + sizeof(ever_wallet_code_hash)); + hash_buffer_offset += sizeof(ever_wallet_code_hash); + + // Data hash + memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); + hash_buffer_offset += sizeof(data_hash); + + int result = + cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } +} - memcpy(address, bc->hashes, HASH_SIZE); +void compute_multisig_address(uint32_t account_number, const uint8_t *wallet, + uint16_t wallet_size, const uint8_t *code_hash, + uint32_t cell_depth, uint8_t *address) { + { + ByteStream_t src; + ByteStream_init(&src, (uint8_t *)wallet, wallet_size); + deserialize_cells_tree(&src); + } + + BocContext_t *bc = &boc_context; + + VALIDATE(bc->cells_count != 0, ERR_INVALID_DATA); + find_public_key_cell(); // sets public key cell index to boc_context + + // Set code hash + memcpy(bc->hashes + (bc->public_key_cell_index + 1) * HASH_SIZE, code_hash, + HASH_SIZE); + bc->cell_depth[bc->public_key_cell_index + 1] = cell_depth; + + VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, + ERR_CELL_IS_EMPTY); + Cell_t *cell = &bc->cells[bc->public_key_cell_index]; + uint8_t cell_data_size = Cell_get_data_size(cell); + VALIDATE(cell_data_size != 0 && + cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, + ERR_INVALID_DATA); + uint8_t *cell_data = Cell_get_data(cell); + + memcpy(bc->public_key_cell_data, cell_data, cell_data_size); + uint8_t *public_key = data_context.pk_context.public_key; + get_public_key(account_number, public_key); + + uint8_t *data = bc->public_key_cell_data; + SliceData_t slice; + SliceData_init(&slice, data, sizeof(bc->public_key_cell_data)); + SliceData_move_by(&slice, bc->public_key_label_size_bits); + SliceData_append(&slice, public_key, PUBLIC_KEY_LENGTH * 8, true); + + for (int16_t i = bc->public_key_cell_index; i >= 0; --i) { + Cell_t *cell = &bc->cells[i]; + calc_cell_hash(cell, i); + } + + memcpy(address, bc->hashes, HASH_SIZE); } -void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* address) { - switch (wallet_type) { - case WALLET_V3: { - compute_wallet_v3_address(account_number, address); - break; - } - case EVER_WALLET: { - compute_ever_wallet_address(account_number, address); - break; - } - case SAFE_MULTISIG_WALLET: { - compute_multisig_address(account_number, - safe_multisig_wallet, - sizeof(safe_multisig_wallet), - safe_multisig_wallet_code_hash, - safe_multisig_wallet_cell_depth, - address); - break; - } - case SAFE_MULTISIG_WALLET_24H: { - compute_multisig_address(account_number, - safe_multisig_wallet_24h, - sizeof(safe_multisig_wallet_24h), - safe_multisig_wallet_24h_code_hash, - safe_multisig_wallet_24h_cell_depth, - address); - break; - } - case SETCODE_MULTISIG_WALLET: { - compute_multisig_address(account_number, - setcode_multisig_wallet, - sizeof(setcode_multisig_wallet), - setcode_multisig_wallet_code_hash, - setcode_multisig_wallet_cell_depth, - address); - break; - } - case BRIDGE_MULTISIG_WALLET: { - compute_multisig_address(account_number, - bridge_multisig_wallet, - sizeof(bridge_multisig_wallet), - bridge_multisig_wallet_code_hash, - bridge_multisig_wallet_cell_depth, - address); - break; - } - case MULTISIG_2: { - compute_multisig_address(account_number, - multisig_2_wallet, - sizeof(multisig_2_wallet), - multisig_2_wallet_code_hash, - multisig_2_wallet_cell_depth, - address); - break; - } - case MULTISIG_2_1: { - compute_multisig_address(account_number, - multisig_2_1_wallet, - sizeof(multisig_2_1_wallet), - multisig_2_1_wallet_code_hash, - multisig_2_1_wallet_cell_depth, - address); - break; - } - case SURF_WALLET: { - compute_multisig_address(account_number, - surf_wallet, - sizeof(surf_wallet), - surf_wallet_code_hash, - surf_wallet_cell_depth, - address); - break; - } - default: - THROW(ERR_INVALID_WALLET_TYPE); - } +void get_address(const uint32_t account_number, uint8_t wallet_type, + uint8_t *address) { + switch (wallet_type) { + case WALLET_V3: { + compute_wallet_v3_address(account_number, address); + break; + } + case EVER_WALLET: { + compute_ever_wallet_address(account_number, address); + break; + } + case SAFE_MULTISIG_WALLET: { + compute_multisig_address(account_number, safe_multisig_wallet, + sizeof(safe_multisig_wallet), + safe_multisig_wallet_code_hash, + safe_multisig_wallet_cell_depth, address); + break; + } + case SAFE_MULTISIG_WALLET_24H: { + compute_multisig_address(account_number, safe_multisig_wallet_24h, + sizeof(safe_multisig_wallet_24h), + safe_multisig_wallet_24h_code_hash, + safe_multisig_wallet_24h_cell_depth, address); + break; + } + case SETCODE_MULTISIG_WALLET: { + compute_multisig_address(account_number, setcode_multisig_wallet, + sizeof(setcode_multisig_wallet), + setcode_multisig_wallet_code_hash, + setcode_multisig_wallet_cell_depth, address); + break; + } + case BRIDGE_MULTISIG_WALLET: { + compute_multisig_address(account_number, bridge_multisig_wallet, + sizeof(bridge_multisig_wallet), + bridge_multisig_wallet_code_hash, + bridge_multisig_wallet_cell_depth, address); + break; + } + case MULTISIG_2: { + compute_multisig_address( + account_number, multisig_2_wallet, sizeof(multisig_2_wallet), + multisig_2_wallet_code_hash, multisig_2_wallet_cell_depth, address); + break; + } + case MULTISIG_2_1: { + compute_multisig_address( + account_number, multisig_2_1_wallet, sizeof(multisig_2_1_wallet), + multisig_2_1_wallet_code_hash, multisig_2_1_wallet_cell_depth, address); + break; + } + case SURF_WALLET: { + compute_multisig_address(account_number, surf_wallet, sizeof(surf_wallet), + surf_wallet_code_hash, surf_wallet_cell_depth, + address); + break; + } + default: + THROW(ERR_INVALID_WALLET_TYPE); + } } diff --git a/src/get_address.c b/src/get_address.c index 36ec21f..8b6153d 100644 --- a/src/get_address.c +++ b/src/get_address.c @@ -1,81 +1,75 @@ #include "apdu_constants.h" -#include "globals.h" -#include "utils.h" +#include "byte_stream.h" #include "contract.h" +#include "globals.h" #include "slice_data.h" -#include "byte_stream.h" +#include "utils.h" static uint8_t set_result_get_address() { - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = ADDRESS_LENGTH; - memmove(G_io_apdu_buffer + tx, data_context.addr_context.address, ADDRESS_LENGTH); - tx += ADDRESS_LENGTH; - reset_app_context(); - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = ADDRESS_LENGTH; + memmove(G_io_apdu_buffer + tx, data_context.addr_context.address, + ADDRESS_LENGTH); + tx += ADDRESS_LENGTH; + reset_app_context(); + return tx; } -UX_STEP_NOCB( - ux_display_address_flow_1_step, - pnn, - { - &C_icon_eye, - "Verify", - "address", - }); -UX_STEP_NOCB( - ux_display_address_flow_2_step, - bnnn_paging, - { - .title = "Address", - .text = data_context.addr_context.address_str, - }); -UX_STEP_CB( - ux_display_address_flow_3_step, - pb, - send_response(0, false), - { - &C_icon_crossmark, - "Reject", - }); -UX_STEP_CB( - ux_display_address_flow_4_step, - pb, - send_response(set_result_get_address(), true), - { - &C_icon_validate_14, - "Approve", - }); +UX_STEP_NOCB(ux_display_address_flow_1_step, pnn, + { + &C_icon_eye, + "Verify", + "address", + }); +UX_STEP_NOCB(ux_display_address_flow_2_step, bnnn_paging, + { + .title = "Address", + .text = data_context.addr_context.address_str, + }); +UX_STEP_CB(ux_display_address_flow_3_step, pb, send_response(0, false), + { + &C_icon_crossmark, + "Reject", + }); +UX_STEP_CB(ux_display_address_flow_4_step, pb, + send_response(set_result_get_address(), true), + { + &C_icon_validate_14, + "Approve", + }); -UX_FLOW(ux_display_address_flow, - &ux_display_address_flow_1_step, - &ux_display_address_flow_2_step, - &ux_display_address_flow_3_step, - &ux_display_address_flow_4_step -); +UX_FLOW(ux_display_address_flow, &ux_display_address_flow_1_step, + &ux_display_address_flow_2_step, &ux_display_address_flow_3_step, + &ux_display_address_flow_4_step); -void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - VALIDATE(p2 == 0 && dataLength == (sizeof(uint32_t) + sizeof(uint8_t)), ERR_INVALID_REQUEST); +void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, + uint16_t dataLength, volatile unsigned int *flags, + volatile unsigned int *tx) { + VALIDATE(p2 == 0 && dataLength == (sizeof(uint32_t) + sizeof(uint8_t)), + ERR_INVALID_REQUEST); - size_t offset = 0; + size_t offset = 0; - uint32_t account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(account_number); + uint32_t account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(account_number); - uint8_t wallet_type = dataBuffer[offset];; + uint8_t wallet_type = dataBuffer[offset]; + ; - get_address(account_number, wallet_type, data_context.addr_context.address); + get_address(account_number, wallet_type, data_context.addr_context.address); - if (p1 == P1_NON_CONFIRM) { - *tx = set_result_get_address(); - THROW(SUCCESS); - } - if (p1 == P1_CONFIRM) { - AddressContext_t* context = &data_context.addr_context; - snprintf(context->address_str, sizeof(context->address_str), "%.*H", sizeof(context->address), context->address); - ux_flow_init(0, ux_display_address_flow, NULL); - *flags |= IO_ASYNCH_REPLY; - return; - } + if (p1 == P1_NON_CONFIRM) { + *tx = set_result_get_address(); + THROW(SUCCESS); + } + if (p1 == P1_CONFIRM) { + AddressContext_t *context = &data_context.addr_context; + snprintf(context->address_str, sizeof(context->address_str), "%.*H", + sizeof(context->address), context->address); + ux_flow_init(0, ux_display_address_flow, NULL); + *flags |= IO_ASYNCH_REPLY; + return; + } - THROW(ERR_INVALID_REQUEST); + THROW(ERR_INVALID_REQUEST); } diff --git a/src/get_app_configuration.c b/src/get_app_configuration.c index a6fb31d..6ee59b4 100644 --- a/src/get_app_configuration.c +++ b/src/get_app_configuration.c @@ -1,18 +1,21 @@ #include "apdu_constants.h" -#include "utils.h" #include "errors.h" +#include "utils.h" -void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(p1); - UNUSED(p2); - UNUSED(dataBuffer); - UNUSED(dataLength); - UNUSED(flags); - VALIDATE(p1 == 0 && p2 == 0 && dataLength == 0, ERR_INVALID_REQUEST); +void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, + uint16_t dataLength, + volatile unsigned int *flags, + volatile unsigned int *tx) { + UNUSED(p1); + UNUSED(p2); + UNUSED(dataBuffer); + UNUSED(dataLength); + UNUSED(flags); + VALIDATE(p1 == 0 && p2 == 0 && dataLength == 0, ERR_INVALID_REQUEST); - G_io_apdu_buffer[0] = LEDGER_MAJOR_VERSION; - G_io_apdu_buffer[1] = LEDGER_MINOR_VERSION; - G_io_apdu_buffer[2] = LEDGER_PATCH_VERSION; - *tx = 3; - THROW(SUCCESS); + G_io_apdu_buffer[0] = LEDGER_MAJOR_VERSION; + G_io_apdu_buffer[1] = LEDGER_MINOR_VERSION; + G_io_apdu_buffer[2] = LEDGER_PATCH_VERSION; + *tx = 3; + THROW(SUCCESS); } diff --git a/src/get_public_key.c b/src/get_public_key.c index a9b3889..6d55fb5 100644 --- a/src/get_public_key.c +++ b/src/get_public_key.c @@ -1,65 +1,59 @@ -#include "os.h" -#include "ux.h" -#include "utils.h" #include "apdu_constants.h" #include "errors.h" +#include "os.h" +#include "utils.h" +#include "ux.h" static uint8_t set_result_get_public_key() { - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = PUBLIC_KEY_LENGTH; - memmove(G_io_apdu_buffer + tx, data_context.pk_context.public_key, PUBLIC_KEY_LENGTH); - tx += PUBLIC_KEY_LENGTH; - reset_app_context(); - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = PUBLIC_KEY_LENGTH; + memmove(G_io_apdu_buffer + tx, data_context.pk_context.public_key, + PUBLIC_KEY_LENGTH); + tx += PUBLIC_KEY_LENGTH; + reset_app_context(); + return tx; } -UX_STEP_NOCB( - ux_display_public_flow_1_step, - bnnn_paging, - { - .title = "Public key", - .text = data_context.pk_context.public_key_str, - }); -UX_STEP_CB( - ux_display_public_flow_2_step, - pb, - send_response(0, false), - { - &C_icon_crossmark, - "Reject", - }); -UX_STEP_CB( - ux_display_public_flow_3_step, - pb, - send_response(set_result_get_public_key(), true), - { - &C_icon_validate_14, - "Approve", - }); +UX_STEP_NOCB(ux_display_public_flow_1_step, bnnn_paging, + { + .title = "Public key", + .text = data_context.pk_context.public_key_str, + }); +UX_STEP_CB(ux_display_public_flow_2_step, pb, send_response(0, false), + { + &C_icon_crossmark, + "Reject", + }); +UX_STEP_CB(ux_display_public_flow_3_step, pb, + send_response(set_result_get_public_key(), true), + { + &C_icon_validate_14, + "Approve", + }); -UX_FLOW(ux_display_public_flow, - &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, - &ux_display_public_flow_3_step -); +UX_FLOW(ux_display_public_flow, &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, &ux_display_public_flow_3_step); -void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - VALIDATE(p2 == 0 && dataLength == sizeof(uint32_t), ERR_INVALID_REQUEST); +void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, + uint16_t dataLength, volatile unsigned int *flags, + volatile unsigned int *tx) { + VALIDATE(p2 == 0 && dataLength == sizeof(uint32_t), ERR_INVALID_REQUEST); - uint32_t account_number = readUint32BE(dataBuffer); - PublicKeyContext_t* context = &data_context.pk_context; - get_public_key(account_number, context->public_key); - if (p1 == P1_NON_CONFIRM) { - *tx = set_result_get_public_key(); - THROW(SUCCESS); - } + uint32_t account_number = readUint32BE(dataBuffer); + PublicKeyContext_t *context = &data_context.pk_context; + get_public_key(account_number, context->public_key); + if (p1 == P1_NON_CONFIRM) { + *tx = set_result_get_public_key(); + THROW(SUCCESS); + } - if (p1 == P1_CONFIRM) { - snprintf(context->public_key_str, sizeof(context->public_key_str), "%.*H", sizeof(context->public_key), context->public_key); - ux_flow_init(0, ux_display_public_flow, NULL); - *flags |= IO_ASYNCH_REPLY; - return; - } + if (p1 == P1_CONFIRM) { + snprintf(context->public_key_str, sizeof(context->public_key_str), "%.*H", + sizeof(context->public_key), context->public_key); + ux_flow_init(0, ux_display_public_flow, NULL); + *flags |= IO_ASYNCH_REPLY; + return; + } - THROW(ERR_INVALID_REQUEST); + THROW(ERR_INVALID_REQUEST); } diff --git a/src/hashmap_label.c b/src/hashmap_label.c index 84e5fe2..df8ae76 100644 --- a/src/hashmap_label.c +++ b/src/hashmap_label.c @@ -1,80 +1,88 @@ #include "hashmap_label.h" #include "cell.h" +#include "errors.h" #include "slice_data.h" #include "utils.h" -#include "errors.h" -uint8_t get_label_same(uint8_t max, struct SliceData_t* slice, struct SliceData_t* label) { - uint8_t value = SliceData_get_next_bit(slice) ? 0xff : 0; - uint8_t length = SliceData_get_next_size(slice, max); - VALIDATE(length <= 64, ERR_RANGE_CHECK); +uint8_t get_label_same(uint8_t max, struct SliceData_t *slice, + struct SliceData_t *label) { + uint8_t value = SliceData_get_next_bit(slice) ? 0xff : 0; + uint8_t length = SliceData_get_next_size(slice, max); + VALIDATE(length <= 64, ERR_RANGE_CHECK); - uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0); - SliceData_fill(label, value, length_bytes); - SliceData_truncate(label, length); - return length >= max ? 0 : (max - length); + uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0); + SliceData_fill(label, value, length_bytes); + SliceData_truncate(label, length); + return length >= max ? 0 : (max - length); } -uint8_t get_label(uint8_t max, struct SliceData_t* slice, struct SliceData_t* label) { - VALIDATE(SliceData_is_empty(slice) == false, ERR_SLICE_IS_EMPTY); - VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short - VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long +uint8_t get_label(uint8_t max, struct SliceData_t *slice, + struct SliceData_t *label) { + VALIDATE(SliceData_is_empty(slice) == false, ERR_SLICE_IS_EMPTY); + VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short + VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long - return get_label_same(max, slice, label); + return get_label_same(max, slice, label); } -void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t* key) { - VALIDATE(cell_index != 0 && cell_index <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); - static const uint8_t key_len_bytes = 8; - VALIDATE(key && key->data_size_bytes == key_len_bytes, ERR_RANGE_CHECK); - for (uint8_t i = 0; i < key_len_bytes; ++i) { - VALIDATE(key->data[i] == 0, ERR_INVALID_KEY); - } - - Cell_t* cell = &boc_context.cells[cell_index]; - SliceData_t slice; - SliceData_init(&slice, Cell_get_data(cell), Cell_get_data_size(cell)); +void put_to_node(uint8_t cell_index, uint16_t bit_len, + struct SliceData_t *key) { + VALIDATE(cell_index != 0 && cell_index <= MAX_CONTRACT_CELLS_COUNT, + ERR_INVALID_DATA); + static const uint8_t key_len_bytes = 8; + VALIDATE(key && key->data_size_bytes == key_len_bytes, ERR_RANGE_CHECK); + for (uint8_t i = 0; i < key_len_bytes; ++i) { + VALIDATE(key->data[i] == 0, ERR_INVALID_KEY); + } - SliceData_t label; - uint8_t label_data[8]; - memset(label_data, 0, sizeof(label_data)); - SliceData_init(&label, label_data, sizeof(label_data)); - get_label(bit_len, &slice, &label); + Cell_t *cell = &boc_context.cells[cell_index]; + SliceData_t slice; + SliceData_init(&slice, Cell_get_data(cell), Cell_get_data_size(cell)); - if (SliceData_equal(&label, key)) { - uint8_t len = 16 - leading_zeros(bit_len); - uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len - boc_context.public_key_label_size_bits = label_size_bits; - boc_context.public_key_cell_index = cell_index; - return; - } + SliceData_t label; + uint8_t label_data[8]; + memset(label_data, 0, sizeof(label_data)); + SliceData_init(&label, label_data, sizeof(label_data)); + get_label(bit_len, &slice, &label); - // common prefix - { - uint8_t max_prefix_len = MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key)); - VALIDATE(max_prefix_len <= 64, ERR_RANGE_CHECK); - uint8_t i = 0; - while (i < max_prefix_len && SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) { - i += 1; - } + if (SliceData_equal(&label, key)) { + uint8_t len = 16 - leading_zeros(bit_len); + uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len + boc_context.public_key_label_size_bits = label_size_bits; + boc_context.public_key_cell_index = cell_index; + return; + } - SliceData_move_by(key, i); - SliceData_truncate(&label, i); - uint8_t label_rb = SliceData_remaining_bits(&label); - VALIDATE(bit_len >= label_rb, ERR_CELL_UNDERFLOW); - bit_len -= label_rb; + // common prefix + { + uint8_t max_prefix_len = + MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key)); + VALIDATE(max_prefix_len <= 64, ERR_RANGE_CHECK); + uint8_t i = 0; + while (i < max_prefix_len && + SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) { + i += 1; } - VALIDATE(bit_len >= 1, ERR_CELL_UNDERFLOW); - uint8_t next_index = SliceData_get_next_bit(key); - VALIDATE(next_index == 0, ERR_INVALID_KEY); + SliceData_move_by(key, i); + SliceData_truncate(&label, i); + uint8_t label_rb = SliceData_remaining_bits(&label); + VALIDATE(bit_len >= label_rb, ERR_CELL_UNDERFLOW); + bit_len -= label_rb; + } + + VALIDATE(bit_len >= 1, ERR_CELL_UNDERFLOW); + uint8_t next_index = SliceData_get_next_bit(key); + VALIDATE(next_index == 0, ERR_INVALID_KEY); - uint8_t refs_count = 0; - uint8_t* refs = Cell_get_refs(&boc_context.cells[cell_index], &refs_count); - VALIDATE(refs_count > 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - uint8_t next_cell = refs[next_index]; - VALIDATE(next_cell != 0 && next_cell <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); - bit_len -= 1; + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(&boc_context.cells[cell_index], &refs_count); + VALIDATE(refs_count > 0 && refs_count <= MAX_REFERENCES_COUNT, + ERR_INVALID_DATA); + uint8_t next_cell = refs[next_index]; + VALIDATE(next_cell != 0 && next_cell <= MAX_CONTRACT_CELLS_COUNT, + ERR_INVALID_DATA); + bit_len -= 1; - return put_to_node(next_cell, bit_len, key); + return put_to_node(next_cell, bit_len, key); } diff --git a/src/main.c b/src/main.c index fc1f0f1..4dcb2c6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,23 +1,23 @@ /******************************************************************************* -* Ledger Free TON App -* (c) 2016 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger Free TON App + * (c) 2016 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#include "utils.h" -#include "menu.h" #include "apdu_constants.h" +#include "menu.h" +#include "utils.h" unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; @@ -25,290 +25,288 @@ BocContext_t boc_context; DataContext_t data_context; void reset_app_context() { - memset(&boc_context, 0, sizeof(boc_context)); - memset(&data_context, 0, sizeof(data_context)); + memset(&boc_context, 0, sizeof(boc_context)); + memset(&data_context, 0, sizeof(data_context)); } void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) { - unsigned short sw = 0; - - BEGIN_TRY { - TRY { - if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { - THROW(0x6E00); - } - - switch (G_io_apdu_buffer[OFFSET_INS]) { - - case INS_GET_APP_CONFIGURATION: - handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_GET_PUBLIC_KEY: - handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_SIGN: - handleSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_GET_ADDRESS: - handleGetAddress(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; + unsigned short sw = 0; + + BEGIN_TRY { + TRY { + if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { + THROW(0x6E00); + } + + switch (G_io_apdu_buffer[OFFSET_INS]) { + + case INS_GET_APP_CONFIGURATION: + handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], flags, tx); + break; + + case INS_GET_PUBLIC_KEY: + handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], flags, tx); + break; + + case INS_SIGN: + handleSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], + flags, tx); + break; + + case INS_GET_ADDRESS: + handleGetAddress(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], flags, tx); + break; + + case INS_SIGN_TRANSACTION: + handleSignTransaction(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], flags, tx); + break; + + default: + THROW(0x6D00); + break; + } + } + CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } + CATCH_OTHER(e) { + switch (e & 0xF000) { + case 0x6000: + sw = e; + reset_app_context(); + break; + case 0x9000: + // All is well + sw = e; + break; + default: + // Internal error + sw = 0x6800 | (e & 0x7FF); + reset_app_context(); + break; + } + // Unexpected exception => report + G_io_apdu_buffer[*tx] = sw >> 8; + G_io_apdu_buffer[*tx + 1] = sw; + *tx += 2; + } + FINALLY {} + } + END_TRY; +} - case INS_SIGN_TRANSACTION: - handleSignTransaction(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; +void app_main(void) { + volatile unsigned int rx = 0; + volatile unsigned int tx = 0; + volatile unsigned int flags = 0; + reset_app_context(); + + // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only + // goal is to retrieve APDU. + // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make + // sure the io_event is called with a + // switch event, before the apdu is replied to the bootloader. This avoid + // APDU injection faults. + for (;;) { + volatile unsigned short sw = 0; - default: - THROW(0x6D00); - break; - } - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); + BEGIN_TRY { + TRY { + rx = tx; + tx = 0; // ensure no race in catch_other if io_exchange throws + // an error + rx = io_exchange(CHANNEL_APDU | flags, rx); + flags = 0; + + // no apdu received, well, reset the session, and reset the + // bootloader configuration + if (rx == 0) { + THROW(0x6982); } - CATCH_OTHER(e) { + + // PRINTF("New APDU received:\n%.*h\n", rx, G_io_apdu_buffer); + handleApdu(&flags, &tx); + } + CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } + CATCH_OTHER(e) { switch (e & 0xF000) { - case 0x6000: - sw = e; - reset_app_context(); - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - reset_app_context(); - break; - } - // Unexpected exception => report - G_io_apdu_buffer[*tx] = sw >> 8; - G_io_apdu_buffer[*tx + 1] = sw; - *tx += 2; + case 0x6000: + sw = e; + reset_app_context(); + break; + case 0x9000: + // All is well + sw = e; + break; + default: + // Internal error + sw = 0x6800 | (e & 0x7FF); + reset_app_context(); + break; } - FINALLY { + if (e != 0x9000) { + flags &= ~IO_ASYNCH_REPLY; } + // Unexpected exception => report + G_io_apdu_buffer[tx] = sw >> 8; + G_io_apdu_buffer[tx + 1] = sw; + tx += 2; + } + FINALLY {} } END_TRY; -} + } -void app_main(void) { - volatile unsigned int rx = 0; - volatile unsigned int tx = 0; - volatile unsigned int flags = 0; - reset_app_context(); - - // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only - // goal is to retrieve APDU. - // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make - // sure the io_event is called with a - // switch event, before the apdu is replied to the bootloader. This avoid - // APDU injection faults. - for (;;) { - volatile unsigned short sw = 0; - - BEGIN_TRY { - TRY { - rx = tx; - tx = 0; // ensure no race in catch_other if io_exchange throws - // an error - rx = io_exchange(CHANNEL_APDU | flags, rx); - flags = 0; - - // no apdu received, well, reset the session, and reset the - // bootloader configuration - if (rx == 0) { - THROW(0x6982); - } - - // PRINTF("New APDU received:\n%.*h\n", rx, G_io_apdu_buffer); - handleApdu(&flags, &tx); - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); - } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - sw = e; - reset_app_context(); - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - reset_app_context(); - break; - } - if (e != 0x9000) { - flags &= ~IO_ASYNCH_REPLY; - } - // Unexpected exception => report - G_io_apdu_buffer[tx] = sw >> 8; - G_io_apdu_buffer[tx + 1] = sw; - tx += 2; - } - FINALLY { - } - } - END_TRY; - } - -//return_to_dashboard: - return; + // return_to_dashboard: + return; } // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t*)element); + io_seproxyhal_display_default((bagl_element_t *)element); } unsigned char io_event(unsigned char channel) { - UNUSED(channel); - - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && !(U4BE(G_io_seproxyhal_spi_buffer, 3) & SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - default: - UX_DEFAULT_EVENT(); - break; + UNUSED(channel); + + // nothing done with the event, throw an error on the transport layer if + // needed + + // can't have more than one tag in the reply, not supported yet. + switch (G_io_seproxyhal_spi_buffer[0]) { + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + // no break is intentional + default: + UX_DEFAULT_EVENT(); + break; - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: + UX_DISPLAYED_EVENT({}); + break; - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, - { + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { #ifndef TARGET_NANOX - if (UX_ALLOWED) { - if (ux_step_count) { - // prepare next screen - ux_step = (ux_step+1)%ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } - } + if (UX_ALLOWED) { + if (ux_step_count) { + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); + } + } #endif // TARGET_NANOX - }); - break; - } + }); + break; + } - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } + // close the event if not done previously (by a display or whatever) + if (!io_seproxyhal_spi_is_status_sent()) { + io_seproxyhal_general_status(); + } - // command has been processed, DO NOT reset the current APDU transport - return 1; + // command has been processed, DO NOT reset the current APDU transport + return 1; } - unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); + switch (channel & ~(IO_FLAGS)) { + case CHANNEL_KEYBOARD: + break; + + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); + } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), + 0); } - return 0; -} + default: + THROW(INVALID_PARAMETER); + } + return 0; +} void app_exit(void) { - BEGIN_TRY_L(exit) { - TRY_L(exit) { - os_sched_exit(-1); - } - FINALLY_L(exit) { - - } - } - END_TRY_L(exit); + BEGIN_TRY_L(exit) { + TRY_L(exit) { os_sched_exit(-1); } + FINALLY_L(exit) {} + } + END_TRY_L(exit); } -void nv_app_state_init() { - -} +void nv_app_state_init() {} __attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); + // exit critical section + __asm volatile("cpsie i"); - // ensure exception will work as planned - os_boot(); + // ensure exception will work as planned + os_boot(); - for (;;) { - UX_INIT(); + for (;;) { + UX_INIT(); - BEGIN_TRY { - TRY { - io_seproxyhal_init(); + BEGIN_TRY { + TRY { + io_seproxyhal_init(); - nv_app_state_init(); + nv_app_state_init(); - USB_power(0); - USB_power(1); + USB_power(0); + USB_power(1); - ui_idle(); + ui_idle(); #ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); + BLE_power(0, NULL); + BLE_power(1, "Nano X"); #endif // HAVE_BLE - app_main(); - } - CATCH(EXCEPTION_IO_RESET) { - // reset IO and UX before continuing - continue; - } - CATCH_ALL { - break; - } - FINALLY { - } - } - END_TRY; + app_main(); + } + CATCH(EXCEPTION_IO_RESET) { + // reset IO and UX before continuing + continue; + } + CATCH_ALL { break; } + FINALLY {} } - app_exit(); - return 0; + END_TRY; + } + app_exit(); + return 0; } diff --git a/src/menu.c b/src/menu.c index 45d143f..9916c65 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2,39 +2,28 @@ #include "os.h" ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_idle_flow_1_step, - nn, - { - "Application", - "is ready", - }); -UX_STEP_NOCB( - ux_idle_flow_3_step, - bn, - { - "Version", - APPVERSION, - }); -UX_STEP_VALID( - ux_idle_flow_4_step, - pb, - os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); -UX_FLOW(ux_idle_flow, - &ux_idle_flow_1_step, - &ux_idle_flow_3_step, - &ux_idle_flow_4_step, - FLOW_LOOP -); +UX_STEP_NOCB(ux_idle_flow_1_step, nn, + { + "Application", + "is ready", + }); +UX_STEP_NOCB(ux_idle_flow_3_step, bn, + { + "Version", + APPVERSION, + }); +UX_STEP_VALID(ux_idle_flow_4_step, pb, os_sched_exit(-1), + { + &C_icon_dashboard_x, + "Quit", + }); +UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_3_step, + &ux_idle_flow_4_step, FLOW_LOOP); void ui_idle(void) { - // reserve a display stack slot if none yet - if(G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); + // reserve a display stack slot if none yet + if (G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); } diff --git a/src/message.c b/src/message.c index accd30a..e6a5900 100644 --- a/src/message.c +++ b/src/message.c @@ -1,560 +1,589 @@ #include "message.h" -#include "utils.h" -#include "errors.h" -#include "slice_data.h" #include "byte_stream.h" #include "contract.h" +#include "errors.h" +#include "slice_data.h" +#include "utils.h" #define ROOT_CELL_INDEX 0 #define GIFT_CELL_INDEX 1 -void deserialize_array(uint8_t* in, uint8_t in_size, uint16_t offset, uint8_t* out, uint8_t out_size) { - uint8_t shift = offset % 8; - uint8_t first_data_byte = offset / 8; - for (uint16_t i = first_data_byte, j = 0; j < out_size; ++i, ++j) { - VALIDATE(i == (j + first_data_byte) && (i + 1) <= in_size, ERR_INVALID_DATA); +void deserialize_array(uint8_t *in, uint8_t in_size, uint16_t offset, + uint8_t *out, uint8_t out_size) { + uint8_t shift = offset % 8; + uint8_t first_data_byte = offset / 8; + for (uint16_t i = first_data_byte, j = 0; j < out_size; ++i, ++j) { + VALIDATE(i == (j + first_data_byte) && (i + 1) <= in_size, + ERR_INVALID_DATA); - uint8_t cur = in[i] << shift; - out[j] = cur; + uint8_t cur = in[i] << shift; + out[j] = cur; - if (j == out_size - 1) { - out[j] |= in[i + 1] >> (8 - shift); - } + if (j == out_size - 1) { + out[j] |= in[i + 1] >> (8 - shift); + } - if (i != first_data_byte) { - out[j - 1] |= in[i] >> (8 - shift); - } + if (i != first_data_byte) { + out[j - 1] |= in[i] >> (8 - shift); } + } } -void deserialize_address(struct SliceData_t* slice, int8_t* wc, uint8_t* address) { - uint8_t addr_type = SliceData_get_next_int(slice, 2); - VALIDATE(addr_type == 0 || addr_type == 2, ERR_INVALID_DATA); +void deserialize_address(struct SliceData_t *slice, int8_t *wc, + uint8_t *address) { + uint8_t addr_type = SliceData_get_next_int(slice, 2); + VALIDATE(addr_type == 0 || addr_type == 2, ERR_INVALID_DATA); - if (addr_type == 2) { - uint8_t anycast = SliceData_get_next_bit(slice); - UNUSED(anycast); + if (addr_type == 2) { + uint8_t anycast = SliceData_get_next_bit(slice); + UNUSED(anycast); - *wc = (int8_t)SliceData_get_next_byte(slice); + *wc = (int8_t)SliceData_get_next_byte(slice); - uint8_t* data = SliceData_begin(slice); - uint16_t offset = SliceData_get_cursor(slice); - uint16_t data_size = SliceData_data_size(slice); + uint8_t *data = SliceData_begin(slice); + uint16_t offset = SliceData_get_cursor(slice); + uint16_t data_size = SliceData_data_size(slice); - deserialize_array(data, data_size, offset, address, ADDRESS_LENGTH); + deserialize_array(data, data_size, offset, address, ADDRESS_LENGTH); - SliceData_move_by(slice, ADDRESS_LENGTH * 8); - } + SliceData_move_by(slice, ADDRESS_LENGTH * 8); + } } -void deserialize_value(struct SliceData_t* slice, uint8_t* value, uint8_t value_length) { - uint8_t* data = SliceData_begin(slice); - uint16_t data_size = SliceData_data_size(slice); +void deserialize_value(struct SliceData_t *slice, uint8_t *value, + uint8_t value_length) { + uint8_t *data = SliceData_begin(slice); + uint16_t data_size = SliceData_data_size(slice); - uint16_t offset = SliceData_get_cursor(slice); - deserialize_array(data, data_size, offset, value, value_length); - SliceData_move_by(slice, value_length * 8); + uint16_t offset = SliceData_get_cursor(slice); + deserialize_array(data, data_size, offset, value, value_length); + SliceData_move_by(slice, value_length * 8); } -void set_dst_address(uint8_t wc, const uint8_t* address) { - char wc_temp[6]; // snprintf always returns zero - snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t)wc); - int wc_len = strlen(wc_temp); +void set_dst_address(uint8_t wc, const uint8_t *address) { + char wc_temp[6]; // snprintf always returns zero + snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t)wc); + int wc_len = strlen(wc_temp); - char* address_str = data_context.sign_tr_context.address_str; - memcpy(address_str, wc_temp, wc_len); - address_str += wc_len; + char *address_str = data_context.sign_tr_context.address_str; + memcpy(address_str, wc_temp, wc_len); + address_str += wc_len; - snprintf(address_str, sizeof(data_context.sign_tr_context.address_str) - wc_len, "%.*H", ADDRESS_LENGTH, address); + snprintf(address_str, + sizeof(data_context.sign_tr_context.address_str) - wc_len, "%.*H", + ADDRESS_LENGTH, address); } -void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uint8_t decimals, const char* ticker) { - char* amount_str = data_context.sign_tr_context.amount_str; - memset(amount_str, 0, sizeof(data_context.sign_tr_context.amount_str)); - - switch (flags) { - case NORMAL_FLAG: { - uint8_t text_size = convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str); - - const char* space = " "; - strncpy(amount_str + text_size, space, strlen(space)); - strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker)); - - break; - } - case ALL_BALANCE_FLAG: { - const char* text = "All balance"; - strncpy(amount_str, text, strlen(text)); - break; - } - case ALL_BALANCE_AND_DELETE_FLAG: { - const char* text = "All balance and delete account"; - strncpy(amount_str, text, strlen(text)); - break; - } - default: - THROW(ERR_INVALID_FLAG); - } +void set_amount(const uint8_t *amount, uint8_t amount_length, uint8_t flags, + uint8_t decimals, const char *ticker) { + char *amount_str = data_context.sign_tr_context.amount_str; + memset(amount_str, 0, sizeof(data_context.sign_tr_context.amount_str)); + + switch (flags) { + case NORMAL_FLAG: { + uint8_t text_size = convert_hex_amount_to_displayable( + amount, decimals, amount_length, amount_str); + + const char *space = " "; + strncpy(amount_str + text_size, space, strlen(space)); + strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker)); + + break; + } + case ALL_BALANCE_FLAG: { + const char *text = "All balance"; + strncpy(amount_str, text, strlen(text)); + break; + } + case ALL_BALANCE_AND_DELETE_FLAG: { + const char *text = "All balance and delete account"; + strncpy(amount_str, text, strlen(text)); + break; + } + default: + THROW(ERR_INVALID_FLAG); + } } -void set_transaction_id(const uint8_t* transaction_id) { - char* transaction_id_str = data_context.sign_tr_context.transaction_id_str; - memset(transaction_id_str, 0, sizeof(data_context.sign_tr_context.transaction_id_str)); +void set_transaction_id(const uint8_t *transaction_id) { + char *transaction_id_str = data_context.sign_tr_context.transaction_id_str; + memset(transaction_id_str, 0, + sizeof(data_context.sign_tr_context.transaction_id_str)); - snprintf(transaction_id_str, sizeof(data_context.sign_tr_context.transaction_id_str), "%.*H", TRANSACTION_ID_LENGTH, transaction_id); + snprintf(transaction_id_str, + sizeof(data_context.sign_tr_context.transaction_id_str), "%.*H", + TRANSACTION_ID_LENGTH, transaction_id); } -void deserialize_int_message_header(struct SliceData_t* slice, uint8_t flags, SignTransactionContext_t* ctx) { - uint8_t int_msg = SliceData_get_next_bit(slice); - VALIDATE(!int_msg, ERR_INVALID_DATA); +void deserialize_int_message_header(struct SliceData_t *slice, uint8_t flags, + SignTransactionContext_t *ctx) { + uint8_t int_msg = SliceData_get_next_bit(slice); + VALIDATE(!int_msg, ERR_INVALID_DATA); - uint8_t ihr_disabled = SliceData_get_next_bit(slice); - UNUSED(ihr_disabled); + uint8_t ihr_disabled = SliceData_get_next_bit(slice); + UNUSED(ihr_disabled); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t bounced = SliceData_get_next_bit(slice); - UNUSED(bounced); + uint8_t bounced = SliceData_get_next_bit(slice); + UNUSED(bounced); - // Sender address - int8_t src_wc = 0; - uint8_t src_addr[ADDRESS_LENGTH]; - deserialize_address(slice, &src_wc, src_addr); + // Sender address + int8_t src_wc = 0; + uint8_t src_addr[ADDRESS_LENGTH]; + deserialize_address(slice, &src_wc, src_addr); - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = SliceData_get_next_int(slice, 4); - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + // Amount + uint8_t amount_length = SliceData_get_next_int(slice, 4); + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - uint8_t other = SliceData_get_next_bit(slice); - UNUSED(other); + uint8_t other = SliceData_get_next_bit(slice); + UNUSED(other); - // Fee - uint8_t ihr_fee_length = SliceData_get_next_int(slice, 4); - VALIDATE(ihr_fee_length == 0, ERR_INVALID_DATA); + // Fee + uint8_t ihr_fee_length = SliceData_get_next_int(slice, 4); + VALIDATE(ihr_fee_length == 0, ERR_INVALID_DATA); - uint8_t fwd_fee_length = SliceData_get_next_int(slice, 4); - VALIDATE(fwd_fee_length == 0, ERR_INVALID_DATA); + uint8_t fwd_fee_length = SliceData_get_next_int(slice, 4); + VALIDATE(fwd_fee_length == 0, ERR_INVALID_DATA); - // Created - uint64_t created_lt = SliceData_get_next_int(slice, 64); - UNUSED(created_lt); + // Created + uint64_t created_lt = SliceData_get_next_int(slice, 64); + UNUSED(created_lt); - uint32_t created_at = SliceData_get_next_int(slice, 32); - UNUSED(created_at); + uint32_t created_at = SliceData_get_next_int(slice, 32); + UNUSED(created_at); } - -int deserialize_token_body(struct SliceData_t* slice, struct SliceData_t* ref_slice, SignTransactionContext_t* ctx) { - // FunctionId - if (SliceData_remaining_bits(slice) < sizeof(uint32_t) * 8) { - if (!ref_slice || !ref_slice->data || (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) { - // Empty payload is ok - return SIGN_TRANSACTION_FLOW_TRANSFER; - } - slice = ref_slice; +int deserialize_token_body(struct SliceData_t *slice, + struct SliceData_t *ref_slice, + SignTransactionContext_t *ctx) { + // FunctionId + if (SliceData_remaining_bits(slice) < sizeof(uint32_t) * 8) { + if (!ref_slice || !ref_slice->data || + (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) { + // Empty payload is ok + return SIGN_TRANSACTION_FLOW_TRANSFER; } + slice = ref_slice; + } - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - uint32_t function_id = SliceData_get_next_int(slice, sizeof(uint32_t) * 8); - switch (function_id) { - case TOKEN_TRANSFER: - case TOKEN_TRANSFER_TO_WALLET: { - // Amount - if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + uint32_t function_id = SliceData_get_next_int(slice, sizeof(uint32_t) * 8); + switch (function_id) { + case TOKEN_TRANSFER: + case TOKEN_TRANSFER_TO_WALLET: { + // Amount + if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - uint8_t amount[AMOUNT_LENGHT]; - deserialize_value(slice, amount, sizeof(amount)); + uint8_t amount[AMOUNT_LENGHT]; + deserialize_value(slice, amount, sizeof(amount)); - set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); + set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); - // Address - if (SliceData_remaining_bits(slice) < ADDRESS_LENGTH * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + // Address + if (SliceData_remaining_bits(slice) < ADDRESS_LENGTH * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - int8_t wc = 0; - uint8_t address[ADDRESS_LENGTH]; - deserialize_address(slice, &wc, address); + int8_t wc = 0; + uint8_t address[ADDRESS_LENGTH]; + deserialize_address(slice, &wc, address); - set_dst_address(wc, address); + set_dst_address(wc, address); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case TOKEN_BURN: { - // Amount - if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + break; + } + case TOKEN_BURN: { + // Amount + if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - uint8_t amount[AMOUNT_LENGHT]; - deserialize_value(slice, amount, sizeof(amount)); + uint8_t amount[AMOUNT_LENGHT]; + deserialize_value(slice, amount, sizeof(amount)); - set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); + set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_BURN; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_BURN; - break; - } - default: { - // All other methods could be treated as plain transfers + break; + } + default: { + // All other methods could be treated as plain transfers - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - } + break; + } + } - return sign_transaction_flow; + return sign_transaction_flow; } -int deserialize_multisig_params(struct SliceData_t* slice, uint32_t function_id, uint8_t wc, uint8_t* address, SignTransactionContext_t* ctx) { - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; +int deserialize_multisig_params(struct SliceData_t *slice, uint32_t function_id, + uint8_t wc, uint8_t *address, + SignTransactionContext_t *ctx) { + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - switch (function_id) { - case MULTISIG_DEPLOY_TRANSACTION: - case MULTISIG2_DEPLOY_TRANSACTION: { - // Address to deploy - set_dst_address(wc, address); + switch (function_id) { + case MULTISIG_DEPLOY_TRANSACTION: + case MULTISIG2_DEPLOY_TRANSACTION: { + // Address to deploy + set_dst_address(wc, address); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_DEPLOY; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_DEPLOY; - break; - } - case MULTISIG_SEND_TRANSACTION: { - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + break; + } + case MULTISIG_SEND_TRANSACTION: { + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = 16; - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); + // Amount + uint8_t amount_length = 16; + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t flags = SliceData_get_next_byte(slice); + uint8_t flags = SliceData_get_next_byte(slice); - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case MULTISIG_SUBMIT_TRANSACTION: - case MULTISIG2_SUBMIT_TRANSACTION: { - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + break; + } + case MULTISIG_SUBMIT_TRANSACTION: + case MULTISIG2_SUBMIT_TRANSACTION: { + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = 16; - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); + // Amount + uint8_t amount_length = 16; + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t all_balance = SliceData_get_next_bit(slice); + uint8_t all_balance = SliceData_get_next_bit(slice); - uint8_t flags; - if (!all_balance) { - flags = NORMAL_FLAG; - } else { - flags = ALL_BALANCE_FLAG; - } + uint8_t flags; + if (!all_balance) { + flags = NORMAL_FLAG; + } else { + flags = ALL_BALANCE_FLAG; + } - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case MULTISIG_CONFIRM_TRANSACTION: { - // Transaction id - uint8_t id[TRANSACTION_ID_LENGTH]; - deserialize_value(slice, id, sizeof(id)); + break; + } + case MULTISIG_CONFIRM_TRANSACTION: { + // Transaction id + uint8_t id[TRANSACTION_ID_LENGTH]; + deserialize_value(slice, id, sizeof(id)); - set_transaction_id(id); + set_transaction_id(id); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_CONFIRM; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_CONFIRM; - break; - } - default: - THROW(ERR_INVALID_FUNCTION_ID); - } + break; + } + default: + THROW(ERR_INVALID_FUNCTION_ID); + } - return sign_transaction_flow; + return sign_transaction_flow; } -void prepare_payload_hash(BocContext_t* bc) { - for (int16_t i = bc->cells_count - 1; i >= 0; --i) { - Cell_t* cell = &bc->cells[i]; - calc_cell_hash(cell, i); - } - - if (!data_context.sign_tr_context.sign_with_chain_id) { - memcpy(data_context.sign_tr_context.to_sign, &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); - } else { - memcpy(data_context.sign_tr_context.to_sign, data_context.sign_tr_context.chain_id, CHAIN_ID_LENGTH); - memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH, &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); - } +void prepare_payload_hash(BocContext_t *bc) { + for (int16_t i = bc->cells_count - 1; i >= 0; --i) { + Cell_t *cell = &bc->cells[i]; + calc_cell_hash(cell, i); + } + + if (!data_context.sign_tr_context.sign_with_chain_id) { + memcpy(data_context.sign_tr_context.to_sign, + &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); + } else { + memcpy(data_context.sign_tr_context.to_sign, + data_context.sign_tr_context.chain_id, CHAIN_ID_LENGTH); + memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH, + &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); + } } -uint32_t deserialize_wallet_v3(struct SliceData_t* slice) { - uint32_t id = SliceData_get_next_int(slice, 32); - VALIDATE(id == WALLET_ID, ERR_INVALID_DATA); +uint32_t deserialize_wallet_v3(struct SliceData_t *slice) { + uint32_t id = SliceData_get_next_int(slice, 32); + VALIDATE(id == WALLET_ID, ERR_INVALID_DATA); - uint32_t expire_at = SliceData_get_next_int(slice, 32); - UNUSED(expire_at); + uint32_t expire_at = SliceData_get_next_int(slice, 32); + UNUSED(expire_at); - uint32_t seqno = SliceData_get_next_int(slice, 32); - UNUSED(seqno); + uint32_t seqno = SliceData_get_next_int(slice, 32); + UNUSED(seqno); - uint8_t flags = SliceData_get_next_byte(slice); + uint8_t flags = SliceData_get_next_byte(slice); - uint16_t remaining_bits = SliceData_remaining_bits(slice); - VALIDATE(remaining_bits == 0, ERR_INVALID_DATA); + uint16_t remaining_bits = SliceData_remaining_bits(slice); + VALIDATE(remaining_bits == 0, ERR_INVALID_DATA); - return flags; + return flags; } -uint32_t deserialize_contract_header(struct SliceData_t* slice) { - uint8_t is_pubkey_present = SliceData_get_next_bit(slice); - if (is_pubkey_present) { - SliceData_move_by(slice, PUBLIC_KEY_LENGTH * 8); - } +uint32_t deserialize_contract_header(struct SliceData_t *slice) { + uint8_t is_pubkey_present = SliceData_get_next_bit(slice); + if (is_pubkey_present) { + SliceData_move_by(slice, PUBLIC_KEY_LENGTH * 8); + } - uint64_t time = SliceData_get_next_int(slice, 64); - UNUSED(time); + uint64_t time = SliceData_get_next_int(slice, 64); + UNUSED(time); - uint64_t expire = SliceData_get_next_int(slice, 32); - UNUSED(expire); + uint64_t expire = SliceData_get_next_int(slice, 32); + UNUSED(expire); - uint32_t function_id = SliceData_get_next_int(slice, 32); - return function_id; + uint32_t function_id = SliceData_get_next_int(slice, 32); + return function_id; } -void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, struct Cell_t* cell, uint8_t wc, uint8_t* address) { - uint16_t bit_len = Cell_bit_len(cell); - bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8) +void prepend_address_to_cell(uint8_t *cell_buffer, uint16_t cell_buffer_size, + struct Cell_t *cell, uint8_t wc, + uint8_t *address) { + uint16_t bit_len = Cell_bit_len(cell); + bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8) - uint8_t d1 = Cell_get_d1(cell); - uint8_t d2 = ((bit_len >> 2) & 0b11111110) | (bit_len % 8 != 0); + uint8_t d1 = Cell_get_d1(cell); + uint8_t d2 = ((bit_len >> 2) & 0b11111110) | (bit_len % 8 != 0); - cell_buffer[0] = d1; - cell_buffer[1] = d2; + cell_buffer[0] = d1; + cell_buffer[1] = d2; - SliceData_t slice; - SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size); + SliceData_t slice; + SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size); - // Append prefix - uint8_t prefix[] = { 0x80 }; // $100 prefix AddrStd - SliceData_append(&slice, prefix, 3, false); + // Append prefix + uint8_t prefix[] = {0x80}; // $100 prefix AddrStd + SliceData_append(&slice, prefix, 3, false); - // Append workchain - uint8_t wc_buf[] = { wc }; - SliceData_append(&slice, wc_buf, 8, false); + // Append workchain + uint8_t wc_buf[] = {wc}; + SliceData_append(&slice, wc_buf, 8, false); - // Append address - SliceData_append(&slice, address, ADDRESS_LENGTH * 8, false); + // Append address + SliceData_append(&slice, address, ADDRESS_LENGTH * 8, false); - // Append cell data - uint8_t* data = Cell_get_data(cell); - uint8_t data_size = Cell_get_data_size(cell); - SliceData_append(&slice, data, data_size * 8, false); + // Append cell data + uint8_t *data = Cell_get_data(cell); + uint8_t data_size = Cell_get_data_size(cell); + SliceData_append(&slice, data, data_size * 8, false); - // Append references - uint8_t refs_count = 0; - uint8_t* refs = Cell_get_refs(cell, &refs_count); + // Append references + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(cell, &refs_count); - VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t cell_data_size = (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); - cell_buffer[CELL_DATA_OFFSET + cell_data_size + child] = refs[child]; - } + VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, + ERR_INVALID_DATA); + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t cell_data_size = (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); + cell_buffer[CELL_DATA_OFFSET + cell_data_size + child] = refs[child]; + } - // Replace cell - cell->cell_begin = cell_buffer; + // Replace cell + cell->cell_begin = cell_buffer; } -int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint8_t* prepend_address) { - // Init context - BocContext_t* bc = &boc_context; - DataContext_t* dc = &data_context; +int prepare_to_sign(struct ByteStream_t *src, uint8_t wc, uint8_t *address, + uint8_t *prepend_address) { + // Init context + BocContext_t *bc = &boc_context; + DataContext_t *dc = &data_context; - // Parse transaction boc - deserialize_cells_tree(src); + // Parse transaction boc + deserialize_cells_tree(src); - Cell_t* root_cell = &bc->cells[ROOT_CELL_INDEX]; + Cell_t *root_cell = &bc->cells[ROOT_CELL_INDEX]; - SliceData_t root_slice; - SliceData_from_cell(&root_slice, root_cell); + SliceData_t root_slice; + SliceData_from_cell(&root_slice, root_cell); - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - switch (dc->sign_tr_context.current_wallet_type) { - case WALLET_V3: { - uint8_t flags = deserialize_wallet_v3(&root_slice); + switch (dc->sign_tr_context.current_wallet_type) { + case WALLET_V3: { + uint8_t flags = deserialize_wallet_v3(&root_slice); - // Gift - VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); - Cell_t* gift_cell = &bc->cells[GIFT_CELL_INDEX]; + // Gift + VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); + Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; - SliceData_t gift_slice; - SliceData_from_cell(&gift_slice, gift_cell); + SliceData_t gift_slice; + SliceData_from_cell(&gift_slice, gift_cell); - // Deserialize header - deserialize_int_message_header(&gift_slice, flags, &dc->sign_tr_context); + // Deserialize header + deserialize_int_message_header(&gift_slice, flags, &dc->sign_tr_context); - // Deserialize StateInit - uint8_t state_init_bit = SliceData_get_next_bit(&gift_slice); - VALIDATE(state_init_bit == 0, ERR_INVALID_DATA); + // Deserialize StateInit + uint8_t state_init_bit = SliceData_get_next_bit(&gift_slice); + VALIDATE(state_init_bit == 0, ERR_INVALID_DATA); - // Deserialize Body - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); + // Deserialize Body + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - uint8_t body_bit = SliceData_get_next_bit(&gift_slice); - if (body_bit || gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t* ref_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + uint8_t body_bit = SliceData_get_next_bit(&gift_slice); + if (body_bit || gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *ref_cell = &bc->cells[GIFT_CELL_INDEX + 1]; - SliceData_t ref_slice; - SliceData_from_cell(&ref_slice, ref_cell); + SliceData_t ref_slice; + SliceData_from_cell(&ref_slice, ref_cell); - sign_transaction_flow = deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context); - } + sign_transaction_flow = + deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context); + } - // Calculate payload hash to sign - prepare_payload_hash(bc); + // Calculate payload hash to sign + prepare_payload_hash(bc); - break; - } - case SAFE_MULTISIG_WALLET: - case SAFE_MULTISIG_WALLET_24H: - case SETCODE_MULTISIG_WALLET: - case BRIDGE_MULTISIG_WALLET: - case SURF_WALLET: { - // Header - uint32_t function_id = deserialize_contract_header(&root_slice); + break; + } + case SAFE_MULTISIG_WALLET: + case SAFE_MULTISIG_WALLET_24H: + case SETCODE_MULTISIG_WALLET: + case BRIDGE_MULTISIG_WALLET: + case SURF_WALLET: { + // Header + uint32_t function_id = deserialize_contract_header(&root_slice); - bool in_same_cell = function_id == MULTISIG_CONFIRM_TRANSACTION; + bool in_same_cell = function_id == MULTISIG_CONFIRM_TRANSACTION; - // Gift - Cell_t* gift_cell = in_same_cell ? root_cell : &bc->cells[GIFT_CELL_INDEX]; + // Gift + Cell_t *gift_cell = in_same_cell ? root_cell : &bc->cells[GIFT_CELL_INDEX]; - SliceData_t gift_slice; - if (in_same_cell) { - gift_slice = root_slice; - } else { - SliceData_from_cell(&gift_slice, gift_cell); - } + SliceData_t gift_slice; + if (in_same_cell) { + gift_slice = root_slice; + } else { + SliceData_from_cell(&gift_slice, gift_cell); + } - sign_transaction_flow = deserialize_multisig_params(&gift_slice, function_id, wc, address, &dc->sign_tr_context); + sign_transaction_flow = deserialize_multisig_params( + &gift_slice, function_id, wc, address, &dc->sign_tr_context); - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); - // Gift body - if (gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t* body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + // Gift body + if (gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; - SliceData_t body_slice; - SliceData_from_cell(&body_slice, body_cell); + SliceData_t body_slice; + SliceData_from_cell(&body_slice, body_cell); - if (!SliceData_is_empty(&body_slice)) { - sign_transaction_flow = deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); - } - } + if (!SliceData_is_empty(&body_slice)) { + sign_transaction_flow = + deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); + } + } - // Calculate payload hash to sign - prepare_payload_hash(bc); + // Calculate payload hash to sign + prepare_payload_hash(bc); - break; - } - case EVER_WALLET: - case MULTISIG_2: - case MULTISIG_2_1: { - // Header - uint32_t function_id = deserialize_contract_header(&root_slice); + break; + } + case EVER_WALLET: + case MULTISIG_2: + case MULTISIG_2_1: { + // Header + uint32_t function_id = deserialize_contract_header(&root_slice); - // Gift - VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); - Cell_t* gift_cell = &bc->cells[GIFT_CELL_INDEX]; + // Gift + VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); + Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; - SliceData_t gift_slice; - SliceData_from_cell(&gift_slice, gift_cell); + SliceData_t gift_slice; + SliceData_from_cell(&gift_slice, gift_cell); - sign_transaction_flow = deserialize_multisig_params(&gift_slice, function_id, wc, address, &dc->sign_tr_context); + sign_transaction_flow = deserialize_multisig_params( + &gift_slice, function_id, wc, address, &dc->sign_tr_context); - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); - // Gift body - if (gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t* body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + // Gift body + if (gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; - SliceData_t body_slice; - SliceData_from_cell(&body_slice, body_cell); + SliceData_t body_slice; + SliceData_from_cell(&body_slice, body_cell); - if (!SliceData_is_empty(&body_slice)) { - sign_transaction_flow = deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); - } - } + if (!SliceData_is_empty(&body_slice)) { + sign_transaction_flow = + deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); + } + } - // Prepend address to root cell - uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128) - prepend_address_to_cell(cell_buffer, sizeof(cell_buffer), root_cell, wc, prepend_address); + // Prepend address to root cell + uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128) + prepend_address_to_cell(cell_buffer, sizeof(cell_buffer), root_cell, wc, + prepend_address); - // Calculate payload hash to sign - prepare_payload_hash(bc); + // Calculate payload hash to sign + prepare_payload_hash(bc); - // Detach cell_buffer reference from global boc context - memset(bc, 0, sizeof(boc_context)); + // Detach cell_buffer reference from global boc context + memset(bc, 0, sizeof(boc_context)); - break; - } - default: - THROW(ERR_INVALID_WALLET_TYPE); - } + break; + } + default: + THROW(ERR_INVALID_WALLET_TYPE); + } - return sign_transaction_flow; + return sign_transaction_flow; } diff --git a/src/sign.c b/src/sign.c index 7788dd6..f444254 100644 --- a/src/sign.c +++ b/src/sign.c @@ -1,104 +1,98 @@ #include "apdu_constants.h" -#include "utils.h" #include "errors.h" +#include "utils.h" static uint8_t set_result_sign() { - cx_ecfp_private_key_t privateKey; - SignContext_t* context = &data_context.sign_context; + cx_ecfp_private_key_t privateKey; + SignContext_t *context = &data_context.sign_context; - BEGIN_TRY { - TRY { - get_private_key(context->account_number, &privateKey); - if (!context->sign_with_chain_id) { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL); - } else { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL); - } - } FINALLY { - memset(&privateKey, 0, sizeof(privateKey)); - } + BEGIN_TRY { + TRY { + get_private_key(context->account_number, &privateKey); + if (!context->sign_with_chain_id) { + cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, + TO_SIGN_LENGTH, NULL, 0, context->signature, + SIGNATURE_LENGTH, NULL); + } else { + cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, + context->signature, SIGNATURE_LENGTH, NULL); + } } - END_TRY; + FINALLY { memset(&privateKey, 0, sizeof(privateKey)); } + } + END_TRY; - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; - memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); - tx += SIGNATURE_LENGTH; - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; + memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); + tx += SIGNATURE_LENGTH; + return tx; } -UX_STEP_NOCB( - ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB( - ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = data_context.sign_context.to_sign_str, - }); -UX_STEP_CB( - ux_sign_flow_3_step, - pbb, - send_response(0, false), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); -UX_STEP_CB( - ux_sign_flow_4_step, - pbb, - send_response(set_result_sign(), true), - { - &C_icon_validate_14, - "Sign", - "message.", - }); +UX_STEP_NOCB(ux_sign_flow_1_step, pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB(ux_sign_flow_2_step, bnnn_paging, + { + .title = "Message hash", + .text = data_context.sign_context.to_sign_str, + }); +UX_STEP_CB(ux_sign_flow_3_step, pbb, send_response(0, false), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); +UX_STEP_CB(ux_sign_flow_4_step, pbb, send_response(set_result_sign(), true), + { + &C_icon_validate_14, + "Sign", + "message.", + }); -UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step -); +UX_FLOW(ux_sign_flow, &ux_sign_flow_1_step, &ux_sign_flow_2_step, + &ux_sign_flow_3_step, &ux_sign_flow_4_step); -void handleSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(tx); +void handleSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, + uint16_t dataLength, volatile unsigned int *flags, + volatile unsigned int *tx) { + UNUSED(tx); - VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); - SignContext_t* context = &data_context.sign_context; + VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); + SignContext_t *context = &data_context.sign_context; - size_t offset = 0; + size_t offset = 0; - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); + context->account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(context->account_number); - uint8_t metadata = dataBuffer[offset]; - offset += sizeof(metadata); + uint8_t metadata = dataBuffer[offset]; + offset += sizeof(metadata); - // Read chain id if present - if (metadata & FLAG_WITH_CHAIN_ID) { - context->sign_with_chain_id = true; + // Read chain id if present + if (metadata & FLAG_WITH_CHAIN_ID) { + context->sign_with_chain_id = true; - memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); - offset += sizeof(context->chain_id); - } + memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); + offset += sizeof(context->chain_id); + } - if (!context->sign_with_chain_id) { - memcpy(context->to_sign, dataBuffer + offset, TO_SIGN_LENGTH); - snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", TO_SIGN_LENGTH, context->to_sign); - } else { - memcpy(context->to_sign, context->chain_id, CHAIN_ID_LENGTH); - memcpy(context->to_sign + CHAIN_ID_LENGTH, dataBuffer + offset, TO_SIGN_LENGTH); - snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", CHAIN_ID_LENGTH + TO_SIGN_LENGTH, context->to_sign); - } + if (!context->sign_with_chain_id) { + memcpy(context->to_sign, dataBuffer + offset, TO_SIGN_LENGTH); + snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", + TO_SIGN_LENGTH, context->to_sign); + } else { + memcpy(context->to_sign, context->chain_id, CHAIN_ID_LENGTH); + memcpy(context->to_sign + CHAIN_ID_LENGTH, dataBuffer + offset, + TO_SIGN_LENGTH); + snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, context->to_sign); + } - ux_flow_init(0, ux_sign_flow, NULL); - *flags |= IO_ASYNCH_REPLY; + ux_flow_init(0, ux_sign_flow, NULL); + *flags |= IO_ASYNCH_REPLY; } diff --git a/src/sign_transaction.c b/src/sign_transaction.c index d5f5639..657c768 100644 --- a/src/sign_transaction.c +++ b/src/sign_transaction.c @@ -1,234 +1,190 @@ #include "apdu_constants.h" -#include "utils.h" -#include "errors.h" #include "byte_stream.h" -#include "message.h" #include "contract.h" +#include "errors.h" +#include "message.h" +#include "utils.h" static uint8_t set_result_sign_transaction() { - cx_ecfp_private_key_t privateKey; - SignTransactionContext_t* context = &data_context.sign_tr_context; - - BEGIN_TRY { - TRY { - get_private_key(context->account_number, &privateKey); - if (!context->sign_with_chain_id) { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL); - } else { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL); - } - } FINALLY { - memset(&privateKey, 0, sizeof(privateKey)); - } + cx_ecfp_private_key_t privateKey; + SignTransactionContext_t *context = &data_context.sign_tr_context; + + BEGIN_TRY { + TRY { + get_private_key(context->account_number, &privateKey); + if (!context->sign_with_chain_id) { + cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, + TO_SIGN_LENGTH, NULL, 0, context->signature, + SIGNATURE_LENGTH, NULL); + } else { + cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, + context->signature, SIGNATURE_LENGTH, NULL); + } } - END_TRY; - - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; - memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); - tx += SIGNATURE_LENGTH; - return tx; + FINALLY { memset(&privateKey, 0, sizeof(privateKey)); } + } + END_TRY; + + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; + memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); + tx += SIGNATURE_LENGTH; + return tx; } -UX_STEP_NOCB( - ux_sign_transaction_intro, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB( - ux_sign_transaction_burn, - bnnn_paging, - { - .title = "Action", - .text = "Burn" - }); -UX_STEP_NOCB( - ux_sign_transaction_deploy, - bnnn_paging, - { - .title = "Action", - .text = "Deploy" - }); -UX_STEP_NOCB( - ux_sign_transaction_confirm, - bnnn_paging, - { - .title = "Action", - .text = "Confirm" - }); -UX_STEP_NOCB( - ux_sign_transaction_transfer, - bnnn_paging, - { - .title = "Action", - .text = "Transfer" - }); -UX_STEP_NOCB( - ux_sign_transaction_amount, - bnnn_paging, - { - .title = "Amount", - .text = data_context.sign_tr_context.amount_str, - }); -UX_STEP_NOCB( - ux_sign_transaction_address, - bnnn_paging, - { - .title = "Address", - .text = data_context.sign_tr_context.address_str, - }); -UX_STEP_NOCB( - ux_sign_transaction_transaction_id, - bnnn_paging, - { - .title = "Transaction id", - .text = data_context.sign_tr_context.transaction_id_str, - }); -UX_STEP_CB( - ux_sign_transaction_accept, - pbb, - send_response(set_result_sign_transaction(), true), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_CB( - ux_sign_transaction_reject, - pb, - send_response(0, false), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_sign_transaction_burn_flow, - &ux_sign_transaction_intro, - &ux_sign_transaction_burn, - &ux_sign_transaction_amount, - &ux_sign_transaction_accept, - &ux_sign_transaction_reject -); - -UX_FLOW(ux_sign_transaction_deploy_flow, - &ux_sign_transaction_intro, - &ux_sign_transaction_deploy, - &ux_sign_transaction_address, - &ux_sign_transaction_accept, - &ux_sign_transaction_reject -); - -UX_FLOW(ux_sign_transaction_confirm_flow, - &ux_sign_transaction_intro, - &ux_sign_transaction_confirm, - &ux_sign_transaction_transaction_id, - &ux_sign_transaction_accept, - &ux_sign_transaction_reject -); - -UX_FLOW(ux_sign_transaction_transfer_flow, - &ux_sign_transaction_intro, - &ux_sign_transaction_transfer, - &ux_sign_transaction_amount, - &ux_sign_transaction_address, - &ux_sign_transaction_accept, - &ux_sign_transaction_reject -); - -void handleSignTransaction(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(tx); - - VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); - SignTransactionContext_t* context = &data_context.sign_tr_context; - - size_t offset = 0; - - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); - - context->origin_wallet_type = dataBuffer[offset]; - offset += sizeof(context->origin_wallet_type); - - context->decimals = dataBuffer[offset]; - offset += sizeof(context->decimals); - - uint8_t ticker_len = dataBuffer[offset]; - offset += sizeof(ticker_len); - - VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); - - memcpy(context->ticker, dataBuffer + offset, ticker_len); - offset += ticker_len; - - uint8_t metadata = dataBuffer[offset]; - offset += sizeof(metadata); - - // Read wallet type if present - if (metadata & FLAG_WITH_WALLET_ID) { - context->current_wallet_type = dataBuffer[offset]; - offset += sizeof(context->current_wallet_type); - } else { - context->current_wallet_type = context->origin_wallet_type; - } - - // Get address - uint8_t address[ADDRESS_LENGTH]; - get_address(context->account_number, context->origin_wallet_type, address); - memset(&boc_context, 0, sizeof(boc_context)); - - // Read wc if present - uint8_t wc = DEFAULT_WORKCHAIN_ID; - if (metadata & FLAG_WITH_WORKCHAIN_ID) { - wc = dataBuffer[offset]; - offset += sizeof(wc); - } - - // Read initial address if present - uint8_t prepend_address[ADDRESS_LENGTH]; - if (metadata & FLAG_WITH_ADDRESS) { - memcpy(prepend_address, dataBuffer + offset, ADDRESS_LENGTH); - offset += sizeof(address); - } else { - memcpy(prepend_address, address, ADDRESS_LENGTH); - } - - // Read chain id if present - if (metadata & FLAG_WITH_CHAIN_ID) { - context->sign_with_chain_id = true; - - memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); - offset += sizeof(context->chain_id); - } else { - context->sign_with_chain_id = false; - } - - uint8_t* msg_begin = dataBuffer + offset; - uint8_t msg_length = dataLength - offset; - - ByteStream_t src; - ByteStream_init(&src, msg_begin, msg_length); - - int flow = prepare_to_sign(&src, wc, address, prepend_address); - - switch (flow) { - case SIGN_TRANSACTION_FLOW_TRANSFER: - ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_DEPLOY: - ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_CONFIRM: - ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_BURN: - ux_flow_init(0, ux_sign_transaction_burn_flow, NULL); - break; - default: - THROW(ERR_INVALID_REQUEST); - } - - *flags |= IO_ASYNCH_REPLY; +UX_STEP_NOCB(ux_sign_transaction_intro, pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB(ux_sign_transaction_burn, bnnn_paging, + {.title = "Action", .text = "Burn"}); +UX_STEP_NOCB(ux_sign_transaction_deploy, bnnn_paging, + {.title = "Action", .text = "Deploy"}); +UX_STEP_NOCB(ux_sign_transaction_confirm, bnnn_paging, + {.title = "Action", .text = "Confirm"}); +UX_STEP_NOCB(ux_sign_transaction_transfer, bnnn_paging, + {.title = "Action", .text = "Transfer"}); +UX_STEP_NOCB(ux_sign_transaction_amount, bnnn_paging, + { + .title = "Amount", + .text = data_context.sign_tr_context.amount_str, + }); +UX_STEP_NOCB(ux_sign_transaction_address, bnnn_paging, + { + .title = "Address", + .text = data_context.sign_tr_context.address_str, + }); +UX_STEP_NOCB(ux_sign_transaction_transaction_id, bnnn_paging, + { + .title = "Transaction id", + .text = data_context.sign_tr_context.transaction_id_str, + }); +UX_STEP_CB(ux_sign_transaction_accept, pbb, + send_response(set_result_sign_transaction(), true), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_CB(ux_sign_transaction_reject, pb, send_response(0, false), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_sign_transaction_burn_flow, &ux_sign_transaction_intro, + &ux_sign_transaction_burn, &ux_sign_transaction_amount, + &ux_sign_transaction_accept, &ux_sign_transaction_reject); + +UX_FLOW(ux_sign_transaction_deploy_flow, &ux_sign_transaction_intro, + &ux_sign_transaction_deploy, &ux_sign_transaction_address, + &ux_sign_transaction_accept, &ux_sign_transaction_reject); + +UX_FLOW(ux_sign_transaction_confirm_flow, &ux_sign_transaction_intro, + &ux_sign_transaction_confirm, &ux_sign_transaction_transaction_id, + &ux_sign_transaction_accept, &ux_sign_transaction_reject); + +UX_FLOW(ux_sign_transaction_transfer_flow, &ux_sign_transaction_intro, + &ux_sign_transaction_transfer, &ux_sign_transaction_amount, + &ux_sign_transaction_address, &ux_sign_transaction_accept, + &ux_sign_transaction_reject); + +void handleSignTransaction(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, + uint16_t dataLength, volatile unsigned int *flags, + volatile unsigned int *tx) { + UNUSED(tx); + + VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); + SignTransactionContext_t *context = &data_context.sign_tr_context; + + size_t offset = 0; + + context->account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(context->account_number); + + context->origin_wallet_type = dataBuffer[offset]; + offset += sizeof(context->origin_wallet_type); + + context->decimals = dataBuffer[offset]; + offset += sizeof(context->decimals); + + uint8_t ticker_len = dataBuffer[offset]; + offset += sizeof(ticker_len); + + VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); + + memcpy(context->ticker, dataBuffer + offset, ticker_len); + offset += ticker_len; + + uint8_t metadata = dataBuffer[offset]; + offset += sizeof(metadata); + + // Read wallet type if present + if (metadata & FLAG_WITH_WALLET_ID) { + context->current_wallet_type = dataBuffer[offset]; + offset += sizeof(context->current_wallet_type); + } else { + context->current_wallet_type = context->origin_wallet_type; + } + + // Get address + uint8_t address[ADDRESS_LENGTH]; + get_address(context->account_number, context->origin_wallet_type, address); + memset(&boc_context, 0, sizeof(boc_context)); + + // Read wc if present + uint8_t wc = DEFAULT_WORKCHAIN_ID; + if (metadata & FLAG_WITH_WORKCHAIN_ID) { + wc = dataBuffer[offset]; + offset += sizeof(wc); + } + + // Read initial address if present + uint8_t prepend_address[ADDRESS_LENGTH]; + if (metadata & FLAG_WITH_ADDRESS) { + memcpy(prepend_address, dataBuffer + offset, ADDRESS_LENGTH); + offset += sizeof(address); + } else { + memcpy(prepend_address, address, ADDRESS_LENGTH); + } + + // Read chain id if present + if (metadata & FLAG_WITH_CHAIN_ID) { + context->sign_with_chain_id = true; + + memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); + offset += sizeof(context->chain_id); + } else { + context->sign_with_chain_id = false; + } + + uint8_t *msg_begin = dataBuffer + offset; + uint8_t msg_length = dataLength - offset; + + ByteStream_t src; + ByteStream_init(&src, msg_begin, msg_length); + + int flow = prepare_to_sign(&src, wc, address, prepend_address); + + switch (flow) { + case SIGN_TRANSACTION_FLOW_TRANSFER: + ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_DEPLOY: + ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_CONFIRM: + ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_BURN: + ux_flow_init(0, ux_sign_transaction_burn_flow, NULL); + break; + default: + THROW(ERR_INVALID_REQUEST); + } + + *flags |= IO_ASYNCH_REPLY; } diff --git a/src/slice_data.c b/src/slice_data.c index e34d94f..5868fe1 100644 --- a/src/slice_data.c +++ b/src/slice_data.c @@ -1,201 +1,207 @@ #include "slice_data.h" +#include "cell.h" #include "globals.h" #include "utils.h" -#include "cell.h" - -void SliceData_init(struct SliceData_t* self, uint8_t* data, uint16_t data_size_bytes) { - VALIDATE(self && data, ERR_SLICE_IS_EMPTY); - self->data = data; - self->data_window_start = 0; - self->data_window_end = data_size_bytes * 8; - self->data_size_bytes = data_size_bytes; -} - -void SliceData_from_cell(struct SliceData_t* self, struct Cell_t* cell) { - uint8_t* cell_data = Cell_get_data(cell); - uint8_t cell_data_size = Cell_get_data_size(cell); - SliceData_init(self, cell_data, cell_data_size); -} -void SliceData_fill(struct SliceData_t* self, uint8_t value, uint16_t data_size_bytes) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(self->data_size_bytes >= data_size_bytes, ERR_INVALID_DATA); - memset(self->data, value, data_size_bytes); -} - -void SliceData_truncate(struct SliceData_t* self, uint16_t size) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(size <= self->data_window_end, ERR_CELL_UNDERFLOW); - self->data_window_end = size; -} - -uint16_t SliceData_remaining_bits(const struct SliceData_t* self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - if (self->data_window_start > self->data_window_end) { - return 0; +void SliceData_init(struct SliceData_t *self, uint8_t *data, + uint16_t data_size_bytes) { + VALIDATE(self && data, ERR_SLICE_IS_EMPTY); + self->data = data; + self->data_window_start = 0; + self->data_window_end = data_size_bytes * 8; + self->data_size_bytes = data_size_bytes; +} + +void SliceData_from_cell(struct SliceData_t *self, struct Cell_t *cell) { + uint8_t *cell_data = Cell_get_data(cell); + uint8_t cell_data_size = Cell_get_data_size(cell); + SliceData_init(self, cell_data, cell_data_size); +} + +void SliceData_fill(struct SliceData_t *self, uint8_t value, + uint16_t data_size_bytes) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(self->data_size_bytes >= data_size_bytes, ERR_INVALID_DATA); + memset(self->data, value, data_size_bytes); +} + +void SliceData_truncate(struct SliceData_t *self, uint16_t size) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(size <= self->data_window_end, ERR_CELL_UNDERFLOW); + self->data_window_end = size; +} + +uint16_t SliceData_remaining_bits(const struct SliceData_t *self) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + if (self->data_window_start > self->data_window_end) { + return 0; + } + return self->data_window_end - self->data_window_start; +} + +void SliceData_move_by(struct SliceData_t *self, uint16_t offset) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(self->data_window_start + offset <= self->data_window_end, + ERR_CELL_UNDERFLOW); + self->data_window_start += offset; +} + +uint8_t SliceData_get_bits(const struct SliceData_t *self, uint16_t offset, + uint8_t bits) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(offset + bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); + VALIDATE(bits != 0 && bits <= 8, ERR_RANGE_CHECK); + + uint16_t index = self->data_window_start + offset; + uint8_t q = index / 8; + uint8_t r = index % 8; + if (r == 0) { + return self->data[q] >> (8 - r - bits); + } else if (bits <= (8 - r)) { + return self->data[q] >> (8 - r - bits) & ((1 << bits) - 1); + } else { + uint16_t ret = 0; + if (q < self->data_size_bytes) { + uint16_t byte = self->data[q]; + ret |= byte << 8; } - return self->data_window_end - self->data_window_start; -} - -void SliceData_move_by(struct SliceData_t* self, uint16_t offset) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(self->data_window_start + offset <= self->data_window_end, ERR_CELL_UNDERFLOW); - self->data_window_start += offset; -} - -uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint8_t bits) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(offset + bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); - VALIDATE(bits != 0 && bits <= 8, ERR_RANGE_CHECK); - - uint16_t index = self->data_window_start + offset; - uint8_t q = index / 8; - uint8_t r = index % 8; - if (r == 0) { - return self->data[q] >> (8 - r - bits); - } else if (bits <= (8 - r)) { - return self->data[q] >> (8 - r - bits) & ((1 << bits) - 1); - } else { - uint16_t ret = 0; - if (q < self->data_size_bytes) { - uint16_t byte = self->data[q]; - ret |= byte << 8; - } - if (q < self->data_size_bytes - 1) { - ret |= self->data[q + 1]; - } - - ret = (ret >> (8 - r)) >> (8 - bits); - return (uint8_t)ret; + if (q < self->data_size_bytes - 1) { + ret |= self->data[q + 1]; } + + ret = (ret >> (8 - r)) >> (8 - bits); + return (uint8_t)ret; + } } -uint8_t SliceData_get_next_bit(struct SliceData_t* self) { - uint8_t bit = SliceData_get_bits(self, 0, 1); - SliceData_move_by(self, 1); - return bit; +uint8_t SliceData_get_next_bit(struct SliceData_t *self) { + uint8_t bit = SliceData_get_bits(self, 0, 1); + SliceData_move_by(self, 1); + return bit; } -uint8_t SliceData_get_byte(const struct SliceData_t* self, uint16_t offset) { - return SliceData_get_bits(self, offset, 8); +uint8_t SliceData_get_byte(const struct SliceData_t *self, uint16_t offset) { + return SliceData_get_bits(self, offset, 8); } -uint8_t SliceData_get_next_byte(struct SliceData_t* self) { - uint8_t value = SliceData_get_byte(self, 0); - SliceData_move_by(self, 8); - return value; +uint8_t SliceData_get_next_byte(struct SliceData_t *self) { + uint8_t value = SliceData_get_byte(self, 0); + SliceData_move_by(self, 8); + return value; } -uint64_t SliceData_get_int(const struct SliceData_t* self, uint8_t bits) { - VALIDATE(bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); - VALIDATE(bits <= 64, ERR_RANGE_CHECK); - if (bits == 0) { - return 0; - } +uint64_t SliceData_get_int(const struct SliceData_t *self, uint8_t bits) { + VALIDATE(bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); + VALIDATE(bits <= 64, ERR_RANGE_CHECK); + if (bits == 0) { + return 0; + } - uint64_t value = 0; - uint8_t bytes = bits / 8; - for (uint8_t i = 0; i < bytes; ++i) { - uint64_t byte = SliceData_get_byte(self, 8 * i); - value |= byte << (8 * (7 - i)); - } + uint64_t value = 0; + uint8_t bytes = bits / 8; + for (uint8_t i = 0; i < bytes; ++i) { + uint64_t byte = SliceData_get_byte(self, 8 * i); + value |= byte << (8 * (7 - i)); + } - volatile uint8_t remainder = bits % 8; - if (remainder != 0) { - uint64_t r = SliceData_get_bits(self, bytes * 8, remainder); - value |= r << (8 * (7 - bytes) + (8 - remainder)); - } + volatile uint8_t remainder = bits % 8; + if (remainder != 0) { + uint64_t r = SliceData_get_bits(self, bytes * 8, remainder); + value |= r << (8 * (7 - bytes) + (8 - remainder)); + } - return value >> (64 - bits); + return value >> (64 - bits); } -uint64_t SliceData_get_next_int(struct SliceData_t* self, uint8_t bits) { - uint64_t value = SliceData_get_int(self, bits); - SliceData_move_by(self, bits); - return value; +uint64_t SliceData_get_next_int(struct SliceData_t *self, uint8_t bits) { + uint64_t value = SliceData_get_int(self, bits); + SliceData_move_by(self, bits); + return value; } -uint64_t SliceData_get_next_size(struct SliceData_t* self, uint16_t max_value) { - if (max_value == 0) { - return 0; - } - uint8_t bits = 16 - leading_zeros(max_value); - uint64_t res = SliceData_get_next_int(self, bits); - return res; +uint64_t SliceData_get_next_size(struct SliceData_t *self, uint16_t max_value) { + if (max_value == 0) { + return 0; + } + uint8_t bits = 16 - leading_zeros(max_value); + uint64_t res = SliceData_get_next_int(self, bits); + return res; } -bool SliceData_is_empty(const struct SliceData_t* self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_window_start >= self->data_window_end; +bool SliceData_is_empty(const struct SliceData_t *self) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_window_start >= self->data_window_end; } -bool SliceData_equal(const struct SliceData_t* self, const struct SliceData_t* other) { - uint32_t self_rb = SliceData_remaining_bits(self); - uint32_t other_rb = SliceData_remaining_bits(other); - if (self_rb != other_rb) { - return false; - } +bool SliceData_equal(const struct SliceData_t *self, + const struct SliceData_t *other) { + uint32_t self_rb = SliceData_remaining_bits(self); + uint32_t other_rb = SliceData_remaining_bits(other); + if (self_rb != other_rb) { + return false; + } - return SliceData_get_int(self, self_rb) == SliceData_get_int(other, other_rb); + return SliceData_get_int(self, self_rb) == SliceData_get_int(other, other_rb); } -uint16_t SliceData_get_cursor(const struct SliceData_t* self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_window_start; +uint16_t SliceData_get_cursor(const struct SliceData_t *self) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_window_start; } -uint8_t* SliceData_begin(const struct SliceData_t* self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data; +uint8_t *SliceData_begin(const struct SliceData_t *self) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data; } -uint16_t SliceData_data_size(const struct SliceData_t* self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_size_bytes; +uint16_t SliceData_data_size(const struct SliceData_t *self) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_size_bytes; } -void SliceData_append(struct SliceData_t* self, uint8_t* in, uint16_t bits, bool append_tag) { - uint8_t bytes = bits / 8; - VALIDATE(bytes <= SliceData_remaining_bits(self) * 8, ERR_CELL_UNDERFLOW); +void SliceData_append(struct SliceData_t *self, uint8_t *in, uint16_t bits, + bool append_tag) { + uint8_t bytes = bits / 8; + VALIDATE(bytes <= SliceData_remaining_bits(self) * 8, ERR_CELL_UNDERFLOW); - uint16_t offset = self->data_window_start; - if (offset % 8 == 0 || bytes == 0) { - memcpy(self->data + offset / 8, in, bytes ? bytes : 1); - } - else { - uint8_t shift = offset % 8; - uint8_t first_data_byte = offset / 8; - uint8_t prev = 0; - for (uint16_t i = first_data_byte, j = 0; j < bytes; ++i, ++j) { - VALIDATE(i == (j + first_data_byte) && i < self->data_size_bytes, ERR_INVALID_DATA); - - uint8_t cur = in[j] >> shift; - if (j == 0) { - uint8_t first_byte = self->data[i] >> (8 - shift); - first_byte <<= 8 - shift; - self->data[i] = first_byte | cur; - } else { - self->data[i] = prev | cur; - } - - prev = in[j] << (8 - shift); - if (j == bytes - 1) { - uint8_t last_byte = prev; - if (append_tag) { - if (shift != 7) { - last_byte >>= 7 - shift; - } - last_byte |= 1; - if (shift != 7) { - last_byte <<= 7 - shift; - } - - bits += 8 - shift; - } - self->data[i + 1] = last_byte; - } + uint16_t offset = self->data_window_start; + if (offset % 8 == 0 || bytes == 0) { + memcpy(self->data + offset / 8, in, bytes ? bytes : 1); + } else { + uint8_t shift = offset % 8; + uint8_t first_data_byte = offset / 8; + uint8_t prev = 0; + for (uint16_t i = first_data_byte, j = 0; j < bytes; ++i, ++j) { + VALIDATE(i == (j + first_data_byte) && i < self->data_size_bytes, + ERR_INVALID_DATA); + + uint8_t cur = in[j] >> shift; + if (j == 0) { + uint8_t first_byte = self->data[i] >> (8 - shift); + first_byte <<= 8 - shift; + self->data[i] = first_byte | cur; + } else { + self->data[i] = prev | cur; + } + + prev = in[j] << (8 - shift); + if (j == bytes - 1) { + uint8_t last_byte = prev; + if (append_tag) { + if (shift != 7) { + last_byte >>= 7 - shift; + } + last_byte |= 1; + if (shift != 7) { + last_byte <<= 7 - shift; + } + + bits += 8 - shift; } + self->data[i + 1] = last_byte; + } } + } - self->data_window_start += bits; + self->data_window_start += bits; } diff --git a/src/utils.c b/src/utils.c index 058788c..59bb067 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,212 +1,196 @@ -#include "os.h" -#include "cx.h" #include "utils.h" +#include "cx.h" #include "menu.h" +#include "os.h" #include -void get_public_key(uint32_t account_number, uint8_t* publicKeyArray) { - cx_ecfp_private_key_t privateKey; - cx_ecfp_public_key_t publicKey; - - get_private_key(account_number, &privateKey); - BEGIN_TRY { - TRY { - cx_ecfp_generate_pair(CX_CURVE_Ed25519, &publicKey, &privateKey, 1); - } - CATCH_OTHER(e) { - THROW(e); - } - FINALLY { - explicit_bzero(&privateKey, sizeof(privateKey)); - } - } - END_TRY; - - for (int i = 0; i < 32; i++) { - publicKeyArray[i] = publicKey.W[64 - i]; - } - if ((publicKey.W[32] & 1) != 0) { - publicKeyArray[31] |= 0x80; - } +void get_public_key(uint32_t account_number, uint8_t *publicKeyArray) { + cx_ecfp_private_key_t privateKey; + cx_ecfp_public_key_t publicKey; + + get_private_key(account_number, &privateKey); + BEGIN_TRY { + TRY { cx_ecfp_generate_pair(CX_CURVE_Ed25519, &publicKey, &privateKey, 1); } + CATCH_OTHER(e) { THROW(e); } + FINALLY { explicit_bzero(&privateKey, sizeof(privateKey)); } + } + END_TRY; + + for (int i = 0; i < 32; i++) { + publicKeyArray[i] = publicKey.W[64 - i]; + } + if ((publicKey.W[32] & 1) != 0) { + publicKeyArray[31] |= 0x80; + } } static const uint32_t HARDENED_OFFSET = 0x80000000; -void get_private_key(uint32_t account_number, cx_ecfp_private_key_t *privateKey) { - const uint32_t derivePath[BIP32_PATH] = { - 44 | HARDENED_OFFSET, - 396 | HARDENED_OFFSET, - account_number | HARDENED_OFFSET, - 0 | HARDENED_OFFSET, - 0 | HARDENED_OFFSET - }; - - uint8_t privateKeyData[32]; - BEGIN_TRY { - TRY { - os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10, - CX_CURVE_Ed25519, - derivePath, - BIP32_PATH, - privateKeyData, - NULL, - NULL, - 0); - cx_ecfp_init_private_key(CX_CURVE_Ed25519, - privateKeyData, - 32, - privateKey); - } - CATCH_OTHER(e) { - THROW(e); - } - FINALLY { - explicit_bzero(&privateKey, sizeof(privateKey)); - } +void get_private_key(uint32_t account_number, + cx_ecfp_private_key_t *privateKey) { + const uint32_t derivePath[BIP32_PATH] = { + 44 | HARDENED_OFFSET, 396 | HARDENED_OFFSET, + account_number | HARDENED_OFFSET, 0 | HARDENED_OFFSET, + 0 | HARDENED_OFFSET}; + + uint8_t privateKeyData[32]; + BEGIN_TRY { + TRY { + os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10, CX_CURVE_Ed25519, + derivePath, BIP32_PATH, + privateKeyData, NULL, NULL, 0); + cx_ecfp_init_private_key(CX_CURVE_Ed25519, privateKeyData, 32, + privateKey); } - END_TRY; + CATCH_OTHER(e) { THROW(e); } + FINALLY { explicit_bzero(&privateKey, sizeof(privateKey)); } + } + END_TRY; } void send_response(uint8_t tx, bool approve) { - G_io_apdu_buffer[tx++] = approve? 0x90 : 0x69; - G_io_apdu_buffer[tx++] = approve? 0x00 : 0x85; - reset_app_context(); - // Send back the response, do not restart the event loop - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); - // Display back the original UX - ui_idle(); + G_io_apdu_buffer[tx++] = approve ? 0x90 : 0x69; + G_io_apdu_buffer[tx++] = approve ? 0x00 : 0x85; + reset_app_context(); + // Send back the response, do not restart the event loop + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); + // Display back the original UX + ui_idle(); } unsigned int ui_prepro(const bagl_element_t *element) { - unsigned int display = 1; - if (element->component.userid > 0) { - display = (ux_step == element->component.userid - 1); - if (display) { - if (element->component.userid == 1) { - UX_CALLBACK_SET_INTERVAL(2000); - } - else { - UX_CALLBACK_SET_INTERVAL(MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - } - } + unsigned int display = 1; + if (element->component.userid > 0) { + display = (ux_step == element->component.userid - 1); + if (display) { + if (element->component.userid == 1) { + UX_CALLBACK_SET_INTERVAL(2000); + } else { + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + } } - return display; + } + return display; } void writeUint32BE(uint32_t val, uint8_t *bytes) { - bytes[0] = (val >> 24) & 0xFF; - bytes[1] = (val >> 16) & 0xFF; - bytes[2] = (val >> 8) & 0xFF; - bytes[3] = val & 0xFF; + bytes[0] = (val >> 24) & 0xFF; + bytes[1] = (val >> 16) & 0xFF; + bytes[2] = (val >> 8) & 0xFF; + bytes[3] = val & 0xFF; } void writeUint64BE(uint64_t val, uint8_t *bytes) { - bytes[0] = (val >> 56) & 0xFF; - bytes[1] = (val >> 48) & 0xFF; - bytes[2] = (val >> 40) & 0xFF; - bytes[3] = (val >> 32) & 0xFF; - bytes[4] = (val >> 24) & 0xFF; - bytes[5] = (val >> 16) & 0xFF; - bytes[6] = (val >> 8) & 0xFF; - bytes[7] = val & 0xFF; + bytes[0] = (val >> 56) & 0xFF; + bytes[1] = (val >> 48) & 0xFF; + bytes[2] = (val >> 40) & 0xFF; + bytes[3] = (val >> 32) & 0xFF; + bytes[4] = (val >> 24) & 0xFF; + bytes[5] = (val >> 16) & 0xFF; + bytes[6] = (val >> 8) & 0xFF; + bytes[7] = val & 0xFF; } uint16_t readUint16BE(uint8_t *buffer) { - return (buffer[0] << 8) | (buffer[1]); + return (buffer[0] << 8) | (buffer[1]); } uint32_t readUint32BE(uint8_t *buffer) { - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); } uint64_t readUint64BE(uint8_t *buffer) { - uint32_t i1 = buffer[3] + (buffer[2] << 8u) + (buffer[1] << 16u) + (buffer[0] << 24u); - uint32_t i2 = buffer[7] + (buffer[6] << 8u) + (buffer[5] << 16u) + (buffer[4] << 24u); - return i2 | ((uint64_t) i1 << 32u); + uint32_t i1 = + buffer[3] + (buffer[2] << 8u) + (buffer[1] << 16u) + (buffer[0] << 24u); + uint32_t i2 = + buffer[7] + (buffer[6] << 8u) + (buffer[5] << 16u) + (buffer[4] << 24u); + return i2 | ((uint64_t)i1 << 32u); } uint8_t leading_zeros(uint16_t value) { - uint8_t lz = 0; - uint16_t msb = 0x8000; - for (uint8_t i = 0; i < 16; ++i) { - if ((value << i) & msb) { - break; - } - ++lz; + uint8_t lz = 0; + uint16_t msb = 0x8000; + for (uint8_t i = 0; i < 16; ++i) { + if ((value << i) & msb) { + break; } + ++lz; + } - return lz; + return lz; } #define SCRATCH_SIZE 37 -uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimals, uint8_t amount_length, char* out) { - uint8_t LOOP1 = SCRATCH_SIZE - decimals; - uint8_t LOOP2 = decimals; - uint16_t scratch[SCRATCH_SIZE]; - uint8_t offset = 0; - uint8_t nonZero = 0; - uint8_t i; - uint8_t targetOffset = 0; - uint8_t workOffset; - uint8_t j; - uint8_t nscratch = SCRATCH_SIZE; - uint8_t smin = nscratch - 2; - uint8_t comma = 0; - - for (i = 0; i < SCRATCH_SIZE; i++) { - scratch[i] = 0; +uint8_t convert_hex_amount_to_displayable(const uint8_t *amount, + uint8_t decimals, + uint8_t amount_length, char *out) { + uint8_t LOOP1 = SCRATCH_SIZE - decimals; + uint8_t LOOP2 = decimals; + uint16_t scratch[SCRATCH_SIZE]; + uint8_t offset = 0; + uint8_t nonZero = 0; + uint8_t i; + uint8_t targetOffset = 0; + uint8_t workOffset; + uint8_t j; + uint8_t nscratch = SCRATCH_SIZE; + uint8_t smin = nscratch - 2; + uint8_t comma = 0; + + for (i = 0; i < SCRATCH_SIZE; i++) { + scratch[i] = 0; + } + for (i = 0; i < amount_length; i++) { + for (j = 0; j < 8; j++) { + uint8_t k; + uint16_t shifted_in = + (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 : (short)0; + for (k = smin; k < nscratch; k++) { + scratch[k] += ((scratch[k] >= 5) ? 3 : 0); + } + if (scratch[smin] >= 8) { + smin -= 1; + } + for (k = smin; k < nscratch - 1; k++) { + scratch[k] = + ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); + } + scratch[nscratch - 1] = + ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0); } - for (i = 0; i < amount_length; i++) { - for (j = 0; j < 8; j++) { - uint8_t k; - uint16_t shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 - : (short)0; - for (k = smin; k < nscratch; k++) { - scratch[k] += ((scratch[k] >= 5) ? 3 : 0); - } - if (scratch[smin] >= 8) { - smin -= 1; - } - for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); - } - scratch[nscratch - 1] = ((scratch[nscratch - 1] << 1) & 0x0F) | - (shifted_in == 1 ? 1 : 0); - } + } + + for (i = 0; i < LOOP1; i++) { + if (!nonZero && (scratch[offset] == 0)) { + offset++; + } else { + nonZero = 1; + out[targetOffset++] = scratch[offset++] + '0'; } - - for (i = 0; i < LOOP1; i++) { - if (!nonZero && (scratch[offset] == 0)) { - offset++; - } else { - nonZero = 1; - out[targetOffset++] = scratch[offset++] + '0'; - } + } + if (targetOffset == 0) { + out[targetOffset++] = '0'; + } + workOffset = offset; + for (i = 0; i < LOOP2; i++) { + unsigned char allZero = 1; + unsigned char j; + for (j = i; j < LOOP2; j++) { + if (scratch[workOffset + j] != 0) { + allZero = 0; + break; + } } - if (targetOffset == 0) { - out[targetOffset++] = '0'; + if (allZero) { + break; } - workOffset = offset; - for (i = 0; i < LOOP2; i++) { - unsigned char allZero = 1; - unsigned char j; - for (j = i; j < LOOP2; j++) { - if (scratch[workOffset + j] != 0) { - allZero = 0; - break; - } - } - if (allZero) { - break; - } - if (!comma) { - out[targetOffset++] = '.'; - comma = 1; - } - out[targetOffset++] = scratch[offset++] + '0'; + if (!comma) { + out[targetOffset++] = '.'; + comma = 1; } - return targetOffset; + out[targetOffset++] = scratch[offset++] + '0'; + } + return targetOffset; } From 2c3d4521af0a1dc37fdb407f69f6896cc2d142a6 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:50:19 +0100 Subject: [PATCH 21/33] ops: remove unused workflow --- .github/workflows/unit_tests.yml | 61 -------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 .github/workflows/unit_tests.yml diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml deleted file mode 100644 index 4eec9af..0000000 --- a/.github/workflows/unit_tests.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Unit testing with Codecov coverage checking - -on: - workflow_dispatch: - push: - branches: - - master - - main - - develop - pull_request: - -jobs: - job_unit_test: - name: Unit test - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - name: Clone - uses: actions/checkout@v4 - - - name: Clone SDK - uses: actions/checkout@v4 - with: - repository: ledgerHQ/ledger-secure-sdk - path: sdk - - - name: Build unit tests - run: | - cd unit-tests/ - export BOLOS_SDK=../sdk - cmake -Bbuild -H. && make -C build && make -C build test - - - name: Generate code coverage - run: | - cd unit-tests/ - lcov --directory . -b "$(realpath build/)" --capture --initial -o coverage.base && \ - lcov --rc lcov_branch_coverage=1 --directory . -b "$(realpath build/)" --capture -o coverage.capture && \ - lcov --directory . -b "$(realpath build/)" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info && \ - lcov --directory . -b "$(realpath build/)" --remove coverage.info '*/unit-tests/*' -o coverage.info && \ - genhtml coverage.info -o coverage - - - uses: actions/upload-artifact@v4 - with: - name: code-coverage - path: unit-tests/coverage - - - name: Install codecov dependencies - run: apk update && apk add curl gpg - - - name: Upload to codecov.io - uses: codecov/codecov-action@v5 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: ./unit-tests/coverage.info - flags: unittests - name: codecov-app-everscale - fail_ci_if_error: true - verbose: true From 86096781ffd39f920e982018e90cb4cbd7730d3e Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:58:58 +0100 Subject: [PATCH 22/33] style: clean up and format Everscale command sender and response unpacker - Remove trailing commas from Errors enum - Improve code formatting and consistency - Remove TODO comment in response unpacker --- .../everscale_command_sender.py | 167 ++++++++++-------- .../everscale_response_unpacker.py | 1 - 2 files changed, 92 insertions(+), 76 deletions(-) diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 86a3aab..54484e5 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -10,27 +10,31 @@ CLA: int = 0xE0 + class P1(IntEnum): # Parameter 1 for first APDU number. P1_START = 0x00 # Parameter 1 for maximum APDU number. - P1_MAX = 0x03 + P1_MAX = 0x03 # Parameter 1 for screen confirmation for GET_PUBLIC_KEY. P1_CONFIRM = 0x01 + class P2(IntEnum): # Parameter 2 for last APDU to receive. P2_LAST = 0x00 # Parameter 2 for more APDU to receive. P2_MORE = 0x80 + class InsType(IntEnum): GET_APP_CONFIGURATION = 0x01 GET_PUBLIC_KEY = 0x02 SIGN_MESSAGE = 0x03 - GET_ADDRESS = 0X04 + GET_ADDRESS = 0x04 SIGN_TRANSACTION = 0x05 + class WalletType(IntEnum): WALLET_V3 = 0 EVER_WALLET = 1 @@ -42,25 +46,26 @@ class WalletType(IntEnum): MULTISIG_2 = 7 MULTISIG_2_1 = 8 + class Errors(IntEnum): - SW_INVALID_DATA = 0x6B00, - SW_CELL_UNDERFLOW = 0x6B01, - SW_RANGE_CHECK_FAIL = 0x6B02, - SW_WRONG_LABEL = 0x6B03, - SW_INVALID_FLAG = 0x6B04, - SW_END_OF_STREAM = 0x6B05, - SW_SLICE_IS_EMPTY = 0x6B06, - SW_INVALID_KEY = 0x6B07, - SW_CELL_IS_EMPTY = 0x6B08, - SW_INVALID_HASH = 0x6B09, - SW_INVALID_CELL_INDEX = 0x6B10, - SW_INVALID_REQUEST = 0x6B11, - SW_INVALID_FUNCTION_ID = 0x6B12, - SW_INVALID_SRC_ADDRESS = 0x6B13, - SW_INVALID_WALLET_ID = 0x6B14, - SW_INVALID_WALLET_TYPE = 0x6B15, - SW_INVALID_TICKER_LENGTH = 0x6B16, - SW_DENY = 0x6985, + SW_INVALID_DATA = 0x6B00 + SW_CELL_UNDERFLOW = 0x6B01 + SW_RANGE_CHECK_FAIL = 0x6B02 + SW_WRONG_LABEL = 0x6B03 + SW_INVALID_FLAG = 0x6B04 + SW_END_OF_STREAM = 0x6B05 + SW_SLICE_IS_EMPTY = 0x6B06 + SW_INVALID_KEY = 0x6B07 + SW_CELL_IS_EMPTY = 0x6B08 + SW_INVALID_HASH = 0x6B09 + SW_INVALID_CELL_INDEX = 0x6B10 + SW_INVALID_REQUEST = 0x6B11 + SW_INVALID_FUNCTION_ID = 0x6B12 + SW_INVALID_SRC_ADDRESS = 0x6B13 + SW_INVALID_WALLET_ID = 0x6B14 + SW_INVALID_WALLET_TYPE = 0x6B15 + SW_INVALID_TICKER_LENGTH = 0x6B16 + SW_DENY = 0x6985 # Status Word from everscale app # SW_WRONG_P1P2 = 0x6A86 # SW_WRONG_DATA_LENGTH = 0x6A87 @@ -78,88 +83,100 @@ class Errors(IntEnum): def split_message(message: bytes, max_size: int) -> List[bytes]: - return [message[x:x + max_size] for x in range(0, len(message), max_size)] + return [message[x : x + max_size] for x in range(0, len(message), max_size)] class EverscaleCommandSender: def __init__(self, backend: BackendInterface) -> None: self.backend = backend - def get_app_and_version(self) -> RAPDU: - return self.backend.exchange(cla=0xB0, # specific CLA for BOLOS - ins=0x01, # specific INS for get_app_and_version - p1=P1.P1_START, - p2=P2.P2_LAST, - data=b"") - + return self.backend.exchange( + cla=0xB0, # specific CLA for BOLOS + ins=0x01, # specific INS for get_app_and_version + p1=P1.P1_START, + p2=P2.P2_LAST, + data=b"", + ) def get_app_config(self) -> RAPDU: - return self.backend.exchange(cla=CLA, - ins=InsType.GET_APP_CONFIGURATION, - p1=P1.P1_START, - p2=P2.P2_LAST, - data=b"") - + return self.backend.exchange( + cla=CLA, + ins=InsType.GET_APP_CONFIGURATION, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=b"", + ) def get_app_name(self) -> RAPDU: - return self.backend.exchange(cla=CLA, - ins=InsType.GET_APP_NAME, - p1=P1.P1_START, - p2=P2.P2_LAST, - data=b"") - + return self.backend.exchange( + cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_LAST, data=b"" + ) def get_public_key(self, account_number: int) -> RAPDU: - return self.backend.exchange(cla=CLA, - ins=InsType.GET_PUBLIC_KEY, - p1=P1.P1_START, - p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big")) - + return self.backend.exchange( + cla=CLA, + ins=InsType.GET_PUBLIC_KEY, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big"), + ) @contextmanager - def get_public_key_with_confirmation(self, account_number: int) -> Generator[None, None, None]: - with self.backend.exchange_async(cla=CLA, - ins=InsType.GET_PUBLIC_KEY, - p1=P1.P1_CONFIRM, - p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big")) as response: + def get_public_key_with_confirmation( + self, account_number: int + ) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.GET_PUBLIC_KEY, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big"), + ) as response: yield response def get_address(self, account_number: int, wallet_type: WalletType) -> RAPDU: - return self.backend.exchange(cla=CLA, - ins=InsType.GET_ADDRESS, - p1=P1.P1_START, - p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big")) + return self.backend.exchange( + cla=CLA, + ins=InsType.GET_ADDRESS, + p1=P1.P1_START, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big"), + ) @contextmanager - def get_address_with_confirmation(self, account_number: int, wallet_type: WalletType) -> Generator[None, None, None]: - with self.backend.exchange_async(cla=CLA, - ins=InsType.GET_ADDRESS, - p1=P1.P1_CONFIRM, - p2=P2.P2_LAST, - data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big")) as response: + def get_address_with_confirmation( + self, account_number: int, wallet_type: WalletType + ) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.GET_ADDRESS, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big"), + ) as response: yield response - @contextmanager - def sign_message(self, payload: bytes) -> Generator[None, None, None]: - with self.backend.exchange_async(cla=CLA, - ins=InsType.SIGN_MESSAGE, - p1=P1.P1_CONFIRM, - p2=P2.P2_LAST, - data=payload) as response: + def sign_message(self, payload: bytes) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_MESSAGE, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=payload, + ) as response: yield response @contextmanager def sign_tx(self, transaction: bytes) -> Generator[None, None, None]: - with self.backend.exchange_async(cla=CLA, - ins=InsType.SIGN_TRANSACTION, - p1=P1.P1_CONFIRM, - p2=P2.P2_LAST, - data=transaction) as response: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_TRANSACTION, + p1=P1.P1_CONFIRM, + p2=P2.P2_LAST, + data=transaction, + ) as response: yield response def get_async_response(self) -> Optional[RAPDU]: diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py index b08e690..9c6fed4 100644 --- a/tests/application_client/everscale_response_unpacker.py +++ b/tests/application_client/everscale_response_unpacker.py @@ -68,7 +68,6 @@ def unpack_get_address_response(response: bytes) -> Tuple[int, bytes]: # response = der_sig_len (1) # der_sig (var) # v (1) -# TODO: check if this needs to be edited def unpack_sign_tx_response(response: bytes) -> Tuple[int, bytes, int]: response, der_sig_len, der_sig = pop_size_prefixed_buf_from_buf(response) response, v = pop_sized_buf_from_buffer(response, 1) From 2bf30597c3a3260c47296f593d639dc2bedb4909 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:59:24 +0100 Subject: [PATCH 23/33] chore: delete unused rust files --- client/Cargo.lock | 2380 ---------------------------- client/Cargo.toml | 31 - client/src/main.rs | 1036 ------------ tests/old_to_delete/.gitignore | 1 - tests/old_to_delete/Cargo.lock | 2594 ------------------------------- tests/old_to_delete/Cargo.toml | 33 - tests/old_to_delete/src/main.rs | 278 ---- 7 files changed, 6353 deletions(-) delete mode 100644 client/Cargo.lock delete mode 100644 client/Cargo.toml delete mode 100644 client/src/main.rs delete mode 100644 tests/old_to_delete/.gitignore delete mode 100644 tests/old_to_delete/Cargo.lock delete mode 100644 tests/old_to_delete/Cargo.toml delete mode 100644 tests/old_to_delete/src/main.rs diff --git a/client/Cargo.lock b/client/Cargo.lock deleted file mode 100644 index e71dd74..0000000 --- a/client/Cargo.lock +++ /dev/null @@ -1,2380 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anyhow" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "async-compression" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-trait" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64ct" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" - -[[package]] -name = "bigdecimal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" - -[[package]] -name = "cc" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clap" -version = "4.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca505fd2c00136e0d0cd34bcd8b6bd0b59d5779aab396054b716334230c1c" -dependencies = [ - "atty", - "bitflags", - "clap_derive", - "clap_lex", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "client" -version = "0.1.0" -dependencies = [ - "anyhow", - "bigdecimal", - "clap", - "ed25519-dalek", - "everscale-jrpc-client", - "everscale-ledger-wallet", - "hex", - "nekoton", - "nekoton-abi", - "nekoton-contracts", - "nekoton-utils", - "rust_decimal", - "tokio", - "ton_block", - "ton_types", - "url", -] - -[[package]] -name = "console" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "terminal_size", - "unicode-width", - "winapi", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "countme" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" -dependencies = [ - "byteorder", - "digest", - "rand_core", - "subtle-ng", - "zeroize", -] - -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "dialoguer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" -dependencies = [ - "console", - "tempfile", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" - -[[package]] -name = "dyn-clone" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" - -[[package]] -name = "ed25519" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "git+https://github.com/broxus/ed25519-dalek.git#e5d68fd1490a7f6a0d473c6c1b1acef868960471" -dependencies = [ - "curve25519-dalek-ng", - "ed25519", - "rand", - "serde", - "sha2", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "everscale-jrpc-client" -version = "0.1.1" -source = "git+https://github.com/broxus/everscale-jrpc.git#818acdcb2a32ac5bcffa3ccbea998258249aebf8" -dependencies = [ - "anyhow", - "base64", - "everscale-jrpc-models", - "futures", - "log", - "nekoton", - "nekoton-abi", - "nekoton-utils", - "parking_lot", - "rand", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", -] - -[[package]] -name = "everscale-jrpc-models" -version = "0.1.0" -source = "git+https://github.com/broxus/everscale-jrpc.git#818acdcb2a32ac5bcffa3ccbea998258249aebf8" -dependencies = [ - "nekoton-abi", - "nekoton-utils", - "serde", - "ton_block", -] - -[[package]] -name = "everscale-ledger-wallet" -version = "0.1.0" -source = "git+https://github.com/broxus/everscale-ledger-wallet.git#5dbbda2813f5bb501ea2fd486209f4d9d04ec1cc" -dependencies = [ - "anyhow", - "console", - "dialoguer", - "ed25519-dalek", - "hex", - "hidapi", - "log", - "num-derive", - "num-traits", - "parking_lot", - "qstring", - "semver", - "thiserror", - "uriparse", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" - -[[package]] -name = "futures-task" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" - -[[package]] -name = "futures-util" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "h2" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hidapi" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" -dependencies = [ - "cc", - "libc", - "pkg-config", - "winapi", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest", - "generic-array", - "hmac 0.8.1", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ipnet" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" - -[[package]] -name = "libsecp256k1" -version = "0.7.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "arrayref", - "base64", - "digest", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand", - "serde", - "sha2", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "crunchy", - "digest", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lru" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memzero" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db" - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "miniz_oxide" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.42.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nekoton" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#8fe5c4fdfc23807d51b4f715e24cde86449b7dfc" -dependencies = [ - "anyhow", - "async-trait", - "base64", - "chacha20poly1305", - "curve25519-dalek-ng", - "downcast-rs", - "dyn-clone", - "ed25519-dalek", - "futures-util", - "getrandom", - "hex", - "hmac 0.11.0", - "log", - "lru", - "nekoton-abi", - "nekoton-contracts", - "nekoton-utils", - "num-bigint", - "once_cell", - "parking_lot", - "pbkdf2", - "rand", - "secstr", - "serde", - "serde_json", - "sha2", - "thiserror", - "tiny-bip39", - "tiny-hderive", - "tokio", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", - "zeroize", -] - -[[package]] -name = "nekoton-abi" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#8fe5c4fdfc23807d51b4f715e24cde86449b7dfc" -dependencies = [ - "anyhow", - "base64", - "ed25519-dalek", - "hex", - "log", - "nekoton-derive", - "nekoton-utils", - "num-bigint", - "num-traits", - "rustc-hash", - "serde", - "serde_json", - "smallvec", - "thiserror", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", - "ton_vm", -] - -[[package]] -name = "nekoton-contracts" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#8fe5c4fdfc23807d51b4f715e24cde86449b7dfc" -dependencies = [ - "anyhow", - "nekoton-abi", - "once_cell", - "thiserror", - "ton_abi", - "ton_block", - "ton_types", -] - -[[package]] -name = "nekoton-derive" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#8fe5c4fdfc23807d51b4f715e24cde86449b7dfc" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "nekoton-utils" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#8fe5c4fdfc23807d51b4f715e24cde86449b7dfc" -dependencies = [ - "anyhow", - "base64", - "chacha20poly1305", - "ed25519-dalek", - "hex", - "hmac 0.11.0", - "pbkdf2", - "secstr", - "serde", - "sha2", - "thiserror", - "ton_block", - "ton_types", - "zeroize", -] - -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" -dependencies = [ - "parking_lot_core", -] - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_str_bytes" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", -] - -[[package]] -name = "password-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" -dependencies = [ - "crypto-mac 0.11.1", - "hmac 0.11.0", - "password-hash", - "sha2", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "reqwest" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" -dependencies = [ - "async-compression", - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rust_decimal" -version = "1.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" -dependencies = [ - "arrayvec", - "num-traits", - "serde", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "secstr" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04f657244f605c4cf38f6de5993e8bd050c8a303f86aeabff142d5c7c113e12" -dependencies = [ - "libc", - "serde", -] - -[[package]] -name = "security-framework" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" - -[[package]] -name = "serde" -version = "1.0.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-ng" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" - -[[package]] -name = "syn" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-bip39" -version = "0.8.0" -source = "git+https://github.com/broxus/tiny-bip39.git#d2a73124c2fbead4f969f8a5e075ee22040f63cc" -dependencies = [ - "anyhow", - "hmac 0.11.0", - "once_cell", - "pbkdf2", - "rand", - "rustc-hash", - "sha2", - "thiserror", - "unicode-normalization", - "zeroize", -] - -[[package]] -name = "tiny-hderive" -version = "0.3.0" -source = "git+https://github.com/broxus/tiny-hderive.git#050986d85711497076ba552ce53806885274a4d2" -dependencies = [ - "base58", - "hmac 0.11.0", - "libsecp256k1", - "memzero", - "sha2", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "ton_abi" -version = "2.1.0" -source = "git+https://github.com/broxus/ton-labs-abi#5429246f11bdb794910c295a5aab4318accdd894" -dependencies = [ - "anyhow", - "base64", - "byteorder", - "ed25519", - "ed25519-dalek", - "hex", - "num-bigint", - "num-traits", - "serde", - "serde_json", - "sha2", - "smallvec", - "thiserror", - "ton_block", - "ton_types", -] - -[[package]] -name = "ton_block" -version = "1.7.14" -source = "git+https://github.com/broxus/ton-labs-block#bf7a53587cc98da4b51b58f3c4160e8f85985159" -dependencies = [ - "anyhow", - "base64", - "crc", - "ed25519", - "ed25519-dalek", - "hex", - "log", - "num", - "num-traits", - "rand", - "rustc-hash", - "sha2", - "smallvec", - "thiserror", - "ton_types", -] - -[[package]] -name = "ton_executor" -version = "1.15.54" -source = "git+https://github.com/broxus/ton-labs-executor.git#d8e8fed291948ff66e9d1f6d8f44f37f1cf0de6f" -dependencies = [ - "anyhow", - "log", - "thiserror", - "ton_block", - "ton_types", - "ton_vm", -] - -[[package]] -name = "ton_types" -version = "1.10.2" -source = "git+https://github.com/broxus/ton-labs-types#dea1147b9fa25153e20dc79d9f0141f325f3921a" -dependencies = [ - "anyhow", - "base64", - "countme", - "crc", - "dashmap", - "hex", - "log", - "num", - "num-derive", - "num-traits", - "rand", - "rustc-hash", - "sha2", - "smallvec", - "thiserror", -] - -[[package]] -name = "ton_vm" -version = "1.8.29" -source = "git+https://github.com/broxus/ton-labs-vm.git#72059801850016bad0a2b909600a043e0694feda" -dependencies = [ - "anyhow", - "ed25519", - "ed25519-dalek", - "hex", - "lazy_static", - "log", - "num", - "num-traits", - "rand", - "sha2", - "smallvec", - "thiserror", - "ton_block", - "ton_types", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "uriparse" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" -dependencies = [ - "fnv", - "lazy_static", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/client/Cargo.toml b/client/Cargo.toml deleted file mode 100644 index f9e4270..0000000 --- a/client/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "client" -version = "0.1.0" -edition = "2021" -authors = ["Broxus team"] - -[dependencies] -anyhow = "1.0" -bigdecimal = "0.3.0" -clap = { version = "4.0.18", features = ["derive"] } -hex = "0.4.3" -rust_decimal = "1" -tokio = { version = "1.21.2", features = ["sync", "rt-multi-thread", "macros"] } -url = { version = "2.3.1" } - -# Basic types -ed25519-dalek = { git = "https://github.com/broxus/ed25519-dalek.git" } -ton_block = { git = "https://github.com/broxus/ton-labs-block" } -ton_types = { git = "https://github.com/broxus/ton-labs-types" } - -# JRPC client -everscale-jrpc-client = { git = "https://github.com/broxus/everscale-jrpc.git" } - -# Ledger wallet -everscale-ledger-wallet = { git = "https://github.com/broxus/everscale-ledger-wallet.git" } - -# Nekoton SDK -nekoton = { git = "https://github.com/broxus/nekoton.git", default-features = false } -nekoton-abi = { git = "https://github.com/broxus/nekoton.git" } -nekoton-utils = { git = "https://github.com/broxus/nekoton.git" } -nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" } \ No newline at end of file diff --git a/client/src/main.rs b/client/src/main.rs deleted file mode 100644 index c877c04..0000000 --- a/client/src/main.rs +++ /dev/null @@ -1,1036 +0,0 @@ -use bigdecimal::BigDecimal; -use std::str::FromStr; -use std::sync::Arc; - -use bigdecimal::num_bigint::ToBigInt; -use clap::Parser; -use ed25519_dalek::{PublicKey, SIGNATURE_LENGTH}; -use everscale_ledger_wallet::ledger::{LedgerWallet, WalletType}; -use everscale_ledger_wallet::locator::Manufacturer; -use everscale_ledger_wallet::remote_wallet::{initialize_wallet_manager, RemoteWallet}; -use nekoton::core::models::{Expiration, TokenWalletVersion}; -use nekoton::core::token_wallet::{RootTokenContractState, TokenWalletContractState}; -use nekoton::core::ton_wallet::{Gift, MultisigType, TransferAction, DEFAULT_WORKCHAIN}; -use nekoton::crypto::UnsignedMessage; -use nekoton::transport::models::ExistingContract; -use nekoton_abi::num_bigint::BigUint; -use nekoton_abi::{BigUint128, MessageBuilder}; -use nekoton_contracts::tip3_1; -use nekoton_utils::{SimpleClock, TrustMe}; -use rust_decimal::prelude::{FromPrimitive, ToPrimitive}; -use rust_decimal::Decimal; -use ton_block::{AccountState, GetRepresentationHash, MsgAddressInt}; -use ton_types::{AccountId, SliceData, UInt256}; -use url::Url; - -const EVER_DECIMALS: u8 = 9; -const EVER_TICKER: &str = "EVER"; - -const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec -const INITIAL_BALANCE: u64 = 100_000_000; // 0.1 EVER -const ATTACHED_AMOUNT: u64 = 500_000_000; // 0.5 EVER - -const RPC_ENDPOINT: &str = "https://extension-api.broxus.com/rpc"; - -#[derive(clap::Parser)] -struct Args { - #[command(subcommand)] - command: SubCommand, -} - -#[derive(clap::Subcommand)] -enum SubCommand { - /// Get public key - GetPubkey { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - /// Confirm key - #[clap(long, short, action, default_value_t = false)] - confirm: bool, - }, - - /// Get address - GetAddress { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - - /// Confirm key - #[clap(long, short, action, default_value_t = false)] - confirm: bool, - }, - - /// Get balance - GetBalance { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - }, - - /// Send transaction - SendTransaction { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - - #[arg(long)] - /// Amount to send - amount: String, - - #[arg(long)] - /// Destination address - address: String, - }, - - /// Get balance - GetTokenBalance { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - - #[arg(short, long)] - /// Token name (WEVER, USDT, USDC, DAI) - token: String, - }, - - /// Send token transaction - SendTokenTransaction { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - - #[arg(long)] - /// Amount to send - amount: String, - - #[arg(long)] - /// Destination address - address: String, - - #[arg(short, long)] - /// Token name (WEVER, USDT, USDC, DAI) - token: String, - }, - - /// Deploy wallet - Deploy { - #[arg(short, long, default_value_t = 0)] - /// Number of account on Ledger - account: u32, - - #[arg(short, long, default_value_t = ("EverWallet").to_string())] - /// Wallet type - wallet: String, - }, - - /// List of Everscale Wallets - GetWallets, - - /// List of tokens - GetTokens, -} - -struct TokenDetails<'a> { - ticker: &'a str, - decimals: u8, - factor: BigDecimal, - root: MsgAddressInt, -} - -enum Token { - Usdt, - Usdc, - Dai, - Wever, -} - -impl FromStr for Token { - type Err = anyhow::Error; - - fn from_str(input: &str) -> Result { - match input { - "WEVER" => Ok(Token::Wever), - "USDT" => Ok(Token::Usdt), - "USDC" => Ok(Token::Usdc), - "DAI" => Ok(Token::Dai), - _ => anyhow::bail!("Invalid token"), - } - } -} - -impl Token { - fn details(&self) -> TokenDetails { - match *self { - Token::Wever => TokenDetails { - ticker: "WEVER", - decimals: 9, - factor: BigDecimal::from_u128(1_000_000_000).trust_me(), - root: MsgAddressInt::from_str( - "0:a49cd4e158a9a15555e624759e2e4e766d22600b7800d891e46f9291f044a93d", - ) - .trust_me(), - }, - Token::Usdt => TokenDetails { - ticker: "USDT", - decimals: 6, - factor: BigDecimal::from_u128(1_000_000).trust_me(), - root: MsgAddressInt::from_str( - "0:a519f99bb5d6d51ef958ed24d337ad75a1c770885dcd42d51d6663f9fcdacfb2", - ) - .trust_me(), - }, - Token::Usdc => TokenDetails { - ticker: "USDC", - decimals: 6, - factor: BigDecimal::from_u128(1_000_000).trust_me(), - root: MsgAddressInt::from_str( - "0:c37b3fafca5bf7d3704b081fde7df54f298736ee059bf6d32fac25f5e6085bf6", - ) - .trust_me(), - }, - Token::Dai => TokenDetails { - ticker: "DAI", - decimals: 18, - factor: BigDecimal::from_u128(1_000_000_000_000_000_000).trust_me(), - root: MsgAddressInt::from_str( - "0:eb2ccad2020d9af9cec137d3146dde067039965c13a27d97293c931dae22b2b9", - ) - .trust_me(), - }, - } - } -} - -fn get_ledger() -> (Arc, PublicKey) { - let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager"); - - // Update device list - const NO_DEVICE_HELP: &str = "No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Everscale running"; - wallet_manager.update_devices().expect(NO_DEVICE_HELP); - assert!( - !wallet_manager.list_devices().is_empty(), - "{}", - NO_DEVICE_HELP - ); - - // Fetch the device path and base pubkey of a connected ledger device - let (base_pubkey, device_path) = wallet_manager - .list_devices() - .iter() - .find(|d| d.manufacturer == Manufacturer::Ledger) - .cloned() - .map(|d| (d.pubkey, d.host_device_path)) - .expect("No ledger device detected"); - - let ledger = wallet_manager.get_ledger(&device_path).expect("get device"); - - (ledger, base_pubkey) -} - -fn prepare_wallet_v3_transfer( - pubkey: PublicKey, - amount: u64, - destination: MsgAddressInt, - contract: ExistingContract, - body: Option, -) -> anyhow::Result<(ton_types::Cell, Box)> { - let gift = Gift { - flags: 3, - bounce: true, - destination, - amount, - body, - state_init: None, - }; - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let seqno_offset = nekoton::core::ton_wallet::wallet_v3::estimate_seqno_offset( - &SimpleClock, - &contract.account, - &[], - ); - - let action = nekoton::core::ton_wallet::wallet_v3::prepare_transfer( - &SimpleClock, - &pubkey, - &contract.account, - seqno_offset, - vec![gift], - expiration, - )?; - - let unsigned_message = match action { - TransferAction::Sign(message) => message, - TransferAction::DeployFirst => { - anyhow::bail!("WalletV3 unreachable action") - } - }; - - // Sign with null signature to extract payload later - let signed_message = unsigned_message.sign(&[0_u8; 64])?; - let mut data = signed_message.message.body().trust_me(); - - // Skip null signature - data.move_by(SIGNATURE_LENGTH * 8)?; - - let payload = data.into_cell(); - - Ok((payload, unsigned_message)) -} - -fn prepare_ever_wallet_transfer( - pubkey: PublicKey, - address: MsgAddressInt, - amount: u64, - destination: MsgAddressInt, - contract: ExistingContract, - body: Option, -) -> anyhow::Result<(ton_types::Cell, Box)> { - let gift = Gift { - flags: 3, - bounce: true, - destination, - amount, - body, - state_init: None, - }; - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let action = nekoton::core::ton_wallet::ever_wallet::prepare_transfer( - &SimpleClock, - &pubkey, - &contract.account, - address, - vec![gift], - expiration, - )?; - - let unsigned_message = match action { - TransferAction::Sign(message) => message, - TransferAction::DeployFirst => { - anyhow::bail!("EverWallet unreachable action") - } - }; - - // Sign with null signature to extract payload later - let signed_message = unsigned_message.sign(&[0_u8; 64])?; - let mut data = signed_message.message.body().trust_me(); - - let first_bit = data.get_next_bit()?; - assert!(first_bit); - - // Skip null signature - data.move_by(SIGNATURE_LENGTH * 8)?; - - let payload = data.into_cell(); - - Ok((payload, unsigned_message)) -} - -fn prepare_multisig_wallet_transfer( - pubkey: PublicKey, - address: MsgAddressInt, - amount: u64, - destination: MsgAddressInt, - wallet_type: WalletType, - body: Option, -) -> anyhow::Result<(ton_types::Cell, Box)> { - let multisig_type = match wallet_type { - WalletType::SafeMultisig => MultisigType::SafeMultisigWallet, - WalletType::SafeMultisig24h => MultisigType::SafeMultisigWallet24h, - WalletType::SetcodeMultisig => MultisigType::SetcodeMultisigWallet, - WalletType::BridgeMultisig => MultisigType::BridgeMultisigWallet, - WalletType::Multisig2 => MultisigType::Multisig2, - WalletType::Multisig2_1 => MultisigType::Multisig2_1, - _ => anyhow::bail!("Invalid multisig type"), - }; - - let gift = Gift { - flags: 3, - bounce: true, - destination, - amount, - body, - state_init: None, - }; - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let action = nekoton::core::ton_wallet::multisig::prepare_transfer( - &SimpleClock, - multisig_type, - &pubkey, - false, - address, - gift, - expiration, - )?; - - let unsigned_message = match action { - TransferAction::Sign(message) => message, - TransferAction::DeployFirst => { - anyhow::bail!("EverWallet unreachable action") - } - }; - - // Sign with null signature to extract payload later - let signed_message = unsigned_message.sign(&[0_u8; 64])?; - let mut data = signed_message.message.body().trust_me(); - - let first_bit = data.get_next_bit()?; - assert!(first_bit); - - // Skip null signature - data.move_by(SIGNATURE_LENGTH * 8)?; - - let payload = data.into_cell(); - - Ok((payload, unsigned_message)) -} - -fn prepare_multisig_wallet_deploy( - pubkey: PublicKey, - wallet_type: WalletType, -) -> anyhow::Result<(ton_types::Cell, Box)> { - let multisig_type = match wallet_type { - WalletType::SafeMultisig => MultisigType::SafeMultisigWallet, - WalletType::SafeMultisig24h => MultisigType::SafeMultisigWallet24h, - WalletType::SetcodeMultisig => MultisigType::SetcodeMultisigWallet, - WalletType::BridgeMultisig => MultisigType::BridgeMultisigWallet, - WalletType::Multisig2 => MultisigType::Multisig2, - WalletType::Multisig2_1 => MultisigType::Multisig2_1, - _ => anyhow::bail!("Invalid multisig type"), - }; - - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let deploy_params = nekoton::core::ton_wallet::multisig::DeployParams { - owners: &[pubkey], - req_confirms: 1, - expiration_time: None, - }; - - let unsigned_message = nekoton::core::ton_wallet::multisig::prepare_deploy( - &SimpleClock, - &pubkey, - multisig_type, - DEFAULT_WORKCHAIN, - expiration, - deploy_params, - )?; - - // Sign with null signature to extract payload later - let signed_message = unsigned_message.sign(&[0_u8; 64])?; - let mut data = signed_message.message.body().trust_me(); - - let first_bit = data.get_next_bit()?; - assert!(first_bit); - - // Skip null signature - data.move_by(SIGNATURE_LENGTH * 8)?; - - let payload = data.into_cell(); - - Ok((payload, unsigned_message)) -} - -fn prepare_token_body( - tokens: BigUint, - owner: &MsgAddressInt, - destiantion: &MsgAddressInt, -) -> anyhow::Result { - let payload: ton_types::Cell = Default::default(); - - let (function_token, input_token) = - MessageBuilder::new(tip3_1::token_wallet_contract::transfer()) - .arg(BigUint128(tokens)) // amount - .arg(destiantion) // recipient owner wallet - .arg(BigUint128(INITIAL_BALANCE.into())) // deployWalletValue - .arg(owner) // remainingGasTo - .arg(false) // notify - .arg(payload) // payload - .build(); - - Ok(function_token.encode_internal_input(&input_token)?.into()) -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let args = Args::parse(); - - let (ledger, _) = get_ledger(); - - match args.command { - SubCommand::GetPubkey { account, confirm } => { - let pubkey = ledger.get_pubkey(account, confirm)?; - println!("Public key: 0x{}", hex::encode(pubkey.to_bytes())); - } - SubCommand::GetAddress { - account, - wallet, - confirm, - } => { - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, confirm)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - println!("Address: {}", address); - } - SubCommand::GetBalance { account, wallet } => { - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, false)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - let client = everscale_jrpc_client::JrpcClient::new( - vec![Url::parse(RPC_ENDPOINT)?], - everscale_jrpc_client::JrpcClientOptions::default(), - ) - .await?; - - let contract = client.get_contract_state(&address).await?; - match contract { - Some(contract) => { - let mut balance = - Decimal::from_u128(contract.account.storage.balance.grams.0).trust_me(); - balance.set_scale(EVER_DECIMALS as u32)?; - println!("Balance: {} EVER", balance); - } - None => { - println!("Account haven't deployed yet"); - } - } - } - SubCommand::SendTransaction { - account, - wallet, - amount, - address, - } => { - let amount = (Decimal::from_str(&amount)? * Decimal::from(1_000_000_000)) - .to_u64() - .trust_me(); - let destination = MsgAddressInt::from_str(&address)?; - - let pubkey = ledger.get_pubkey(account, false)?; - - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, false)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - let client = everscale_jrpc_client::JrpcClient::new( - vec![Url::parse(RPC_ENDPOINT)?], - everscale_jrpc_client::JrpcClientOptions::default(), - ) - .await?; - - let contract = client.get_contract_state(&address).await?; - match contract { - Some(contract) => match wallet_type { - WalletType::WalletV3 => { - let (payload, unsigned_message) = prepare_wallet_v3_transfer( - pubkey, - amount, - destination, - contract, - None, - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - &boc, - )?; - - let signed_message = - unsigned_message.sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - WalletType::EverWallet => { - let (payload, unsigned_message) = prepare_ever_wallet_transfer( - pubkey, - address.clone(), - amount, - destination, - contract, - None, - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - &boc, - )?; - - let signed_message = - unsigned_message.sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - WalletType::SafeMultisig - | WalletType::SafeMultisig24h - | WalletType::SetcodeMultisig - | WalletType::BridgeMultisig - | WalletType::Multisig2 - | WalletType::Multisig2_1 => { - if let AccountState::AccountUninit = contract.account.storage.state { - println!("Account haven't deployed yet"); - return Ok(()); - } - - let (payload, unsigned_message) = prepare_multisig_wallet_transfer( - pubkey, - address.clone(), - amount, - destination, - wallet_type, - None, - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - &boc, - )?; - - let signed_message = - unsigned_message.sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - _ => unimplemented!(), - }, - None => { - println!( - "Account state not found. You should send 1 EVER to {}", - address - ); - } - } - } - SubCommand::GetTokenBalance { - account, - wallet, - token, - } => { - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, false)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - let client = everscale_jrpc_client::JrpcClient::new( - vec![Url::parse(RPC_ENDPOINT)?], - everscale_jrpc_client::JrpcClientOptions::default(), - ) - .await?; - - let contract = client.get_contract_state(&address).await?; - match contract { - Some(_) => { - let token: Token = Token::from_str(&token)?; - let token_details = token.details(); - - let root_contract = client - .get_contract_state(&token_details.root) - .await? - .trust_me(); - - let token_address = RootTokenContractState(&root_contract).get_wallet_address( - &SimpleClock, - TokenWalletVersion::Tip3, - &address, - )?; - - let token_contract = client.get_contract_state(&token_address).await?; - match token_contract { - Some(token_contract) => { - let state = TokenWalletContractState(&token_contract); - let balance = - state.get_balance(&SimpleClock, TokenWalletVersion::Tip3)?; - - println!( - "Balance: {} {}", - BigDecimal::new( - balance.to_bigint().trust_me(), - token_details.decimals as i64 - ), - token_details.ticker - ); - } - None => { - println!("Token account haven't deployed yet"); - } - } - } - None => { - println!("Account haven't deployed yet"); - } - } - } - SubCommand::SendTokenTransaction { - account, - wallet, - amount, - address, - token, - } => { - let token: Token = Token::from_str(&token)?; - let token_details = token.details(); - - let amount = (BigDecimal::from_str(&amount)? * token_details.factor) - .with_scale(0) - .into_bigint_and_exponent() - .0 - .to_biguint() - .trust_me(); - - let destination = MsgAddressInt::from_str(&address)?; - - let pubkey = ledger.get_pubkey(account, false)?; - - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, false)?; - let owner = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - let client = everscale_jrpc_client::JrpcClient::new( - vec![Url::parse(RPC_ENDPOINT)?], - everscale_jrpc_client::JrpcClientOptions::default(), - ) - .await?; - - let owner_contract = client.get_contract_state(&owner).await?; - match owner_contract { - Some(owner_contract) => { - let root_contract = client - .get_contract_state(&token_details.root) - .await? - .trust_me(); - let owner_token = RootTokenContractState(&root_contract).get_wallet_address( - &SimpleClock, - TokenWalletVersion::Tip3, - &owner, - )?; - - let token_body = prepare_token_body(amount, &owner, &destination)?; - - match wallet_type { - WalletType::WalletV3 => { - let (payload, unsigned_message) = prepare_wallet_v3_transfer( - pubkey, - ATTACHED_AMOUNT, - owner_token, - owner_contract, - Some(token_body), - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - token_details.decimals, - token_details.ticker, - &boc, - )?; - - let signed_message = unsigned_message - .sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - WalletType::EverWallet => { - let (payload, unsigned_message) = prepare_ever_wallet_transfer( - pubkey, - owner, - ATTACHED_AMOUNT, - owner_token, - owner_contract, - Some(token_body), - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - token_details.decimals, - token_details.ticker, - &boc, - )?; - - let signed_message = unsigned_message - .sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - WalletType::SafeMultisig - | WalletType::SafeMultisig24h - | WalletType::SetcodeMultisig - | WalletType::BridgeMultisig - | WalletType::Multisig2 - | WalletType::Multisig2_1 => { - if let AccountState::AccountUninit = - owner_contract.account.storage.state - { - println!("Owner account haven't deployed yet"); - return Ok(()); - } - - let (payload, unsigned_message) = prepare_multisig_wallet_transfer( - pubkey, - owner, - ATTACHED_AMOUNT, - owner_token, - wallet_type, - Some(token_body), - )?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - token_details.decimals, - token_details.ticker, - &boc, - )?; - - let signed_message = unsigned_message - .sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - _ => unimplemented!(), - } - } - None => { - println!( - "Account state not found. You should send 1 EVER to {}", - address - ); - } - } - } - SubCommand::GetWallets => { - println!( - "WalletV3\nEverWallet\nSafeMultisig\nSafeMultisig24h\nSetcodeMultisig\nBridgeMultisig\nMultisig2\nMultisig2_1\nSurf (unimplemented)", - ); - } - SubCommand::GetTokens => { - println!("WEVER\nUSDT\nUSDC\nDAI",); - } - SubCommand::Deploy { account, wallet } => { - let pubkey = ledger.get_pubkey(account, false)?; - - let wallet_type = WalletType::from_str(&wallet).map_err(|s| anyhow::anyhow!(s))?; - - let bytes = ledger.get_address(account, wallet_type, false)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&bytes)), - )?; - - let client = everscale_jrpc_client::JrpcClient::new( - vec![Url::parse(RPC_ENDPOINT)?], - everscale_jrpc_client::JrpcClientOptions::default(), - ) - .await?; - - let contract = client.get_contract_state(&address).await?; - match contract { - Some(contract) => match wallet_type { - WalletType::WalletV3 | WalletType::EverWallet => { - println!("No need to deploy"); - } - WalletType::SafeMultisig - | WalletType::SafeMultisig24h - | WalletType::SetcodeMultisig - | WalletType::BridgeMultisig - | WalletType::Multisig2 - | WalletType::Multisig2_1 => { - if let AccountState::AccountActive { .. } = contract.account.storage.state { - println!("Account have already deployed"); - return Ok(()); - } - - let (payload, unsigned_message) = - prepare_multisig_wallet_deploy(pubkey, wallet_type)?; - - let boc = ton_types::serialize_toc(&payload)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - &boc, - )?; - - let signed_message = - unsigned_message.sign(&nekoton::crypto::Signature::from(signature))?; - - println!( - "Sending message with hash '{}'...", - signed_message.message.hash()?.to_hex_string() - ); - - let status = client - .send_message( - signed_message.message, - everscale_jrpc_client::SendOptions::default(), - ) - .await?; - - println!("Send status: {:?}", status); - } - _ => unimplemented!(), - }, - None => { - println!( - "Account state not found. You should send 1 EVER to {}", - address - ); - } - } - } - }; - - Ok(()) -} diff --git a/tests/old_to_delete/.gitignore b/tests/old_to_delete/.gitignore deleted file mode 100644 index b83d222..0000000 --- a/tests/old_to_delete/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/tests/old_to_delete/Cargo.lock b/tests/old_to_delete/Cargo.lock deleted file mode 100644 index 20f9f97..0000000 --- a/tests/old_to_delete/Cargo.lock +++ /dev/null @@ -1,2594 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anyhow" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "async-compression" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-trait" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64ct" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" - -[[package]] -name = "bigdecimal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "borsh" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" -dependencies = [ - "borsh-derive", - "hashbrown 0.11.2", -] - -[[package]] -name = "borsh-derive" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate", - "proc-macro2", - "syn", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "bytecheck" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f" -dependencies = [ - "bytecheck_derive", - "ptr_meta", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cc" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chacha20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clap" -version = "4.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2" -dependencies = [ - "bitflags", - "clap_derive", - "clap_lex", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "console" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "terminal_size", - "unicode-width", - "winapi", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "countme" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" -dependencies = [ - "byteorder", - "digest", - "rand_core", - "subtle-ng", - "zeroize", -] - -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if", - "hashbrown 0.12.3", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "dialoguer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" -dependencies = [ - "console", - "tempfile", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" - -[[package]] -name = "dyn-clone" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" - -[[package]] -name = "ed25519" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "git+https://github.com/broxus/ed25519-dalek.git#e5d68fd1490a7f6a0d473c6c1b1acef868960471" -dependencies = [ - "curve25519-dalek-ng", - "ed25519", - "rand", - "serde", - "sha2", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "everscale-jrpc-client" -version = "0.3.1" -source = "git+https://github.com/broxus/everscale-jrpc.git#1c8f32c57523384ff6351ffa5c828fa25d0e2610" -dependencies = [ - "anyhow", - "base64", - "everscale-jrpc-models", - "futures", - "hex", - "log", - "nekoton", - "nekoton-abi", - "nekoton-utils", - "parking_lot", - "rand", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", -] - -[[package]] -name = "everscale-jrpc-models" -version = "0.1.0" -source = "git+https://github.com/broxus/everscale-jrpc.git#1c8f32c57523384ff6351ffa5c828fa25d0e2610" -dependencies = [ - "nekoton-abi", - "nekoton-utils", - "serde", - "ton_block", -] - -[[package]] -name = "everscale-ledger-wallet" -version = "0.1.0" -source = "git+https://github.com/broxus/everscale-ledger-wallet.git#ca18c00428b85befb5838d40df684d484fc90981" -dependencies = [ - "anyhow", - "console", - "dialoguer", - "ed25519-dalek", - "hex", - "hidapi", - "log", - "num-derive", - "num-traits", - "parking_lot", - "qstring", - "semver", - "thiserror", - "uriparse", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "flate2" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" - -[[package]] -name = "futures-task" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" - -[[package]] -name = "futures-util" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "h2" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hidapi" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" -dependencies = [ - "cc", - "libc", - "pkg-config", - "winapi", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest", - "generic-array", - "hmac 0.8.1", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" -dependencies = [ - "libc", - "windows-sys 0.42.0", -] - -[[package]] -name = "ipnet" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys 0.42.0", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "ledger-app-everscale-tests" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64", - "bigdecimal", - "clap", - "ed25519-dalek", - "everscale-jrpc-client", - "everscale-ledger-wallet", - "hex", - "nekoton", - "nekoton-abi", - "nekoton-contracts", - "nekoton-utils", - "rust_decimal", - "tokio", - "ton_block", - "ton_types", - "url", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "libsecp256k1" -version = "0.7.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "arrayref", - "base64", - "digest", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand", - "serde", - "sha2", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "crunchy", - "digest", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lru" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" -dependencies = [ - "hashbrown 0.12.3", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memzero" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db" - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.42.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nekoton" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#06ffd9ec42f31a207ef0ed31866d99c7629fc37e" -dependencies = [ - "anyhow", - "async-trait", - "base64", - "chacha20poly1305", - "curve25519-dalek-ng", - "downcast-rs", - "dyn-clone", - "ed25519-dalek", - "futures-util", - "getrandom", - "hex", - "hmac 0.11.0", - "log", - "lru", - "nekoton-abi", - "nekoton-contracts", - "nekoton-utils", - "num-bigint", - "once_cell", - "parking_lot", - "pbkdf2", - "rand", - "secstr", - "serde", - "serde_json", - "sha2", - "thiserror", - "tiny-bip39", - "tiny-hderive", - "tokio", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", - "zeroize", -] - -[[package]] -name = "nekoton-abi" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#06ffd9ec42f31a207ef0ed31866d99c7629fc37e" -dependencies = [ - "anyhow", - "base64", - "ed25519-dalek", - "hex", - "log", - "nekoton-derive", - "nekoton-utils", - "num-bigint", - "num-traits", - "rustc-hash", - "serde", - "serde_json", - "smallvec", - "thiserror", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", - "ton_vm", -] - -[[package]] -name = "nekoton-contracts" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#06ffd9ec42f31a207ef0ed31866d99c7629fc37e" -dependencies = [ - "anyhow", - "nekoton-abi", - "once_cell", - "thiserror", - "ton_abi", - "ton_block", - "ton_types", -] - -[[package]] -name = "nekoton-derive" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#06ffd9ec42f31a207ef0ed31866d99c7629fc37e" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "nekoton-utils" -version = "0.11.0" -source = "git+https://github.com/broxus/nekoton.git#06ffd9ec42f31a207ef0ed31866d99c7629fc37e" -dependencies = [ - "anyhow", - "base64", - "chacha20poly1305", - "ed25519-dalek", - "hex", - "hmac 0.11.0", - "pbkdf2", - "secstr", - "serde", - "sha2", - "thiserror", - "ton_block", - "ton_types", - "zeroize", -] - -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" -dependencies = [ - "parking_lot_core", -] - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", -] - -[[package]] -name = "password-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" -dependencies = [ - "crypto-mac 0.11.1", - "hmac 0.11.0", - "password-hash", - "sha2", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rend" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "reqwest" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" -dependencies = [ - "async-compression", - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rkyv" -version = "0.7.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" -dependencies = [ - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rust_decimal" -version = "1.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c321ee4e17d2b7abe12b5d20c1231db708dd36185c8a21e9de5fed6da4dbe9" -dependencies = [ - "arrayvec", - "borsh", - "bytecheck", - "byteorder", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.42.0", -] - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "secstr" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04f657244f605c4cf38f6de5993e8bd050c8a303f86aeabff142d5c7c113e12" -dependencies = [ - "libc", - "serde", -] - -[[package]] -name = "security-framework" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" - -[[package]] -name = "serde" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-ng" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-bip39" -version = "0.8.0" -source = "git+https://github.com/broxus/tiny-bip39.git#d2a73124c2fbead4f969f8a5e075ee22040f63cc" -dependencies = [ - "anyhow", - "hmac 0.11.0", - "once_cell", - "pbkdf2", - "rand", - "rustc-hash", - "sha2", - "thiserror", - "unicode-normalization", - "zeroize", -] - -[[package]] -name = "tiny-hderive" -version = "0.3.0" -source = "git+https://github.com/broxus/tiny-hderive.git#050986d85711497076ba552ce53806885274a4d2" -dependencies = [ - "base58", - "hmac 0.11.0", - "libsecp256k1", - "memzero", - "sha2", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.42.0", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" -dependencies = [ - "serde", -] - -[[package]] -name = "ton_abi" -version = "2.1.0" -source = "git+https://github.com/broxus/ton-labs-abi#5429246f11bdb794910c295a5aab4318accdd894" -dependencies = [ - "anyhow", - "base64", - "byteorder", - "ed25519", - "ed25519-dalek", - "hex", - "num-bigint", - "num-traits", - "serde", - "serde_json", - "sha2", - "smallvec", - "thiserror", - "ton_block", - "ton_types", -] - -[[package]] -name = "ton_block" -version = "1.7.14" -source = "git+https://github.com/broxus/ton-labs-block#bf7a53587cc98da4b51b58f3c4160e8f85985159" -dependencies = [ - "anyhow", - "base64", - "crc", - "ed25519", - "ed25519-dalek", - "hex", - "log", - "num", - "num-traits", - "rand", - "rustc-hash", - "sha2", - "smallvec", - "thiserror", - "ton_types", -] - -[[package]] -name = "ton_executor" -version = "1.15.54" -source = "git+https://github.com/broxus/ton-labs-executor#d8e8fed291948ff66e9d1f6d8f44f37f1cf0de6f" -dependencies = [ - "anyhow", - "log", - "thiserror", - "ton_block", - "ton_types", - "ton_vm", -] - -[[package]] -name = "ton_types" -version = "1.10.2" -source = "git+https://github.com/broxus/ton-labs-types#dea1147b9fa25153e20dc79d9f0141f325f3921a" -dependencies = [ - "anyhow", - "base64", - "countme", - "crc", - "dashmap", - "hex", - "log", - "num", - "num-derive", - "num-traits", - "rand", - "rustc-hash", - "sha2", - "smallvec", - "thiserror", -] - -[[package]] -name = "ton_vm" -version = "1.8.29" -source = "git+https://github.com/broxus/ton-labs-vm.git#72059801850016bad0a2b909600a043e0694feda" -dependencies = [ - "anyhow", - "ed25519", - "ed25519-dalek", - "hex", - "lazy_static", - "log", - "num", - "num-traits", - "rand", - "sha2", - "smallvec", - "thiserror", - "ton_block", - "ton_types", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "uriparse" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" -dependencies = [ - "fnv", - "lazy_static", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/tests/old_to_delete/Cargo.toml b/tests/old_to_delete/Cargo.toml deleted file mode 100644 index 00dda06..0000000 --- a/tests/old_to_delete/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "ledger-app-everscale-tests" -version = "0.1.0" -edition = "2021" -description = "Ledger-app integration tests using Everscale tools" -authors = ["Broxus team"] - -[dependencies] -anyhow = "1.0" -base64 = "0.13" -bigdecimal = "0.3.0" -clap = { version = "4.0.18", features = ["derive"] } -hex = "0.4.3" -rust_decimal = "1" -tokio = { version = "1.21.2", features = ["sync", "rt-multi-thread", "macros"] } -url = { version = "2.3.1" } - -# Basic types -ed25519-dalek = { git = "https://github.com/broxus/ed25519-dalek.git" } -ton_block = { git = "https://github.com/broxus/ton-labs-block" } -ton_types = { git = "https://github.com/broxus/ton-labs-types" } - -# JRPC client -everscale-jrpc-client = { git = "https://github.com/broxus/everscale-jrpc.git" } - -# Ledger wallet -everscale-ledger-wallet = { git = "https://github.com/broxus/everscale-ledger-wallet.git" } - -# Nekoton SDK -nekoton = { git = "https://github.com/broxus/nekoton.git", default-features = false } -nekoton-abi = { git = "https://github.com/broxus/nekoton.git" } -nekoton-utils = { git = "https://github.com/broxus/nekoton.git" } -nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" } diff --git a/tests/old_to_delete/src/main.rs b/tests/old_to_delete/src/main.rs deleted file mode 100644 index 27f0f49..0000000 --- a/tests/old_to_delete/src/main.rs +++ /dev/null @@ -1,278 +0,0 @@ -use std::borrow::Cow; -use std::str::FromStr; -use std::sync::Arc; - -use ed25519_dalek::{PublicKey, Verifier, SIGNATURE_LENGTH}; - -use everscale_ledger_wallet::ledger::{LedgerWallet, WalletType}; -use everscale_ledger_wallet::locator::Manufacturer; -use everscale_ledger_wallet::remote_wallet::{initialize_wallet_manager, RemoteWallet}; -use nekoton::core::models::Expiration; -use nekoton::core::ton_wallet::wallet_v3::InitData; -use nekoton::core::ton_wallet::Gift; -use nekoton::core::utils::make_labs_unsigned_message; -use nekoton::crypto::Signature; -use nekoton_abi::{BigUint128, MessageBuilder}; -use nekoton_utils::{SimpleClock, TrustMe}; -use ton_block::MsgAddressInt; -use ton_types::{AccountId, UInt256}; - -const EVER_DECIMALS: u8 = 9; -const EVER_TICKER: &str = "EVER"; - -const WALLET_ID: u32 = 0x4BA92D8A; - -const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec - -fn get_ledger() -> (Arc, PublicKey) { - let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager"); - - // Update device list - const NO_DEVICE_HELP: &str = "No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Everscale running"; - wallet_manager.update_devices().expect(NO_DEVICE_HELP); - assert!( - !wallet_manager.list_devices().is_empty(), - "{}", - NO_DEVICE_HELP - ); - - // Fetch the device path and base pubkey of a connected ledger device - let (base_pubkey, device_path) = wallet_manager - .list_devices() - .iter() - .find(|d| d.manufacturer == Manufacturer::Ledger) - .cloned() - .map(|d| (d.pubkey, d.host_device_path)) - .expect("No ledger device detected"); - - let ledger = wallet_manager.get_ledger(&device_path).expect("get device"); - - (ledger, base_pubkey) -} - -fn test_ledger_pubkey() -> anyhow::Result<()> { - let (ledger, _) = get_ledger(); - - let pubkey = ledger.get_pubkey(0, false)?; - assert_eq!( - hex::encode(pubkey.as_bytes()), - "6775b6a6ba3711a1c9ac1a62cacf62890ad1df5fbe4308dd9a17405c75b57f2e" - ); - - let pubkey = ledger.get_pubkey(1, false)?; - assert_eq!( - hex::encode(pubkey.as_bytes()), - "874dbbeb87f22f7c687cf5bfc33dc103d78c4a9c1e63dde53869202458ca7009" - ); - - let pubkey = ledger.get_pubkey(2, false)?; - assert_eq!( - hex::encode(pubkey.as_bytes()), - "3ca0c86c268d5e27f80e234cb66dc811afcd277f5882c3208466e1f3c9395b87" - ); - - Ok(()) -} - -fn test_ledger_address() -> anyhow::Result<()> { - let (ledger, _) = get_ledger(); - - let wallet_v3 = ledger.get_address(0, WalletType::WalletV3, false)?; - assert_eq!( - hex::encode(&wallet_v3), - "ed7439e12d67d23fcaf701ff3bd4e30d390c1e8e14f6f40d52089590e28d9c70" - ); - - let ever_wallet = ledger.get_address(0, WalletType::EverWallet, false)?; - assert_eq!( - hex::encode(&ever_wallet), - "3b94dd326f32f5ab14caef0a61d23e716271b20d7e273fc315ea3cfd0023c431" - ); - - let safe_multisig = ledger.get_address(0, WalletType::SafeMultisig, false)?; - assert_eq!( - hex::encode(&safe_multisig), - "aafa193fdf6c11cd20a0831ae2a33f7ff4a5add95db7b7b30e7ceef6538e2621" - ); - - let safe_multisig_24 = ledger.get_address(0, WalletType::SafeMultisig24h, false)?; - assert_eq!( - hex::encode(&safe_multisig_24), - "b4f9941d96904c22613581a4d905051f37ef41c5c0b995a60d5ebfc254e57a1a" - ); - - let setcode_multisig = ledger.get_address(0, WalletType::SetcodeMultisig, false)?; - assert_eq!( - hex::encode(&setcode_multisig), - "7c75e3bff88ec399edc5ee3a31189ccff6fd564ad2708f3e7208d5c899077f9a" - ); - - let bridge_multisig = ledger.get_address(0, WalletType::BridgeMultisig, false)?; - assert_eq!( - hex::encode(&bridge_multisig), - "95daf2ffc6c780ca4d4ef63495cf86f8a5f011d3e9fa10edb462ecdc64275136" - ); - - let surf = ledger.get_address(0, WalletType::Surf, false)?; - assert_eq!( - hex::encode(&surf), - "a1297485df8e1608109ef009b02fab5668d16b6eec7f8c763bd4ec6474be40c5" - ); - - let multisig2 = ledger.get_address(0, WalletType::Multisig2, false)?; - assert_eq!( - hex::encode(&multisig2), - "2bb06296f9c0be8d4290517d33018ea903b5de40504192953bf631f2e8b56b0b" - ); - - let multisig2_1 = ledger.get_address(0, WalletType::Multisig2_1, false)?; - assert_eq!( - hex::encode(&multisig2_1), - "bcac3b0b6d2b65b29b18c48b72f76eed1d8dfc86b462086e2731948f1a2550b8" - ); - - Ok(()) -} - -// This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_message() -> anyhow::Result<()> { - let (ledger, _) = get_ledger(); - - let account = 0; - - // Get public key - let public_key = ledger.get_pubkey(account, false)?; - - // Transfer parameters - let flags = 3; - let bounce = true; - let amount = 123_456_785_012_345_678; - let destination = MsgAddressInt::from_str( - "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56", - )?; - - let gift = Gift { - flags, - bounce, - destination, - amount, - body: None, - state_init: None, - }; - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let init_data = InitData::from_key(&public_key).with_wallet_id(WALLET_ID); - let (hash, _) = - init_data.make_transfer_payload(vec![gift], expiration.timestamp(&SimpleClock))?; - - let signature = ledger.sign_message_hash(account, hash.as_slice())?; - assert!(public_key.verify(hash.as_slice(), &signature).is_ok()); - - Ok(()) -} - -// This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_transaction() -> anyhow::Result<()> { - let (ledger, _) = get_ledger(); - - let account = 0; - let wallet_type = WalletType::EverWallet; - - // Get public key - let public_key = ledger.get_pubkey(account, false)?; - - // Get address - let address_bytes = ledger.get_address(account, wallet_type, false)?; - let address = MsgAddressInt::with_standart( - None, - ton_block::BASE_WORKCHAIN_ID as i8, - AccountId::from(UInt256::from_be_bytes(&address_bytes)), - )?; - - // Prepare message - let message = ton_block::Message::with_ext_in_header(ton_block::ExternalInboundMessageHeader { - dst: address, - ..Default::default() - }); - - // Transfer parameters - let flags: u8 = 3; - let bounce = true; - let amount: u64 = 123_456_785_012_345_678; - let destination = MsgAddressInt::from_str( - "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56", - )?; - let body: ton_types::Cell = ton_types::deserialize_tree_of_cells(&mut base64::decode("te6ccgECBwEAAUwAAYtz4iFDAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAQFDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAIBi3PiIUMAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABADAUOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAGLc+IhQwAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAUBQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgGAAA=")?.as_slice())?; - - let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); - - let (function, input) = - MessageBuilder::new(nekoton_contracts::wallets::ever_wallet::send_transaction()) - .arg(destination) - .arg(BigUint128(amount.into())) - .arg(bounce) - .arg(flags) - .arg(body) - .build(); - - // Create unsigned message - let unsigned_message = make_labs_unsigned_message( - &SimpleClock, - message, - expiration, - &public_key, - Cow::Borrowed(function), - input, - )?; - let message_hash = unsigned_message.hash(); - - // Fake sign - let signature: Signature = [0_u8; 64]; - let signed = unsigned_message.sign_with_pruned_payload(&signature, 2)?; - - // Extract message body - let mut data = signed.message.body().trust_me(); - - let bit = data.get_next_bit()?; - assert!(bit); - - // Strip empty signature - data.move_by(SIGNATURE_LENGTH * 8)?; - - let cell = data.into_cell(); - let boc = ton_types::serialize_toc(&cell)?; - - let signature = ledger.sign_transaction( - account, - wallet_type, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - &boc, - )?; - assert!(public_key.verify(message_hash, &signature).is_ok()); - - Ok(()) -} - -fn main() { - if let Err(e) = do_run_tests() { - Err(e).unwrap() - } -} - -macro_rules! run { - ($test:ident) => { - println!(" >>> Running {} <<<", stringify!($test)); - $test()?; - }; -} - -fn do_run_tests() -> anyhow::Result<()> { - run!(test_ledger_pubkey); - run!(test_ledger_address); - run!(test_ledger_sign_message); - run!(test_ledger_sign_transaction); - - Ok(()) -} From 83d597ccd841b00c1e1d091c61eaeed2abc0303c Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 17:59:54 +0100 Subject: [PATCH 24/33] chore: correct a typo in the Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 85b9957..feea26b 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ APPVERSION_P = 9 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ########################### -# Set Chain environnement # +# Set Chain environement # ########################### ifeq ($(CHAIN),) From 6531a7e18351fcb3149b25e42246c7740dc35024 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 18:00:04 +0100 Subject: [PATCH 25/33] chore: comment out entire Everscale transaction class --- .../everscale_transaction.py | 366 +++++++++--------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/tests/application_client/everscale_transaction.py b/tests/application_client/everscale_transaction.py index 5094dfc..e82d4ec 100644 --- a/tests/application_client/everscale_transaction.py +++ b/tests/application_client/everscale_transaction.py @@ -1,188 +1,188 @@ -from application_client.everscale_command_sender import WalletType - -class Transaction: - ADDRESS_LENGTH = 32 - CHAIN_ID_LENGTH = 4 - - FLAG_WITH_WALLET_ID = 0x01 - FLAG_WITH_WORKCHAIN_ID = 0x02 - FLAG_WITH_ADDRESS = 0x04 - FLAG_WITH_CHAIN_ID = 0x08 - - def __init__(self, - decimals: int, - ticker: str, - message: bytes, - current_wallet_type: WalletType, - workchain_id: int | None = None, - prepend_address: bytes | None = None, - chain_id: bytes | None = None) -> None: - """ - Construct a Transaction. +# from application_client.everscale_command_sender import WalletType + +# class Transaction: +# ADDRESS_LENGTH = 32 +# CHAIN_ID_LENGTH = 4 + +# FLAG_WITH_WALLET_ID = 0x01 +# FLAG_WITH_WORKCHAIN_ID = 0x02 +# FLAG_WITH_ADDRESS = 0x04 +# FLAG_WITH_CHAIN_ID = 0x08 + +# def __init__(self, +# decimals: int, +# ticker: str, +# message: bytes, +# current_wallet_type: WalletType, +# workchain_id: int | None = None, +# prepend_address: bytes | None = None, +# chain_id: bytes | None = None) -> None: +# """ +# Construct a Transaction. - The metadata byte is deduced as follows: - - FLAG_WITH_WALLET_ID is set if a current_wallet_type is provided and - it differs from the origin_wallet_type. - - FLAG_WITH_WORKCHAIN_ID is set if workchain_id is provided. - - FLAG_WITH_ADDRESS is set if prepend_address is provided. - - FLAG_WITH_CHAIN_ID is set if chain_id is provided. +# The metadata byte is deduced as follows: +# - FLAG_WITH_WALLET_ID is set if a current_wallet_type is provided and +# it differs from the origin_wallet_type. +# - FLAG_WITH_WORKCHAIN_ID is set if workchain_id is provided. +# - FLAG_WITH_ADDRESS is set if prepend_address is provided. +# - FLAG_WITH_CHAIN_ID is set if chain_id is provided. - If current_wallet_type is None or equals origin_wallet_type, then that field is omitted - and on deserialization the origin_wallet_type will be used. - """ - self.decimals = decimals - self.ticker = ticker - self.message = message - self.workchain_id = workchain_id - self.prepend_address = prepend_address - self.chain_id = chain_id - - # Deduce metadata flags based on optional inputs. - metadata = 0 - if current_wallet_type is not None: - metadata |= self.FLAG_WITH_WALLET_ID - self.current_wallet_type = current_wallet_type - else: - # Do not include the field; on the device, it will be set to origin_wallet_type. - self.current_wallet_type = None - - if workchain_id is not None: - metadata |= self.FLAG_WITH_WORKCHAIN_ID - - if prepend_address is not None: - if len(prepend_address) != self.ADDRESS_LENGTH: - raise ValueError(f"prepend_address must be {self.ADDRESS_LENGTH} bytes") - metadata |= self.FLAG_WITH_ADDRESS - - if chain_id is not None: - if len(chain_id) != self.CHAIN_ID_LENGTH: - raise ValueError(f"chain_id must be {self.CHAIN_ID_LENGTH} bytes") - metadata |= self.FLAG_WITH_CHAIN_ID - - self.metadata = metadata - - # Nice-to-haves: check ticker length constraints. - ticker_len = len(ticker) - if ticker_len == 0 or ticker_len > 10: - raise ValueError("Ticker length must be between 1 and 10 bytes.") - - def serialize(self) -> bytes: - """ - Serialize the transaction into a byte-buffer with the following structure: +# If current_wallet_type is None or equals origin_wallet_type, then that field is omitted +# and on deserialization the origin_wallet_type will be used. +# """ +# self.decimals = decimals +# self.ticker = ticker +# self.message = message +# self.workchain_id = workchain_id +# self.prepend_address = prepend_address +# self.chain_id = chain_id + +# # Deduce metadata flags based on optional inputs. +# metadata = 0 +# if current_wallet_type is not None: +# metadata |= self.FLAG_WITH_WALLET_ID +# self.current_wallet_type = current_wallet_type +# else: +# # Do not include the field; on the device, it will be set to origin_wallet_type. +# self.current_wallet_type = None + +# if workchain_id is not None: +# metadata |= self.FLAG_WITH_WORKCHAIN_ID + +# if prepend_address is not None: +# if len(prepend_address) != self.ADDRESS_LENGTH: +# raise ValueError(f"prepend_address must be {self.ADDRESS_LENGTH} bytes") +# metadata |= self.FLAG_WITH_ADDRESS + +# if chain_id is not None: +# if len(chain_id) != self.CHAIN_ID_LENGTH: +# raise ValueError(f"chain_id must be {self.CHAIN_ID_LENGTH} bytes") +# metadata |= self.FLAG_WITH_CHAIN_ID + +# self.metadata = metadata + +# # Nice-to-haves: check ticker length constraints. +# ticker_len = len(ticker) +# if ticker_len == 0 or ticker_len > 10: +# raise ValueError("Ticker length must be between 1 and 10 bytes.") + +# def serialize(self) -> bytes: +# """ +# Serialize the transaction into a byte-buffer with the following structure: - [decimals:1] [ticker_length:1] [ticker:N] [metadata:1] - [optional fields (if flagged)...] [message:remaining bytes] - """ - result = bytearray() - # 1. Decimals (1 byte) - result.append(self.decimals) - - # 2. Ticker: length (1 byte) followed by its ASCII bytes - ticker_bytes = self.ticker.encode("ascii") - ticker_len = len(ticker_bytes) - result.append(ticker_len) - result.extend(ticker_bytes) - - # 3. Metadata (1 byte; deduced from optional parameters) - result.append(self.metadata) - - # 4. Conditionally append optional fields based on metadata flags. - if self.metadata & self.FLAG_WITH_WALLET_ID: - # current_wallet_type is provided and differs from origin_wallet_type. - result.append(self.current_wallet_type) - # Workchain id. - if self.metadata & self.FLAG_WITH_WORKCHAIN_ID: - result.append(self.workchain_id) - # Prepend address. - if self.metadata & self.FLAG_WITH_ADDRESS: - result.extend(self.prepend_address) - # Chain id. - if self.metadata & self.FLAG_WITH_CHAIN_ID: - result.extend(self.chain_id) - - # 5. Append the message (payload). - result.extend(self.message) - - return bytes(result) - - @classmethod - def from_bytes(cls, data: bytes) -> "Transaction": - """ - Deserialize a byte-buffer into a Transaction object. +# [decimals:1] [ticker_length:1] [ticker:N] [metadata:1] +# [optional fields (if flagged)...] [message:remaining bytes] +# """ +# result = bytearray() +# # 1. Decimals (1 byte) +# result.append(self.decimals) + +# # 2. Ticker: length (1 byte) followed by its ASCII bytes +# ticker_bytes = self.ticker.encode("ascii") +# ticker_len = len(ticker_bytes) +# result.append(ticker_len) +# result.extend(ticker_bytes) + +# # 3. Metadata (1 byte; deduced from optional parameters) +# result.append(self.metadata) + +# # 4. Conditionally append optional fields based on metadata flags. +# if self.metadata & self.FLAG_WITH_WALLET_ID: +# # current_wallet_type is provided and differs from origin_wallet_type. +# result.append(self.current_wallet_type) +# # Workchain id. +# if self.metadata & self.FLAG_WITH_WORKCHAIN_ID: +# result.append(self.workchain_id) +# # Prepend address. +# if self.metadata & self.FLAG_WITH_ADDRESS: +# result.extend(self.prepend_address) +# # Chain id. +# if self.metadata & self.FLAG_WITH_CHAIN_ID: +# result.extend(self.chain_id) + +# # 5. Append the message (payload). +# result.extend(self.message) + +# return bytes(result) + +# @classmethod +# def from_bytes(cls, data: bytes) -> "Transaction": +# """ +# Deserialize a byte-buffer into a Transaction object. - The parsing order in the buffer is: - decimals (1 byte) -> - ticker_length (1 byte) -> - ticker -> - metadata (1 byte) -> - [optional fields... based on metadata] -> - message (remaining bytes) +# The parsing order in the buffer is: +# decimals (1 byte) -> +# ticker_length (1 byte) -> +# ticker -> +# metadata (1 byte) -> +# [optional fields... based on metadata] -> +# message (remaining bytes) - If the metadata does NOT include FLAG_WITH_WALLET_ID, then current_wallet_type - defaults to origin_wallet_type. - """ - offset = 0 - - # Read decimals (1 byte) - if len(data) < offset + 1: - raise ValueError("Data too short for decimals") - decimals = data[offset] - offset += 1 - - # Read ticker: first its length (1 byte) then the ticker string - if len(data) < offset + 1: - raise ValueError("Data too short for ticker length") - ticker_len = data[offset] - offset += 1 - if len(data) < offset + ticker_len: - raise ValueError("Data too short for ticker") - ticker = data[offset:offset+ticker_len].decode("ascii") - offset += ticker_len - - # Read metadata (1 byte) - if len(data) < offset + 1: - raise ValueError("Data too short for metadata") - metadata = data[offset] - offset += 1 - - # Read optional fields based on metadata flags. - current_wallet_type = None - if metadata & cls.FLAG_WITH_WALLET_ID: - if len(data) < offset + 1: - raise ValueError("Data too short for current_wallet_type") - current_wallet_type = data[offset] - offset += 1 - - workchain_id = None - if metadata & cls.FLAG_WITH_WORKCHAIN_ID: - if len(data) < offset + 1: - raise ValueError("Data too short for workchain_id") - workchain_id = data[offset] - offset += 1 - - prepend_address = None - if metadata & cls.FLAG_WITH_ADDRESS: - if len(data) < offset + cls.ADDRESS_LENGTH: - raise ValueError("Data too short for prepend_address") - prepend_address = data[offset:offset+cls.ADDRESS_LENGTH] - offset += cls.ADDRESS_LENGTH - - chain_id = None - if metadata & cls.FLAG_WITH_CHAIN_ID: - if len(data) < offset + cls.CHAIN_ID_LENGTH: - raise ValueError("Data too short for chain_id") - chain_id = data[offset:offset+cls.CHAIN_ID_LENGTH] - offset += cls.CHAIN_ID_LENGTH - - # The remaining bytes are the message. - message = data[offset:] - - return cls( - decimals=decimals, - ticker=ticker, - message=message, - current_wallet_type=current_wallet_type, - workchain_id=workchain_id, - prepend_address=prepend_address, - chain_id=chain_id - ) \ No newline at end of file +# If the metadata does NOT include FLAG_WITH_WALLET_ID, then current_wallet_type +# defaults to origin_wallet_type. +# """ +# offset = 0 + +# # Read decimals (1 byte) +# if len(data) < offset + 1: +# raise ValueError("Data too short for decimals") +# decimals = data[offset] +# offset += 1 + +# # Read ticker: first its length (1 byte) then the ticker string +# if len(data) < offset + 1: +# raise ValueError("Data too short for ticker length") +# ticker_len = data[offset] +# offset += 1 +# if len(data) < offset + ticker_len: +# raise ValueError("Data too short for ticker") +# ticker = data[offset:offset+ticker_len].decode("ascii") +# offset += ticker_len + +# # Read metadata (1 byte) +# if len(data) < offset + 1: +# raise ValueError("Data too short for metadata") +# metadata = data[offset] +# offset += 1 + +# # Read optional fields based on metadata flags. +# current_wallet_type = None +# if metadata & cls.FLAG_WITH_WALLET_ID: +# if len(data) < offset + 1: +# raise ValueError("Data too short for current_wallet_type") +# current_wallet_type = data[offset] +# offset += 1 + +# workchain_id = None +# if metadata & cls.FLAG_WITH_WORKCHAIN_ID: +# if len(data) < offset + 1: +# raise ValueError("Data too short for workchain_id") +# workchain_id = data[offset] +# offset += 1 + +# prepend_address = None +# if metadata & cls.FLAG_WITH_ADDRESS: +# if len(data) < offset + cls.ADDRESS_LENGTH: +# raise ValueError("Data too short for prepend_address") +# prepend_address = data[offset:offset+cls.ADDRESS_LENGTH] +# offset += cls.ADDRESS_LENGTH + +# chain_id = None +# if metadata & cls.FLAG_WITH_CHAIN_ID: +# if len(data) < offset + cls.CHAIN_ID_LENGTH: +# raise ValueError("Data too short for chain_id") +# chain_id = data[offset:offset+cls.CHAIN_ID_LENGTH] +# offset += cls.CHAIN_ID_LENGTH + +# # The remaining bytes are the message. +# message = data[offset:] + +# return cls( +# decimals=decimals, +# ticker=ticker, +# message=message, +# current_wallet_type=current_wallet_type, +# workchain_id=workchain_id, +# prepend_address=prepend_address, +# chain_id=chain_id +# ) \ No newline at end of file From cc4100158dad10c6fae810cc37245a112271f0ec Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 18:02:19 +0100 Subject: [PATCH 26/33] chore: fix typo in Makefile comment --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index feea26b..7221b4a 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ APPVERSION_P = 9 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ########################### -# Set Chain environement # +# Set Chain environment # ########################### ifeq ($(CHAIN),) From fd0a4161b937f579b66b9bf28811f3ab9ac27f9c Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 18:04:46 +0100 Subject: [PATCH 27/33] refactor: remove unused get_app_name method from Everscale command sender --- tests/application_client/everscale_command_sender.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py index 54484e5..b774bb6 100644 --- a/tests/application_client/everscale_command_sender.py +++ b/tests/application_client/everscale_command_sender.py @@ -3,8 +3,6 @@ from contextlib import contextmanager from ragger.backend.interface import BackendInterface, RAPDU -from ragger.bip import pack_derivation_path - MAX_APDU_LEN: int = 255 @@ -108,11 +106,6 @@ def get_app_config(self) -> RAPDU: data=b"", ) - def get_app_name(self) -> RAPDU: - return self.backend.exchange( - cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_LAST, data=b"" - ) - def get_public_key(self, account_number: int) -> RAPDU: return self.backend.exchange( cla=CLA, From f16c8a84207d53478e8f5d4531b786da76106432 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 12 Feb 2025 18:05:18 +0100 Subject: [PATCH 28/33] style: format commented Everscale transaction class code --- .../application_client/everscale_transaction.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/application_client/everscale_transaction.py b/tests/application_client/everscale_transaction.py index e82d4ec..31aa1d7 100644 --- a/tests/application_client/everscale_transaction.py +++ b/tests/application_client/everscale_transaction.py @@ -10,7 +10,7 @@ # FLAG_WITH_CHAIN_ID = 0x08 # def __init__(self, -# decimals: int, +# decimals: int, # ticker: str, # message: bytes, # current_wallet_type: WalletType, @@ -19,14 +19,14 @@ # chain_id: bytes | None = None) -> None: # """ # Construct a Transaction. - + # The metadata byte is deduced as follows: # - FLAG_WITH_WALLET_ID is set if a current_wallet_type is provided and # it differs from the origin_wallet_type. # - FLAG_WITH_WORKCHAIN_ID is set if workchain_id is provided. # - FLAG_WITH_ADDRESS is set if prepend_address is provided. # - FLAG_WITH_CHAIN_ID is set if chain_id is provided. - + # If current_wallet_type is None or equals origin_wallet_type, then that field is omitted # and on deserialization the origin_wallet_type will be used. # """ @@ -69,8 +69,8 @@ # def serialize(self) -> bytes: # """ # Serialize the transaction into a byte-buffer with the following structure: - -# [decimals:1] [ticker_length:1] [ticker:N] [metadata:1] + +# [decimals:1] [ticker_length:1] [ticker:N] [metadata:1] # [optional fields (if flagged)...] [message:remaining bytes] # """ # result = bytearray() @@ -109,7 +109,7 @@ # def from_bytes(cls, data: bytes) -> "Transaction": # """ # Deserialize a byte-buffer into a Transaction object. - + # The parsing order in the buffer is: # decimals (1 byte) -> # ticker_length (1 byte) -> @@ -117,7 +117,7 @@ # metadata (1 byte) -> # [optional fields... based on metadata] -> # message (remaining bytes) - + # If the metadata does NOT include FLAG_WITH_WALLET_ID, then current_wallet_type # defaults to origin_wallet_type. # """ @@ -185,4 +185,4 @@ # workchain_id=workchain_id, # prepend_address=prepend_address, # chain_id=chain_id -# ) \ No newline at end of file +# ) From d3d9a74a8ccef2d606e94f110e690550e00d04bd Mon Sep 17 00:00:00 2001 From: Meg4me Date: Thu, 13 Feb 2025 09:42:10 +0100 Subject: [PATCH 29/33] ops: remove useless GitHub CI workflow --- .github/workflows/ci.yml | 53 ---------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 30ba6e0..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: CI - -on: - # Triggers the workflow on push or pull request events but only for the master branch - push: - branches: [ master, develop ] - pull_request: - branches: [ master, develop ] - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - nano-build: - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest - strategy: - matrix: - sdk: - - path: $NANOS_SDK - name: nanos - - path: $NANOX_SDK - name: nanox - - path: $NANOSP_SDK - name: nanosp - steps: - - uses: actions/checkout@v2 - - name: Build application for SDK ${{ matrix.sdk.name }} - run: | - make clean - make BOLOS_SDK=${{ matrix.sdk.path }} - - name: Upload app binary - uses: actions/upload-artifact@v2 - with: - name: app - path: bin - - scan-build: - name: Clang Static Analyzer - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest - steps: - - uses: actions/checkout@v2 - - name: Build with Clang Static Analyzer - run: | - make clean - scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default - - uses: actions/upload-artifact@v2 - if: failure() - with: - name: scan-build - path: scan-build From 13b84c0b717e41436440c5d4a635d420ede6703e Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 13 Feb 2025 11:49:19 +0100 Subject: [PATCH 30/33] ops: update CodeQL workflow to reduce SDK matrix --- .github/workflows/codeql_checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml index cc2aae4..a0c4c5b 100644 --- a/.github/workflows/codeql_checks.yml +++ b/.github/workflows/codeql_checks.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: ["$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK"] + sdk: ["$NANOX_SDK", "$NANOSP_SDK"] # 'cpp' covers C and C++ language: ['cpp'] runs-on: ubuntu-latest From 957eec29a0af57286d0dcae5f5551c38d771217e Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 13 Feb 2025 11:50:12 +0100 Subject: [PATCH 31/33] style: add .clang-format and format the code accordingly --- .clang-format | 18 + src/byte_stream.c | 65 ++- src/cell.c | 231 +++++---- src/contract.c | 676 +++++++++++++------------- src/get_address.c | 83 ++-- src/get_app_configuration.c | 26 +- src/get_public_key.c | 71 +-- src/hashmap_label.c | 128 +++-- src/main.c | 507 +++++++++---------- src/menu.c | 23 +- src/message.c | 940 ++++++++++++++++++------------------ src/sign.c | 147 +++--- src/sign_transaction.c | 322 ++++++------ src/slice_data.c | 287 ++++++----- src/utils.c | 302 ++++++------ 15 files changed, 1987 insertions(+), 1839 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d65f1ce --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +--- +BasedOnStyle: Google +IndentWidth: 4 +Language: Cpp +ColumnLimit: 100 +PointerAlignment: Right +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AllowAllParametersOfDeclarationOnNextLine: false +SortIncludes: false +SpaceAfterCStyleCast: true +AllowShortCaseLabelsOnASingleLine: false +AllowAllArgumentsOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: None +BinPackArguments: false +BinPackParameters: false +--- diff --git a/src/byte_stream.c b/src/byte_stream.c index 7d785ff..84dd866 100644 --- a/src/byte_stream.c +++ b/src/byte_stream.c @@ -2,59 +2,58 @@ #include "errors.h" #include "utils.h" -void ByteStream_init(struct ByteStream_t *self, uint8_t *data, - uint16_t data_size) { - VALIDATE(self && data && data_size, ERR_INVALID_DATA); - self->data_size = data_size; - self->offset = 0; - self->data = data; +void ByteStream_init(struct ByteStream_t *self, uint8_t *data, uint16_t data_size) { + VALIDATE(self && data && data_size, ERR_INVALID_DATA); + self->data_size = data_size; + self->offset = 0; + self->data = data; } void ByteStream_move_by(struct ByteStream_t *self, uint16_t data_size) { - VALIDATE(data_size <= self->data_size - self->offset, ERR_END_OF_STREAM); - self->offset += data_size; + VALIDATE(data_size <= self->data_size - self->offset, ERR_END_OF_STREAM); + self->offset += data_size; } uint8_t *ByteStream_read_data(struct ByteStream_t *self, uint32_t data_size) { - uint8_t *data = self->data + self->offset; - ByteStream_move_by(self, data_size); - return data; + uint8_t *data = self->data + self->offset; + ByteStream_move_by(self, data_size); + return data; } uint8_t ByteStream_read_byte(struct ByteStream_t *self) { - uint8_t byte = self->data[self->offset]; - ByteStream_move_by(self, 1); - return byte; + uint8_t byte = self->data[self->offset]; + ByteStream_move_by(self, 1); + return byte; } uint32_t ByteStream_read_u32(struct ByteStream_t *self) { - uint32_t u32 = readUint32BE(self->data + self->offset); - ByteStream_move_by(self, sizeof(uint32_t)); - return u32; + uint32_t u32 = readUint32BE(self->data + self->offset); + ByteStream_move_by(self, sizeof(uint32_t)); + return u32; } uint8_t *ByteStream_get_cursor(struct ByteStream_t *self) { - return self->data + self->offset; + return self->data + self->offset; } uint64_t ByteStream_read_uint(struct ByteStream_t *self, uint16_t bytes) { - VALIDATE(bytes > 0 && bytes <= 8, ERR_INVALID_DATA); + VALIDATE(bytes > 0 && bytes <= 8, ERR_INVALID_DATA); - uint64_t val; + uint64_t val; - if (bytes == 1) { - val = self->data[self->offset]; - } else if (bytes == 2) { - val = readUint16BE(self->data + self->offset); - } else if (bytes >= 3 && bytes <= 4) { - val = readUint32BE(self->data + self->offset); - } else if (bytes >= 5 && bytes <= 8) { - val = readUint64BE(self->data + self->offset); - } else { - THROW(ERR_INVALID_DATA); - } + if (bytes == 1) { + val = self->data[self->offset]; + } else if (bytes == 2) { + val = readUint16BE(self->data + self->offset); + } else if (bytes >= 3 && bytes <= 4) { + val = readUint32BE(self->data + self->offset); + } else if (bytes >= 5 && bytes <= 8) { + val = readUint64BE(self->data + self->offset); + } else { + THROW(ERR_INVALID_DATA); + } - ByteStream_move_by(self, bytes); + ByteStream_move_by(self, bytes); - return val; + return val; } diff --git a/src/cell.c b/src/cell.c index aa20ac0..b3fde9c 100644 --- a/src/cell.c +++ b/src/cell.c @@ -2,147 +2,146 @@ #include "utils.h" void Cell_init(struct Cell_t *self, uint8_t *cell_begin) { - VALIDATE(self && cell_begin, ERR_CELL_IS_EMPTY); - self->cell_begin = cell_begin; + VALIDATE(self && cell_begin, ERR_CELL_IS_EMPTY); + self->cell_begin = cell_begin; } uint8_t Cell_get_d1(const struct Cell_t *self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin[0]; + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin[0]; } uint8_t Cell_get_d2(const struct Cell_t *self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin[1]; + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin[1]; } uint8_t Cell_get_data_size(const struct Cell_t *self) { - uint8_t d2 = Cell_get_d2(self); - return (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); + uint8_t d2 = Cell_get_d2(self); + return (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); } uint8_t *Cell_get_data(const struct Cell_t *self) { - VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); - return self->cell_begin + CELL_DATA_OFFSET; + VALIDATE(self && self->cell_begin, ERR_CELL_IS_EMPTY); + return self->cell_begin + CELL_DATA_OFFSET; } uint8_t *Cell_get_refs(const struct Cell_t *self, uint8_t *refs_count) { - uint8_t d1 = Cell_get_d1(self); - *refs_count = d1 & 7; - uint8_t data_size = Cell_get_data_size(self); - return self->cell_begin + CELL_DATA_OFFSET + data_size; + uint8_t d1 = Cell_get_d1(self); + *refs_count = d1 & 7; + uint8_t data_size = Cell_get_data_size(self); + return self->cell_begin + CELL_DATA_OFFSET + data_size; } uint16_t Cell_bit_len(struct Cell_t *self) { - uint8_t data_size = Cell_get_data_size(self); + uint8_t data_size = Cell_get_data_size(self); - uint16_t bit_len = data_size * 8; - if ((Cell_get_d2(self) & 0b1) == 0) { - return bit_len; - } + uint16_t bit_len = data_size * 8; + if ((Cell_get_d2(self) & 0b1) == 0) { + return bit_len; + } - uint8_t *data = Cell_get_data(self); - for (uint8_t i = data_size - 1; i >= 0; --i) { - if (data[i] == 0) { - bit_len -= 8; - } else { - uint8_t skip = 1; - uint8_t mask = 1; - while ((data[i] & mask) == 0) { - skip += 1; - mask <<= 1; - } - bit_len -= skip; - break; + uint8_t *data = Cell_get_data(self); + for (uint8_t i = data_size - 1; i >= 0; --i) { + if (data[i] == 0) { + bit_len -= 8; + } else { + uint8_t skip = 1; + uint8_t mask = 1; + while ((data[i] & mask) == 0) { + skip += 1; + mask <<= 1; + } + bit_len -= skip; + break; + } } - } - return bit_len; + return bit_len; } -uint16_t deserialize_cell(struct Cell_t *cell, const uint8_t cell_index, +uint16_t deserialize_cell(struct Cell_t *cell, + const uint8_t cell_index, const uint8_t cells_count) { - uint8_t d1 = Cell_get_d1(cell); - uint8_t level = d1 >> 5; // level - uint8_t hashes = (d1 & 16) == 16; // with hashes - uint8_t exotic = (d1 & 8) == 8; // exotic - uint8_t refs_count = d1 & 7; // refs count - uint8_t absent = refs_count == 7 && hashes; - uint8_t pruned = d1 == PRUNED_BRANCH_D1; - UNUSED(level); - - VALIDATE(!hashes, ERR_INVALID_DATA); - VALIDATE(!exotic || pruned, - ERR_INVALID_DATA); // only ordinary or pruned cells are valid - VALIDATE(refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); - VALIDATE(!absent, ERR_INVALID_DATA); - - uint8_t data_size = Cell_get_data_size(cell); - VALIDATE(!pruned || pruned && (data_size == PRUNED_BRANCH_DATA_SIZE), - ERR_INVALID_DATA); - - uint8_t *refs = Cell_get_refs(cell, &refs_count); - for (uint8_t i = 0; i < refs_count; ++i) { - uint8_t ref = refs[i]; - VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_DATA); - } - - return CELL_DATA_OFFSET + data_size + refs_count; // cell size + uint8_t d1 = Cell_get_d1(cell); + uint8_t level = d1 >> 5; // level + uint8_t hashes = (d1 & 16) == 16; // with hashes + uint8_t exotic = (d1 & 8) == 8; // exotic + uint8_t refs_count = d1 & 7; // refs count + uint8_t absent = refs_count == 7 && hashes; + uint8_t pruned = d1 == PRUNED_BRANCH_D1; + UNUSED(level); + + VALIDATE(!hashes, ERR_INVALID_DATA); + VALIDATE(!exotic || pruned, + ERR_INVALID_DATA); // only ordinary or pruned cells are valid + VALIDATE(refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + VALIDATE(!absent, ERR_INVALID_DATA); + + uint8_t data_size = Cell_get_data_size(cell); + VALIDATE(!pruned || pruned && (data_size == PRUNED_BRANCH_DATA_SIZE), ERR_INVALID_DATA); + + uint8_t *refs = Cell_get_refs(cell, &refs_count); + for (uint8_t i = 0; i < refs_count; ++i) { + uint8_t ref = refs[i]; + VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_DATA); + } + + return CELL_DATA_OFFSET + data_size + refs_count; // cell size } void calc_cell_hash(Cell_t *cell, const uint8_t cell_index) { - BocContext_t *bc = &boc_context; - - uint8_t d1 = Cell_get_d1(cell); - if (d1 == PRUNED_BRANCH_D1) { - // handle pruned branch case - // 1 byte - cell type - // 1 byte - level mask - // 32 bytes - hash - // 2 bytes - cell depth (BE) - uint8_t *cell_data = Cell_get_data(cell); - memcpy(bc->hashes + cell_index * HASH_SIZE, cell_data + 2, HASH_SIZE); - bc->cell_depth[cell_index] = *(cell_data + 2 + HASH_SIZE + 1); - return; - } - - uint8_t - hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32)) - - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = d1 & 0b00011111; - hash_buffer[1] = Cell_get_d2(cell); - hash_buffer_offset += 2; - uint8_t data_size = Cell_get_data_size(cell); - if (bc->public_key_cell_index && cell_index == bc->public_key_cell_index) { - memcpy(hash_buffer + hash_buffer_offset, bc->public_key_cell_data, - data_size); - } else { - memcpy(hash_buffer + hash_buffer_offset, Cell_get_data(cell), data_size); - } - hash_buffer_offset += data_size; - - uint8_t refs_count = 0; - uint8_t *refs = Cell_get_refs(cell, &refs_count); - VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, - ERR_INVALID_DATA); - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t *depth = &bc->cell_depth[cell_index]; - uint8_t child_depth = bc->cell_depth[refs[child]]; - *depth = (*depth > child_depth + 1) ? *depth : (child_depth + 1); - uint8_t buf[2]; - buf[0] = 0; - buf[1] = child_depth; - memcpy(hash_buffer + hash_buffer_offset, buf, sizeof(buf)); - hash_buffer_offset += sizeof(buf); - } - - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t *cell_hash = bc->hashes + refs[child] * HASH_SIZE; - memcpy(hash_buffer + hash_buffer_offset, cell_hash, HASH_SIZE); - hash_buffer_offset += HASH_SIZE; - } - - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, - bc->hashes + cell_index * HASH_SIZE, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + BocContext_t *bc = &boc_context; + + uint8_t d1 = Cell_get_d1(cell); + if (d1 == PRUNED_BRANCH_D1) { + // handle pruned branch case + // 1 byte - cell type + // 1 byte - level mask + // 32 bytes - hash + // 2 bytes - cell depth (BE) + uint8_t *cell_data = Cell_get_data(cell); + memcpy(bc->hashes + cell_index * HASH_SIZE, cell_data + 2, HASH_SIZE); + bc->cell_depth[cell_index] = *(cell_data + 2 + HASH_SIZE + 1); + return; + } + + uint8_t hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32)) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = d1 & 0b00011111; + hash_buffer[1] = Cell_get_d2(cell); + hash_buffer_offset += 2; + uint8_t data_size = Cell_get_data_size(cell); + if (bc->public_key_cell_index && cell_index == bc->public_key_cell_index) { + memcpy(hash_buffer + hash_buffer_offset, bc->public_key_cell_data, data_size); + } else { + memcpy(hash_buffer + hash_buffer_offset, Cell_get_data(cell), data_size); + } + hash_buffer_offset += data_size; + + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(cell, &refs_count); + VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t *depth = &bc->cell_depth[cell_index]; + uint8_t child_depth = bc->cell_depth[refs[child]]; + *depth = (*depth > child_depth + 1) ? *depth : (child_depth + 1); + uint8_t buf[2]; + buf[0] = 0; + buf[1] = child_depth; + memcpy(hash_buffer + hash_buffer_offset, buf, sizeof(buf)); + hash_buffer_offset += sizeof(buf); + } + + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t *cell_hash = bc->hashes + refs[child] * HASH_SIZE; + memcpy(hash_buffer + hash_buffer_offset, cell_hash, HASH_SIZE); + hash_buffer_offset += HASH_SIZE; + } + + int result = cx_hash_sha256(hash_buffer, + hash_buffer_offset, + bc->hashes + cell_index * HASH_SIZE, + HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); } diff --git a/src/contract.c b/src/contract.c index f675f0b..a704a18 100644 --- a/src/contract.c +++ b/src/contract.c @@ -8,102 +8,86 @@ // Wallets code const uint8_t safe_multisig_wallet[] = { - 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, - 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, - 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, - 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, + 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; const uint8_t safe_multisig_wallet_24h[] = { - 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, - 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, - 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, - 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, + 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; const uint8_t setcode_multisig_wallet[] = { - 0x01, 0x02, 0x65, 0x01, 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, - 0x06, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, - 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, 0x03, 0xD0, 0x20, 0x00, 0x41, - 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; + 0x01, 0x02, 0x65, 0x01, 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00, + 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; const uint8_t bridge_multisig_wallet[] = { - 0x01, 0x02, 0x45, 0x01, 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, - 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + 0x01, 0x02, 0x45, 0x01, 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; const uint8_t multisig_2_wallet[] = { - 0x01, 0x02, 0x56, 0x01, 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, - 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + 0x01, 0x02, 0x56, 0x01, 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; const uint8_t multisig_2_1_wallet[] = { - 0x01, 0x02, 0x4D, 0x01, 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, - 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; - -const uint8_t surf_wallet[] = { - 0x01, 0x02, 0x4D, 0x01, 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34, - 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + 0x01, 0x02, 0x4D, 0x01, 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01, + 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; + +const uint8_t surf_wallet[] = {0x01, 0x02, 0x4D, 0x01, 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34, + 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; // Wallets code hash const uint8_t wallet_v3_code_hash[] = { - 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98, 0x77, 0x89, 0xBA, - 0x23, 0x23, 0x58, 0x07, 0x2B, 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, - 0x02, 0xA5, 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99}; + 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98, 0x77, 0x89, 0xBA, 0x23, 0x23, 0x58, 0x07, 0x2B, + 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, 0x02, 0xA5, 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99}; const uint8_t ever_wallet_code_hash[] = { - 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11, 0x81, 0x80, 0xAA, - 0x3B, 0xD1, 0x0D, 0xD1, 0x9F, 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, - 0xCF, 0x58, 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6}; + 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11, 0x81, 0x80, 0xAA, 0x3B, 0xD1, 0x0D, 0xD1, 0x9F, + 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, 0xCF, 0x58, 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6}; const uint8_t safe_multisig_wallet_code_hash[] = { - 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c, 0x9b, 0x39, 0x7b, - 0x71, 0x71, 0x6f, 0x3f, 0xae, 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, - 0xc5, 0x2e, 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05}; + 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c, 0x9b, 0x39, 0x7b, 0x71, 0x71, 0x6f, 0x3f, 0xae, + 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, 0xc5, 0x2e, 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05}; const uint8_t safe_multisig_wallet_24h_code_hash[] = { - 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6, 0x2a, 0x4f, 0xf2, - 0x91, 0xb1, 0x22, 0x8b, 0xf0, 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, - 0x43, 0x6c, 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2}; + 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6, 0x2a, 0x4f, 0xf2, 0x91, 0xb1, 0x22, 0x8b, 0xf0, + 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, 0x43, 0x6c, 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2}; const uint8_t setcode_multisig_wallet_code_hash[] = { - 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce, 0xd7, 0xea, 0x8e, - 0xde, 0x4b, 0xdf, 0x96, 0x34, 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, - 0x06, 0x6f, 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08}; + 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce, 0xd7, 0xea, 0x8e, 0xde, 0x4b, 0xdf, 0x96, 0x34, + 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, 0x06, 0x6f, 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08}; const uint8_t bridge_multisig_wallet_code_hash[] = { - 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25, 0x9D, 0x7F, 0xA4, - 0x84, 0x7B, 0x86, 0x33, 0x5B, 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, - 0xBA, 0x4B, 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18}; + 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25, 0x9D, 0x7F, 0xA4, 0x84, 0x7B, 0x86, 0x33, 0x5B, + 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, 0xBA, 0x4B, 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18}; const uint8_t multisig_2_wallet_code_hash[] = { - 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05, 0xc5, 0xa1, 0xb8, - 0xd8, 0xfd, 0x75, 0xcb, 0x72, 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, - 0x53, 0x32, 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90}; + 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05, 0xc5, 0xa1, 0xb8, 0xd8, 0xfd, 0x75, 0xcb, 0x72, + 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, 0x53, 0x32, 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90}; const uint8_t multisig_2_1_wallet_code_hash[] = { - 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1, 0x25, 0x3f, 0x34, - 0x15, 0x82, 0x6c, 0x94, 0x6c, 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, - 0x08, 0x62, 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3, + 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1, 0x25, 0x3f, 0x34, 0x15, 0x82, 0x6c, 0x94, 0x6c, + 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, 0x08, 0x62, 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3, }; const uint8_t surf_wallet_code_hash[] = { - 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1, 0xa2, 0xc1, 0x47, - 0x93, 0x56, 0xf8, 0xf3, 0xee, 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, - 0xf4, 0x78, 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82}; + 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1, 0xa2, 0xc1, 0x47, 0x93, 0x56, 0xf8, 0xf3, 0xee, + 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, 0xf4, 0x78, 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82}; // Cell depths const uint32_t safe_multisig_wallet_cell_depth = 0x0C; @@ -115,303 +99,313 @@ const uint32_t multisig_2_1_wallet_cell_depth = 0x0A; const uint32_t surf_wallet_cell_depth = 0x0C; void deserialize_cells_tree(struct ByteStream_t *src) { - uint8_t first_byte = ByteStream_read_byte(src); - { - bool index_included = (first_byte & 0x80) != 0; - bool has_crc = (first_byte & 0x40) != 0; - bool has_cache_bits = (first_byte & 0x20) != 0; - uint8_t flags = (first_byte & 0x18) >> 3; - UNUSED(flags); - VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_DATA); - } - - uint8_t ref_size = first_byte & 0x7; // size in bytes - VALIDATE(ref_size == 1, ERR_INVALID_DATA); - - uint8_t offset_size = ByteStream_read_byte(src); - VALIDATE(offset_size != 0 && offset_size <= 8, ERR_INVALID_DATA); - - uint8_t cells_count = ByteStream_read_uint(src, ref_size); - uint8_t roots_count = ByteStream_read_uint(src, ref_size); - VALIDATE(roots_count == MAX_ROOTS_COUNT, ERR_INVALID_DATA); - boc_context.cells_count = cells_count; - - { - uint8_t absent_count = ByteStream_read_uint(src, ref_size); - UNUSED(absent_count); - uint8_t *total_cells_size = ByteStream_read_data(src, offset_size); - UNUSED(total_cells_size); - uint8_t *buf = ByteStream_read_data(src, roots_count * ref_size); - UNUSED(buf); - } - - Cell_t cell; - for (uint8_t i = 0; i < cells_count; ++i) { - uint8_t *cell_begin = ByteStream_get_cursor(src); - Cell_init(&cell, cell_begin); - uint16_t offset = deserialize_cell(&cell, i, cells_count); - boc_context.cells[i] = cell; - ByteStream_read_data(src, offset); - - if (src->offset >= src->data_size) { - break; + uint8_t first_byte = ByteStream_read_byte(src); + { + bool index_included = (first_byte & 0x80) != 0; + bool has_crc = (first_byte & 0x40) != 0; + bool has_cache_bits = (first_byte & 0x20) != 0; + uint8_t flags = (first_byte & 0x18) >> 3; + UNUSED(flags); + VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_DATA); + } + + uint8_t ref_size = first_byte & 0x7; // size in bytes + VALIDATE(ref_size == 1, ERR_INVALID_DATA); + + uint8_t offset_size = ByteStream_read_byte(src); + VALIDATE(offset_size != 0 && offset_size <= 8, ERR_INVALID_DATA); + + uint8_t cells_count = ByteStream_read_uint(src, ref_size); + uint8_t roots_count = ByteStream_read_uint(src, ref_size); + VALIDATE(roots_count == MAX_ROOTS_COUNT, ERR_INVALID_DATA); + boc_context.cells_count = cells_count; + + { + uint8_t absent_count = ByteStream_read_uint(src, ref_size); + UNUSED(absent_count); + uint8_t *total_cells_size = ByteStream_read_data(src, offset_size); + UNUSED(total_cells_size); + uint8_t *buf = ByteStream_read_data(src, roots_count * ref_size); + UNUSED(buf); + } + + Cell_t cell; + for (uint8_t i = 0; i < cells_count; ++i) { + uint8_t *cell_begin = ByteStream_get_cursor(src); + Cell_init(&cell, cell_begin); + uint16_t offset = deserialize_cell(&cell, i, cells_count); + boc_context.cells[i] = cell; + ByteStream_read_data(src, offset); + + if (src->offset >= src->data_size) { + break; + } } - } } void find_public_key_cell() { - BocContext_t *bc = &boc_context; - VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, - ERR_INVALID_DATA); // has data branch - - uint8_t refs_count = 0; - uint8_t *refs = Cell_get_refs(&bc->cells[0], &refs_count); - VALIDATE(refs_count > 0 && refs_count <= 2, ERR_INVALID_DATA); - - uint8_t data_root = refs[refs_count - 1]; - VALIDATE(data_root != 0 && data_root <= MAX_CONTRACT_CELLS_COUNT, - ERR_INVALID_DATA); - refs = Cell_get_refs(&bc->cells[data_root], &refs_count); - VALIDATE(refs_count != 0 && refs_count <= MAX_REFERENCES_COUNT, - ERR_INVALID_DATA); - - uint8_t key_buffer[8]; - SliceData_t key; - memset(key_buffer, 0, sizeof(key_buffer)); - SliceData_init(&key, key_buffer, sizeof(key_buffer)); - - uint16_t bit_len = SliceData_remaining_bits(&key); - put_to_node(refs[0], bit_len, &key); + BocContext_t *bc = &boc_context; + VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, + ERR_INVALID_DATA); // has data branch + + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(&bc->cells[0], &refs_count); + VALIDATE(refs_count > 0 && refs_count <= 2, ERR_INVALID_DATA); + + uint8_t data_root = refs[refs_count - 1]; + VALIDATE(data_root != 0 && data_root <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); + refs = Cell_get_refs(&bc->cells[data_root], &refs_count); + VALIDATE(refs_count != 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + + uint8_t key_buffer[8]; + SliceData_t key; + memset(key_buffer, 0, sizeof(key_buffer)); + SliceData_init(&key, key_buffer, sizeof(key_buffer)); + + uint16_t bit_len = SliceData_remaining_bits(&key); + put_to_node(refs[0], bit_len, &key); } void compute_wallet_v3_address(uint32_t account_number, uint8_t *address) { - uint8_t data_hash[HASH_SIZE]; + uint8_t data_hash[HASH_SIZE]; - // Compute data hash - { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32) + // Compute data hash + { + uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32) - uint16_t hash_buffer_offset = 0; + uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x00; // d1(1) - hash_buffer[1] = 0x50; // d2(1) - hash_buffer_offset += 2; + hash_buffer[0] = 0x00; // d1(1) + hash_buffer[1] = 0x50; // d2(1) + hash_buffer_offset += 2; - // Data - writeUint64BE(WALLET_ID, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint64_t); + // Data + writeUint64BE(WALLET_ID, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint64_t); - // Pubkey - uint8_t public_key[PUBLIC_KEY_LENGTH]; - get_public_key(account_number, public_key); + // Pubkey + uint8_t public_key[PUBLIC_KEY_LENGTH]; + get_public_key(account_number, public_key); + + memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); + hash_buffer_offset += PUBLIC_KEY_LENGTH; + + // Calculate data hash + int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } - memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); - hash_buffer_offset += PUBLIC_KEY_LENGTH; - - // Calculate data hash - int result = - cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } - - // Compute address - { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + - // data_hash(32) - - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x02; // d1(1) - hash_buffer[1] = 0x01; // d2(1) - hash_buffer_offset += 2; - - // Data - hash_buffer[2] = 0x34; - hash_buffer_offset += 1; - - writeUint32BE(0x00, hash_buffer + hash_buffer_offset); - hash_buffer_offset += 4; - - // Code hash - memcpy(hash_buffer + hash_buffer_offset, wallet_v3_code_hash, - sizeof(wallet_v3_code_hash)); - hash_buffer_offset += sizeof(wallet_v3_code_hash); - - // Data hash - memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); - hash_buffer_offset += sizeof(data_hash); - - int result = - cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } + // Compute address + { + uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + + // data_hash(32) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) + hash_buffer_offset += 2; + + // Data + hash_buffer[2] = 0x34; + hash_buffer_offset += 1; + + writeUint32BE(0x00, hash_buffer + hash_buffer_offset); + hash_buffer_offset += 4; + + // Code hash + memcpy(hash_buffer + hash_buffer_offset, wallet_v3_code_hash, sizeof(wallet_v3_code_hash)); + hash_buffer_offset += sizeof(wallet_v3_code_hash); + + // Data hash + memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); + hash_buffer_offset += sizeof(data_hash); + + int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } } void compute_ever_wallet_address(uint32_t account_number, uint8_t *address) { - uint8_t data_hash[HASH_SIZE]; + uint8_t data_hash[HASH_SIZE]; - // Compute data hash - { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) + // Compute data hash + { + uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) - uint16_t hash_buffer_offset = 0; + uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x00; // d1(1) - hash_buffer[1] = 0x50; // d2(1) - hash_buffer_offset += 2; + hash_buffer[0] = 0x00; // d1(1) + hash_buffer[1] = 0x50; // d2(1) + hash_buffer_offset += 2; - // Pubkey - uint8_t public_key[PUBLIC_KEY_LENGTH]; - get_public_key(account_number, public_key); + // Pubkey + uint8_t public_key[PUBLIC_KEY_LENGTH]; + get_public_key(account_number, public_key); + + memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); + hash_buffer_offset += PUBLIC_KEY_LENGTH; + + // Data + writeUint64BE(0, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint64_t); - memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); - hash_buffer_offset += PUBLIC_KEY_LENGTH; - - // Data - writeUint64BE(0, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint64_t); - - // Calculate data hash - int result = - cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } - - // Compute address - { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + - // data_hash(32) - - uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x02; // d1(1) - hash_buffer[1] = 0x01; // d2(1) - hash_buffer_offset += 2; - - // Data - hash_buffer[2] = 0x34; - hash_buffer_offset += 1; - - writeUint32BE(0x30000, hash_buffer + hash_buffer_offset); - hash_buffer_offset += sizeof(uint32_t); - - // Code hash - memcpy(hash_buffer + hash_buffer_offset, ever_wallet_code_hash, - sizeof(ever_wallet_code_hash)); - hash_buffer_offset += sizeof(ever_wallet_code_hash); - - // Data hash - memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); - hash_buffer_offset += sizeof(data_hash); - - int result = - cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); - VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); - } + // Calculate data hash + int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, data_hash, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } + + // Compute address + { + uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + + // data_hash(32) + + uint16_t hash_buffer_offset = 0; + hash_buffer[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) + hash_buffer_offset += 2; + + // Data + hash_buffer[2] = 0x34; + hash_buffer_offset += 1; + + writeUint32BE(0x30000, hash_buffer + hash_buffer_offset); + hash_buffer_offset += sizeof(uint32_t); + + // Code hash + memcpy(hash_buffer + hash_buffer_offset, + ever_wallet_code_hash, + sizeof(ever_wallet_code_hash)); + hash_buffer_offset += sizeof(ever_wallet_code_hash); + + // Data hash + memcpy(hash_buffer + hash_buffer_offset, data_hash, sizeof(data_hash)); + hash_buffer_offset += sizeof(data_hash); + + int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, address, HASH_SIZE); + VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH); + } } -void compute_multisig_address(uint32_t account_number, const uint8_t *wallet, - uint16_t wallet_size, const uint8_t *code_hash, - uint32_t cell_depth, uint8_t *address) { - { - ByteStream_t src; - ByteStream_init(&src, (uint8_t *)wallet, wallet_size); - deserialize_cells_tree(&src); - } - - BocContext_t *bc = &boc_context; - - VALIDATE(bc->cells_count != 0, ERR_INVALID_DATA); - find_public_key_cell(); // sets public key cell index to boc_context - - // Set code hash - memcpy(bc->hashes + (bc->public_key_cell_index + 1) * HASH_SIZE, code_hash, - HASH_SIZE); - bc->cell_depth[bc->public_key_cell_index + 1] = cell_depth; - - VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, - ERR_CELL_IS_EMPTY); - Cell_t *cell = &bc->cells[bc->public_key_cell_index]; - uint8_t cell_data_size = Cell_get_data_size(cell); - VALIDATE(cell_data_size != 0 && - cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, - ERR_INVALID_DATA); - uint8_t *cell_data = Cell_get_data(cell); - - memcpy(bc->public_key_cell_data, cell_data, cell_data_size); - uint8_t *public_key = data_context.pk_context.public_key; - get_public_key(account_number, public_key); - - uint8_t *data = bc->public_key_cell_data; - SliceData_t slice; - SliceData_init(&slice, data, sizeof(bc->public_key_cell_data)); - SliceData_move_by(&slice, bc->public_key_label_size_bits); - SliceData_append(&slice, public_key, PUBLIC_KEY_LENGTH * 8, true); - - for (int16_t i = bc->public_key_cell_index; i >= 0; --i) { - Cell_t *cell = &bc->cells[i]; - calc_cell_hash(cell, i); - } - - memcpy(address, bc->hashes, HASH_SIZE); +void compute_multisig_address(uint32_t account_number, + const uint8_t *wallet, + uint16_t wallet_size, + const uint8_t *code_hash, + uint32_t cell_depth, + uint8_t *address) { + { + ByteStream_t src; + ByteStream_init(&src, (uint8_t *) wallet, wallet_size); + deserialize_cells_tree(&src); + } + + BocContext_t *bc = &boc_context; + + VALIDATE(bc->cells_count != 0, ERR_INVALID_DATA); + find_public_key_cell(); // sets public key cell index to boc_context + + // Set code hash + memcpy(bc->hashes + (bc->public_key_cell_index + 1) * HASH_SIZE, code_hash, HASH_SIZE); + bc->cell_depth[bc->public_key_cell_index + 1] = cell_depth; + + VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, ERR_CELL_IS_EMPTY); + Cell_t *cell = &bc->cells[bc->public_key_cell_index]; + uint8_t cell_data_size = Cell_get_data_size(cell); + VALIDATE(cell_data_size != 0 && cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, + ERR_INVALID_DATA); + uint8_t *cell_data = Cell_get_data(cell); + + memcpy(bc->public_key_cell_data, cell_data, cell_data_size); + uint8_t *public_key = data_context.pk_context.public_key; + get_public_key(account_number, public_key); + + uint8_t *data = bc->public_key_cell_data; + SliceData_t slice; + SliceData_init(&slice, data, sizeof(bc->public_key_cell_data)); + SliceData_move_by(&slice, bc->public_key_label_size_bits); + SliceData_append(&slice, public_key, PUBLIC_KEY_LENGTH * 8, true); + + for (int16_t i = bc->public_key_cell_index; i >= 0; --i) { + Cell_t *cell = &bc->cells[i]; + calc_cell_hash(cell, i); + } + + memcpy(address, bc->hashes, HASH_SIZE); } -void get_address(const uint32_t account_number, uint8_t wallet_type, - uint8_t *address) { - switch (wallet_type) { - case WALLET_V3: { - compute_wallet_v3_address(account_number, address); - break; - } - case EVER_WALLET: { - compute_ever_wallet_address(account_number, address); - break; - } - case SAFE_MULTISIG_WALLET: { - compute_multisig_address(account_number, safe_multisig_wallet, - sizeof(safe_multisig_wallet), - safe_multisig_wallet_code_hash, - safe_multisig_wallet_cell_depth, address); - break; - } - case SAFE_MULTISIG_WALLET_24H: { - compute_multisig_address(account_number, safe_multisig_wallet_24h, - sizeof(safe_multisig_wallet_24h), - safe_multisig_wallet_24h_code_hash, - safe_multisig_wallet_24h_cell_depth, address); - break; - } - case SETCODE_MULTISIG_WALLET: { - compute_multisig_address(account_number, setcode_multisig_wallet, - sizeof(setcode_multisig_wallet), - setcode_multisig_wallet_code_hash, - setcode_multisig_wallet_cell_depth, address); - break; - } - case BRIDGE_MULTISIG_WALLET: { - compute_multisig_address(account_number, bridge_multisig_wallet, - sizeof(bridge_multisig_wallet), - bridge_multisig_wallet_code_hash, - bridge_multisig_wallet_cell_depth, address); - break; - } - case MULTISIG_2: { - compute_multisig_address( - account_number, multisig_2_wallet, sizeof(multisig_2_wallet), - multisig_2_wallet_code_hash, multisig_2_wallet_cell_depth, address); - break; - } - case MULTISIG_2_1: { - compute_multisig_address( - account_number, multisig_2_1_wallet, sizeof(multisig_2_1_wallet), - multisig_2_1_wallet_code_hash, multisig_2_1_wallet_cell_depth, address); - break; - } - case SURF_WALLET: { - compute_multisig_address(account_number, surf_wallet, sizeof(surf_wallet), - surf_wallet_code_hash, surf_wallet_cell_depth, - address); - break; - } - default: - THROW(ERR_INVALID_WALLET_TYPE); - } +void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t *address) { + switch (wallet_type) { + case WALLET_V3: { + compute_wallet_v3_address(account_number, address); + break; + } + case EVER_WALLET: { + compute_ever_wallet_address(account_number, address); + break; + } + case SAFE_MULTISIG_WALLET: { + compute_multisig_address(account_number, + safe_multisig_wallet, + sizeof(safe_multisig_wallet), + safe_multisig_wallet_code_hash, + safe_multisig_wallet_cell_depth, + address); + break; + } + case SAFE_MULTISIG_WALLET_24H: { + compute_multisig_address(account_number, + safe_multisig_wallet_24h, + sizeof(safe_multisig_wallet_24h), + safe_multisig_wallet_24h_code_hash, + safe_multisig_wallet_24h_cell_depth, + address); + break; + } + case SETCODE_MULTISIG_WALLET: { + compute_multisig_address(account_number, + setcode_multisig_wallet, + sizeof(setcode_multisig_wallet), + setcode_multisig_wallet_code_hash, + setcode_multisig_wallet_cell_depth, + address); + break; + } + case BRIDGE_MULTISIG_WALLET: { + compute_multisig_address(account_number, + bridge_multisig_wallet, + sizeof(bridge_multisig_wallet), + bridge_multisig_wallet_code_hash, + bridge_multisig_wallet_cell_depth, + address); + break; + } + case MULTISIG_2: { + compute_multisig_address(account_number, + multisig_2_wallet, + sizeof(multisig_2_wallet), + multisig_2_wallet_code_hash, + multisig_2_wallet_cell_depth, + address); + break; + } + case MULTISIG_2_1: { + compute_multisig_address(account_number, + multisig_2_1_wallet, + sizeof(multisig_2_1_wallet), + multisig_2_1_wallet_code_hash, + multisig_2_1_wallet_cell_depth, + address); + break; + } + case SURF_WALLET: { + compute_multisig_address(account_number, + surf_wallet, + sizeof(surf_wallet), + surf_wallet_code_hash, + surf_wallet_cell_depth, + address); + break; + } + default: + THROW(ERR_INVALID_WALLET_TYPE); + } } diff --git a/src/get_address.c b/src/get_address.c index 8b6153d..fb33723 100644 --- a/src/get_address.c +++ b/src/get_address.c @@ -6,70 +6,81 @@ #include "utils.h" static uint8_t set_result_get_address() { - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = ADDRESS_LENGTH; - memmove(G_io_apdu_buffer + tx, data_context.addr_context.address, - ADDRESS_LENGTH); - tx += ADDRESS_LENGTH; - reset_app_context(); - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = ADDRESS_LENGTH; + memmove(G_io_apdu_buffer + tx, data_context.addr_context.address, ADDRESS_LENGTH); + tx += ADDRESS_LENGTH; + reset_app_context(); + return tx; } -UX_STEP_NOCB(ux_display_address_flow_1_step, pnn, +UX_STEP_NOCB(ux_display_address_flow_1_step, + pnn, { &C_icon_eye, "Verify", "address", }); -UX_STEP_NOCB(ux_display_address_flow_2_step, bnnn_paging, +UX_STEP_NOCB(ux_display_address_flow_2_step, + bnnn_paging, { .title = "Address", .text = data_context.addr_context.address_str, }); -UX_STEP_CB(ux_display_address_flow_3_step, pb, send_response(0, false), +UX_STEP_CB(ux_display_address_flow_3_step, + pb, + send_response(0, false), { &C_icon_crossmark, "Reject", }); -UX_STEP_CB(ux_display_address_flow_4_step, pb, +UX_STEP_CB(ux_display_address_flow_4_step, + pb, send_response(set_result_get_address(), true), { &C_icon_validate_14, "Approve", }); -UX_FLOW(ux_display_address_flow, &ux_display_address_flow_1_step, - &ux_display_address_flow_2_step, &ux_display_address_flow_3_step, +UX_FLOW(ux_display_address_flow, + &ux_display_address_flow_1_step, + &ux_display_address_flow_2_step, + &ux_display_address_flow_3_step, &ux_display_address_flow_4_step); -void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, - uint16_t dataLength, volatile unsigned int *flags, +void handleGetAddress(uint8_t p1, + uint8_t p2, + uint8_t *dataBuffer, + uint16_t dataLength, + volatile unsigned int *flags, volatile unsigned int *tx) { - VALIDATE(p2 == 0 && dataLength == (sizeof(uint32_t) + sizeof(uint8_t)), - ERR_INVALID_REQUEST); + VALIDATE(p2 == 0 && dataLength == (sizeof(uint32_t) + sizeof(uint8_t)), ERR_INVALID_REQUEST); - size_t offset = 0; + size_t offset = 0; - uint32_t account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(account_number); + uint32_t account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(account_number); - uint8_t wallet_type = dataBuffer[offset]; - ; + uint8_t wallet_type = dataBuffer[offset]; + ; - get_address(account_number, wallet_type, data_context.addr_context.address); + get_address(account_number, wallet_type, data_context.addr_context.address); - if (p1 == P1_NON_CONFIRM) { - *tx = set_result_get_address(); - THROW(SUCCESS); - } - if (p1 == P1_CONFIRM) { - AddressContext_t *context = &data_context.addr_context; - snprintf(context->address_str, sizeof(context->address_str), "%.*H", - sizeof(context->address), context->address); - ux_flow_init(0, ux_display_address_flow, NULL); - *flags |= IO_ASYNCH_REPLY; - return; - } + if (p1 == P1_NON_CONFIRM) { + *tx = set_result_get_address(); + THROW(SUCCESS); + } + if (p1 == P1_CONFIRM) { + AddressContext_t *context = &data_context.addr_context; + snprintf(context->address_str, + sizeof(context->address_str), + "%.*H", + sizeof(context->address), + context->address); + ux_flow_init(0, ux_display_address_flow, NULL); + *flags |= IO_ASYNCH_REPLY; + return; + } - THROW(ERR_INVALID_REQUEST); + THROW(ERR_INVALID_REQUEST); } diff --git a/src/get_app_configuration.c b/src/get_app_configuration.c index 6ee59b4..8785f72 100644 --- a/src/get_app_configuration.c +++ b/src/get_app_configuration.c @@ -2,20 +2,22 @@ #include "errors.h" #include "utils.h" -void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, +void handleGetAppConfiguration(uint8_t p1, + uint8_t p2, + uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(p1); - UNUSED(p2); - UNUSED(dataBuffer); - UNUSED(dataLength); - UNUSED(flags); - VALIDATE(p1 == 0 && p2 == 0 && dataLength == 0, ERR_INVALID_REQUEST); + UNUSED(p1); + UNUSED(p2); + UNUSED(dataBuffer); + UNUSED(dataLength); + UNUSED(flags); + VALIDATE(p1 == 0 && p2 == 0 && dataLength == 0, ERR_INVALID_REQUEST); - G_io_apdu_buffer[0] = LEDGER_MAJOR_VERSION; - G_io_apdu_buffer[1] = LEDGER_MINOR_VERSION; - G_io_apdu_buffer[2] = LEDGER_PATCH_VERSION; - *tx = 3; - THROW(SUCCESS); + G_io_apdu_buffer[0] = LEDGER_MAJOR_VERSION; + G_io_apdu_buffer[1] = LEDGER_MINOR_VERSION; + G_io_apdu_buffer[2] = LEDGER_PATCH_VERSION; + *tx = 3; + THROW(SUCCESS); } diff --git a/src/get_public_key.c b/src/get_public_key.c index 6d55fb5..d92b6e8 100644 --- a/src/get_public_key.c +++ b/src/get_public_key.c @@ -5,55 +5,66 @@ #include "ux.h" static uint8_t set_result_get_public_key() { - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = PUBLIC_KEY_LENGTH; - memmove(G_io_apdu_buffer + tx, data_context.pk_context.public_key, - PUBLIC_KEY_LENGTH); - tx += PUBLIC_KEY_LENGTH; - reset_app_context(); - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = PUBLIC_KEY_LENGTH; + memmove(G_io_apdu_buffer + tx, data_context.pk_context.public_key, PUBLIC_KEY_LENGTH); + tx += PUBLIC_KEY_LENGTH; + reset_app_context(); + return tx; } -UX_STEP_NOCB(ux_display_public_flow_1_step, bnnn_paging, +UX_STEP_NOCB(ux_display_public_flow_1_step, + bnnn_paging, { .title = "Public key", .text = data_context.pk_context.public_key_str, }); -UX_STEP_CB(ux_display_public_flow_2_step, pb, send_response(0, false), +UX_STEP_CB(ux_display_public_flow_2_step, + pb, + send_response(0, false), { &C_icon_crossmark, "Reject", }); -UX_STEP_CB(ux_display_public_flow_3_step, pb, +UX_STEP_CB(ux_display_public_flow_3_step, + pb, send_response(set_result_get_public_key(), true), { &C_icon_validate_14, "Approve", }); -UX_FLOW(ux_display_public_flow, &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, &ux_display_public_flow_3_step); +UX_FLOW(ux_display_public_flow, + &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, + &ux_display_public_flow_3_step); -void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, - uint16_t dataLength, volatile unsigned int *flags, +void handleGetPublicKey(uint8_t p1, + uint8_t p2, + uint8_t *dataBuffer, + uint16_t dataLength, + volatile unsigned int *flags, volatile unsigned int *tx) { - VALIDATE(p2 == 0 && dataLength == sizeof(uint32_t), ERR_INVALID_REQUEST); + VALIDATE(p2 == 0 && dataLength == sizeof(uint32_t), ERR_INVALID_REQUEST); - uint32_t account_number = readUint32BE(dataBuffer); - PublicKeyContext_t *context = &data_context.pk_context; - get_public_key(account_number, context->public_key); - if (p1 == P1_NON_CONFIRM) { - *tx = set_result_get_public_key(); - THROW(SUCCESS); - } + uint32_t account_number = readUint32BE(dataBuffer); + PublicKeyContext_t *context = &data_context.pk_context; + get_public_key(account_number, context->public_key); + if (p1 == P1_NON_CONFIRM) { + *tx = set_result_get_public_key(); + THROW(SUCCESS); + } - if (p1 == P1_CONFIRM) { - snprintf(context->public_key_str, sizeof(context->public_key_str), "%.*H", - sizeof(context->public_key), context->public_key); - ux_flow_init(0, ux_display_public_flow, NULL); - *flags |= IO_ASYNCH_REPLY; - return; - } + if (p1 == P1_CONFIRM) { + snprintf(context->public_key_str, + sizeof(context->public_key_str), + "%.*H", + sizeof(context->public_key), + context->public_key); + ux_flow_init(0, ux_display_public_flow, NULL); + *flags |= IO_ASYNCH_REPLY; + return; + } - THROW(ERR_INVALID_REQUEST); + THROW(ERR_INVALID_REQUEST); } diff --git a/src/hashmap_label.c b/src/hashmap_label.c index df8ae76..29ba369 100644 --- a/src/hashmap_label.c +++ b/src/hashmap_label.c @@ -4,85 +4,79 @@ #include "slice_data.h" #include "utils.h" -uint8_t get_label_same(uint8_t max, struct SliceData_t *slice, - struct SliceData_t *label) { - uint8_t value = SliceData_get_next_bit(slice) ? 0xff : 0; - uint8_t length = SliceData_get_next_size(slice, max); - VALIDATE(length <= 64, ERR_RANGE_CHECK); +uint8_t get_label_same(uint8_t max, struct SliceData_t *slice, struct SliceData_t *label) { + uint8_t value = SliceData_get_next_bit(slice) ? 0xff : 0; + uint8_t length = SliceData_get_next_size(slice, max); + VALIDATE(length <= 64, ERR_RANGE_CHECK); - uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0); - SliceData_fill(label, value, length_bytes); - SliceData_truncate(label, length); - return length >= max ? 0 : (max - length); + uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0); + SliceData_fill(label, value, length_bytes); + SliceData_truncate(label, length); + return length >= max ? 0 : (max - length); } -uint8_t get_label(uint8_t max, struct SliceData_t *slice, - struct SliceData_t *label) { - VALIDATE(SliceData_is_empty(slice) == false, ERR_SLICE_IS_EMPTY); - VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short - VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long +uint8_t get_label(uint8_t max, struct SliceData_t *slice, struct SliceData_t *label) { + VALIDATE(SliceData_is_empty(slice) == false, ERR_SLICE_IS_EMPTY); + VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short + VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long - return get_label_same(max, slice, label); + return get_label_same(max, slice, label); } -void put_to_node(uint8_t cell_index, uint16_t bit_len, - struct SliceData_t *key) { - VALIDATE(cell_index != 0 && cell_index <= MAX_CONTRACT_CELLS_COUNT, - ERR_INVALID_DATA); - static const uint8_t key_len_bytes = 8; - VALIDATE(key && key->data_size_bytes == key_len_bytes, ERR_RANGE_CHECK); - for (uint8_t i = 0; i < key_len_bytes; ++i) { - VALIDATE(key->data[i] == 0, ERR_INVALID_KEY); - } - - Cell_t *cell = &boc_context.cells[cell_index]; - SliceData_t slice; - SliceData_init(&slice, Cell_get_data(cell), Cell_get_data_size(cell)); +void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t *key) { + VALIDATE(cell_index != 0 && cell_index <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); + static const uint8_t key_len_bytes = 8; + VALIDATE(key && key->data_size_bytes == key_len_bytes, ERR_RANGE_CHECK); + for (uint8_t i = 0; i < key_len_bytes; ++i) { + VALIDATE(key->data[i] == 0, ERR_INVALID_KEY); + } - SliceData_t label; - uint8_t label_data[8]; - memset(label_data, 0, sizeof(label_data)); - SliceData_init(&label, label_data, sizeof(label_data)); - get_label(bit_len, &slice, &label); + Cell_t *cell = &boc_context.cells[cell_index]; + SliceData_t slice; + SliceData_init(&slice, Cell_get_data(cell), Cell_get_data_size(cell)); - if (SliceData_equal(&label, key)) { - uint8_t len = 16 - leading_zeros(bit_len); - uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len - boc_context.public_key_label_size_bits = label_size_bits; - boc_context.public_key_cell_index = cell_index; - return; - } + SliceData_t label; + uint8_t label_data[8]; + memset(label_data, 0, sizeof(label_data)); + SliceData_init(&label, label_data, sizeof(label_data)); + get_label(bit_len, &slice, &label); - // common prefix - { - uint8_t max_prefix_len = - MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key)); - VALIDATE(max_prefix_len <= 64, ERR_RANGE_CHECK); - uint8_t i = 0; - while (i < max_prefix_len && - SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) { - i += 1; + if (SliceData_equal(&label, key)) { + uint8_t len = 16 - leading_zeros(bit_len); + uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len + boc_context.public_key_label_size_bits = label_size_bits; + boc_context.public_key_cell_index = cell_index; + return; } - SliceData_move_by(key, i); - SliceData_truncate(&label, i); - uint8_t label_rb = SliceData_remaining_bits(&label); - VALIDATE(bit_len >= label_rb, ERR_CELL_UNDERFLOW); - bit_len -= label_rb; - } + // common prefix + { + uint8_t max_prefix_len = + MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key)); + VALIDATE(max_prefix_len <= 64, ERR_RANGE_CHECK); + uint8_t i = 0; + while (i < max_prefix_len && + SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) { + i += 1; + } + + SliceData_move_by(key, i); + SliceData_truncate(&label, i); + uint8_t label_rb = SliceData_remaining_bits(&label); + VALIDATE(bit_len >= label_rb, ERR_CELL_UNDERFLOW); + bit_len -= label_rb; + } - VALIDATE(bit_len >= 1, ERR_CELL_UNDERFLOW); - uint8_t next_index = SliceData_get_next_bit(key); - VALIDATE(next_index == 0, ERR_INVALID_KEY); + VALIDATE(bit_len >= 1, ERR_CELL_UNDERFLOW); + uint8_t next_index = SliceData_get_next_bit(key); + VALIDATE(next_index == 0, ERR_INVALID_KEY); - uint8_t refs_count = 0; - uint8_t *refs = Cell_get_refs(&boc_context.cells[cell_index], &refs_count); - VALIDATE(refs_count > 0 && refs_count <= MAX_REFERENCES_COUNT, - ERR_INVALID_DATA); - uint8_t next_cell = refs[next_index]; - VALIDATE(next_cell != 0 && next_cell <= MAX_CONTRACT_CELLS_COUNT, - ERR_INVALID_DATA); - bit_len -= 1; + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(&boc_context.cells[cell_index], &refs_count); + VALIDATE(refs_count > 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + uint8_t next_cell = refs[next_index]; + VALIDATE(next_cell != 0 && next_cell <= MAX_CONTRACT_CELLS_COUNT, ERR_INVALID_DATA); + bit_len -= 1; - return put_to_node(next_cell, bit_len, key); + return put_to_node(next_cell, bit_len, key); } diff --git a/src/main.c b/src/main.c index 4dcb2c6..fb60073 100644 --- a/src/main.c +++ b/src/main.c @@ -25,288 +25,309 @@ BocContext_t boc_context; DataContext_t data_context; void reset_app_context() { - memset(&boc_context, 0, sizeof(boc_context)); - memset(&data_context, 0, sizeof(data_context)); + memset(&boc_context, 0, sizeof(boc_context)); + memset(&data_context, 0, sizeof(data_context)); } void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) { - unsigned short sw = 0; - - BEGIN_TRY { - TRY { - if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { - THROW(0x6E00); - } - - switch (G_io_apdu_buffer[OFFSET_INS]) { - - case INS_GET_APP_CONFIGURATION: - handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_GET_PUBLIC_KEY: - handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_SIGN: - handleSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], - flags, tx); - break; - - case INS_GET_ADDRESS: - handleGetAddress(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - case INS_SIGN_TRANSACTION: - handleSignTransaction(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], flags, tx); - break; - - default: - THROW(0x6D00); - break; - } - } - CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - sw = e; - reset_app_context(); - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - reset_app_context(); - break; - } - // Unexpected exception => report - G_io_apdu_buffer[*tx] = sw >> 8; - G_io_apdu_buffer[*tx + 1] = sw; - *tx += 2; - } - FINALLY {} - } - END_TRY; -} - -void app_main(void) { - volatile unsigned int rx = 0; - volatile unsigned int tx = 0; - volatile unsigned int flags = 0; - reset_app_context(); - - // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only - // goal is to retrieve APDU. - // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make - // sure the io_event is called with a - // switch event, before the apdu is replied to the bootloader. This avoid - // APDU injection faults. - for (;;) { - volatile unsigned short sw = 0; + unsigned short sw = 0; BEGIN_TRY { - TRY { - rx = tx; - tx = 0; // ensure no race in catch_other if io_exchange throws - // an error - rx = io_exchange(CHANNEL_APDU | flags, rx); - flags = 0; - - // no apdu received, well, reset the session, and reset the - // bootloader configuration - if (rx == 0) { - THROW(0x6982); + TRY { + if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { + THROW(0x6E00); + } + + switch (G_io_apdu_buffer[OFFSET_INS]) { + case INS_GET_APP_CONFIGURATION: + handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + + case INS_GET_PUBLIC_KEY: + handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + + case INS_SIGN: + handleSign(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + + case INS_GET_ADDRESS: + handleGetAddress(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + + case INS_SIGN_TRANSACTION: + handleSignTransaction(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + + default: + THROW(0x6D00); + break; + } } - - // PRINTF("New APDU received:\n%.*h\n", rx, G_io_apdu_buffer); - handleApdu(&flags, &tx); - } - CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - sw = e; - reset_app_context(); - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - reset_app_context(); - break; + CATCH(EXCEPTION_IO_RESET) { + THROW(EXCEPTION_IO_RESET); + } + CATCH_OTHER(e) { + switch (e & 0xF000) { + case 0x6000: + sw = e; + reset_app_context(); + break; + case 0x9000: + // All is well + sw = e; + break; + default: + // Internal error + sw = 0x6800 | (e & 0x7FF); + reset_app_context(); + break; + } + // Unexpected exception => report + G_io_apdu_buffer[*tx] = sw >> 8; + G_io_apdu_buffer[*tx + 1] = sw; + *tx += 2; } - if (e != 0x9000) { - flags &= ~IO_ASYNCH_REPLY; + FINALLY { } - // Unexpected exception => report - G_io_apdu_buffer[tx] = sw >> 8; - G_io_apdu_buffer[tx + 1] = sw; - tx += 2; - } - FINALLY {} } END_TRY; - } +} + +void app_main(void) { + volatile unsigned int rx = 0; + volatile unsigned int tx = 0; + volatile unsigned int flags = 0; + reset_app_context(); + + // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only + // goal is to retrieve APDU. + // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make + // sure the io_event is called with a + // switch event, before the apdu is replied to the bootloader. This avoid + // APDU injection faults. + for (;;) { + volatile unsigned short sw = 0; + + BEGIN_TRY { + TRY { + rx = tx; + tx = 0; // ensure no race in catch_other if io_exchange throws + // an error + rx = io_exchange(CHANNEL_APDU | flags, rx); + flags = 0; + + // no apdu received, well, reset the session, and reset the + // bootloader configuration + if (rx == 0) { + THROW(0x6982); + } + + // PRINTF("New APDU received:\n%.*h\n", rx, G_io_apdu_buffer); + handleApdu(&flags, &tx); + } + CATCH(EXCEPTION_IO_RESET) { + THROW(EXCEPTION_IO_RESET); + } + CATCH_OTHER(e) { + switch (e & 0xF000) { + case 0x6000: + sw = e; + reset_app_context(); + break; + case 0x9000: + // All is well + sw = e; + break; + default: + // Internal error + sw = 0x6800 | (e & 0x7FF); + reset_app_context(); + break; + } + if (e != 0x9000) { + flags &= ~IO_ASYNCH_REPLY; + } + // Unexpected exception => report + G_io_apdu_buffer[tx] = sw >> 8; + G_io_apdu_buffer[tx + 1] = sw; + tx += 2; + } + FINALLY { + } + } + END_TRY; + } - // return_to_dashboard: - return; + // return_to_dashboard: + return; } // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t *)element); + io_seproxyhal_display_default((bagl_element_t *) element); } unsigned char io_event(unsigned char channel) { - UNUSED(channel); - - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - default: - UX_DEFAULT_EVENT(); - break; + UNUSED(channel); + + // nothing done with the event, throw an error on the transport layer if + // needed + + // can't have more than one tag in the reply, not supported yet. + switch (G_io_seproxyhal_spi_buffer[0]) { + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + // no break is intentional + default: + UX_DEFAULT_EVENT(); + break; - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: + UX_DISPLAYED_EVENT({}); + break; - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { #ifndef TARGET_NANOX - if (UX_ALLOWED) { - if (ux_step_count) { - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } - } -#endif // TARGET_NANOX - }); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; + if (UX_ALLOWED) { + if (ux_step_count) { + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); + } + } +#endif // TARGET_NANOX + }); + break; + } + + // close the event if not done previously (by a display or whatever) + if (!io_seproxyhal_spi_is_status_sent()) { + io_seproxyhal_general_status(); + } + + // command has been processed, DO NOT reset the current APDU transport + return 1; } unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), - 0); - } + switch (channel & ~(IO_FLAGS)) { + case CHANNEL_KEYBOARD: + break; + + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); + } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); + } - default: - THROW(INVALID_PARAMETER); - } - return 0; + default: + THROW(INVALID_PARAMETER); + } + return 0; } void app_exit(void) { - - BEGIN_TRY_L(exit) { - TRY_L(exit) { os_sched_exit(-1); } - FINALLY_L(exit) {} - } - END_TRY_L(exit); + BEGIN_TRY_L(exit) { + TRY_L(exit) { + os_sched_exit(-1); + } + FINALLY_L(exit) { + } + } + END_TRY_L(exit); } -void nv_app_state_init() {} +void nv_app_state_init() { +} __attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); + // exit critical section + __asm volatile("cpsie i"); - // ensure exception will work as planned - os_boot(); + // ensure exception will work as planned + os_boot(); - for (;;) { - UX_INIT(); + for (;;) { + UX_INIT(); - BEGIN_TRY { - TRY { - io_seproxyhal_init(); + BEGIN_TRY { + TRY { + io_seproxyhal_init(); - nv_app_state_init(); + nv_app_state_init(); - USB_power(0); - USB_power(1); + USB_power(0); + USB_power(1); - ui_idle(); + ui_idle(); #ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); -#endif // HAVE_BLE - - app_main(); - } - CATCH(EXCEPTION_IO_RESET) { - // reset IO and UX before continuing - continue; - } - CATCH_ALL { break; } - FINALLY {} + BLE_power(0, NULL); + BLE_power(1, "Nano X"); +#endif // HAVE_BLE + + app_main(); + } + CATCH(EXCEPTION_IO_RESET) { + // reset IO and UX before continuing + continue; + } + CATCH_ALL { + break; + } + FINALLY { + } + } + END_TRY; } - END_TRY; - } - app_exit(); - return 0; + app_exit(); + return 0; } diff --git a/src/menu.c b/src/menu.c index 9916c65..29b5499 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2,28 +2,31 @@ #include "os.h" ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_idle_flow_1_step, nn, +UX_STEP_NOCB(ux_idle_flow_1_step, + nn, { "Application", "is ready", }); -UX_STEP_NOCB(ux_idle_flow_3_step, bn, +UX_STEP_NOCB(ux_idle_flow_3_step, + bn, { "Version", APPVERSION, }); -UX_STEP_VALID(ux_idle_flow_4_step, pb, os_sched_exit(-1), +UX_STEP_VALID(ux_idle_flow_4_step, + pb, + os_sched_exit(-1), { &C_icon_dashboard_x, "Quit", }); -UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_3_step, - &ux_idle_flow_4_step, FLOW_LOOP); +UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_3_step, &ux_idle_flow_4_step, FLOW_LOOP); void ui_idle(void) { - // reserve a display stack slot if none yet - if (G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); + // reserve a display stack slot if none yet + if (G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); } diff --git a/src/message.c b/src/message.c index e6a5900..e0dd3bb 100644 --- a/src/message.c +++ b/src/message.c @@ -8,582 +8,606 @@ #define ROOT_CELL_INDEX 0 #define GIFT_CELL_INDEX 1 -void deserialize_array(uint8_t *in, uint8_t in_size, uint16_t offset, - uint8_t *out, uint8_t out_size) { - uint8_t shift = offset % 8; - uint8_t first_data_byte = offset / 8; - for (uint16_t i = first_data_byte, j = 0; j < out_size; ++i, ++j) { - VALIDATE(i == (j + first_data_byte) && (i + 1) <= in_size, - ERR_INVALID_DATA); - - uint8_t cur = in[i] << shift; - out[j] = cur; - - if (j == out_size - 1) { - out[j] |= in[i + 1] >> (8 - shift); +void deserialize_array(uint8_t *in, + uint8_t in_size, + uint16_t offset, + uint8_t *out, + uint8_t out_size) { + uint8_t shift = offset % 8; + uint8_t first_data_byte = offset / 8; + for (uint16_t i = first_data_byte, j = 0; j < out_size; ++i, ++j) { + VALIDATE(i == (j + first_data_byte) && (i + 1) <= in_size, ERR_INVALID_DATA); + + uint8_t cur = in[i] << shift; + out[j] = cur; + + if (j == out_size - 1) { + out[j] |= in[i + 1] >> (8 - shift); + } + + if (i != first_data_byte) { + out[j - 1] |= in[i] >> (8 - shift); + } } - - if (i != first_data_byte) { - out[j - 1] |= in[i] >> (8 - shift); - } - } } -void deserialize_address(struct SliceData_t *slice, int8_t *wc, - uint8_t *address) { - uint8_t addr_type = SliceData_get_next_int(slice, 2); - VALIDATE(addr_type == 0 || addr_type == 2, ERR_INVALID_DATA); +void deserialize_address(struct SliceData_t *slice, int8_t *wc, uint8_t *address) { + uint8_t addr_type = SliceData_get_next_int(slice, 2); + VALIDATE(addr_type == 0 || addr_type == 2, ERR_INVALID_DATA); - if (addr_type == 2) { - uint8_t anycast = SliceData_get_next_bit(slice); - UNUSED(anycast); + if (addr_type == 2) { + uint8_t anycast = SliceData_get_next_bit(slice); + UNUSED(anycast); - *wc = (int8_t)SliceData_get_next_byte(slice); + *wc = (int8_t) SliceData_get_next_byte(slice); - uint8_t *data = SliceData_begin(slice); - uint16_t offset = SliceData_get_cursor(slice); - uint16_t data_size = SliceData_data_size(slice); + uint8_t *data = SliceData_begin(slice); + uint16_t offset = SliceData_get_cursor(slice); + uint16_t data_size = SliceData_data_size(slice); - deserialize_array(data, data_size, offset, address, ADDRESS_LENGTH); + deserialize_array(data, data_size, offset, address, ADDRESS_LENGTH); - SliceData_move_by(slice, ADDRESS_LENGTH * 8); - } + SliceData_move_by(slice, ADDRESS_LENGTH * 8); + } } -void deserialize_value(struct SliceData_t *slice, uint8_t *value, - uint8_t value_length) { - uint8_t *data = SliceData_begin(slice); - uint16_t data_size = SliceData_data_size(slice); +void deserialize_value(struct SliceData_t *slice, uint8_t *value, uint8_t value_length) { + uint8_t *data = SliceData_begin(slice); + uint16_t data_size = SliceData_data_size(slice); - uint16_t offset = SliceData_get_cursor(slice); - deserialize_array(data, data_size, offset, value, value_length); - SliceData_move_by(slice, value_length * 8); + uint16_t offset = SliceData_get_cursor(slice); + deserialize_array(data, data_size, offset, value, value_length); + SliceData_move_by(slice, value_length * 8); } void set_dst_address(uint8_t wc, const uint8_t *address) { - char wc_temp[6]; // snprintf always returns zero - snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t)wc); - int wc_len = strlen(wc_temp); - - char *address_str = data_context.sign_tr_context.address_str; - memcpy(address_str, wc_temp, wc_len); - address_str += wc_len; - - snprintf(address_str, - sizeof(data_context.sign_tr_context.address_str) - wc_len, "%.*H", - ADDRESS_LENGTH, address); + char wc_temp[6]; // snprintf always returns zero + snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t) wc); + int wc_len = strlen(wc_temp); + + char *address_str = data_context.sign_tr_context.address_str; + memcpy(address_str, wc_temp, wc_len); + address_str += wc_len; + + snprintf(address_str, + sizeof(data_context.sign_tr_context.address_str) - wc_len, + "%.*H", + ADDRESS_LENGTH, + address); } -void set_amount(const uint8_t *amount, uint8_t amount_length, uint8_t flags, - uint8_t decimals, const char *ticker) { - char *amount_str = data_context.sign_tr_context.amount_str; - memset(amount_str, 0, sizeof(data_context.sign_tr_context.amount_str)); - - switch (flags) { - case NORMAL_FLAG: { - uint8_t text_size = convert_hex_amount_to_displayable( - amount, decimals, amount_length, amount_str); - - const char *space = " "; - strncpy(amount_str + text_size, space, strlen(space)); - strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker)); - - break; - } - case ALL_BALANCE_FLAG: { - const char *text = "All balance"; - strncpy(amount_str, text, strlen(text)); - break; - } - case ALL_BALANCE_AND_DELETE_FLAG: { - const char *text = "All balance and delete account"; - strncpy(amount_str, text, strlen(text)); - break; - } - default: - THROW(ERR_INVALID_FLAG); - } +void set_amount(const uint8_t *amount, + uint8_t amount_length, + uint8_t flags, + uint8_t decimals, + const char *ticker) { + char *amount_str = data_context.sign_tr_context.amount_str; + memset(amount_str, 0, sizeof(data_context.sign_tr_context.amount_str)); + + switch (flags) { + case NORMAL_FLAG: { + uint8_t text_size = + convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str); + + const char *space = " "; + strncpy(amount_str + text_size, space, strlen(space)); + strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker)); + + break; + } + case ALL_BALANCE_FLAG: { + const char *text = "All balance"; + strncpy(amount_str, text, strlen(text)); + break; + } + case ALL_BALANCE_AND_DELETE_FLAG: { + const char *text = "All balance and delete account"; + strncpy(amount_str, text, strlen(text)); + break; + } + default: + THROW(ERR_INVALID_FLAG); + } } void set_transaction_id(const uint8_t *transaction_id) { - char *transaction_id_str = data_context.sign_tr_context.transaction_id_str; - memset(transaction_id_str, 0, - sizeof(data_context.sign_tr_context.transaction_id_str)); - - snprintf(transaction_id_str, - sizeof(data_context.sign_tr_context.transaction_id_str), "%.*H", - TRANSACTION_ID_LENGTH, transaction_id); + char *transaction_id_str = data_context.sign_tr_context.transaction_id_str; + memset(transaction_id_str, 0, sizeof(data_context.sign_tr_context.transaction_id_str)); + + snprintf(transaction_id_str, + sizeof(data_context.sign_tr_context.transaction_id_str), + "%.*H", + TRANSACTION_ID_LENGTH, + transaction_id); } -void deserialize_int_message_header(struct SliceData_t *slice, uint8_t flags, +void deserialize_int_message_header(struct SliceData_t *slice, + uint8_t flags, SignTransactionContext_t *ctx) { - uint8_t int_msg = SliceData_get_next_bit(slice); - VALIDATE(!int_msg, ERR_INVALID_DATA); + uint8_t int_msg = SliceData_get_next_bit(slice); + VALIDATE(!int_msg, ERR_INVALID_DATA); - uint8_t ihr_disabled = SliceData_get_next_bit(slice); - UNUSED(ihr_disabled); + uint8_t ihr_disabled = SliceData_get_next_bit(slice); + UNUSED(ihr_disabled); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t bounced = SliceData_get_next_bit(slice); - UNUSED(bounced); + uint8_t bounced = SliceData_get_next_bit(slice); + UNUSED(bounced); - // Sender address - int8_t src_wc = 0; - uint8_t src_addr[ADDRESS_LENGTH]; - deserialize_address(slice, &src_wc, src_addr); + // Sender address + int8_t src_wc = 0; + uint8_t src_addr[ADDRESS_LENGTH]; + deserialize_address(slice, &src_wc, src_addr); - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = SliceData_get_next_int(slice, 4); - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + // Amount + uint8_t amount_length = SliceData_get_next_int(slice, 4); + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - uint8_t other = SliceData_get_next_bit(slice); - UNUSED(other); + uint8_t other = SliceData_get_next_bit(slice); + UNUSED(other); - // Fee - uint8_t ihr_fee_length = SliceData_get_next_int(slice, 4); - VALIDATE(ihr_fee_length == 0, ERR_INVALID_DATA); + // Fee + uint8_t ihr_fee_length = SliceData_get_next_int(slice, 4); + VALIDATE(ihr_fee_length == 0, ERR_INVALID_DATA); - uint8_t fwd_fee_length = SliceData_get_next_int(slice, 4); - VALIDATE(fwd_fee_length == 0, ERR_INVALID_DATA); + uint8_t fwd_fee_length = SliceData_get_next_int(slice, 4); + VALIDATE(fwd_fee_length == 0, ERR_INVALID_DATA); - // Created - uint64_t created_lt = SliceData_get_next_int(slice, 64); - UNUSED(created_lt); + // Created + uint64_t created_lt = SliceData_get_next_int(slice, 64); + UNUSED(created_lt); - uint32_t created_at = SliceData_get_next_int(slice, 32); - UNUSED(created_at); + uint32_t created_at = SliceData_get_next_int(slice, 32); + UNUSED(created_at); } int deserialize_token_body(struct SliceData_t *slice, struct SliceData_t *ref_slice, SignTransactionContext_t *ctx) { - // FunctionId - if (SliceData_remaining_bits(slice) < sizeof(uint32_t) * 8) { - if (!ref_slice || !ref_slice->data || - (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) { - // Empty payload is ok - return SIGN_TRANSACTION_FLOW_TRANSFER; + // FunctionId + if (SliceData_remaining_bits(slice) < sizeof(uint32_t) * 8) { + if (!ref_slice || !ref_slice->data || + (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) { + // Empty payload is ok + return SIGN_TRANSACTION_FLOW_TRANSFER; + } + slice = ref_slice; } - slice = ref_slice; - } - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - uint32_t function_id = SliceData_get_next_int(slice, sizeof(uint32_t) * 8); - switch (function_id) { - case TOKEN_TRANSFER: - case TOKEN_TRANSFER_TO_WALLET: { - // Amount - if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + uint32_t function_id = SliceData_get_next_int(slice, sizeof(uint32_t) * 8); + switch (function_id) { + case TOKEN_TRANSFER: + case TOKEN_TRANSFER_TO_WALLET: { + // Amount + if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - uint8_t amount[AMOUNT_LENGHT]; - deserialize_value(slice, amount, sizeof(amount)); + uint8_t amount[AMOUNT_LENGHT]; + deserialize_value(slice, amount, sizeof(amount)); - set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); + set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); - // Address - if (SliceData_remaining_bits(slice) < ADDRESS_LENGTH * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + // Address + if (SliceData_remaining_bits(slice) < ADDRESS_LENGTH * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - int8_t wc = 0; - uint8_t address[ADDRESS_LENGTH]; - deserialize_address(slice, &wc, address); + int8_t wc = 0; + uint8_t address[ADDRESS_LENGTH]; + deserialize_address(slice, &wc, address); - set_dst_address(wc, address); + set_dst_address(wc, address); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case TOKEN_BURN: { - // Amount - if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { - VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); - slice = ref_slice; - } + break; + } + case TOKEN_BURN: { + // Amount + if (SliceData_remaining_bits(slice) < AMOUNT_LENGHT * 8) { + VALIDATE(ref_slice && ref_slice->data, ERR_SLICE_IS_EMPTY); + slice = ref_slice; + } - uint8_t amount[AMOUNT_LENGHT]; - deserialize_value(slice, amount, sizeof(amount)); + uint8_t amount[AMOUNT_LENGHT]; + deserialize_value(slice, amount, sizeof(amount)); - set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); + set_amount(amount, sizeof(amount), NORMAL_FLAG, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_BURN; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_BURN; - break; - } - default: { - // All other methods could be treated as plain transfers + break; + } + default: { + // All other methods could be treated as plain transfers - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - } + break; + } + } - return sign_transaction_flow; + return sign_transaction_flow; } -int deserialize_multisig_params(struct SliceData_t *slice, uint32_t function_id, - uint8_t wc, uint8_t *address, +int deserialize_multisig_params(struct SliceData_t *slice, + uint32_t function_id, + uint8_t wc, + uint8_t *address, SignTransactionContext_t *ctx) { - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - switch (function_id) { - case MULTISIG_DEPLOY_TRANSACTION: - case MULTISIG2_DEPLOY_TRANSACTION: { - // Address to deploy - set_dst_address(wc, address); + switch (function_id) { + case MULTISIG_DEPLOY_TRANSACTION: + case MULTISIG2_DEPLOY_TRANSACTION: { + // Address to deploy + set_dst_address(wc, address); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_DEPLOY; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_DEPLOY; - break; - } - case MULTISIG_SEND_TRANSACTION: { - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + break; + } + case MULTISIG_SEND_TRANSACTION: { + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = 16; - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); + // Amount + uint8_t amount_length = 16; + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t flags = SliceData_get_next_byte(slice); + uint8_t flags = SliceData_get_next_byte(slice); - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case MULTISIG_SUBMIT_TRANSACTION: - case MULTISIG2_SUBMIT_TRANSACTION: { - // Recipient address - int8_t dst_wc = 0; - uint8_t dst_address[ADDRESS_LENGTH]; - deserialize_address(slice, &dst_wc, dst_address); + break; + } + case MULTISIG_SUBMIT_TRANSACTION: + case MULTISIG2_SUBMIT_TRANSACTION: { + // Recipient address + int8_t dst_wc = 0; + uint8_t dst_address[ADDRESS_LENGTH]; + deserialize_address(slice, &dst_wc, dst_address); - set_dst_address(dst_wc, dst_address); + set_dst_address(dst_wc, dst_address); - // Amount - uint8_t amount_length = 16; - uint8_t amount[amount_length]; - deserialize_value(slice, amount, amount_length); + // Amount + uint8_t amount_length = 16; + uint8_t amount[amount_length]; + deserialize_value(slice, amount, amount_length); - uint8_t bounce = SliceData_get_next_bit(slice); - UNUSED(bounce); + uint8_t bounce = SliceData_get_next_bit(slice); + UNUSED(bounce); - uint8_t all_balance = SliceData_get_next_bit(slice); + uint8_t all_balance = SliceData_get_next_bit(slice); - uint8_t flags; - if (!all_balance) { - flags = NORMAL_FLAG; - } else { - flags = ALL_BALANCE_FLAG; - } + uint8_t flags; + if (!all_balance) { + flags = NORMAL_FLAG; + } else { + flags = ALL_BALANCE_FLAG; + } - set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); + set_amount(amount, amount_length, flags, ctx->decimals, ctx->ticker); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - break; - } - case MULTISIG_CONFIRM_TRANSACTION: { - // Transaction id - uint8_t id[TRANSACTION_ID_LENGTH]; - deserialize_value(slice, id, sizeof(id)); + break; + } + case MULTISIG_CONFIRM_TRANSACTION: { + // Transaction id + uint8_t id[TRANSACTION_ID_LENGTH]; + deserialize_value(slice, id, sizeof(id)); - set_transaction_id(id); + set_transaction_id(id); - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_CONFIRM; + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_CONFIRM; - break; - } - default: - THROW(ERR_INVALID_FUNCTION_ID); - } + break; + } + default: + THROW(ERR_INVALID_FUNCTION_ID); + } - return sign_transaction_flow; + return sign_transaction_flow; } void prepare_payload_hash(BocContext_t *bc) { - for (int16_t i = bc->cells_count - 1; i >= 0; --i) { - Cell_t *cell = &bc->cells[i]; - calc_cell_hash(cell, i); - } - - if (!data_context.sign_tr_context.sign_with_chain_id) { - memcpy(data_context.sign_tr_context.to_sign, - &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); - } else { - memcpy(data_context.sign_tr_context.to_sign, - data_context.sign_tr_context.chain_id, CHAIN_ID_LENGTH); - memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH, - &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH); - } + for (int16_t i = bc->cells_count - 1; i >= 0; --i) { + Cell_t *cell = &bc->cells[i]; + calc_cell_hash(cell, i); + } + + if (!data_context.sign_tr_context.sign_with_chain_id) { + memcpy(data_context.sign_tr_context.to_sign, + &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], + TO_SIGN_LENGTH); + } else { + memcpy(data_context.sign_tr_context.to_sign, + data_context.sign_tr_context.chain_id, + CHAIN_ID_LENGTH); + memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH, + &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], + TO_SIGN_LENGTH); + } } uint32_t deserialize_wallet_v3(struct SliceData_t *slice) { - uint32_t id = SliceData_get_next_int(slice, 32); - VALIDATE(id == WALLET_ID, ERR_INVALID_DATA); + uint32_t id = SliceData_get_next_int(slice, 32); + VALIDATE(id == WALLET_ID, ERR_INVALID_DATA); - uint32_t expire_at = SliceData_get_next_int(slice, 32); - UNUSED(expire_at); + uint32_t expire_at = SliceData_get_next_int(slice, 32); + UNUSED(expire_at); - uint32_t seqno = SliceData_get_next_int(slice, 32); - UNUSED(seqno); + uint32_t seqno = SliceData_get_next_int(slice, 32); + UNUSED(seqno); - uint8_t flags = SliceData_get_next_byte(slice); + uint8_t flags = SliceData_get_next_byte(slice); - uint16_t remaining_bits = SliceData_remaining_bits(slice); - VALIDATE(remaining_bits == 0, ERR_INVALID_DATA); + uint16_t remaining_bits = SliceData_remaining_bits(slice); + VALIDATE(remaining_bits == 0, ERR_INVALID_DATA); - return flags; + return flags; } uint32_t deserialize_contract_header(struct SliceData_t *slice) { - uint8_t is_pubkey_present = SliceData_get_next_bit(slice); - if (is_pubkey_present) { - SliceData_move_by(slice, PUBLIC_KEY_LENGTH * 8); - } + uint8_t is_pubkey_present = SliceData_get_next_bit(slice); + if (is_pubkey_present) { + SliceData_move_by(slice, PUBLIC_KEY_LENGTH * 8); + } - uint64_t time = SliceData_get_next_int(slice, 64); - UNUSED(time); + uint64_t time = SliceData_get_next_int(slice, 64); + UNUSED(time); - uint64_t expire = SliceData_get_next_int(slice, 32); - UNUSED(expire); + uint64_t expire = SliceData_get_next_int(slice, 32); + UNUSED(expire); - uint32_t function_id = SliceData_get_next_int(slice, 32); - return function_id; + uint32_t function_id = SliceData_get_next_int(slice, 32); + return function_id; } -void prepend_address_to_cell(uint8_t *cell_buffer, uint16_t cell_buffer_size, - struct Cell_t *cell, uint8_t wc, +void prepend_address_to_cell(uint8_t *cell_buffer, + uint16_t cell_buffer_size, + struct Cell_t *cell, + uint8_t wc, uint8_t *address) { - uint16_t bit_len = Cell_bit_len(cell); - bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8) + uint16_t bit_len = Cell_bit_len(cell); + bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8) - uint8_t d1 = Cell_get_d1(cell); - uint8_t d2 = ((bit_len >> 2) & 0b11111110) | (bit_len % 8 != 0); + uint8_t d1 = Cell_get_d1(cell); + uint8_t d2 = ((bit_len >> 2) & 0b11111110) | (bit_len % 8 != 0); - cell_buffer[0] = d1; - cell_buffer[1] = d2; + cell_buffer[0] = d1; + cell_buffer[1] = d2; - SliceData_t slice; - SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size); + SliceData_t slice; + SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size); - // Append prefix - uint8_t prefix[] = {0x80}; // $100 prefix AddrStd - SliceData_append(&slice, prefix, 3, false); + // Append prefix + uint8_t prefix[] = {0x80}; // $100 prefix AddrStd + SliceData_append(&slice, prefix, 3, false); - // Append workchain - uint8_t wc_buf[] = {wc}; - SliceData_append(&slice, wc_buf, 8, false); + // Append workchain + uint8_t wc_buf[] = {wc}; + SliceData_append(&slice, wc_buf, 8, false); - // Append address - SliceData_append(&slice, address, ADDRESS_LENGTH * 8, false); + // Append address + SliceData_append(&slice, address, ADDRESS_LENGTH * 8, false); - // Append cell data - uint8_t *data = Cell_get_data(cell); - uint8_t data_size = Cell_get_data_size(cell); - SliceData_append(&slice, data, data_size * 8, false); + // Append cell data + uint8_t *data = Cell_get_data(cell); + uint8_t data_size = Cell_get_data_size(cell); + SliceData_append(&slice, data, data_size * 8, false); - // Append references - uint8_t refs_count = 0; - uint8_t *refs = Cell_get_refs(cell, &refs_count); + // Append references + uint8_t refs_count = 0; + uint8_t *refs = Cell_get_refs(cell, &refs_count); - VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, - ERR_INVALID_DATA); - for (uint8_t child = 0; child < refs_count; ++child) { - uint8_t cell_data_size = (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); - cell_buffer[CELL_DATA_OFFSET + cell_data_size + child] = refs[child]; - } + VALIDATE(refs_count >= 0 && refs_count <= MAX_REFERENCES_COUNT, ERR_INVALID_DATA); + for (uint8_t child = 0; child < refs_count; ++child) { + uint8_t cell_data_size = (d2 >> 1) + (((d2 & 1) != 0) ? 1 : 0); + cell_buffer[CELL_DATA_OFFSET + cell_data_size + child] = refs[child]; + } - // Replace cell - cell->cell_begin = cell_buffer; + // Replace cell + cell->cell_begin = cell_buffer; } -int prepare_to_sign(struct ByteStream_t *src, uint8_t wc, uint8_t *address, +int prepare_to_sign(struct ByteStream_t *src, + uint8_t wc, + uint8_t *address, uint8_t *prepend_address) { - // Init context - BocContext_t *bc = &boc_context; - DataContext_t *dc = &data_context; - - // Parse transaction boc - deserialize_cells_tree(src); - - Cell_t *root_cell = &bc->cells[ROOT_CELL_INDEX]; - - SliceData_t root_slice; - SliceData_from_cell(&root_slice, root_cell); - - int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - - switch (dc->sign_tr_context.current_wallet_type) { - case WALLET_V3: { - uint8_t flags = deserialize_wallet_v3(&root_slice); - - // Gift - VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); - Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; - - SliceData_t gift_slice; - SliceData_from_cell(&gift_slice, gift_cell); - - // Deserialize header - deserialize_int_message_header(&gift_slice, flags, &dc->sign_tr_context); - - // Deserialize StateInit - uint8_t state_init_bit = SliceData_get_next_bit(&gift_slice); - VALIDATE(state_init_bit == 0, ERR_INVALID_DATA); - - // Deserialize Body - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); - - // Set ux sign flow - sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; - - uint8_t body_bit = SliceData_get_next_bit(&gift_slice); - if (body_bit || gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t *ref_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + // Init context + BocContext_t *bc = &boc_context; + DataContext_t *dc = &data_context; - SliceData_t ref_slice; - SliceData_from_cell(&ref_slice, ref_cell); + // Parse transaction boc + deserialize_cells_tree(src); - sign_transaction_flow = - deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context); - } - - // Calculate payload hash to sign - prepare_payload_hash(bc); - - break; - } - case SAFE_MULTISIG_WALLET: - case SAFE_MULTISIG_WALLET_24H: - case SETCODE_MULTISIG_WALLET: - case BRIDGE_MULTISIG_WALLET: - case SURF_WALLET: { - // Header - uint32_t function_id = deserialize_contract_header(&root_slice); - - bool in_same_cell = function_id == MULTISIG_CONFIRM_TRANSACTION; + Cell_t *root_cell = &bc->cells[ROOT_CELL_INDEX]; + + SliceData_t root_slice; + SliceData_from_cell(&root_slice, root_cell); + + int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR; - // Gift - Cell_t *gift_cell = in_same_cell ? root_cell : &bc->cells[GIFT_CELL_INDEX]; + switch (dc->sign_tr_context.current_wallet_type) { + case WALLET_V3: { + uint8_t flags = deserialize_wallet_v3(&root_slice); - SliceData_t gift_slice; - if (in_same_cell) { - gift_slice = root_slice; - } else { - SliceData_from_cell(&gift_slice, gift_cell); + // Gift + VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); + Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; + + SliceData_t gift_slice; + SliceData_from_cell(&gift_slice, gift_cell); + + // Deserialize header + deserialize_int_message_header(&gift_slice, flags, &dc->sign_tr_context); + + // Deserialize StateInit + uint8_t state_init_bit = SliceData_get_next_bit(&gift_slice); + VALIDATE(state_init_bit == 0, ERR_INVALID_DATA); + + // Deserialize Body + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); + + // Set ux sign flow + sign_transaction_flow = SIGN_TRANSACTION_FLOW_TRANSFER; + + uint8_t body_bit = SliceData_get_next_bit(&gift_slice); + if (body_bit || gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *ref_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + + SliceData_t ref_slice; + SliceData_from_cell(&ref_slice, ref_cell); + + sign_transaction_flow = + deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context); + } + + // Calculate payload hash to sign + prepare_payload_hash(bc); + + break; + } + case SAFE_MULTISIG_WALLET: + case SAFE_MULTISIG_WALLET_24H: + case SETCODE_MULTISIG_WALLET: + case BRIDGE_MULTISIG_WALLET: + case SURF_WALLET: { + // Header + uint32_t function_id = deserialize_contract_header(&root_slice); + + bool in_same_cell = function_id == MULTISIG_CONFIRM_TRANSACTION; + + // Gift + Cell_t *gift_cell = in_same_cell ? root_cell : &bc->cells[GIFT_CELL_INDEX]; + + SliceData_t gift_slice; + if (in_same_cell) { + gift_slice = root_slice; + } else { + SliceData_from_cell(&gift_slice, gift_cell); + } + + sign_transaction_flow = deserialize_multisig_params(&gift_slice, + function_id, + wc, + address, + &dc->sign_tr_context); + + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); + + // Gift body + if (gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + + SliceData_t body_slice; + SliceData_from_cell(&body_slice, body_cell); + + if (!SliceData_is_empty(&body_slice)) { + sign_transaction_flow = + deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); + } + } + + // Calculate payload hash to sign + prepare_payload_hash(bc); + + break; + } + case EVER_WALLET: + case MULTISIG_2: + case MULTISIG_2_1: { + // Header + uint32_t function_id = deserialize_contract_header(&root_slice); + + // Gift + VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); + Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; + + SliceData_t gift_slice; + SliceData_from_cell(&gift_slice, gift_cell); + + sign_transaction_flow = deserialize_multisig_params(&gift_slice, + function_id, + wc, + address, + &dc->sign_tr_context); + + uint8_t gift_refs_count; + Cell_get_refs(gift_cell, &gift_refs_count); + + // Gift body + if (gift_refs_count) { + VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); + Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; + + SliceData_t body_slice; + SliceData_from_cell(&body_slice, body_cell); + + if (!SliceData_is_empty(&body_slice)) { + sign_transaction_flow = + deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); + } + } + + // Prepend address to root cell + uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128) + prepend_address_to_cell(cell_buffer, + sizeof(cell_buffer), + root_cell, + wc, + prepend_address); + + // Calculate payload hash to sign + prepare_payload_hash(bc); + + // Detach cell_buffer reference from global boc context + memset(bc, 0, sizeof(boc_context)); + + break; + } + default: + THROW(ERR_INVALID_WALLET_TYPE); } - sign_transaction_flow = deserialize_multisig_params( - &gift_slice, function_id, wc, address, &dc->sign_tr_context); - - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); - - // Gift body - if (gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; - - SliceData_t body_slice; - SliceData_from_cell(&body_slice, body_cell); - - if (!SliceData_is_empty(&body_slice)) { - sign_transaction_flow = - deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); - } - } - - // Calculate payload hash to sign - prepare_payload_hash(bc); - - break; - } - case EVER_WALLET: - case MULTISIG_2: - case MULTISIG_2_1: { - // Header - uint32_t function_id = deserialize_contract_header(&root_slice); - - // Gift - VALIDATE(bc->cells_count > GIFT_CELL_INDEX, ERR_INVALID_CELL_INDEX); - Cell_t *gift_cell = &bc->cells[GIFT_CELL_INDEX]; - - SliceData_t gift_slice; - SliceData_from_cell(&gift_slice, gift_cell); - - sign_transaction_flow = deserialize_multisig_params( - &gift_slice, function_id, wc, address, &dc->sign_tr_context); - - uint8_t gift_refs_count; - Cell_get_refs(gift_cell, &gift_refs_count); - - // Gift body - if (gift_refs_count) { - VALIDATE(bc->cells_count > GIFT_CELL_INDEX + 1, ERR_INVALID_CELL_INDEX); - Cell_t *body_cell = &bc->cells[GIFT_CELL_INDEX + 1]; - - SliceData_t body_slice; - SliceData_from_cell(&body_slice, body_cell); - - if (!SliceData_is_empty(&body_slice)) { - sign_transaction_flow = - deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); - } - } - - // Prepend address to root cell - uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128) - prepend_address_to_cell(cell_buffer, sizeof(cell_buffer), root_cell, wc, - prepend_address); - - // Calculate payload hash to sign - prepare_payload_hash(bc); - - // Detach cell_buffer reference from global boc context - memset(bc, 0, sizeof(boc_context)); - - break; - } - default: - THROW(ERR_INVALID_WALLET_TYPE); - } - - return sign_transaction_flow; + return sign_transaction_flow; } diff --git a/src/sign.c b/src/sign.c index f444254..ce48366 100644 --- a/src/sign.c +++ b/src/sign.c @@ -3,96 +3,129 @@ #include "utils.h" static uint8_t set_result_sign() { - cx_ecfp_private_key_t privateKey; - SignContext_t *context = &data_context.sign_context; + cx_ecfp_private_key_t privateKey; + SignContext_t *context = &data_context.sign_context; - BEGIN_TRY { - TRY { - get_private_key(context->account_number, &privateKey); - if (!context->sign_with_chain_id) { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, - TO_SIGN_LENGTH, NULL, 0, context->signature, - SIGNATURE_LENGTH, NULL); - } else { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, - CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, - context->signature, SIGNATURE_LENGTH, NULL); - } + BEGIN_TRY { + TRY { + get_private_key(context->account_number, &privateKey); + if (!context->sign_with_chain_id) { + cx_eddsa_sign(&privateKey, + CX_LAST, + CX_SHA512, + context->to_sign, + TO_SIGN_LENGTH, + NULL, + 0, + context->signature, + SIGNATURE_LENGTH, + NULL); + } else { + cx_eddsa_sign(&privateKey, + CX_LAST, + CX_SHA512, + context->to_sign, + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, + NULL, + 0, + context->signature, + SIGNATURE_LENGTH, + NULL); + } + } + FINALLY { + memset(&privateKey, 0, sizeof(privateKey)); + } } - FINALLY { memset(&privateKey, 0, sizeof(privateKey)); } - } - END_TRY; + END_TRY; - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; - memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); - tx += SIGNATURE_LENGTH; - return tx; + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; + memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); + tx += SIGNATURE_LENGTH; + return tx; } -UX_STEP_NOCB(ux_sign_flow_1_step, pnn, +UX_STEP_NOCB(ux_sign_flow_1_step, + pnn, { &C_icon_certificate, "Sign", "message", }); -UX_STEP_NOCB(ux_sign_flow_2_step, bnnn_paging, +UX_STEP_NOCB(ux_sign_flow_2_step, + bnnn_paging, { .title = "Message hash", .text = data_context.sign_context.to_sign_str, }); -UX_STEP_CB(ux_sign_flow_3_step, pbb, send_response(0, false), +UX_STEP_CB(ux_sign_flow_3_step, + pbb, + send_response(0, false), { &C_icon_crossmark, "Cancel", "signature", }); -UX_STEP_CB(ux_sign_flow_4_step, pbb, send_response(set_result_sign(), true), +UX_STEP_CB(ux_sign_flow_4_step, + pbb, + send_response(set_result_sign(), true), { &C_icon_validate_14, "Sign", "message.", }); -UX_FLOW(ux_sign_flow, &ux_sign_flow_1_step, &ux_sign_flow_2_step, - &ux_sign_flow_3_step, &ux_sign_flow_4_step); +UX_FLOW(ux_sign_flow, + &ux_sign_flow_1_step, + &ux_sign_flow_2_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step); -void handleSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, - uint16_t dataLength, volatile unsigned int *flags, +void handleSign(uint8_t p1, + uint8_t p2, + uint8_t *dataBuffer, + uint16_t dataLength, + volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(tx); + UNUSED(tx); - VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); - SignContext_t *context = &data_context.sign_context; + VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); + SignContext_t *context = &data_context.sign_context; - size_t offset = 0; + size_t offset = 0; - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); + context->account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(context->account_number); - uint8_t metadata = dataBuffer[offset]; - offset += sizeof(metadata); + uint8_t metadata = dataBuffer[offset]; + offset += sizeof(metadata); - // Read chain id if present - if (metadata & FLAG_WITH_CHAIN_ID) { - context->sign_with_chain_id = true; + // Read chain id if present + if (metadata & FLAG_WITH_CHAIN_ID) { + context->sign_with_chain_id = true; - memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); - offset += sizeof(context->chain_id); - } + memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); + offset += sizeof(context->chain_id); + } - if (!context->sign_with_chain_id) { - memcpy(context->to_sign, dataBuffer + offset, TO_SIGN_LENGTH); - snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", - TO_SIGN_LENGTH, context->to_sign); - } else { - memcpy(context->to_sign, context->chain_id, CHAIN_ID_LENGTH); - memcpy(context->to_sign + CHAIN_ID_LENGTH, dataBuffer + offset, - TO_SIGN_LENGTH); - snprintf(context->to_sign_str, sizeof(context->to_sign_str), "%.*H", - CHAIN_ID_LENGTH + TO_SIGN_LENGTH, context->to_sign); - } + if (!context->sign_with_chain_id) { + memcpy(context->to_sign, dataBuffer + offset, TO_SIGN_LENGTH); + snprintf(context->to_sign_str, + sizeof(context->to_sign_str), + "%.*H", + TO_SIGN_LENGTH, + context->to_sign); + } else { + memcpy(context->to_sign, context->chain_id, CHAIN_ID_LENGTH); + memcpy(context->to_sign + CHAIN_ID_LENGTH, dataBuffer + offset, TO_SIGN_LENGTH); + snprintf(context->to_sign_str, + sizeof(context->to_sign_str), + "%.*H", + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, + context->to_sign); + } - ux_flow_init(0, ux_sign_flow, NULL); - *flags |= IO_ASYNCH_REPLY; + ux_flow_init(0, ux_sign_flow, NULL); + *flags |= IO_ASYNCH_REPLY; } diff --git a/src/sign_transaction.c b/src/sign_transaction.c index 657c768..3363522 100644 --- a/src/sign_transaction.c +++ b/src/sign_transaction.c @@ -6,185 +6,219 @@ #include "utils.h" static uint8_t set_result_sign_transaction() { - cx_ecfp_private_key_t privateKey; - SignTransactionContext_t *context = &data_context.sign_tr_context; - - BEGIN_TRY { - TRY { - get_private_key(context->account_number, &privateKey); - if (!context->sign_with_chain_id) { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, - TO_SIGN_LENGTH, NULL, 0, context->signature, - SIGNATURE_LENGTH, NULL); - } else { - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, - CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, - context->signature, SIGNATURE_LENGTH, NULL); - } + cx_ecfp_private_key_t privateKey; + SignTransactionContext_t *context = &data_context.sign_tr_context; + + BEGIN_TRY { + TRY { + get_private_key(context->account_number, &privateKey); + if (!context->sign_with_chain_id) { + cx_eddsa_sign(&privateKey, + CX_LAST, + CX_SHA512, + context->to_sign, + TO_SIGN_LENGTH, + NULL, + 0, + context->signature, + SIGNATURE_LENGTH, + NULL); + } else { + cx_eddsa_sign(&privateKey, + CX_LAST, + CX_SHA512, + context->to_sign, + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, + NULL, + 0, + context->signature, + SIGNATURE_LENGTH, + NULL); + } + } + FINALLY { + memset(&privateKey, 0, sizeof(privateKey)); + } } - FINALLY { memset(&privateKey, 0, sizeof(privateKey)); } - } - END_TRY; - - uint8_t tx = 0; - G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; - memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); - tx += SIGNATURE_LENGTH; - return tx; + END_TRY; + + uint8_t tx = 0; + G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH; + memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH); + tx += SIGNATURE_LENGTH; + return tx; } -UX_STEP_NOCB(ux_sign_transaction_intro, pnn, +UX_STEP_NOCB(ux_sign_transaction_intro, + pnn, { &C_icon_eye, "Review", "transaction", }); -UX_STEP_NOCB(ux_sign_transaction_burn, bnnn_paging, - {.title = "Action", .text = "Burn"}); -UX_STEP_NOCB(ux_sign_transaction_deploy, bnnn_paging, - {.title = "Action", .text = "Deploy"}); -UX_STEP_NOCB(ux_sign_transaction_confirm, bnnn_paging, - {.title = "Action", .text = "Confirm"}); -UX_STEP_NOCB(ux_sign_transaction_transfer, bnnn_paging, - {.title = "Action", .text = "Transfer"}); -UX_STEP_NOCB(ux_sign_transaction_amount, bnnn_paging, +UX_STEP_NOCB(ux_sign_transaction_burn, bnnn_paging, {.title = "Action", .text = "Burn"}); +UX_STEP_NOCB(ux_sign_transaction_deploy, bnnn_paging, {.title = "Action", .text = "Deploy"}); +UX_STEP_NOCB(ux_sign_transaction_confirm, bnnn_paging, {.title = "Action", .text = "Confirm"}); +UX_STEP_NOCB(ux_sign_transaction_transfer, bnnn_paging, {.title = "Action", .text = "Transfer"}); +UX_STEP_NOCB(ux_sign_transaction_amount, + bnnn_paging, { .title = "Amount", .text = data_context.sign_tr_context.amount_str, }); -UX_STEP_NOCB(ux_sign_transaction_address, bnnn_paging, +UX_STEP_NOCB(ux_sign_transaction_address, + bnnn_paging, { .title = "Address", .text = data_context.sign_tr_context.address_str, }); -UX_STEP_NOCB(ux_sign_transaction_transaction_id, bnnn_paging, +UX_STEP_NOCB(ux_sign_transaction_transaction_id, + bnnn_paging, { .title = "Transaction id", .text = data_context.sign_tr_context.transaction_id_str, }); -UX_STEP_CB(ux_sign_transaction_accept, pbb, +UX_STEP_CB(ux_sign_transaction_accept, + pbb, send_response(set_result_sign_transaction(), true), { &C_icon_validate_14, "Accept", "and send", }); -UX_STEP_CB(ux_sign_transaction_reject, pb, send_response(0, false), +UX_STEP_CB(ux_sign_transaction_reject, + pb, + send_response(0, false), { &C_icon_crossmark, "Reject", }); -UX_FLOW(ux_sign_transaction_burn_flow, &ux_sign_transaction_intro, - &ux_sign_transaction_burn, &ux_sign_transaction_amount, - &ux_sign_transaction_accept, &ux_sign_transaction_reject); +UX_FLOW(ux_sign_transaction_burn_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_burn, + &ux_sign_transaction_amount, + &ux_sign_transaction_accept, + &ux_sign_transaction_reject); -UX_FLOW(ux_sign_transaction_deploy_flow, &ux_sign_transaction_intro, - &ux_sign_transaction_deploy, &ux_sign_transaction_address, - &ux_sign_transaction_accept, &ux_sign_transaction_reject); +UX_FLOW(ux_sign_transaction_deploy_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_deploy, + &ux_sign_transaction_address, + &ux_sign_transaction_accept, + &ux_sign_transaction_reject); -UX_FLOW(ux_sign_transaction_confirm_flow, &ux_sign_transaction_intro, - &ux_sign_transaction_confirm, &ux_sign_transaction_transaction_id, - &ux_sign_transaction_accept, &ux_sign_transaction_reject); +UX_FLOW(ux_sign_transaction_confirm_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_confirm, + &ux_sign_transaction_transaction_id, + &ux_sign_transaction_accept, + &ux_sign_transaction_reject); -UX_FLOW(ux_sign_transaction_transfer_flow, &ux_sign_transaction_intro, - &ux_sign_transaction_transfer, &ux_sign_transaction_amount, - &ux_sign_transaction_address, &ux_sign_transaction_accept, +UX_FLOW(ux_sign_transaction_transfer_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_transfer, + &ux_sign_transaction_amount, + &ux_sign_transaction_address, + &ux_sign_transaction_accept, &ux_sign_transaction_reject); -void handleSignTransaction(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, - uint16_t dataLength, volatile unsigned int *flags, +void handleSignTransaction(uint8_t p1, + uint8_t p2, + uint8_t *dataBuffer, + uint16_t dataLength, + volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(tx); - - VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); - SignTransactionContext_t *context = &data_context.sign_tr_context; - - size_t offset = 0; - - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); - - context->origin_wallet_type = dataBuffer[offset]; - offset += sizeof(context->origin_wallet_type); - - context->decimals = dataBuffer[offset]; - offset += sizeof(context->decimals); - - uint8_t ticker_len = dataBuffer[offset]; - offset += sizeof(ticker_len); - - VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); - - memcpy(context->ticker, dataBuffer + offset, ticker_len); - offset += ticker_len; - - uint8_t metadata = dataBuffer[offset]; - offset += sizeof(metadata); - - // Read wallet type if present - if (metadata & FLAG_WITH_WALLET_ID) { - context->current_wallet_type = dataBuffer[offset]; - offset += sizeof(context->current_wallet_type); - } else { - context->current_wallet_type = context->origin_wallet_type; - } - - // Get address - uint8_t address[ADDRESS_LENGTH]; - get_address(context->account_number, context->origin_wallet_type, address); - memset(&boc_context, 0, sizeof(boc_context)); - - // Read wc if present - uint8_t wc = DEFAULT_WORKCHAIN_ID; - if (metadata & FLAG_WITH_WORKCHAIN_ID) { - wc = dataBuffer[offset]; - offset += sizeof(wc); - } - - // Read initial address if present - uint8_t prepend_address[ADDRESS_LENGTH]; - if (metadata & FLAG_WITH_ADDRESS) { - memcpy(prepend_address, dataBuffer + offset, ADDRESS_LENGTH); - offset += sizeof(address); - } else { - memcpy(prepend_address, address, ADDRESS_LENGTH); - } - - // Read chain id if present - if (metadata & FLAG_WITH_CHAIN_ID) { - context->sign_with_chain_id = true; - - memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); - offset += sizeof(context->chain_id); - } else { - context->sign_with_chain_id = false; - } - - uint8_t *msg_begin = dataBuffer + offset; - uint8_t msg_length = dataLength - offset; - - ByteStream_t src; - ByteStream_init(&src, msg_begin, msg_length); - - int flow = prepare_to_sign(&src, wc, address, prepend_address); - - switch (flow) { - case SIGN_TRANSACTION_FLOW_TRANSFER: - ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_DEPLOY: - ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_CONFIRM: - ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL); - break; - case SIGN_TRANSACTION_FLOW_BURN: - ux_flow_init(0, ux_sign_transaction_burn_flow, NULL); - break; - default: - THROW(ERR_INVALID_REQUEST); - } - - *flags |= IO_ASYNCH_REPLY; + UNUSED(tx); + + VALIDATE(p1 == P1_CONFIRM && p2 == 0, ERR_INVALID_REQUEST); + SignTransactionContext_t *context = &data_context.sign_tr_context; + + size_t offset = 0; + + context->account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(context->account_number); + + context->origin_wallet_type = dataBuffer[offset]; + offset += sizeof(context->origin_wallet_type); + + context->decimals = dataBuffer[offset]; + offset += sizeof(context->decimals); + + uint8_t ticker_len = dataBuffer[offset]; + offset += sizeof(ticker_len); + + VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); + + memcpy(context->ticker, dataBuffer + offset, ticker_len); + offset += ticker_len; + + uint8_t metadata = dataBuffer[offset]; + offset += sizeof(metadata); + + // Read wallet type if present + if (metadata & FLAG_WITH_WALLET_ID) { + context->current_wallet_type = dataBuffer[offset]; + offset += sizeof(context->current_wallet_type); + } else { + context->current_wallet_type = context->origin_wallet_type; + } + + // Get address + uint8_t address[ADDRESS_LENGTH]; + get_address(context->account_number, context->origin_wallet_type, address); + memset(&boc_context, 0, sizeof(boc_context)); + + // Read wc if present + uint8_t wc = DEFAULT_WORKCHAIN_ID; + if (metadata & FLAG_WITH_WORKCHAIN_ID) { + wc = dataBuffer[offset]; + offset += sizeof(wc); + } + + // Read initial address if present + uint8_t prepend_address[ADDRESS_LENGTH]; + if (metadata & FLAG_WITH_ADDRESS) { + memcpy(prepend_address, dataBuffer + offset, ADDRESS_LENGTH); + offset += sizeof(address); + } else { + memcpy(prepend_address, address, ADDRESS_LENGTH); + } + + // Read chain id if present + if (metadata & FLAG_WITH_CHAIN_ID) { + context->sign_with_chain_id = true; + + memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); + offset += sizeof(context->chain_id); + } else { + context->sign_with_chain_id = false; + } + + uint8_t *msg_begin = dataBuffer + offset; + uint8_t msg_length = dataLength - offset; + + ByteStream_t src; + ByteStream_init(&src, msg_begin, msg_length); + + int flow = prepare_to_sign(&src, wc, address, prepend_address); + + switch (flow) { + case SIGN_TRANSACTION_FLOW_TRANSFER: + ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_DEPLOY: + ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_CONFIRM: + ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL); + break; + case SIGN_TRANSACTION_FLOW_BURN: + ux_flow_init(0, ux_sign_transaction_burn_flow, NULL); + break; + default: + THROW(ERR_INVALID_REQUEST); + } + + *flags |= IO_ASYNCH_REPLY; } diff --git a/src/slice_data.c b/src/slice_data.c index 5868fe1..b8adf5e 100644 --- a/src/slice_data.c +++ b/src/slice_data.c @@ -3,205 +3,198 @@ #include "globals.h" #include "utils.h" -void SliceData_init(struct SliceData_t *self, uint8_t *data, - uint16_t data_size_bytes) { - VALIDATE(self && data, ERR_SLICE_IS_EMPTY); - self->data = data; - self->data_window_start = 0; - self->data_window_end = data_size_bytes * 8; - self->data_size_bytes = data_size_bytes; +void SliceData_init(struct SliceData_t *self, uint8_t *data, uint16_t data_size_bytes) { + VALIDATE(self && data, ERR_SLICE_IS_EMPTY); + self->data = data; + self->data_window_start = 0; + self->data_window_end = data_size_bytes * 8; + self->data_size_bytes = data_size_bytes; } void SliceData_from_cell(struct SliceData_t *self, struct Cell_t *cell) { - uint8_t *cell_data = Cell_get_data(cell); - uint8_t cell_data_size = Cell_get_data_size(cell); - SliceData_init(self, cell_data, cell_data_size); + uint8_t *cell_data = Cell_get_data(cell); + uint8_t cell_data_size = Cell_get_data_size(cell); + SliceData_init(self, cell_data, cell_data_size); } -void SliceData_fill(struct SliceData_t *self, uint8_t value, - uint16_t data_size_bytes) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(self->data_size_bytes >= data_size_bytes, ERR_INVALID_DATA); - memset(self->data, value, data_size_bytes); +void SliceData_fill(struct SliceData_t *self, uint8_t value, uint16_t data_size_bytes) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(self->data_size_bytes >= data_size_bytes, ERR_INVALID_DATA); + memset(self->data, value, data_size_bytes); } void SliceData_truncate(struct SliceData_t *self, uint16_t size) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(size <= self->data_window_end, ERR_CELL_UNDERFLOW); - self->data_window_end = size; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(size <= self->data_window_end, ERR_CELL_UNDERFLOW); + self->data_window_end = size; } uint16_t SliceData_remaining_bits(const struct SliceData_t *self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - if (self->data_window_start > self->data_window_end) { - return 0; - } - return self->data_window_end - self->data_window_start; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + if (self->data_window_start > self->data_window_end) { + return 0; + } + return self->data_window_end - self->data_window_start; } void SliceData_move_by(struct SliceData_t *self, uint16_t offset) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(self->data_window_start + offset <= self->data_window_end, - ERR_CELL_UNDERFLOW); - self->data_window_start += offset; -} - -uint8_t SliceData_get_bits(const struct SliceData_t *self, uint16_t offset, - uint8_t bits) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - VALIDATE(offset + bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); - VALIDATE(bits != 0 && bits <= 8, ERR_RANGE_CHECK); - - uint16_t index = self->data_window_start + offset; - uint8_t q = index / 8; - uint8_t r = index % 8; - if (r == 0) { - return self->data[q] >> (8 - r - bits); - } else if (bits <= (8 - r)) { - return self->data[q] >> (8 - r - bits) & ((1 << bits) - 1); - } else { - uint16_t ret = 0; - if (q < self->data_size_bytes) { - uint16_t byte = self->data[q]; - ret |= byte << 8; - } - if (q < self->data_size_bytes - 1) { - ret |= self->data[q + 1]; - } + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(self->data_window_start + offset <= self->data_window_end, ERR_CELL_UNDERFLOW); + self->data_window_start += offset; +} + +uint8_t SliceData_get_bits(const struct SliceData_t *self, uint16_t offset, uint8_t bits) { + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + VALIDATE(offset + bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); + VALIDATE(bits != 0 && bits <= 8, ERR_RANGE_CHECK); + + uint16_t index = self->data_window_start + offset; + uint8_t q = index / 8; + uint8_t r = index % 8; + if (r == 0) { + return self->data[q] >> (8 - r - bits); + } else if (bits <= (8 - r)) { + return self->data[q] >> (8 - r - bits) & ((1 << bits) - 1); + } else { + uint16_t ret = 0; + if (q < self->data_size_bytes) { + uint16_t byte = self->data[q]; + ret |= byte << 8; + } + if (q < self->data_size_bytes - 1) { + ret |= self->data[q + 1]; + } - ret = (ret >> (8 - r)) >> (8 - bits); - return (uint8_t)ret; - } + ret = (ret >> (8 - r)) >> (8 - bits); + return (uint8_t) ret; + } } uint8_t SliceData_get_next_bit(struct SliceData_t *self) { - uint8_t bit = SliceData_get_bits(self, 0, 1); - SliceData_move_by(self, 1); - return bit; + uint8_t bit = SliceData_get_bits(self, 0, 1); + SliceData_move_by(self, 1); + return bit; } uint8_t SliceData_get_byte(const struct SliceData_t *self, uint16_t offset) { - return SliceData_get_bits(self, offset, 8); + return SliceData_get_bits(self, offset, 8); } uint8_t SliceData_get_next_byte(struct SliceData_t *self) { - uint8_t value = SliceData_get_byte(self, 0); - SliceData_move_by(self, 8); - return value; + uint8_t value = SliceData_get_byte(self, 0); + SliceData_move_by(self, 8); + return value; } uint64_t SliceData_get_int(const struct SliceData_t *self, uint8_t bits) { - VALIDATE(bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); - VALIDATE(bits <= 64, ERR_RANGE_CHECK); - if (bits == 0) { - return 0; - } + VALIDATE(bits <= SliceData_remaining_bits(self), ERR_CELL_UNDERFLOW); + VALIDATE(bits <= 64, ERR_RANGE_CHECK); + if (bits == 0) { + return 0; + } - uint64_t value = 0; - uint8_t bytes = bits / 8; - for (uint8_t i = 0; i < bytes; ++i) { - uint64_t byte = SliceData_get_byte(self, 8 * i); - value |= byte << (8 * (7 - i)); - } + uint64_t value = 0; + uint8_t bytes = bits / 8; + for (uint8_t i = 0; i < bytes; ++i) { + uint64_t byte = SliceData_get_byte(self, 8 * i); + value |= byte << (8 * (7 - i)); + } - volatile uint8_t remainder = bits % 8; - if (remainder != 0) { - uint64_t r = SliceData_get_bits(self, bytes * 8, remainder); - value |= r << (8 * (7 - bytes) + (8 - remainder)); - } + volatile uint8_t remainder = bits % 8; + if (remainder != 0) { + uint64_t r = SliceData_get_bits(self, bytes * 8, remainder); + value |= r << (8 * (7 - bytes) + (8 - remainder)); + } - return value >> (64 - bits); + return value >> (64 - bits); } uint64_t SliceData_get_next_int(struct SliceData_t *self, uint8_t bits) { - uint64_t value = SliceData_get_int(self, bits); - SliceData_move_by(self, bits); - return value; + uint64_t value = SliceData_get_int(self, bits); + SliceData_move_by(self, bits); + return value; } uint64_t SliceData_get_next_size(struct SliceData_t *self, uint16_t max_value) { - if (max_value == 0) { - return 0; - } - uint8_t bits = 16 - leading_zeros(max_value); - uint64_t res = SliceData_get_next_int(self, bits); - return res; + if (max_value == 0) { + return 0; + } + uint8_t bits = 16 - leading_zeros(max_value); + uint64_t res = SliceData_get_next_int(self, bits); + return res; } bool SliceData_is_empty(const struct SliceData_t *self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_window_start >= self->data_window_end; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_window_start >= self->data_window_end; } -bool SliceData_equal(const struct SliceData_t *self, - const struct SliceData_t *other) { - uint32_t self_rb = SliceData_remaining_bits(self); - uint32_t other_rb = SliceData_remaining_bits(other); - if (self_rb != other_rb) { - return false; - } +bool SliceData_equal(const struct SliceData_t *self, const struct SliceData_t *other) { + uint32_t self_rb = SliceData_remaining_bits(self); + uint32_t other_rb = SliceData_remaining_bits(other); + if (self_rb != other_rb) { + return false; + } - return SliceData_get_int(self, self_rb) == SliceData_get_int(other, other_rb); + return SliceData_get_int(self, self_rb) == SliceData_get_int(other, other_rb); } uint16_t SliceData_get_cursor(const struct SliceData_t *self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_window_start; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_window_start; } uint8_t *SliceData_begin(const struct SliceData_t *self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data; } uint16_t SliceData_data_size(const struct SliceData_t *self) { - VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); - return self->data_size_bytes; -} - -void SliceData_append(struct SliceData_t *self, uint8_t *in, uint16_t bits, - bool append_tag) { - uint8_t bytes = bits / 8; - VALIDATE(bytes <= SliceData_remaining_bits(self) * 8, ERR_CELL_UNDERFLOW); - - uint16_t offset = self->data_window_start; - if (offset % 8 == 0 || bytes == 0) { - memcpy(self->data + offset / 8, in, bytes ? bytes : 1); - } else { - uint8_t shift = offset % 8; - uint8_t first_data_byte = offset / 8; - uint8_t prev = 0; - for (uint16_t i = first_data_byte, j = 0; j < bytes; ++i, ++j) { - VALIDATE(i == (j + first_data_byte) && i < self->data_size_bytes, - ERR_INVALID_DATA); - - uint8_t cur = in[j] >> shift; - if (j == 0) { - uint8_t first_byte = self->data[i] >> (8 - shift); - first_byte <<= 8 - shift; - self->data[i] = first_byte | cur; - } else { - self->data[i] = prev | cur; - } - - prev = in[j] << (8 - shift); - if (j == bytes - 1) { - uint8_t last_byte = prev; - if (append_tag) { - if (shift != 7) { - last_byte >>= 7 - shift; - } - last_byte |= 1; - if (shift != 7) { - last_byte <<= 7 - shift; - } - - bits += 8 - shift; + VALIDATE(self && self->data, ERR_SLICE_IS_EMPTY); + return self->data_size_bytes; +} + +void SliceData_append(struct SliceData_t *self, uint8_t *in, uint16_t bits, bool append_tag) { + uint8_t bytes = bits / 8; + VALIDATE(bytes <= SliceData_remaining_bits(self) * 8, ERR_CELL_UNDERFLOW); + + uint16_t offset = self->data_window_start; + if (offset % 8 == 0 || bytes == 0) { + memcpy(self->data + offset / 8, in, bytes ? bytes : 1); + } else { + uint8_t shift = offset % 8; + uint8_t first_data_byte = offset / 8; + uint8_t prev = 0; + for (uint16_t i = first_data_byte, j = 0; j < bytes; ++i, ++j) { + VALIDATE(i == (j + first_data_byte) && i < self->data_size_bytes, ERR_INVALID_DATA); + + uint8_t cur = in[j] >> shift; + if (j == 0) { + uint8_t first_byte = self->data[i] >> (8 - shift); + first_byte <<= 8 - shift; + self->data[i] = first_byte | cur; + } else { + self->data[i] = prev | cur; + } + + prev = in[j] << (8 - shift); + if (j == bytes - 1) { + uint8_t last_byte = prev; + if (append_tag) { + if (shift != 7) { + last_byte >>= 7 - shift; + } + last_byte |= 1; + if (shift != 7) { + last_byte <<= 7 - shift; + } + + bits += 8 - shift; + } + self->data[i + 1] = last_byte; + } } - self->data[i + 1] = last_byte; - } } - } - self->data_window_start += bits; + self->data_window_start += bits; } diff --git a/src/utils.c b/src/utils.c index 59bb067..b45c2ff 100644 --- a/src/utils.c +++ b/src/utils.c @@ -6,191 +6,203 @@ #include void get_public_key(uint32_t account_number, uint8_t *publicKeyArray) { - cx_ecfp_private_key_t privateKey; - cx_ecfp_public_key_t publicKey; - - get_private_key(account_number, &privateKey); - BEGIN_TRY { - TRY { cx_ecfp_generate_pair(CX_CURVE_Ed25519, &publicKey, &privateKey, 1); } - CATCH_OTHER(e) { THROW(e); } - FINALLY { explicit_bzero(&privateKey, sizeof(privateKey)); } - } - END_TRY; - - for (int i = 0; i < 32; i++) { - publicKeyArray[i] = publicKey.W[64 - i]; - } - if ((publicKey.W[32] & 1) != 0) { - publicKeyArray[31] |= 0x80; - } + cx_ecfp_private_key_t privateKey; + cx_ecfp_public_key_t publicKey; + + get_private_key(account_number, &privateKey); + BEGIN_TRY { + TRY { + cx_ecfp_generate_pair(CX_CURVE_Ed25519, &publicKey, &privateKey, 1); + } + CATCH_OTHER(e) { + THROW(e); + } + FINALLY { + explicit_bzero(&privateKey, sizeof(privateKey)); + } + } + END_TRY; + + for (int i = 0; i < 32; i++) { + publicKeyArray[i] = publicKey.W[64 - i]; + } + if ((publicKey.W[32] & 1) != 0) { + publicKeyArray[31] |= 0x80; + } } static const uint32_t HARDENED_OFFSET = 0x80000000; -void get_private_key(uint32_t account_number, - cx_ecfp_private_key_t *privateKey) { - const uint32_t derivePath[BIP32_PATH] = { - 44 | HARDENED_OFFSET, 396 | HARDENED_OFFSET, - account_number | HARDENED_OFFSET, 0 | HARDENED_OFFSET, - 0 | HARDENED_OFFSET}; - - uint8_t privateKeyData[32]; - BEGIN_TRY { - TRY { - os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10, CX_CURVE_Ed25519, - derivePath, BIP32_PATH, - privateKeyData, NULL, NULL, 0); - cx_ecfp_init_private_key(CX_CURVE_Ed25519, privateKeyData, 32, - privateKey); +void get_private_key(uint32_t account_number, cx_ecfp_private_key_t *privateKey) { + const uint32_t derivePath[BIP32_PATH] = {44 | HARDENED_OFFSET, + 396 | HARDENED_OFFSET, + account_number | HARDENED_OFFSET, + 0 | HARDENED_OFFSET, + 0 | HARDENED_OFFSET}; + + uint8_t privateKeyData[32]; + BEGIN_TRY { + TRY { + os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10, + CX_CURVE_Ed25519, + derivePath, + BIP32_PATH, + privateKeyData, + NULL, + NULL, + 0); + cx_ecfp_init_private_key(CX_CURVE_Ed25519, privateKeyData, 32, privateKey); + } + CATCH_OTHER(e) { + THROW(e); + } + FINALLY { + explicit_bzero(&privateKey, sizeof(privateKey)); + } } - CATCH_OTHER(e) { THROW(e); } - FINALLY { explicit_bzero(&privateKey, sizeof(privateKey)); } - } - END_TRY; + END_TRY; } void send_response(uint8_t tx, bool approve) { - G_io_apdu_buffer[tx++] = approve ? 0x90 : 0x69; - G_io_apdu_buffer[tx++] = approve ? 0x00 : 0x85; - reset_app_context(); - // Send back the response, do not restart the event loop - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); - // Display back the original UX - ui_idle(); + G_io_apdu_buffer[tx++] = approve ? 0x90 : 0x69; + G_io_apdu_buffer[tx++] = approve ? 0x00 : 0x85; + reset_app_context(); + // Send back the response, do not restart the event loop + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); + // Display back the original UX + ui_idle(); } unsigned int ui_prepro(const bagl_element_t *element) { - unsigned int display = 1; - if (element->component.userid > 0) { - display = (ux_step == element->component.userid - 1); - if (display) { - if (element->component.userid == 1) { - UX_CALLBACK_SET_INTERVAL(2000); - } else { - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - } + unsigned int display = 1; + if (element->component.userid > 0) { + display = (ux_step == element->component.userid - 1); + if (display) { + if (element->component.userid == 1) { + UX_CALLBACK_SET_INTERVAL(2000); + } else { + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + } + } } - } - return display; + return display; } void writeUint32BE(uint32_t val, uint8_t *bytes) { - bytes[0] = (val >> 24) & 0xFF; - bytes[1] = (val >> 16) & 0xFF; - bytes[2] = (val >> 8) & 0xFF; - bytes[3] = val & 0xFF; + bytes[0] = (val >> 24) & 0xFF; + bytes[1] = (val >> 16) & 0xFF; + bytes[2] = (val >> 8) & 0xFF; + bytes[3] = val & 0xFF; } void writeUint64BE(uint64_t val, uint8_t *bytes) { - bytes[0] = (val >> 56) & 0xFF; - bytes[1] = (val >> 48) & 0xFF; - bytes[2] = (val >> 40) & 0xFF; - bytes[3] = (val >> 32) & 0xFF; - bytes[4] = (val >> 24) & 0xFF; - bytes[5] = (val >> 16) & 0xFF; - bytes[6] = (val >> 8) & 0xFF; - bytes[7] = val & 0xFF; + bytes[0] = (val >> 56) & 0xFF; + bytes[1] = (val >> 48) & 0xFF; + bytes[2] = (val >> 40) & 0xFF; + bytes[3] = (val >> 32) & 0xFF; + bytes[4] = (val >> 24) & 0xFF; + bytes[5] = (val >> 16) & 0xFF; + bytes[6] = (val >> 8) & 0xFF; + bytes[7] = val & 0xFF; } uint16_t readUint16BE(uint8_t *buffer) { - return (buffer[0] << 8) | (buffer[1]); + return (buffer[0] << 8) | (buffer[1]); } uint32_t readUint32BE(uint8_t *buffer) { - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); } uint64_t readUint64BE(uint8_t *buffer) { - uint32_t i1 = - buffer[3] + (buffer[2] << 8u) + (buffer[1] << 16u) + (buffer[0] << 24u); - uint32_t i2 = - buffer[7] + (buffer[6] << 8u) + (buffer[5] << 16u) + (buffer[4] << 24u); - return i2 | ((uint64_t)i1 << 32u); + uint32_t i1 = buffer[3] + (buffer[2] << 8u) + (buffer[1] << 16u) + (buffer[0] << 24u); + uint32_t i2 = buffer[7] + (buffer[6] << 8u) + (buffer[5] << 16u) + (buffer[4] << 24u); + return i2 | ((uint64_t) i1 << 32u); } uint8_t leading_zeros(uint16_t value) { - uint8_t lz = 0; - uint16_t msb = 0x8000; - for (uint8_t i = 0; i < 16; ++i) { - if ((value << i) & msb) { - break; + uint8_t lz = 0; + uint16_t msb = 0x8000; + for (uint8_t i = 0; i < 16; ++i) { + if ((value << i) & msb) { + break; + } + ++lz; } - ++lz; - } - return lz; + return lz; } #define SCRATCH_SIZE 37 uint8_t convert_hex_amount_to_displayable(const uint8_t *amount, uint8_t decimals, - uint8_t amount_length, char *out) { - uint8_t LOOP1 = SCRATCH_SIZE - decimals; - uint8_t LOOP2 = decimals; - uint16_t scratch[SCRATCH_SIZE]; - uint8_t offset = 0; - uint8_t nonZero = 0; - uint8_t i; - uint8_t targetOffset = 0; - uint8_t workOffset; - uint8_t j; - uint8_t nscratch = SCRATCH_SIZE; - uint8_t smin = nscratch - 2; - uint8_t comma = 0; - - for (i = 0; i < SCRATCH_SIZE; i++) { - scratch[i] = 0; - } - for (i = 0; i < amount_length; i++) { - for (j = 0; j < 8; j++) { - uint8_t k; - uint16_t shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 : (short)0; - for (k = smin; k < nscratch; k++) { - scratch[k] += ((scratch[k] >= 5) ? 3 : 0); - } - if (scratch[smin] >= 8) { - smin -= 1; - } - for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); - } - scratch[nscratch - 1] = - ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0); + uint8_t amount_length, + char *out) { + uint8_t LOOP1 = SCRATCH_SIZE - decimals; + uint8_t LOOP2 = decimals; + uint16_t scratch[SCRATCH_SIZE]; + uint8_t offset = 0; + uint8_t nonZero = 0; + uint8_t i; + uint8_t targetOffset = 0; + uint8_t workOffset; + uint8_t j; + uint8_t nscratch = SCRATCH_SIZE; + uint8_t smin = nscratch - 2; + uint8_t comma = 0; + + for (i = 0; i < SCRATCH_SIZE; i++) { + scratch[i] = 0; } - } - - for (i = 0; i < LOOP1; i++) { - if (!nonZero && (scratch[offset] == 0)) { - offset++; - } else { - nonZero = 1; - out[targetOffset++] = scratch[offset++] + '0'; + for (i = 0; i < amount_length; i++) { + for (j = 0; j < 8; j++) { + uint8_t k; + uint16_t shifted_in = + (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short) 1 : (short) 0; + for (k = smin; k < nscratch; k++) { + scratch[k] += ((scratch[k] >= 5) ? 3 : 0); + } + if (scratch[smin] >= 8) { + smin -= 1; + } + for (k = smin; k < nscratch - 1; k++) { + scratch[k] = ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); + } + scratch[nscratch - 1] = + ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0); + } } - } - if (targetOffset == 0) { - out[targetOffset++] = '0'; - } - workOffset = offset; - for (i = 0; i < LOOP2; i++) { - unsigned char allZero = 1; - unsigned char j; - for (j = i; j < LOOP2; j++) { - if (scratch[workOffset + j] != 0) { - allZero = 0; - break; - } + + for (i = 0; i < LOOP1; i++) { + if (!nonZero && (scratch[offset] == 0)) { + offset++; + } else { + nonZero = 1; + out[targetOffset++] = scratch[offset++] + '0'; + } } - if (allZero) { - break; + if (targetOffset == 0) { + out[targetOffset++] = '0'; } - if (!comma) { - out[targetOffset++] = '.'; - comma = 1; + workOffset = offset; + for (i = 0; i < LOOP2; i++) { + unsigned char allZero = 1; + unsigned char j; + for (j = i; j < LOOP2; j++) { + if (scratch[workOffset + j] != 0) { + allZero = 0; + break; + } + } + if (allZero) { + break; + } + if (!comma) { + out[targetOffset++] = '.'; + comma = 1; + } + out[targetOffset++] = scratch[offset++] + '0'; } - out[targetOffset++] = scratch[offset++] + '0'; - } - return targetOffset; + return targetOffset; } From 635d789e34716527ef9cdd009cc7a38295596ddb Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 13 Feb 2025 13:14:32 +0100 Subject: [PATCH 32/33] test: add 2 test cases and refactor how tests run - Introduce `run_test` function to reduce code duplication - Add new test cases for USDT burn and transaction confirmation - Maintain existing test coverage for transaction signing - Improve test structure and readability --- tests/test_sign_cmd.py | 90 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py index 5e36c3a..c208eb2 100644 --- a/tests/test_sign_cmd.py +++ b/tests/test_sign_cmd.py @@ -10,42 +10,98 @@ from application_client.everscale_response_unpacker import unpack_sign_tx_response from utils import navigate_until_text_and_compare -# In this tests we check the behavior of the device when asked to sign a transaction - -# In this test we send to the device a transaction to sign and validate it on screen -# The transaction is short and will be sent in one chunk -# We will ensure that the displayed information is correct by using screenshots comparison - -@pytest.mark.active_test_scope -def test_sign_tx_transfer(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str) -> None: +def run_test( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, + transaction: str, + expected_signature: str, +) -> None: # Use the app interface instead of raw interface client = EverscaleCommandSender(backend) # Raw transaction - transaction = bytes.fromhex("00000000010904455645520001010301006c000161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7cfb9642b3d6449ea677323640010165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d038020000") - + transaction_bytes = bytes.fromhex(transaction) # Send the sign device instruction. # As it requires on-screen validation, the function is asynchronous. # It will yield the result when the navigation is done - with client.sign_tx(transaction): + with client.sign_tx(transaction_bytes): # Validate the on-screen request by performing the navigation appropriate for this device navigate_until_text_and_compare( - backend.firmware, - navigator, - "Accept", - default_screenshot_path, - test_name + backend.firmware, navigator, "Accept", default_screenshot_path, test_name ) # The device as yielded the result, parse it and ensure that the signature is correct response = client.get_async_response().data _, der_sig, _ = unpack_sign_tx_response(response) - assert der_sig.hex() == "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808" + assert der_sig.hex() == expected_signature + + +# In this tests we check the behavior of the device when asked to sign a transaction + + +# In this test we send to the device a transaction to sign and validate it on screen +# The transaction is short and will be sent in one chunk +# We will ensure that the displayed information is correct by using screenshots comparison + + +@pytest.mark.active_test_scope +def test_sign_tx_burn_usdt( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "0000000001090455534454000101040100c9002161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e2c951fb3d692b2a677323640012165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d03802216b562548ad00000000000000000000000049504f808015e4256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ad00328480101c03bf4894e22cdd500e450cbe5838b9938fda1e4d3727fe3b5385c5114b0293f0001", # Transaction + "a8b3ee327f6a64945e875d59ec49b12bea553b30170be65c541176f052156035428f8a0180e9f8802622b4f3339f2161076790b822e55c0d46f01b919f6de005", # Expected_signature + ) + +@pytest.mark.active_test_scope +def test_sign_tx_confirm( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "00000000020904455645520001010101003b000071b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e395aa2b3d695f78d53a076b24a0de621e6767fc0", # Transaction + "8a5a9435d8b85f37f0d0b6dd0cb39521c8acf3f04cff7d53a4fb83e05313baace8b63b0fc3d8e6d0f9dd1922bc65df11efbecb9c34e4c79ec2a7267d67613e0e", # Expected_signature + ) + + # TODO: Add tests for the other transaction types + +@pytest.mark.active_test_scope +def test_sign_tx_transfer( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "00000000010904455645520001010301006c000161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7cfb9642b3d6449ea677323640010165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d038020000", # Transaction + "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808", # Expected_signature + ) + + # # In this test we send to the device a transaction to trig a blind-signing flow # # The transaction is short and will be sent in one chunk # # We will ensure that the displayed information is correct by using screenshots comparison From 4d2dab104716560b3794f602722520094bac620e Mon Sep 17 00:00:00 2001 From: keiff3r Date: Thu, 13 Feb 2025 13:14:52 +0100 Subject: [PATCH 33/33] test: generate golden snapshots --- .../nanosp/test_sign_tx_burn_usdt/00000.png | Bin 0 -> 414 bytes .../nanosp/test_sign_tx_burn_usdt/00001.png | Bin 0 -> 341 bytes .../nanosp/test_sign_tx_burn_usdt/00002.png | Bin 0 -> 387 bytes .../nanosp/test_sign_tx_burn_usdt/00003.png | Bin 0 -> 472 bytes .../nanosp/test_sign_tx_burn_usdt/00004.png | Bin 0 -> 382 bytes .../nanosp/test_sign_tx_confirm/00000.png | Bin 0 -> 414 bytes .../nanosp/test_sign_tx_confirm/00001.png | Bin 0 -> 354 bytes .../nanosp/test_sign_tx_confirm/00002.png | Bin 0 -> 518 bytes .../nanosp/test_sign_tx_confirm/00003.png | Bin 0 -> 472 bytes .../nanosp/test_sign_tx_confirm/00004.png | Bin 0 -> 382 bytes .../nanox/test_sign_tx_burn_usdt/00000.png | Bin 0 -> 414 bytes .../nanox/test_sign_tx_burn_usdt/00001.png | Bin 0 -> 341 bytes .../nanox/test_sign_tx_burn_usdt/00002.png | Bin 0 -> 387 bytes .../nanox/test_sign_tx_burn_usdt/00003.png | Bin 0 -> 472 bytes .../nanox/test_sign_tx_burn_usdt/00004.png | Bin 0 -> 382 bytes .../nanox/test_sign_tx_confirm/00000.png | Bin 0 -> 414 bytes .../nanox/test_sign_tx_confirm/00001.png | Bin 0 -> 354 bytes .../nanox/test_sign_tx_confirm/00002.png | Bin 0 -> 518 bytes .../nanox/test_sign_tx_confirm/00003.png | Bin 0 -> 472 bytes .../nanox/test_sign_tx_confirm/00004.png | Bin 0 -> 382 bytes 20 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_burn_usdt/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_confirm/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_confirm/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_confirm/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_confirm/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_tx_confirm/00004.png create mode 100644 tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png create mode 100644 tests/snapshots/nanox/test_sign_tx_burn_usdt/00001.png create mode 100644 tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png create mode 100644 tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png create mode 100644 tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png create mode 100644 tests/snapshots/nanox/test_sign_tx_confirm/00000.png create mode 100644 tests/snapshots/nanox/test_sign_tx_confirm/00001.png create mode 100644 tests/snapshots/nanox/test_sign_tx_confirm/00002.png create mode 100644 tests/snapshots/nanox/test_sign_tx_confirm/00003.png create mode 100644 tests/snapshots/nanox/test_sign_tx_confirm/00004.png diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..487ea10fcfeb2f3e6b79239459672251d49addd7 GIT binary patch literal 414 zcmV;P0b%}$P)vpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*>=5`jjNzMlT@h zzae7@N*=PmmFN!W3v{U6=P$CIoUrWl5+z{O*Y_}3zl4#8 zS9qDnBmjVyl&%>Ugr`i8m3IrxoPjI3NXAygp?-VZj{A-D$)0uw6C~h#4|%(JE?JwP z%>)UUC6v!e*9-b@Bw(;uf)d{5J1--ra}eH1ztvoR46^9o=0T`M|7LP9k}5RPL6GI( nQo;)W00000000000GIg$)?uOm8>e-)00000NkvXXu0mjfI1rXX literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..96a5caeb32a1bfacfd54f0948eccd45612dd33fe GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh3=ZQjEQJPv_T zrNZCjPwxK0%o)kTw1n5}lx@68tBp@Vg8)ePaUns$jr+Kn^IuDID7MJ_O09jce82rQ z^9w3UhQ~yf#dti8Sy<(=UF%%%9Ix=rN%l-#=7IlxHePOB6!mX=HRoNM>B&9YF7nG+ zDa`CTYWT?S(@EC2pbPs1|4jVIabe}p8F!-ll8@RbUpN0szqo2f-nMHpzt^chTXNiPesljD^DW;d9?RbLN6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*q z+M3y2)wY&DZVGHbP#55RN*S$|OIDf|DGuQM=U!cu9 zmS~*aG1Yd*zoJUUr*DgA%g;W!{NHn#N1PG6(r5en{@j|keWtpDzWHUQZLYSZQD>ih zE-0|rx%qXlGsZJQ4umW81t!G-80Oy4G#!ONC^M{0J!dBSD~DD zufjc1(-&)=m2+-q;-7V3Zxdg;3aN6=&-0WeQ}?^9pgN{pZzI**q}_R`TBKsNidL-F z+d7@L7JY87D2Rc3iRn_FKO`<3-t9Nx;U zoe%&300FMkQ0u59HQ$q+m%M(Y`hJ<3lZ?(qwIQ|V&YFR+)Es%KJ)F~d^A)e#;)rG# zspg70!&1&)12tE|tnRhqA7cKqls3}8D6B)el`c)yjD`8R4&$s-TxYI7QnWI~YG~yY zbFoVvt_kpeg|B?62WHn_Hdb?X>7?%SLlrrW7CU(PZ|#%Hirns6L#maNzQ_cKH;PVU z{z!|O)qkiA8*1A=&dVx8}jQ%ys zP&4|MF$ceiUFbIr2AMfHis1zS0000000000000000055p2Gz6PuVm3B+W-In07*qo IM6N<$f6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*>=5`jjNzMlT@h zzae7@N*=PmmFN!W3v{U6=P$CIoUrWl5+z{O*Y_}3zl4#8 zS9qDnBmjVyl&%>Ugr`i8m3IrxoPjI3NXAygp?-VZj{A-D$)0uw6C~h#4|%(JE?JwP z%>)UUC6v!e*9-b@Bw(;uf)d{5J1--ra}eH1ztvoR46^9o=0T`M|7LP9k}5RPL6GI( nQo;)W00000000000GIg$)?uOm8>e-)00000NkvXXu0mjfI1rXX literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..96a5caeb32a1bfacfd54f0948eccd45612dd33fe GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh3=ZQjEQJPv_T zrNZCjPwxK0%o)kTw1n5}lx@68tBp@Vg8)ePaUns$jr+Kn^IuDID7MJ_O09jce82rQ z^9w3UhQ~yf#dti8Sy<(=UF%%%9Ix=rN%l-#=7IlxHePOB6!mX=HRoNM>B&9YF7nG+ zDa`CTYWT?S(@EC2pbPs1|4jVIabe}p8F!-ll8@RbUpN0szqo2f-nMHpzt^chTXNiPesljD^DW;d9?RbLN6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*q z+M3y2)wY&DZVGHbP#55RN*S$|OIDf|DGuQM=U!cu9 zmS~*aG1Yd*zoJUUr*DgA%g;W!{NHn#N1PG6(r5en{@j|keWtpDzWHUQZLYSZQD>ih zE-0|rx%qXlGsZJQ4umW81t!G-80Oy4G#!ONC^M{0J!dBSD~DD zufjc1(-&)=m2+-q;-7V3Zxdg;3aN6=&-0WeQ}?^9pgN{pZzI**q}_R`TBKsNidL-F z+d7@L7JY87D2Rc3iRn_FKO`<3-t9Nx;U zoe%&300FMkQ0u59HQ$q+m%M(Y`hJ<3lZ?(qwIQ|V&YFR+)Es%KJ)F~d^A)e#;)rG# zspg70!&1&)12tE|tnRhqA7cKqls3}8D6B)el`c)yjD`8R4&$s-TxYI7QnWI~YG~yY zbFoVvt_kpeg|B?62WHn_Hdb?X>7?%SLlrrW7CU(PZ|#%Hirns6L#maNzQ_cKH;PVU z{z!|O)qkiA8*1A=&dVx8}jQ%ys zP&4|MF$ceiUFbIr2AMfHis1zS0000000000000000055p2Gz6PuVm3B+W-In07*qo IM6N<$f6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o