From a90d59cdda13c6b16d93aa00569524a3f71e5d58 Mon Sep 17 00:00:00 2001 From: keiff3r Date: Wed, 5 Feb 2025 20:14:20 +0100 Subject: [PATCH] feat: edit the structure of the app - Separate the logic from the display - Add the structure for nbgl display - Add some github workflows --- .../workflows/build_and_functional_tests.yml | 43 ++++ .github/workflows/ci.yml | 100 ++++---- .github/workflows/codeql_checks.yml | 44 ++++ .github/workflows/coding_style_checks.yml | 25 ++ .../workflows/documentation_generation.yml | 29 +++ .github/workflows/misspellings_checks.yml | 29 +++ .github/workflows/python_client_checks.yml | 44 ++++ .github/workflows/unit_tests.yml | 60 +++++ Makefile | 4 +- ledger_app.toml | 2 +- src/get_address.c | 81 ------ src/get_public_key.c | 65 ----- src/handler/get_address.c | 34 +++ src/{ => handler}/get_app_configuration.c | 0 src/handler/get_public_key.c | 28 +++ src/handler/sign.c | 39 +++ src/handler/sign_transaction.c | 88 +++++++ src/main.c | 2 +- src/menu.h | 9 - src/sign.c | 104 -------- src/sign_transaction.c | 234 ------------------ src/ui/display.h | 7 + src/ui/display_bagl.c | 168 +++++++++++++ src/ui/display_nbgl.c | 41 +++ src/ui/menu.h | 8 + src/{menu.c => ui/menu_bagl.c} | 6 +- src/ui/menu_nbgl.c | 6 + src/utils.c | 71 +++++- src/utils.h | 6 + 29 files changed, 828 insertions(+), 549 deletions(-) create mode 100644 .github/workflows/build_and_functional_tests.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 delete mode 100644 src/get_address.c delete mode 100644 src/get_public_key.c create mode 100644 src/handler/get_address.c rename src/{ => handler}/get_app_configuration.c (100%) create mode 100644 src/handler/get_public_key.c create mode 100644 src/handler/sign.c create mode 100644 src/handler/sign_transaction.c delete mode 100644 src/menu.h delete mode 100644 src/sign.c delete mode 100644 src/sign_transaction.c create mode 100644 src/ui/display.h create mode 100644 src/ui/display_bagl.c create mode 100644 src/ui/display_nbgl.c create mode 100644 src/ui/menu.h rename src/{menu.c => ui/menu_bagl.c} (88%) create mode 100644 src/ui/menu_nbgl.c diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml new file mode 100644 index 0000000..5f7e434 --- /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 snaphots 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/ci.yml b/.github/workflows/ci.yml index 30ba6e0..64337e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,53 +1,53 @@ -name: CI +# 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: +# 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 +# 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 +# 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 diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml new file mode 100644 index 0000000..73d0fb9 --- /dev/null +++ b/.github/workflows/codeql_checks.yml @@ -0,0 +1,44 @@ +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: + 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@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + 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@v2 diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml new file mode 100644 index 0000000..b14f43c --- /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 Concordium 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: 11 diff --git a/.github/workflows/documentation_generation.yml b/.github/workflows/documentation_generation.yml new file mode 100644 index 0000000..1d00c2e --- /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@v3 + + - name: HTML documentation + run: doxygen .doxygen/Doxyfile + + - uses: actions/upload-artifact@v3 + 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..07037e9 --- /dev/null +++ b/.github/workflows/misspellings_checks.yml @@ -0,0 +1,29 @@ +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@v3 + + - name: Check misspellings + uses: codespell-project/actions-codespell@v1 + with: + builtin: clear,rare + check_filenames: true + skip: "*.ai,submission_graphics/*,./.git" diff --git a/.github/workflows/python_client_checks.yml b/.github/workflows/python_client_checks.yml new file mode 100644 index 0000000..48e87ff --- /dev/null +++ b/.github/workflows/python_client_checks.yml @@ -0,0 +1,44 @@ +name: Checks on the Python client + +# This workflow performs some checks on the Python client used by the Concordium 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: Concordium client linting + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v3 + - 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@v3 + - 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..dd93f24 --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,60 @@ +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@v3 + + - name: Clone SDK + uses: actions/checkout@v3 + 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@v3 + with: + name: code-coverage + path: unit-tests/coverage + + - name: Upload to codecov.io + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./unit-tests/coverage.info + flags: unittests + name: codecov-app-concordium + fail_ci_if_error: true + verbose: true + env: + CODECOV_DEBUG: true diff --git a/Makefile b/Makefile index a679a22..554e386 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ endif APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) # Pending review parameters -APP_LOAD_PARAMS += --tlvraw 9F:01 -DEFINES += HAVE_PENDING_REVIEW_SCREEN +# APP_LOAD_PARAMS += --tlvraw 9F:01 +# DEFINES += HAVE_PENDING_REVIEW_SCREEN ################## # Define Version # diff --git a/ledger_app.toml b/ledger_app.toml index 8f4c403..9cb05b7 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -1,4 +1,4 @@ [app] build_directory = "./" sdk = "C" -devices = ["nanos", "nanox", "nanos+"] +devices = ["nanos", "nanos+", "nanox", "flex", "stax"] diff --git a/src/get_address.c b/src/get_address.c deleted file mode 100644 index 36ec21f..0000000 --- a/src/get_address.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "apdu_constants.h" -#include "globals.h" -#include "utils.h" -#include "contract.h" -#include "slice_data.h" -#include "byte_stream.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; -} - -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 -); - -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; - - uint32_t account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(account_number); - - uint8_t wallet_type = dataBuffer[offset];; - - 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; - } - - THROW(ERR_INVALID_REQUEST); -} diff --git a/src/get_public_key.c b/src/get_public_key.c deleted file mode 100644 index a9b3889..0000000 --- a/src/get_public_key.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "os.h" -#include "ux.h" -#include "utils.h" -#include "apdu_constants.h" -#include "errors.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; -} - -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 -); - -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); - } - - 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); -} diff --git a/src/handler/get_address.c b/src/handler/get_address.c new file mode 100644 index 0000000..b6ccc7a --- /dev/null +++ b/src/handler/get_address.c @@ -0,0 +1,34 @@ +#include "apdu_constants.h" +#include "globals.h" +#include "utils.h" +#include "contract.h" +#include "slice_data.h" +#include "byte_stream.h" +#include "display.h" + +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; + + uint32_t account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(account_number); + + uint8_t wallet_type = dataBuffer[offset];; + + 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); + ui_display_address(); + *flags |= IO_ASYNCH_REPLY; + return; + } + + THROW(ERR_INVALID_REQUEST); +} diff --git a/src/get_app_configuration.c b/src/handler/get_app_configuration.c similarity index 100% rename from src/get_app_configuration.c rename to src/handler/get_app_configuration.c diff --git a/src/handler/get_public_key.c b/src/handler/get_public_key.c new file mode 100644 index 0000000..c905fad --- /dev/null +++ b/src/handler/get_public_key.c @@ -0,0 +1,28 @@ +#include "os.h" +#include "ux.h" +#include "utils.h" +#include "apdu_constants.h" +#include "errors.h" +#include "display.h" + +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); + } + + if (p1 == P1_CONFIRM) { + snprintf(context->public_key_str, sizeof(context->public_key_str), "%.*H", sizeof(context->public_key), context->public_key); + ui_display_public_key(); + *flags |= IO_ASYNCH_REPLY; + return; + + } + + THROW(ERR_INVALID_REQUEST); +} diff --git a/src/handler/sign.c b/src/handler/sign.c new file mode 100644 index 0000000..913a10b --- /dev/null +++ b/src/handler/sign.c @@ -0,0 +1,39 @@ +#include "apdu_constants.h" +#include "utils.h" +#include "errors.h" +#include "display.h" + +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; + + size_t offset = 0; + + context->account_number = readUint32BE(dataBuffer + offset); + offset += sizeof(context->account_number); + + 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; + + 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); + } + + ui_display_sign(); + *flags |= IO_ASYNCH_REPLY; +} diff --git a/src/handler/sign_transaction.c b/src/handler/sign_transaction.c new file mode 100644 index 0000000..10c99f8 --- /dev/null +++ b/src/handler/sign_transaction.c @@ -0,0 +1,88 @@ +#include "apdu_constants.h" +#include "utils.h" +#include "errors.h" +#include "byte_stream.h" +#include "message.h" +#include "contract.h" +#include "display.h" + + +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); + + ui_display_sign_transaction(flow); + + *flags |= IO_ASYNCH_REPLY; +} diff --git a/src/main.c b/src/main.c index fc1f0f1..86fb937 100644 --- a/src/main.c +++ b/src/main.c @@ -288,7 +288,7 @@ __attribute__((section(".boot"))) int main(void) { USB_power(0); USB_power(1); - ui_idle(); + ui_main_menu(); #ifdef HAVE_BLE BLE_power(0, NULL); diff --git a/src/menu.h b/src/menu.h deleted file mode 100644 index 3ce029f..0000000 --- a/src/menu.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "globals.h" -#include "glyphs.h" - -#ifndef _MENU_H_ -#define _MENU_H_ - -void ui_idle(void); - -#endif diff --git a/src/sign.c b/src/sign.c deleted file mode 100644 index d6b0740..0000000 --- a/src/sign.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "apdu_constants.h" -#include "utils.h" -#include "errors.h" - -static uint8_t set_result_sign() { - 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)); - } - } - 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_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 -); - -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; - - size_t offset = 0; - - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); - - 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; - - 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); - } - - ux_flow_init(0, ux_sign_flow, NULL); - *flags |= IO_ASYNCH_REPLY; -} diff --git a/src/sign_transaction.c b/src/sign_transaction.c deleted file mode 100644 index d5f5639..0000000 --- a/src/sign_transaction.c +++ /dev/null @@ -1,234 +0,0 @@ -#include "apdu_constants.h" -#include "utils.h" -#include "errors.h" -#include "byte_stream.h" -#include "message.h" -#include "contract.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)); - } - } - 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; -} diff --git a/src/ui/display.h b/src/ui/display.h new file mode 100644 index 0000000..e7efb9e --- /dev/null +++ b/src/ui/display.h @@ -0,0 +1,7 @@ +#pragma once + +void ui_display_address(); +void ui_display_public_key(); +void ui_display_sign_transaction(int flow); +void ui_display_sign(); + diff --git a/src/ui/display_bagl.c b/src/ui/display_bagl.c new file mode 100644 index 0000000..1840cc7 --- /dev/null +++ b/src/ui/display_bagl.c @@ -0,0 +1,168 @@ +#ifdef HAVE_BAGL + +#include "apdu_constants.h" +#include "contract.h" +#include "display.h" +#include "globals.h" +#include "utils.h" + +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_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_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); + +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); + +void ui_display_address() { ux_flow_init(0, ux_display_address_flow, NULL); } + +void ui_display_public_key() { ux_flow_init(0, ux_display_public_flow, NULL); } + +void ui_display_sign_transaction(int flow) { + 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); + break; + } +} + +void ui_display_sign() { ux_flow_init(0, ux_sign_flow, NULL); } + +#endif \ No newline at end of file diff --git a/src/ui/display_nbgl.c b/src/ui/display_nbgl.c new file mode 100644 index 0000000..391b2e0 --- /dev/null +++ b/src/ui/display_nbgl.c @@ -0,0 +1,41 @@ +#ifdef HAVE_NBGL + +#include "display.h" +#include "globals.h" +#include "utils.h" +#include "apdu_constants.h" +#include "contract.h" + +// TODO: Implement this +void ui_display_address() { + +} + +// TODO: Implement this +void ui_display_public_key() { + +} + +// TODO: Implement this +void ui_display_sign_transaction(int flow) { + switch (flow) { + case SIGN_TRANSACTION_FLOW_TRANSFER: + break; + case SIGN_TRANSACTION_FLOW_DEPLOY: + break; + case SIGN_TRANSACTION_FLOW_CONFIRM: + break; + case SIGN_TRANSACTION_FLOW_BURN: + break; + default: + THROW(ERR_INVALID_REQUEST); + break; + } +} + +// TODO: Implement this +void ui_display_sign() { + +} + +#endif \ No newline at end of file diff --git a/src/ui/menu.h b/src/ui/menu.h new file mode 100644 index 0000000..fb980ac --- /dev/null +++ b/src/ui/menu.h @@ -0,0 +1,8 @@ +#include "globals.h" +#include "glyphs.h" + +#pragma once + +void ui_main_menu(void); + +void ui_about_menu(void); diff --git a/src/menu.c b/src/ui/menu_bagl.c similarity index 88% rename from src/menu.c rename to src/ui/menu_bagl.c index 45d143f..a50e993 100644 --- a/src/menu.c +++ b/src/ui/menu_bagl.c @@ -1,3 +1,5 @@ +#ifdef HAVE_BAGL + #include "menu.h" #include "os.h" @@ -31,10 +33,12 @@ UX_FLOW(ux_idle_flow, FLOW_LOOP ); -void ui_idle(void) { +void ui_main_menu(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); } + +#endif \ No newline at end of file diff --git a/src/ui/menu_nbgl.c b/src/ui/menu_nbgl.c new file mode 100644 index 0000000..7e5405b --- /dev/null +++ b/src/ui/menu_nbgl.c @@ -0,0 +1,6 @@ +#ifdef HAVE_NBGL + +#include "menu.h" + + +#endif \ No newline at end of file diff --git a/src/utils.c b/src/utils.c index 058788c..0bfccb1 100644 --- a/src/utils.c +++ b/src/utils.c @@ -75,7 +75,7 @@ void send_response(uint8_t tx, bool approve) { // 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(); + ui_main_menu(); } unsigned int ui_prepro(const bagl_element_t *element) { @@ -210,3 +210,72 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal } return targetOffset; } + +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 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 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)); + } + } + 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 set_result_sign() { + 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)); + } + } + 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; +} + diff --git a/src/utils.h b/src/utils.h index 0fa396c..8a131ff 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,4 +32,10 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal #define PRINT_LINE() PRINTF("Print line %s: %d\n", __FILE__, __LINE__) +uint8_t set_result_get_address(); +uint8_t set_result_get_public_key(); +uint8_t set_result_sign_transaction(); +uint8_t set_result_sign(); + + #endif