diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5480d6b --- /dev/null +++ b/.clang-format @@ -0,0 +1,21 @@ +--- +BasedOnStyle: Google +IndentWidth: 4 +Language: Cpp +ColumnLimit: 100 +DerivePointerAlignment: false +PointerAlignment: Left +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/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..98b720f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +# Checklist + +- [ ] App update process has been followed +- [ ] Target branch is `develop` +- [ ] Application version has been bumped + + diff --git a/.github/workflows/build-workflow.yml b/.github/workflows/build-workflow.yml deleted file mode 100644 index 5ee747a..0000000 --- a/.github/workflows/build-workflow.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Compilation - -on: - push: - branches: - - master - pull_request: - branches: - - master - - develop - workflow_dispatch: - -jobs: - nano_release_build: - name: Build release application for NanoS, X and S+ - strategy: - matrix: - sdk: ["$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK"] - 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: Build Everscale - run: | - make -j BOLOS_SDK=${{ matrix.sdk }} - - - name: Build Venom - run: | - make clean - make -j BOLOS_SDK=${{ matrix.sdk }} CHAIN=venom 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/ci-workflow.yml b/.github/workflows/ci-workflow.yml deleted file mode 100644 index cd28f5d..0000000 --- a/.github/workflows/ci-workflow.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: CI - -on: - push: - branches: - - master - pull_request: - branches: - - master - - develop - workflow_dispatch: - -jobs: - scan-build: - name: Clang Static Analyzer - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - uses: actions/checkout@v3 - - - 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@v3 - if: failure() - with: - name: scan-build - path: scan-build - - - # ===================================================== - # SPECULOS TESTS - # ===================================================== - - - building_for_e2e_speculos_tests: - name: Building binaries for E2E Speculos tests - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - uses: actions/checkout@v3 - - - name: Build testing binaries - run: | - mkdir tests/speculos/elfs - make clean && make -j DEBUG=1 BOLOS_SDK=$NANOS_SDK && mv bin/app.elf tests/speculos/elfs/nanos.elf - make clean && make -j DEBUG=1 BOLOS_SDK=$NANOX_SDK && mv bin/app.elf tests/speculos/elfs/nanox.elf - make clean && make -j DEBUG=1 BOLOS_SDK=$NANOSP_SDK && mv bin/app.elf tests/speculos/elfs/nanosp.elf - - - name: Upload app binaries - uses: actions/upload-artifact@v3 - with: - name: e2e_speculos_elfs - path: ./tests/speculos/elfs - - - jobs-e2e-speculos-tests: - name: Speculos tests - strategy: - fail-fast: false - matrix: - model: ["nanos", "nanox", "nanosp"] - - needs: [building_for_e2e_speculos_tests] - runs-on: ubuntu-latest - - steps: - - name: Clone - uses: actions/checkout@v3 - - - name: Create tmp folder for artifacts - run: mkdir tests/speculos/elfs - - - name: Download app binaries - uses: actions/download-artifact@v3 - with: - path: tmp/ - - - name: Gather elfs - run: cp `find tmp/e2e_speculos_elfs/ -name "*.elf"` tests/speculos/elfs/ - - - name: Install dependencies - run: | - cd tests/speculos - sudo apt-get update && sudo apt-get install -y qemu-user-static - pip install -r requirements.txt - - - name: Run speculos tests - run: | - cd tests/speculos - # pytest --model ${{ matrix.model }} --path ./elfs/${{ matrix.model }}.elf --display headless diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml new file mode 100644 index 0000000..a0c4c5b --- /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"] + # '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/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml new file mode 100644 index 0000000..fdaf9f2 --- /dev/null +++ b/.github/workflows/guidelines_enforcer.yml @@ -0,0 +1,23 @@ +name: Ensure compliance with Ledger guidelines + +# This workflow is mandatory in all applications +# It calls a reusable workflow guidelines_enforcer developed by Ledger's internal developer team. +# The successful completion of the reusable workflow is a mandatory step for an app to be available on the Ledger +# application store. +# +# More information on the guidelines can be found in the repository: +# LedgerHQ/ledger-app-workflows/ + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + guidelines_enforcer: + name: Call Ledger guidelines_enforcer + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 diff --git a/.github/workflows/misspellings_checks.yml b/.github/workflows/misspellings_checks.yml new file mode 100644 index 0000000..5bbdb91 --- /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@v4 + + - name: Check misspellings + uses: codespell-project/actions-codespell@v2 + with: + builtin: clear,rare + check_filenames: true + skip: "*.lock" 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/.gitignore b/.gitignore index d0ea37a..10a7c4e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ dist *.DS_Store client/target fuzz/cmake-build-fuzz + +__pycache__ +snapshots-tmp \ No newline at end of file diff --git a/Makefile b/Makefile index 9f55b85..de01af1 100644 --- a/Makefile +++ b/Makefile @@ -1,176 +1,129 @@ -#******************************************************************************* -# Ledger App -# (c) 2017 Ledger +# **************************************************************************** +# Ledger App Everscale +# (c) 2023 Ledger SAS. # -# 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 +# 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 +# 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. -#******************************************************************************* +# 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. +# **************************************************************************** ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif + include $(BOLOS_SDK)/Makefile.defines -APP_LOAD_PARAMS = --curve ed25519 -ifeq ($(TARGET_NAME), TARGET_NANOX) - APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS +######################################## +# Mandatory configuration # +######################################## +# Application name +ifeq ($(COIN),VENOM) +APPNAME = "Venom" else - APP_LOAD_PARAMS += --appFlags 0x000 +APPNAME = "Everscale" endif -APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) - -# Pending review parameters -APP_LOAD_PARAMS += --tlvraw 9F:01 -DEFINES += HAVE_PENDING_REVIEW_SCREEN -################## -# Define Version # -################## +APP_LOAD_FLAGS=--appFlags 0x200 +# Application version APPVERSION_M = 1 -APPVERSION_N = 0 -APPVERSION_P = 10 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -########################### -# Set Chain environnement # -########################### - -ifeq ($(CHAIN),) -CHAIN=everscale -endif - -SUPPORTED_CHAINS=$(shell find makefile_conf/chain/ -type f -name '*.mk'| sed 's/.*\/\(.*\).mk/\1/g' | sort) - -# Check if chain is available -ifeq ($(shell test -s ./makefile_conf/chain/$(CHAIN).mk && echo -n yes), yes) -include ./makefile_conf/chain/$(CHAIN).mk -else -$(error Unsupported CHAIN - use $(SUPPORTED_CHAINS)) -endif +APPVERSION_N = 1 +APPVERSION_P = 2 +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" -######### -# Other # -######### - -#prepare hsm generation -ifeq ($(TARGET_NAME),TARGET_NANOS) -ICONNAME=icons/nanos_app_$(CHAIN).gif -else -ICONNAME=icons/nanox_app_$(CHAIN).gif -endif - -################ -# Default rule # -################ -all: default - -DEFINES += $(DEFINES_LIB) -DEFINES += APPNAME=\"$(APPNAME)\" -DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) -DEFINES += OS_IO_SEPROXYHAL -DEFINES += HAVE_BAGL HAVE_UX_FLOW HAVE_SPRINTF -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += USB_SEGMENT_SIZE=64 -DEFINES += BLE_SEGMENT_SIZE=32 -DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" -DEFINES += UNUSED\(x\)=\(void\)x - -ifeq ($(TARGET_NAME),TARGET_NANOX) - DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU -endif - -ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 -else - DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 - DEFINES += HAVE_GLO096 - DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64 - DEFINES += HAVE_BAGL_ELLIPSIS - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -endif +# Application source files +APP_SOURCE_PATH += src -DEBUG = 0 -ifneq ($(DEBUG),0) - DEFINES += HAVE_PRINTF - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += PRINTF=screen_printf - else - DEFINES += PRINTF=mcu_usb_printf - endif +# Application icons following guidelines: +# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon +ifeq ($(COIN),VENOM) +ICON_NANOX = icons/app_venom_14px.gif +ICON_NANOSP = icons/app_venom_14px.gif +ICON_STAX = icons/app_venom_32px.gif +ICON_FLEX = icons/app_venom_40px.gif else - DEFINES += PRINTF\(...\)= +ICON_NANOX = icons/app_everscale_14px.gif +ICON_NANOSP = icons/app_everscale_14px.gif +ICON_STAX = icons/app_everscale_32px.gif +ICON_FLEX = icons/app_everscale_40px.gif endif -############## -# Compiler # -############## -ifneq ($(BOLOS_ENV),) -$(info BOLOS_ENV=$(BOLOS_ENV)) -CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/ -GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/ +# Application allowed derivation curves. +# Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1 +# If your app needs it, you can specify multiple curves by using: +# `CURVE_APP_LOAD_PARAMS = ` +CURVE_APP_LOAD_PARAMS = ed25519 + +# Application allowed derivation paths. +# You should request a specific path for your app. +# This serve as an isolation mechanism. +# Most application will have to request a path according to the BIP-0044 +# and SLIP-0044 standards. +# If your app needs it, you can specify multiple path by using: +# `PATH_APP_LOAD_PARAMS = "44'/1'" "45'/1'"` +PATH_APP_LOAD_PARAMS = "44'/396'" # purpose=coin(44) / coin_type=Testnet(1) + +# Setting to allow building variant applications +# - is the name of the parameter which should be set +# to specify the variant that should be build. +# - a list of variant that can be build using this app code. +# * It must at least contains one value. +# * Values can be the app ticker or anything else but should be unique. +VARIANT_PARAM = COIN + + +ifeq ($(COIN),VENOM) +VARIANT_VALUES = VENOM else -$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH) -endif -ifeq ($(CLANGPATH),) -$(info CLANGPATH is not set: clang will be used from PATH) -endif -ifeq ($(GCCPATH),) -$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH) -endif - -CC := $(CLANGPATH)clang -CFLAGS += -O3 -Os -AS := $(GCCPATH)arm-none-eabi-gcc -LD := $(GCCPATH)arm-none-eabi-gcc -LDFLAGS += -O3 -Os -LDLIBS += -lm -lgcc -lc - -# import rules to compile glyphs(/pone) -include $(BOLOS_SDK)/Makefile.glyphs - -### variables processed by the common makefile.rules of the SDK to grab source files and include dirs -APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_ux - -ifeq ($(TARGET_NAME),TARGET_NANOX) - SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -endif - -WITH_U2F=0 -ifneq ($(WITH_U2F),0) - DEFINES += HAVE_U2F HAVE_IO_U2F - DEFINES += U2F_PROXY_MAGIC=\"~$(COIN)\" - SDK_SOURCE_PATH += lib_u2f +VARIANT_VALUES = EVER endif -load: all load-only -load-only: - python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS) - -load-offline: all - python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS) --offline - -delete: - python3 -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) - -# import generic rules from the sdk -include $(BOLOS_SDK)/Makefile.rules - -#add dependency on custom makefile filename -dep/%.d: %.c Makefile - -listvariants: - @echo VARIANTS CHAIN $(SUPPORTED_CHAINS) +# Enabling DEBUG flag will enable PRINTF and disable optimizations +DEBUG = 1 + +######################################## +# Application custom permissions # +######################################## +# See SDK `include/appflags.h` for the purpose of each permission +#HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +#HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1 +#HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 +#HAVE_APPLICATION_FLAG_LIBRARY = 1 + +######################################## +# Application communication interfaces # +######################################## +ENABLE_BLUETOOTH = 1 +#ENABLE_NFC = 1 +# ENABLE_NBGL_FOR_NANO_DEVICES = 1 + +######################################## +# NBGL custom features # +######################################## +ENABLE_NBGL_QRCODE = 1 +#ENABLE_NBGL_KEYBOARD = 1 +#ENABLE_NBGL_KEYPAD = 1 + +######################################## +# Features disablers # +######################################## +# These advanced settings allow to disable some feature that are by +# default enabled in the SDK `Makefile.standard_app`. +#DISABLE_STANDARD_APP_FILES = 1 +#DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1 # To allow custom size declaration +#DISABLE_STANDARD_APP_DEFINES = 1 # Will set all the following disablers +#DISABLE_STANDARD_SNPRINTF = 1 +#DISABLE_STANDARD_USB = 1 +#DISABLE_STANDARD_WEBUSB = 1 +#DISABLE_DEBUG_LEDGER_ASSERT = 1 +#DISABLE_DEBUG_THROW = 1 + +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/README.md b/README.md index b81cb7b..57f58a6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@

-![Build Status](https://github.com/broxus/ledger-app-everscale/actions/workflows/ci.yml/badge.svg?branch=master) +[![Ensure compliance with Ledger guidelines](https://github.com/blooo-io/app-everscale/actions/workflows/guidelines_enforcer.yml/badge.svg)](https://github.com/blooo-io/app-everscale/actions/workflows/guidelines_enforcer.yml) + +[![Build and run functional tests using ragger through reusable workflow](https://github.com/blooo-io/app-everscale/actions/workflows/build_and_functional_tests.yml/badge.svg)](https://github.com/blooo-io/app-everscale/actions/workflows/build_and_functional_tests.yml) # Everscale app for Ledger Wallet @@ -13,188 +15,252 @@ This app adds support for the Everscale tokens to Ledger hardware wallets. Current Features: + - Pubkey queries - Address queries - Sign transaction hash -- Parse, display and sign Everscale transaction +- Parse, display and sign Everscale transaction -## Build and load application -* [Install Docker](https://docs.docker.com/get-docker/) -* For Linux hosts, install the Ledger [udev rules](https://github.com/LedgerHQ/udev-rules) +## Quick start guide -1. Pull the default image -``` -docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -``` +### With VSCode -2. Compile your app in the container -* For Nano S -```bash -$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make -``` +You can quickly setup a convenient environment to build and test your application +by using [Ledger's VSCode developer tools extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools) +which leverages the [ledger-app-dev-tools](https://github.com/LedgerHQ/ledger-app-builder/pkgs/container/ledger-app-builder%2Fledger-app-dev-tools) +docker image. -* For Nano X -```bash -$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -root@656be163fe84:/app# BOLOS_SDK=$NANOX_SDK make -``` +It will allow you, whether you are developing on macOS, Windows or Linux to quickly **build** your apps, +**test** them on **Speculos** and **load** them on any supported device. -* For Nano S+ -```bash -$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -root@656be163fe84:/app# BOLOS_SDK=$NANOSP_SDK make -``` +- Install and run [Docker](https://www.docker.com/products/docker-desktop/). +- Make sure you have an X11 server running : + - On Ubuntu Linux, it should be running by default. + - On macOS, install and launch [XQuartz](https://www.xquartz.org/) + (make sure to go to XQuartz > Preferences > Security and check "Allow client connections"). + - On Windows, install and launch [VcXsrv](https://sourceforge.net/projects/vcxsrv/) + (make sure to configure it to disable access control). +- Install [VScode](https://code.visualstudio.com/download) and add [Ledger's extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools). +- Open a terminal and clone `app-everscale` with `git clone git@github.com:blooo-io/app-everscale.git`. +- Open the `app-everscale` folder with VSCode. +- Use Ledger extension's sidebar menu or open the tasks menu with `ctrl + shift + b` + (`command + shift + b` on a Mac) to conveniently execute actions : + - Build the app for the device model of your choice with `Build`. + - Test your binary on [Speculos](https://github.com/LedgerHQ/speculos) with `Run with Speculos`. + - You can also run functional tests, load the app on a physical device, and more. -3. Code static analysis -The Docker images include the [Clang Static Analyzer](https://clang-analyzer.llvm.org/), which can be invoked with: -```bash -$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make scan-build -``` +:information_source: The terminal tab of VSCode will show you what commands the extension runs behind the scene. -4. Load the app on a physical device +### With a terminal -:warning: Only Nano S and Nano S+ devices allow application side-loading. This section will not work with a Nano X. +The [ledger-app-dev-tools](https://github.com/LedgerHQ/ledger-app-builder/pkgs/container/ledger-app-builder%2Fledger-app-dev-tools) +docker image contains all the required tools and libraries to **build**, **test** and **load** an application. -To load the app from the container, you will need additional docker arguments in order to allow Docker to access your USB port. -Your physical device must be connected, unlocked and the screen showing the dashboard (not inside an application). Same as for compilation, `BOLOS_SDK` variable is used to specify the target device. Use the following docker command to load the app (here for Nano S device) : +You can download it from the ghcr.io docker repository: -```bash -$ docker run --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest -root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make load +```shell +sudo docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest ``` -## Fuzzing +You can then enter this development environment by executing the following command +from the directory of the application `git` repository: -* Build docker image -```bash -cd fuzz && docker build -t ledger-app-fuzzer . -``` +#### Linux (Ubuntu) -* Build fuzzer -```bash -docker run --rm -ti -v "$(realpath .):/app" ledger-app-fuzzer:latest -root@72edae7503e3:/# cd /app/fuzz && ./build.sh +```shell +sudo docker run --rm -ti --user "$(id -u):$(id -g)" --privileged -v "/dev/bus/usb:/dev/bus/usb" -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest ``` -* Run fuzzer -```bash -root@72edae7503e3:/app/fuzz/cmake-build-fuzz# cd cmake-build-fuzz && mkdir out && ./fuzzer +#### macOS + +```shell +sudo docker run --rm -ti --user "$(id -u):$(id -g)" --privileged -v "$(pwd -P):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest ``` -## Example of Ledger wallet functionality +#### Windows (with PowerShell) -**Install Rust to compile client to interact with Everscale Ledger app** -```bash -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +```shell +docker run --rm -ti --privileged -v "$(Get-Location):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest ``` -**List of Everscale wallets** -```bash -cargo run --manifest-path client/Cargo.toml get-wallets -``` +The application's code will be available from inside the docker container, +you can proceed to the following compilation steps to build your app. -**Request public key** -```bash -cargo run --manifest-path client/Cargo.toml get-pubkey --account ${LEDGER_ACCOUNT_NUMBER} -``` +## Compilation and load -```bash -# Example -cargo run --manifest-path client/Cargo.toml get-pubkey --account 0 -``` +To easily setup a development environment for compilation and loading on a physical device, +you can use the [VSCode integration](#with-vscode) whether you are on Linux, macOS or Windows. -**Request address** -```bash -cargo run --manifest-path client/Cargo.toml get-address --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE} -# send some EVER's to the this address (about 1 should be enough) -``` +If you prefer using a terminal to perform the steps manually, you can use the guide below. -```bash -# Example -cargo run --manifest-path client/Cargo.toml get-address --account 0 --wallet EverWallet -``` +### Compilation -**Check balance** -```bash -cargo run --manifest-path client/Cargo.toml get-balance --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE} -``` +Setup a compilation environment by following the [shell with docker approach](#with-a-terminal). -```bash -# Example -cargo run --manifest-path client/Cargo.toml get-balance --account 0 --wallet EverWallet +From inside the container, use the following command to build the app : + +```shell +make DEBUG=1 # compile optionally with PRINTF ``` -**Deploy wallet** -It only applies to Multisig wallets -```bash -cargo run --manifest-path client/Cargo.toml deploy --account ${LEDGER_ACCOUNT_NUMBER} -wallet ${WALLET_TYPE} +You can choose which device to compile and load for by setting the `BOLOS_SDK` environment variable +to the following values : + +- `BOLOS_SDK=$NANOX_SDK` +- `BOLOS_SDK=$NANOSP_SDK` +- `BOLOS_SDK=$STAX_SDK` +- `BOLOS_SDK=$FLEX_SDK` + +By default this variable is set to build/load for Nano S+. + +### Loading on a physical device + +This step will vary slightly depending on your platform. + +:information_source: Your physical device must be connected, unlocked and the screen showing the dashboard +(not inside an application). + +#### Linux (Ubuntu) + +First make sure you have the proper udev rules added on your host : + +```shell +# Run these commands on your host, from the app's source folder. +sudo cp .vscode/20-ledger.ledgerblue.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules +sudo udevadm trigger ``` -```bash -# Example -cargo run --manifest-path client/Cargo.toml deploy --account 0 --wallet Multisig2_1 +Then once you have [opened a terminal](#with-a-terminal) in the `app-builder` image and [built the app](#compilation-and-load) +for the device you want, run the following command : + +```shell +# Run this command from the app-builder container terminal. +make load # load the app on a Nano S+ by default ``` -**Send EVER transaction** -```bash -cargo run --manifest-path client/Cargo.toml send-transaction \ - --account ${LEDGER_ACCOUNT_NUMBER} \ - --wallet ${WALLET_TYPE} \ - --amount ${AMOUNT} \ - --address ${RECIPIENT_ADDRESS} +[Setting the BOLOS_SDK environment variable](#compilation-and-load) will allow you to load on whichever supported +device you want. + +#### macOS / Windows (with PowerShell) + +:information_source: It is assumed you have [Python](https://www.python.org/downloads/) installed on your computer. + +Run these commands on your host from the app's source folder once you have [built the app](#compilation-and-load) +for the device you want : + +```shell +# Install Python virtualenv +python3 -m pip install virtualenv +# Create the 'ledger' virtualenv +python3 -m virtualenv ledger ``` -```bash -# Example -cargo run --manifest-path client/Cargo.toml send-transaction \ - --account 0 \ - --wallet Multisig2_1 \ - --amount 0.1 \ - --address 0:7094fc3cb69fa1b7bde8e830e2cd74bc9455d93561ce2c562182215686eb45e2 +Enter the Python virtual environment + +- macOS : `source ledger/bin/activate` +- Windows : `.\ledger\Scripts\Activate.ps1` + +```shell +# Install Ledgerblue (tool to load the app) +python3 -m pip install ledgerblue +# Load the app. +python3 -m ledgerblue.runScript --scp --fileName bin/app.apdu --elfFile bin/app.elf ``` -**Get list of supported tokens** -```bash -cargo run --manifest-path client/Cargo.toml get-tokens +## Test + +The Everscale app comes with functional tests implemented with Ledger's [Ragger](https://github.com/LedgerHQ/ragger) +test framework. + +### macOS / Windows + +To test your app on macOS or Windows, it is recommended to use [Ledger's VS Code extension](#with-vscode) +to quickly setup a working test environment. + +You can use the following sequence of tasks and commands (all accessible in the **extension sidebar menu**) : + +- `Select build target` +- `Build app` + +Then you can choose to execute the functional tests : + +- Use `Run tests`. + +Or simply run the app on the Speculos emulator : + +- `Run with Speculos`. + +### Linux (Ubuntu) + +On Linux, you can use [Ledger's VS Code extension](#with-vscode) to run the tests. +If you prefer not to, open a terminal and follow the steps below. + +Install the tests requirements : + +```shell +pip install -r tests/requirements.txt ``` -**Check token balance** -```bash -cargo run --manifest-path client/Cargo.toml get-token-balance --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE} --token ${TOKEN_NAME} +Then you can : + +Run the functional tests (here for nanos+ but available for any device once you have built the binaries) : + +```shell +pytest tests/ --tb=short -v --device nanosp ``` -```bash -# Example -cargo run --manifest-path client/Cargo.toml get-token-balance --account 0 --wallet EverWallet --token WEVER +Or run your app directly with Speculos + +```shell +speculos --model nanosp build/nanos2/bin/app.elf ``` -**Send token transaction** +## Documentation + +This follows the specification available in the [`api.md`](doc/api.md) + +## Building the application + +### Prerequisites + +- Install [Node.js](https://nodejs.org) (lts version) +- Install [Docker](https://docs.docker.com/get-docker/) +- Setup the Ledger development environment by following the [official documentation](https://developers.ledger.com/docs/nano-app/introduction/) +- Make sure the Ledger SDK environment variable is properly set: + ``` + export BOLOS_SDK=/path/to/your/sdk + ``` + +### Building + +This application can be built in two variants: + +- **Everscale** (default) +- **Venom** + +#### Building the Everscale variant (default) + ```bash -cargo run --manifest-path client/Cargo.toml send-token-transaction \ - --account ${LEDGER_ACCOUNT_NUMBER} \ - --wallet ${WALLET_TYPE} \ - --amount ${AMOUNT} \ - --address ${RECIPIENT_ADDRESS} \ - --token ${TOKEN_NAME} +# Build with default configuration (Everscale) +make + +# Or explicitly specify Everscale +make COIN=EVER ``` +#### Building the Venom variant + ```bash -# Example -cargo run --manifest-path client/Cargo.toml send-token-transaction \ - --account 0 \ - --wallet EverWallet \ - --amount 1.5 \ - --address 0:ed7439e12d67d23fcaf701ff3bd4e30d390c1e8e14f6f40d52089590e28d9c70 \ - --token WEVER +# Build the Venom variant +make COIN=VENOM ``` -## Tests -Some tests require interactive approval on the ledger +### Loading the application on your device + ```bash -cargo run --manifest-path tests/Cargo.toml +# Connect your Ledger device and run +make load ``` -## Documentation -This follows the specification available in the [`api.md`](doc/api.md) +When building the application, the appropriate icons and application name will be used based on the selected variant. diff --git a/client/Cargo.lock b/client/Cargo.lock index 518c0bd..6272886 100644 --- a/client/Cargo.lock +++ b/client/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -197,6 +197,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.0.1" @@ -224,9 +230,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -427,6 +433,7 @@ name = "client" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.22.1", "bigdecimal", "clap", "ed25519-dalek", @@ -438,6 +445,7 @@ dependencies = [ "nekoton-contracts", "nekoton-utils", "rust_decimal", + "serial_test", "tokio", "ton_block", "ton_types", @@ -583,13 +591,14 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", "tempfile", + "thiserror", "zeroize", ] @@ -681,19 +690,17 @@ dependencies = [ [[package]] name = "everscale-ledger-wallet" version = "0.1.0" -source = "git+https://github.com/broxus/everscale-ledger-wallet.git#a481b2fa884e5015e0823c92f7d30489e26b8430" +source = "git+https://github.com/broxus/everscale-ledger-wallet.git#c3819438b2ba5c054220cab7def1e1ea82ab6c40" dependencies = [ "anyhow", "console", "dialoguer", "ed25519-dalek", - "hex", "hidapi", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", "parking_lot", - "qstring", "semver", "thiserror", "uriparse", @@ -1172,9 +1179,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -1492,6 +1499,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1555,9 +1573,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" dependencies = [ "parking_lot_core", ] @@ -1614,9 +1632,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1624,15 +1642,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.10", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.52.6", ] [[package]] @@ -1760,15 +1778,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - [[package]] name = "quick_cache" version = "0.3.0" @@ -1834,6 +1843,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "rend" version = "0.4.0" @@ -1946,7 +1964,7 @@ version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", @@ -1965,6 +1983,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "scc" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.22" @@ -1980,6 +2007,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sdd" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" + [[package]] name = "seahash" version = "4.1.0" @@ -2068,6 +2101,31 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] + [[package]] name = "sha2" version = "0.9.9" @@ -2187,7 +2245,7 @@ checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys 0.48.0", ] @@ -2390,7 +2448,7 @@ dependencies = [ "hex", "log", "num", - "num-derive", + "num-derive 0.3.3", "num-traits", "rand", "rustc-hash", @@ -2720,6 +2778,22 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2732,6 +2806,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2744,6 +2824,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2756,6 +2842,18 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2768,6 +2866,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2780,6 +2884,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2792,6 +2902,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2804,6 +2920,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winreg" version = "0.10.1" diff --git a/client/Cargo.toml b/client/Cargo.toml index a662402..b315765 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -28,4 +28,8 @@ everscale-ledger-wallet = { git = "https://github.com/broxus/everscale-ledger-wa 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 +nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" } + +[dev-dependencies] +base64 = "0.22" +serial_test = "3.2.0" diff --git a/client/src/main.rs b/client/src/main.rs index 38d9ac3..4a8901f 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,6 +1,6 @@ use bigdecimal::BigDecimal; +use std::rc::Rc; use std::str::FromStr; -use std::sync::Arc; use bigdecimal::num_bigint::ToBigInt; use clap::Parser; @@ -224,7 +224,7 @@ impl Token { } } -fn get_ledger() -> (Arc, PublicKey) { +fn get_ledger() -> (Rc, PublicKey) { let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager"); // Update device list @@ -459,14 +459,14 @@ fn prepare_multisig_wallet_deploy( fn prepare_token_body( tokens: BigUint, owner: &MsgAddressInt, - destiantion: &MsgAddressInt, + destination: &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(destination) // recipient owner wallet .arg(BigUint128(INITIAL_BALANCE.into())) // deployWalletValue .arg(owner) // remainingGasTo .arg(false) // notify @@ -523,7 +523,8 @@ async fn main() -> anyhow::Result<()> { match contract { Some(contract) => { let mut balance = - Decimal::from_u128(contract.account.storage.balance.grams.as_u128()).trust_me(); + Decimal::from_u128(contract.account.storage.balance.grams.as_u128()) + .trust_me(); balance.set_scale(EVER_DECIMALS as u32)?; println!("Balance: {} EVER", balance); } diff --git a/client/tests/get_address.rs b/client/tests/get_address.rs new file mode 100644 index 0000000..a163078 --- /dev/null +++ b/client/tests/get_address.rs @@ -0,0 +1,23 @@ +use everscale_ledger_wallet::ledger::WalletType; +use everscale_ledger_wallet::remote_wallet::RemoteWallet; + +use crate::utils::get_ledger; + +mod utils; + +#[test] +fn ledger_get_address() -> anyhow::Result<()> { + let (ledger, _) = get_ledger(); + + ledger.get_address(0, WalletType::WalletV3, false)?; + ledger.get_address(0, WalletType::EverWallet, false)?; + ledger.get_address(0, WalletType::SafeMultisig, false)?; + ledger.get_address(0, WalletType::SafeMultisig24h, false)?; + ledger.get_address(0, WalletType::SetcodeMultisig, false)?; + ledger.get_address(0, WalletType::BridgeMultisig, false)?; + ledger.get_address(0, WalletType::Surf, false)?; + ledger.get_address(0, WalletType::Multisig2, false)?; + ledger.get_address(0, WalletType::Multisig2_1, false)?; + + Ok(()) +} diff --git a/client/tests/get_pubkey.rs b/client/tests/get_pubkey.rs new file mode 100644 index 0000000..4d7442a --- /dev/null +++ b/client/tests/get_pubkey.rs @@ -0,0 +1,16 @@ +use everscale_ledger_wallet::remote_wallet::RemoteWallet; + +use crate::utils::get_ledger; + +mod utils; + +#[test] +fn ledger_get_pubkey() -> anyhow::Result<()> { + let (ledger, _) = get_ledger(); + + ledger.get_pubkey(0, false)?; + ledger.get_pubkey(1, false)?; + ledger.get_pubkey(2, false)?; + + Ok(()) +} diff --git a/client/tests/sign_message.rs b/client/tests/sign_message.rs new file mode 100644 index 0000000..302a23f --- /dev/null +++ b/client/tests/sign_message.rs @@ -0,0 +1,57 @@ +use std::str::FromStr; + +use ed25519_dalek::Verifier; +use everscale_ledger_wallet::ledger::SIGN_MAGIC; +use everscale_ledger_wallet::remote_wallet::RemoteWallet; +use nekoton::core::models::Expiration; +use nekoton::core::ton_wallet::wallet_v3::InitData; +use nekoton::core::ton_wallet::Gift; +use nekoton_utils::SimpleClock; +use ton_block::MsgAddressInt; + +use crate::utils::{get_ledger, DEFAULT_EXPIRATION_TIMEOUT, WALLET_ID}; + +mod utils; + +// This test requires interactive approval of message signing on the ledger. +#[test] +fn 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(account, hash.as_slice())?; + + let mut message = Vec::with_capacity(SIGN_MAGIC.len() + hash.as_slice().len()); + message.extend(SIGN_MAGIC.to_vec()); + message.extend(hash.into_vec()); + + assert!(public_key.verify(message.as_slice(), &signature).is_ok()); + + Ok(()) +} diff --git a/tests/src/main.rs b/client/tests/sign_transaction.rs similarity index 50% rename from tests/src/main.rs rename to client/tests/sign_transaction.rs index dc3140d..203796c 100644 --- a/tests/src/main.rs +++ b/client/tests/sign_transaction.rs @@ -1,188 +1,29 @@ use std::borrow::Cow; -use std::rc::Rc; use std::str::FromStr; -use base64::Engine; - -use ed25519_dalek::{PublicKey, Verifier, SIGNATURE_LENGTH}; +use base64::Engine; +use ed25519_dalek::{Verifier, SIGNATURE_LENGTH}; +use everscale_ledger_wallet::ledger::{SignTransactionMeta, WalletType}; +use everscale_ledger_wallet::remote_wallet::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 serial_test::serial; use ton_block::MsgAddressInt; use ton_types::{AccountId, UInt256}; -use everscale_ledger_wallet::ledger::{LedgerWallet, SIGN_MAGIC, SignTransactionMeta, WalletType}; -use everscale_ledger_wallet::locator::Manufacturer; -use everscale_ledger_wallet::remote_wallet::{initialize_wallet_manager, RemoteWallet}; - -const EVER_DECIMALS: u8 = 9; -const EVER_TICKER: &str = "EVER"; - -const USDT_DECIMALS: u8 = 9; -const USDT_TICKER: &str = "USDT"; - -const WALLET_ID: u32 = 0x4BA92D8A; - -const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec - -fn get_ledger() -> (Rc, 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" - ); +use crate::utils::{ + get_ledger, DEFAULT_EXPIRATION_TIMEOUT, EVER_DECIMALS, EVER_TICKER, USDT_DECIMALS, USDT_TICKER, +}; - Ok(()) -} +mod utils; // 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(account, hash.as_slice())?; - - let mut message = Vec::with_capacity(SIGN_MAGIC.len() + hash.as_slice().len()); - message.extend(SIGN_MAGIC.to_vec()); - message.extend(hash.into_vec()); - - assert!(public_key.verify(message.as_slice(), &signature).is_ok()); - - Ok(()) -} - -// This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_send_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_send_transaction() -> anyhow::Result<()> { let (ledger, _) = get_ledger(); let account = 0; @@ -212,9 +53,7 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> { let destination = MsgAddressInt::from_str( "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56", )?; - let body: ton_types::Cell = ton_types::deserialize_tree_of_cells(&mut base64::engine::general_purpose::STANDARD - .decode("te6ccgEBAwEAYAABa0ap1+wAAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AEBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJisgCAAA=")?.as_slice())?; - + let body: ton_types::Cell = Default::default(); let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT); let (function, input) = @@ -239,7 +78,7 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> { // Fake sign let signature: Signature = [0_u8; 64]; - let signed = unsigned_message.sign_with_pruned_payload(&signature, 2)?; + let signed = unsigned_message.sign(&signature)?; // Extract message body let mut data = signed.message.body().trust_me(); @@ -255,21 +94,17 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> { let cell = data.into_cell(); let boc = ton_types::serialize_toc(&cell)?; - let signature = ledger.sign_transaction( - account, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - meta, - &boc, - )?; + let signature = + ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?; assert!(public_key.verify(message_hash, &signature).is_ok()); Ok(()) } // This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_send_token_transaction() -> anyhow::Result<()> { let (ledger, _) = get_ledger(); let account = 0; @@ -295,7 +130,7 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> { // Transfer parameters let flags: u8 = 3; let bounce = true; - let amount: u64 = 123_456_785_012_345_678; + let amount: u64 = 123_456_785_012; let destination = MsgAddressInt::from_str( "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56", )?; @@ -326,7 +161,7 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> { // Fake sign let signature: Signature = [0_u8; 64]; - let signed = unsigned_message.sign_with_pruned_payload(&signature, 2)?; + let signed = unsigned_message.sign(&signature)?; // Extract message body let mut data = signed.message.body().trust_me(); @@ -342,21 +177,17 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> { let cell = data.into_cell(); let boc = ton_types::serialize_toc(&cell)?; - let signature = ledger.sign_transaction( - account, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - meta, - &boc, - )?; + let signature = + ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?; assert!(public_key.verify(message_hash, &signature).is_ok()); Ok(()) } // This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_confirm_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_confirm_transaction() -> anyhow::Result<()> { // let boc = base64::decode("te6ccgEBAQEAOwAAcbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGVwt0ySiJcDVOgdrJKDeYh5nYAwA==")?; let boc = base64::engine::general_purpose::STANDARD @@ -376,21 +207,19 @@ fn test_ledger_sign_confirm_transaction() -> anyhow::Result<()> { let meta = SignTransactionMeta::default(); - let signature = ledger.sign_transaction( - account, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - meta, - &boc, - )?; - assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok()); + let signature = + ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?; + assert!(public_key + .verify(message_hash.as_slice(), &signature) + .is_ok()); Ok(()) } // This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_submit_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_submit_transaction() -> anyhow::Result<()> { let boc = base64::engine::general_purpose::STANDARD .decode("te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGlca+ySiZfiY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa0ap1+wAAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJisgEAAA=")?; let cell = ton_types::deserialize_tree_of_cells(&mut boc.as_slice())?; @@ -407,21 +236,19 @@ fn test_ledger_sign_submit_transaction() -> anyhow::Result<()> { let meta = SignTransactionMeta::default(); - let signature = ledger.sign_transaction( - account, - wallet_type, - USDT_DECIMALS, - USDT_TICKER, - meta, - &boc, - )?; - assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok()); + let signature = + ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?; + assert!(public_key + .verify(message_hash.as_slice(), &signature) + .is_ok()); Ok(()) } // This test requires interactive approval of message signing on the ledger. -fn test_ledger_sign_burn_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_burn_transaction() -> anyhow::Result<()> { let boc = base64::engine::general_purpose::STANDARD .decode("te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA=")?; @@ -439,22 +266,20 @@ fn test_ledger_sign_burn_transaction() -> anyhow::Result<()> { let meta = SignTransactionMeta::default(); - let signature = ledger.sign_transaction( - account, - wallet_type, - USDT_DECIMALS, - USDT_TICKER, - meta, - &boc, - )?; - assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok()); + let signature = + ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?; + assert!(public_key + .verify(message_hash.as_slice(), &signature) + .is_ok()); Ok(()) } // This test requires interactive approval of message signing on the ledger. // Chunks test -fn test_ledger_sign_create_token_transaction() -> anyhow::Result<()> { +#[test] +#[serial] +fn ledger_sign_large_transaction() -> anyhow::Result<()> { let boc = base64::engine::general_purpose::STANDARD .decode("te6ccgECBgEAASwAIWHw5pxqUFVGcS9uHx4H1Hyxqdv8M0fmFpmbpEK2sRE8qgAAAMVB8+fysn958qZ3MjZAASFlgBpSNW8J55zSsfWhyOd5rDEjZgefz1LcWODp5B1bqgHogAAAAAAAAAAAAAAAJUC+QBA4AiOVEMgafQAACAoJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBQQDKEgBAUZsZIPd9xkGAco8YjJOBZgvCE3wlneY/Wx25kfOjumaAAAoSAEB1IDh09lVWihGkWEM9d9w01WXUrJVmfTd7p+dAZMyU/oAAChIAQGQCROE6sQnHzRREUyjfCGGj+o03d7B++Lo06vNLc44JgAA")?; @@ -472,42 +297,41 @@ fn test_ledger_sign_create_token_transaction() -> anyhow::Result<()> { let meta = SignTransactionMeta::default(); - let signature = ledger.sign_transaction( - account, - wallet_type, - EVER_DECIMALS, - EVER_TICKER, - meta, - &boc, - )?; - assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok()); + let signature = + ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?; + assert!(public_key + .verify(message_hash.as_slice(), &signature) + .is_ok()); Ok(()) } -fn main() { - if let Err(e) = do_run_tests() { - panic!("{:?}", e) - } -} +#[test] +#[serial] +fn ledger_many_msig_custodians_transaction() -> anyhow::Result<()> { + // Multisig with 15 custodians + let boc = base64::engine::general_purpose::STANDARD + .decode("te6ccgECHwEAApQAAmuzuttTXRuI0OTWDTFlZ7FEhWjvr98hhG7NC6AuOtq/lwAAAMrQsOrKM+uyhxXYd8eAAAAHwGACAQAIAAAAAQIDzkAQAwIBIAkEAgEgBgUAQUYLBilvnAvo1CkFGNMQGOqQO13kBQQZKVO/Yx8ei1a5KAIBIAgHAEEULBilvnAvo1CkFGNMQGOqQO13kBQQZKVO/Yx8ei1a5KAAQRAsGKW+cC+jUKQUY0xAY6pA7XeQFBBkpU79jHx6LVrkoAIBIA0KAgEgDAsAQQwsGKW+cC+jUKQUY0zAY6pA7XeQFBBkpU79jHy6LVrAoABBCCwYpb5wL6NQpBRfTEBjqkDtd5AUEGSlTv2MfLotWsCgAgEgDw4AQQQsGKW+cC+jUKQUX0yAY6pA7XeQFBBkpU79jHy6LVrAoABBJuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsCgAgEgGBECASAVEgIBIBQTAEEi7BilvnAvo1CkFF9MwGOoQO13kBQQZKVO/Yx8ui1awKAAQR7sGKW+cC+jUKQUX0zAY6oA7XeQFBBkpU79jHy6LVrAoAIBIBcWAEEa7BilvnAvo1CkFF9MwGOoQO13kBQQZKVO/Yx8ui1awuAAQRbsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4AIBIBwZAgEgGxoAQRLsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4ABBDuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsLgAgEgHh0AQQrsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4ABBBuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsLg")?; -macro_rules! run { - ($test:ident) => { - println!(" >>> Running {} <<<", stringify!($test)); - $test()?; - }; -} + let cell = ton_types::deserialize_tree_of_cells(&mut boc.as_slice())?; + + let message_hash = cell.repr_hash(); + + let (ledger, _) = get_ledger(); + + let account = 0; + let wallet_type = WalletType::SafeMultisig; + + // Get public key + let public_key = ledger.get_pubkey(account, false)?; + + let meta = SignTransactionMeta::default(); -fn do_run_tests() -> anyhow::Result<()> { - run!(test_ledger_pubkey); - run!(test_ledger_address); - run!(test_ledger_sign_message); - run!(test_ledger_sign_send_transaction); - run!(test_ledger_sign_send_msig_transaction); - run!(test_ledger_sign_confirm_transaction); - run!(test_ledger_sign_submit_transaction); - run!(test_ledger_sign_burn_transaction); - run!(test_ledger_sign_create_token_transaction); + let signature = + ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?; + assert!(public_key + .verify(message_hash.as_slice(), &signature) + .is_ok()); Ok(()) } diff --git a/client/tests/utils/mod.rs b/client/tests/utils/mod.rs new file mode 100644 index 0000000..d670372 --- /dev/null +++ b/client/tests/utils/mod.rs @@ -0,0 +1,48 @@ +use std::rc::Rc; + +use ed25519_dalek::PublicKey; +use everscale_ledger_wallet::ledger::LedgerWallet; +use everscale_ledger_wallet::locator::Manufacturer; +use everscale_ledger_wallet::remote_wallet::initialize_wallet_manager; + +#[allow(dead_code)] +pub const WALLET_ID: u32 = 0x4BA92D8A; + +#[allow(dead_code)] +pub const EVER_DECIMALS: u8 = 9; +#[allow(dead_code)] +pub const EVER_TICKER: &str = "EVER"; + +#[allow(dead_code)] +pub const USDT_DECIMALS: u8 = 9; +#[allow(dead_code)] +pub const USDT_TICKER: &str = "USDT"; + +#[allow(dead_code)] +pub const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec + +pub fn get_ledger() -> (Rc, 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) +} diff --git a/doc/api.md b/doc/api.md index 49ee42f..0177390 100644 --- a/doc/api.md +++ b/doc/api.md @@ -16,7 +16,7 @@ The application interface can be accessed over HID or BLE ## Command APDU | Field name | Length (bytes) | Description | -| ---------- |----------------| --------------------------------------------------------------------- | +| ---------- | -------------- | --------------------------------------------------------------------- | | CLA | 1 | Instruction class - indicates the type of command | | INS | 1 | Instruction code - indicates the specific command | | P1 | 1 | Instruction parameter 1 for the command | @@ -37,7 +37,7 @@ _This command returns specific application configuration_ ##### Command | _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | -| ----- |:-----:| ---: | ---- |:----:|---------:| +| ----- | :---: | ---: | ---- | :--: | -------: | | E0 | 01 | 00 | 00 | 00 | variable | ##### Input data @@ -60,21 +60,20 @@ _This command returns a public key for the given account number_ ##### Command -| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | -| ----- |:-----:|:---------------------------------------------------------------------------------|------| :------: |----------:| -| E0 | 02 | 00 : return public key
01 : display public key and confirm before returning | 00 | variable | variable | +| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | +| ----- | :---: | :------------------------------------------------------------------------------ | ---- | :------: | -------: | +| E0 | 02 | 00 : return public key
01 : display public key and confirm before returning | 00 | variable | variable | ##### Input data -| _Description_ | _Length_ | -|-------------------------------------|:--------:| -| An account number to retrieve | 4 | - +| _Description_ | _Length_ | +| ----------------------------- | :------: | +| An account number to retrieve | 4 | ##### Output data | _Description_ | _Length_ | -| ------------- |:--------:| +| ------------- | :------: | | Pubkey length | 1 | | Pubkey | 32 | @@ -89,20 +88,20 @@ To avoid blindly signing message hash the application adds a 4-byte prefix [0xFF ##### Command | _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | -| ----- |:-----:| ---: | ---- | :------: |---------:| +| ----- | :---: | ---: | ---- | :------: | -------: | | E0 | 03 | 01 | 00 | variable | variable | ##### Input data -| _Description_ | _Length_ | -|------------------------------------------|:--------:| -| An account number to retrieve | 4 | -| A bytes to sign | 32 | +| _Description_ | _Length_ | +| ----------------------------- | :------: | +| An account number to retrieve | 4 | +| A bytes to sign | 32 | ##### Output data | _Description_ | _Length_ | -|------------------| :------: | +| ---------------- | :------: | | Signature length | 1 | | Signature | 64 | @@ -115,20 +114,20 @@ _This command returns an address for the given account number_ ##### Command | _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | -| ----- |:-----:|:--------------------------------------------------------------------------|------| :------: |---------:| +| ----- | :---: | :------------------------------------------------------------------------ | ---- | :------: | -------: | | E0 | 04 | 00 : return address
01 : display address and confirm before returning | 00 | variable | variable | ##### Input data | _Description_ | _Length_ | -|-------------------------------|:--------:| +| ----------------------------- | :------: | | An account number to retrieve | 4 | | Wallet number to retrieve | 1 | ##### Output data | _Description_ | _Length_ | -|----------------|:--------:| +| -------------- | :------: | | Address length | 1 | | Address | 32 | @@ -140,14 +139,14 @@ _This command signs a transaction message_ ##### Command -| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | -| ----- |:-----:| ---: | ---- | :------: |---------------:| -| E0 | 05 | 01 | 0x01 (last chunk)
0x02 (first chunk)
0x00 (single chunk)
0x03 (intermediate chunk) | variable | variable | +| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ | +| ----- | :---: | ---: | ------------------------------------------------------------------------------------------------- | :------: | -------: | +| E0 | 05 | 01 | 0x01 (last chunk)
0x02 (first chunk)
0x00 (single chunk)
0x03 (intermediate chunk) | variable | variable | ##### Input data | _Description_ | _Length_ | -|--------------------------------------------------------------------------------|:--------:| +| ------------------------------------------------------------------------------ | :------: | | An account number to retrieve | 4 | | Original wallet number to derive address | 1 | | Decimals | 1 | @@ -162,10 +161,24 @@ _This command signs a transaction message_ ##### Output data -| _Description_ | _Length_ | -|-----------------| :------: | -| Address length | 1 | -| Signature | 64 | +| _Description_ | _Length_ | +| -------------- | :------: | +| Address length | 1 | +| Signature | 64 | + +## Status Words + +The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description. + +##### Status Words + +| _SW_ | _Description_ | +| ---- | :-----------------------------------------------: | +| 6700 | Incorrect length | +| 6985 | Canceled by user | +| 6B0x | Invalid request | +| 6Fxx | Technical problem (Internal error, please report) | +| 9000 | Normal ending of the command | ## Transport protocol @@ -214,17 +227,3 @@ The application acts as a GATT server defining service UUID D973F2E0-B19E-11E2-9 When using this service, the client sends requests to the characteristic D973F2E2-B19E-11E2-9E96-0800200C9A66, and gets notified on the characteristic D973F2E1-B19E-11E2-9E96-0800200C9A66 after registering for it. Requests are encoded using the standard BLE 20 bytes MTU size - -## Status Words - -The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description. - -##### Status Words - -| _SW_ | _Description_ | -| ---- |:--------------------------------------------------:| -| 6700 | Incorrect length | -| 6982 | Security status not satisfied (Canceled by user) | -| 6B0x | Invalid request | -| 6Fxx | Technical problem (Internal error, please report) | -| 9000 | Normal ending of the command | diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..73ecd1e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +# version: "3.7" + +services: + nanosp: + image: ghcr.io/blooo-io/speculos:latest + volumes: + - ./bin:/speculos/apps + - ./src:/speculos/sources + - ./build:/speculos/build + ports: + - "5000:5000" # api + - "40000:40000" # apdu + environment: + - GDB_DIRECTORY_LIST="/speculos/sources:/speculos/sources/ui:/speculos/sources/handler:" + command: "-d --model nanosp build/nanos2/bin/app.elf --display headless --apdu-port 40000" + # Add `--vnc-password ""` for macos users to use built-in vnc client. \ No newline at end of file diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt deleted file mode 100644 index 64f22c4..0000000 --- a/fuzz/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(NeoFuzzer VERSION 0.1.9 LANGUAGES C) - -set(CMAKE_C_STANDARD 11) - -# BOLOS SDK -set(BOLOS_SDK $ENV{BOLOS_SDK}) -add_compile_definitions(IO_HID_EP_LENGTH=64) - -find_package(OpenSSL REQUIRED) - -# add_compile_definitions(HAVE_HASH HAVE_SHA256) -include_directories(. - ../src - "${BOLOS_SDK}/include" - "${BOLOS_SDK}/lib_cxng/include" -) - -add_compile_options(-g -O0 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) - -# Build with code coverage generation -if(CODE_COVERAGE) - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - add_compile_options(-fprofile-instr-generate -fcoverage-mapping) - add_link_options(-fprofile-instr-generate -fcoverage-mapping) - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU") - add_compile_options(-fprofile-arcs -ftest-coverage) - link_libraries(gcov) - else() - message(FATAL_ERROR "Unsupported compiler used with code coverage generation") - endif() -endif() - -# Fuzzer target -set(APP_SRC_DIR "../src") - -set(APP_SOURCES - ${APP_SRC_DIR}/byte_stream.c - ${APP_SRC_DIR}/message.c - ${APP_SRC_DIR}/slice_data.c - ${APP_SRC_DIR}/contract.c - ${APP_SRC_DIR}/cell.c - ${APP_SRC_DIR}/hashmap_label.c - ${APP_SRC_DIR}/utils.c -) - -add_executable(fuzzer - fuzzer.c - os_mocks.c - ${APP_SOURCES} -) - -target_include_directories(fuzzer PUBLIC ../src) -target_compile_options(fuzzer PUBLIC -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=undefined) -target_link_options(fuzzer PUBLIC -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=undefined) -target_link_libraries(fuzzer OpenSSL::SSL) diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile deleted file mode 100644 index a54477a..0000000 --- a/fuzz/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM ubuntu:22.04 - -RUN apt update -RUN apt install -y git cmake clang libssl-dev - -# Clone the repository. -# WARNING: use the latest version of the app and integrate the fuzzer -RUN git clone https://github.com/qbLedger/ledger-app-everscale.git -RUN cd ledger-app-everscale && git checkout pr_ready - -# Get the sdk -RUN git clone https://github.com/LedgerHQ/nanos-secure-sdk.git - -# Patch the sdk -RUN echo -e 'diff --git a/include/os_seed.h b/include/os_seed.h\n\ -index 63b12ee..633346b 100644\n\ ---- a/include/os_seed.h\n\ -+++ b/include/os_seed.h\n\ -@@ -4,6 +4,8 @@\n\ - ''#include "decorators.h"\n\ - ''#include "lcx_ecfp.h"\n\ - ''#include "os_types.h"\n\ -+#include "ox_ec.h"\n\ -+#include "exceptions.h"\n\ - \n\ - /* ----------------------------------------------------------------------- */\n\ - /* - SEED FEATURE - */\n' > os_seed-fix.patch -RUN cat /os_seed-fix.patch -RUN patch -p1 -i /os_seed-fix.patch -d /nanos-secure-sdk/ - -# Set the BOLOS_SDK env var -ENV BOLOS_SDK /nanos-secure-sdk/ - -# Build the fuzzer -RUN cd ledger-app-everscale/fuzz && ./build.sh - -# Run the fuzzer. Here you can specify a pre-existing corpus -#RUN cd ledger-app-everscale/fuzz/cmake-build-fuzz && mkdir corpus && ./fuzzer corpus/ diff --git a/fuzz/build.sh b/fuzz/build.sh deleted file mode 100755 index c6ecbd2..0000000 --- a/fuzz/build.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -e - -SCRIPTDIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)" -BUILDDIR="$SCRIPTDIR/cmake-build-fuzz" - -# Compile fuzzer -rm -rf "$BUILDDIR" -mkdir "$BUILDDIR" -cd "$BUILDDIR" - -cmake -DCMAKE_C_COMPILER=clang .. -make clean -make fuzzer \ No newline at end of file diff --git a/fuzz/ux.h b/fuzz/ux.h deleted file mode 100644 index 65fec9e..0000000 --- a/fuzz/ux.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define bagl_element_t int -#define cx_ecfp_private_key_t int diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 0000000..e7f72a5 --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.10) + +if(${CMAKE_VERSION} VERSION_LESS 3.10) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() + +# project information +project(FuzzTxParser + VERSION 1.0 + DESCRIPTION "Fuzzing of transaction parser" + LANGUAGES C) + +find_package(OpenSSL REQUIRED) + +# guard against bad build-type strings +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "Fuzzer needs to be built with Clang") +endif() + +if (NOT DEFINED BOLOS_SDK) + message(FATAL_ERROR "BOLOS_SDK environment variable not found.") +endif() + +if (NOT DEFINED TARGET_DEVICE) + message(FATAL_ERROR "TARGET_DEVICE environment variable not found.") +endif() + +# guard against in-source builds +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") +endif() + +# compatible with ClusterFuzzLite +if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + set(COMPILATION_FLAGS_ "-g -Wall -fsanitize=fuzzer,address,undefined") +else() + set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}") +endif() + +add_compile_options(-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_compile_definitions(IO_HID_EP_LENGTH=64 USB_SEGMENT_SIZE=64 BLE_SEGMENT_SIZE=32) + +string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_}) + +include(extra/TxParser.cmake) + +add_executable(fuzzer fuzzer.c os_mocks.c) + +target_include_directories(fuzzer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../src) + +target_compile_options(fuzzer PUBLIC ${COMPILATION_FLAGS}) +target_link_options(fuzzer PUBLIC ${COMPILATION_FLAGS}) +target_link_libraries(fuzzer PUBLIC txparser OpenSSL::SSL) diff --git a/fuzzing/Dockerfile b/fuzzing/Dockerfile new file mode 100644 index 0000000..ea9f967 --- /dev/null +++ b/fuzzing/Dockerfile @@ -0,0 +1,19 @@ +FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest + +RUN apt update && apt install -y libssl-dev + +# Patch SDK +RUN cd /opt/ledger-secure-sdk && echo -e 'diff --git a/include/os_seed.h b/include/os_seed.h\n\ +index da35f4c5..1f4a224f 100644\n\ +--- a/include/os_seed.h\n\ ++++ b/include/os_seed.h\n\ +@@ -6,6 +6,8 @@\n\ + ''#include "decorators.h"\n\ + ''#include "lcx_ecfp.h"\n\ + ''#include "os_types.h"\n\ ++#include "ox_ec.h"\n\ ++#include "exceptions.h"\n\ + \n\ + /* ----------------------------------------------------------------------- */\n\ + /* - SEED FEATURE - */\n' > os_seed-fix.patch && \ +patch -p1 < os_seed-fix.patch diff --git a/fuzzing/README.md b/fuzzing/README.md new file mode 100644 index 0000000..49c3e32 --- /dev/null +++ b/fuzzing/README.md @@ -0,0 +1,34 @@ +# Fuzzing on transaction parser + +## Compilation + +* Build docker image + +``` +pushd fuzzing && docker build -t ledger-app-fuzzer . && popd +``` + +* Run docker container + +``` +docker run --rm -ti --user "$(id -u):$(id -g)" -v "$(realpath .):/app" ledger-app-fuzzer:latest + +``` + +* Build fuzzer inside the container + +``` +cd /app/fuzzing && cmake -DBOLOS_SDK=/opt/ledger-secure-sdk -DTARGET_DEVICE=nanos -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H. +``` + +then + +``` +make -C build +``` + +## Run + +``` +./build/fuzzer +``` diff --git a/fuzzing/extra/TxParser.cmake b/fuzzing/extra/TxParser.cmake new file mode 100644 index 0000000..ec74ef3 --- /dev/null +++ b/fuzzing/extra/TxParser.cmake @@ -0,0 +1,37 @@ +# project information +project(TxParser + VERSION 1.0 + DESCRIPTION "Transaction parser of Everscale app" + LANGUAGES C) + +# specify C standard +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED True) +set(CMAKE_C_FLAGS_DEBUG + "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0" +) + +add_library(txparser + ${BOLOS_SDK}/lib_standard_app/format.c + ${BOLOS_SDK}/lib_standard_app/buffer.c + ${BOLOS_SDK}/lib_standard_app/read.c + ${BOLOS_SDK}/lib_standard_app/write.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/byte_stream.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/cell.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/contract.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/hashmap_label.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/message.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/slice_data.c + ${CMAKE_CURRENT_SOURCE_DIR}/../src/utils.c +) + +set_target_properties(txparser PROPERTIES SOVERSION 1) + +target_include_directories(txparser PUBLIC + ${BOLOS_SDK}/include + ${BOLOS_SDK}/lib_cxng/include + ${BOLOS_SDK}/lib_standard_app + ${BOLOS_SDK}/target/${TARGET_DEVICE}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ${CMAKE_CURRENT_SOURCE_DIR}/../src/ui +) diff --git a/fuzz/fuzzer.c b/fuzzing/fuzzer.c similarity index 66% rename from fuzz/fuzzer.c rename to fuzzing/fuzzer.c index a872a4b..e69fa65 100644 --- a/fuzz/fuzzer.c +++ b/fuzzing/fuzzer.c @@ -22,15 +22,14 @@ BocContext_t boc_context; DataContext_t data_context; -void hex_to_bytes(const char* hex, uint8_t* bytes) -{ +void hex_to_bytes(const char* hex, uint8_t* bytes) { size_t len = strlen(hex); size_t final_len = len / 2; - for (size_t i=0, j=0; jjmp_buf, exception); } -try_context_t *current_context = NULL; -try_context_t *try_context_get(void) { return current_context; } +try_context_t* current_context = NULL; +try_context_t* try_context_get(void) { + return current_context; +} -try_context_t *try_context_set(try_context_t *ctx) { - try_context_t *previous_ctx = current_context; +try_context_t* try_context_set(try_context_t* ctx) { + try_context_t* previous_ctx = current_context; current_context = ctx; return previous_ctx; } @@ -29,9 +31,9 @@ try_context_t *try_context_set(try_context_t *ctx) { // return CX_OK; // } -size_t cx_hash_sha256(const uint8_t *in, size_t len, uint8_t *out, size_t out_len) { - EVP_MD_CTX *mdctx; - const EVP_MD *md; +size_t cx_hash_sha256(const uint8_t* in, size_t len, uint8_t* out, size_t out_len) { + EVP_MD_CTX* mdctx; + const EVP_MD* md; unsigned int hash_len; uint8_t tmpBuf[EVP_MAX_MD_SIZE]; @@ -47,6 +49,6 @@ size_t cx_hash_sha256(const uint8_t *in, size_t len, uint8_t *out, size_t out_le hash_len = ERR_INVALID_DATA; else memcpy(out, tmpBuf, hash_len); - + return hash_len; } diff --git a/gdb.sh b/gdb.sh new file mode 100755 index 0000000..937fa2c --- /dev/null +++ b/gdb.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +docker compose up -d + +# Wait for the container to start +until docker inspect -f '{{.State.Status}}' app-everscale-nanosp-1 | grep -q "running"; do + sleep 1 +done + +docker exec -it app-everscale-nanosp-1 ./tools/debug.sh apps/app.elf + +docker compose down \ No newline at end of file diff --git a/icons/nanos_app_everscale.gif b/glyphs/app_everscale_16px.gif similarity index 100% rename from icons/nanos_app_everscale.gif rename to glyphs/app_everscale_16px.gif diff --git a/glyphs/app_everscale_64px.gif b/glyphs/app_everscale_64px.gif new file mode 100644 index 0000000..5347c2c Binary files /dev/null and b/glyphs/app_everscale_64px.gif differ diff --git a/icons/nanos_app_venom.gif b/glyphs/app_venom_16px.gif similarity index 100% rename from icons/nanos_app_venom.gif rename to glyphs/app_venom_16px.gif diff --git a/glyphs/app_venom_64px.gif b/glyphs/app_venom_64px.gif new file mode 100644 index 0000000..add4950 Binary files /dev/null and b/glyphs/app_venom_64px.gif differ diff --git a/icons/nanox_app_everscale.gif b/icons/app_everscale_14px.gif similarity index 100% rename from icons/nanox_app_everscale.gif rename to icons/app_everscale_14px.gif diff --git a/icons/app_everscale_16px.gif b/icons/app_everscale_16px.gif new file mode 100644 index 0000000..b362f69 Binary files /dev/null and b/icons/app_everscale_16px.gif differ diff --git a/icons/app_everscale_32px.gif b/icons/app_everscale_32px.gif new file mode 100644 index 0000000..516045f Binary files /dev/null and b/icons/app_everscale_32px.gif differ diff --git a/icons/app_everscale_40px.gif b/icons/app_everscale_40px.gif new file mode 100644 index 0000000..2c61a3d Binary files /dev/null and b/icons/app_everscale_40px.gif differ diff --git a/icons/nanox_app_venom.gif b/icons/app_venom_14px.gif similarity index 100% rename from icons/nanox_app_venom.gif rename to icons/app_venom_14px.gif diff --git a/icons/app_venom_16px.gif b/icons/app_venom_16px.gif new file mode 100644 index 0000000..c98d292 Binary files /dev/null and b/icons/app_venom_16px.gif differ diff --git a/icons/app_venom_32px.gif b/icons/app_venom_32px.gif new file mode 100644 index 0000000..df4c621 Binary files /dev/null and b/icons/app_venom_32px.gif differ diff --git a/icons/app_venom_40px.gif b/icons/app_venom_40px.gif new file mode 100644 index 0000000..d02fbc1 Binary files /dev/null and b/icons/app_venom_40px.gif differ diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 0000000..7794dab --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,7 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos+", "nanox", "flex", "stax"] + +[tests] +pytest_directory = "./tests/" diff --git a/src/apdu/dispatcher.c b/src/apdu/dispatcher.c new file mode 100644 index 0000000..4a463d6 --- /dev/null +++ b/src/apdu/dispatcher.c @@ -0,0 +1,128 @@ +/***************************************************************************** + * Ledger App Everscale. + * (c) 2020 Ledger SAS. + * + * 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 +#include +#include "parser.h" + +#include "buffer.h" +#include "io.h" +#include "ledger_assert.h" +#include "apdu_constants.h" +#include "dispatcher.h" +#include "globals.h" +#include "handler/get_app_configuration.h" +#include "handler/get_public_key.h" +#include "handler/sign_transaction.h" +#include "handler/get_address.h" +#include "handler/sign.h" + +int apdu_dispatcher(const command_t* cmd, volatile unsigned int* flags) { + LEDGER_ASSERT(cmd != NULL, "NULL cmd"); + + if (cmd->cla != CLA) { + return io_send_sw(ERR_CLA_NOT_SUPPORTED); + } + + buffer_t buf = {0}; + + switch (cmd->ins) { + case INS_GET_APP_CONFIGURATION: + if (cmd->p1 != 0 || cmd->p2 != 0) { + return io_send_sw(ERR_WRONG_P1P2); + } + if (cmd->lc != 0) { + return io_send_sw(ERR_WRONG_DATA_LENGTH); + } + + return handleGetAppConfiguration(); + case INS_GET_PUBLIC_KEY: + if (cmd->p1 > 1 || cmd->p2 > 0) { + return io_send_sw(ERR_WRONG_P1P2); + } + if (cmd->lc != sizeof(uint32_t)) { + return io_send_sw(ERR_WRONG_DATA_LENGTH); + } + + if (!cmd->data) { + return io_send_sw(ERR_NO_DATA); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + + return handleGetPublicKey(&buf, (bool) cmd->p1, flags); + case INS_GET_ADDRESS: + if (cmd->p1 > 1 || cmd->p2 > 0) { + return io_send_sw(ERR_WRONG_P1P2); + } + if (cmd->lc != sizeof(uint32_t) + sizeof(uint8_t)) { + return io_send_sw(ERR_WRONG_DATA_LENGTH); + } + + if (!cmd->data) { + return io_send_sw(ERR_NO_DATA); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + + return handleGetAddress(&buf, (bool) cmd->p1, flags); + case INS_SIGN: + if (cmd->p1 != 1 || cmd->p2 > 0) { + return io_send_sw(ERR_WRONG_P1P2); + } + if (cmd->lc == 0) { + return io_send_sw(ERR_WRONG_DATA_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + + return handleSign(&buf, flags); + + case INS_SIGN_TRANSACTION: + if (cmd->p1 != P1_CONFIRM || cmd->p2 > 3) { + return io_send_sw(ERR_WRONG_P1P2); + } + + if (!cmd->data) { + return io_send_sw(ERR_NO_DATA); + } + // P2_MORE is a signal for more apdu to receive in current chunk; + // P2_EXTEND is a signal for extended buffer and can't be in first chunk; + // P2_MORE && !P2_EXTEND = first chunk; + // P2_EXTEND && !P2_MORE = last chunk; + // P2_EXTEND && P2_MORE = ordinary request without chunks; + + // P2_EXTEND is set to signal that this APDU buffer extends, rather + // than replaces, the current message buffer + bool more = (bool) (cmd->p2 & P2_MORE); + bool first_data_chunk = !(cmd->p2 & P2_EXTEND); + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + + return handleSignTransaction(&buf, first_data_chunk, more, flags); + default: + return io_send_sw(ERR_INS_NOT_SUPPORTED); + } +} diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h new file mode 100644 index 0000000..34e0841 --- /dev/null +++ b/src/apdu/dispatcher.h @@ -0,0 +1,3 @@ +#pragma once + +int apdu_dispatcher(const command_t* cmd, volatile unsigned int* flags); diff --git a/src/apdu_constants.h b/src/apdu_constants.h index cfefca3..d8f1160 100644 --- a/src/apdu_constants.h +++ b/src/apdu_constants.h @@ -1,5 +1,4 @@ -#ifndef _APDU_CONSTANTS_H_ -#define _APDU_CONSTANTS_H_ +#pragma once #include #include @@ -9,24 +8,18 @@ #include "cx.h" #include "os_io_seproxyhal.h" -#define CLA 0xE0 +#define CLA 0xE0 #define INS_GET_APP_CONFIGURATION 0x01 -#define INS_GET_PUBLIC_KEY 0x02 -#define INS_SIGN 0x03 -#define INS_GET_ADDRESS 0x04 -#define INS_SIGN_TRANSACTION 0x05 +#define INS_GET_PUBLIC_KEY 0x02 +#define INS_SIGN 0x03 +#define INS_GET_ADDRESS 0x04 +#define INS_SIGN_TRANSACTION 0x05 -#define OFFSET_CLA 0 -#define OFFSET_INS 1 -#define OFFSET_P1 2 -#define OFFSET_P2 3 -#define OFFSET_LC 4 +#define OFFSET_CLA 0 +#define OFFSET_INS 1 +#define OFFSET_P1 2 +#define OFFSET_P2 3 +#define OFFSET_LC 4 #define OFFSET_CDATA 5 -void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx); -void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx); -void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx); -void handleSign(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags); -int handleSignTransaction(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, bool is_first_chunk, bool more); - -#endif +#define APPVERSION_LEN 3 diff --git a/src/cell.c b/src/cell.c index 5cd703f..c3595ec 100644 --- a/src/cell.c +++ b/src/cell.c @@ -62,18 +62,20 @@ uint16_t Cell_bit_len(struct Cell_t* self) { return bit_len; } -uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const uint8_t cells_count) { +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 rc = d1 & 7; // refs count + uint8_t level = d1 >> 5; // level + uint8_t hashes = (d1 & 16) == 16; // with hashes + uint8_t exotic = (d1 & 8) == 8; // exotic + uint8_t rc = d1 & 7; // refs count uint8_t absent = rc == 7 && hashes; uint8_t pruned = d1 == PRUNED_BRANCH_D1; UNUSED(level); VALIDATE(!hashes, ERR_INVALID_CELL); - VALIDATE(!exotic || pruned, ERR_INVALID_CELL); // only ordinary or pruned cells are valid + VALIDATE(!exotic || pruned, ERR_INVALID_CELL); // only ordinary or pruned cells are valid VALIDATE(rc <= MAX_REFERENCES_COUNT, ERR_INVALID_CELL); VALIDATE(!absent, ERR_INVALID_CELL); @@ -89,7 +91,7 @@ uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const u VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_CELL); } - return CELL_DATA_OFFSET + data_size + refs_count; // cell size + return CELL_DATA_OFFSET + data_size + refs_count; // cell size } void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) { @@ -108,7 +110,7 @@ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) { return; } - uint8_t hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32)) + 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; @@ -143,6 +145,9 @@ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) { hash_buffer_offset += HASH_SIZE; } - int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, bc->hashes + cell_index * HASH_SIZE, 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/cell.h b/src/cell.h index 28fa859..f14105f 100644 --- a/src/cell.h +++ b/src/cell.h @@ -4,7 +4,7 @@ #include #include -#define CELL_DATA_OFFSET 2 +#define CELL_DATA_OFFSET 2 #define MAX_REFERENCES_COUNT 4 typedef struct Cell_t { diff --git a/src/contract.c b/src/contract.c index 45b353e..2b2acdf 100644 --- a/src/contract.c +++ b/src/contract.c @@ -7,117 +7,87 @@ #include "hashmap_label.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; @@ -139,7 +109,7 @@ void deserialize_cells_tree(struct ByteStream_t* src) { VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_CONTRACT); } - uint8_t ref_size = first_byte & 0x7; // size in bytes + uint8_t ref_size = first_byte & 0x7; // size in bytes VALIDATE(ref_size == 1, ERR_INVALID_CONTRACT); uint8_t offset_size = ByteStream_read_byte(src); @@ -184,7 +154,7 @@ void deserialize_cells_tree(struct ByteStream_t* src) { void find_public_key_cell() { BocContext_t* bc = &boc_context; - VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, ERR_INVALID_CONTRACT); // has data branch + VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, ERR_INVALID_CONTRACT); // has data branch uint8_t refs_count = 0; uint8_t* refs = Cell_get_refs(&bc->cells[0], &refs_count); @@ -211,12 +181,12 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) { // Compute data hash { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32) + 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[0] = 0x00; // d1(1) + hash_buffer[1] = 0x50; // d2(1) hash_buffer_offset += 2; // Data @@ -225,7 +195,7 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) { // Pubkey uint8_t public_key[PUBLIC_KEY_LENGTH]; - get_public_key(account_number, public_key); + VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED); memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); hash_buffer_offset += PUBLIC_KEY_LENGTH; @@ -237,11 +207,11 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) { // Compute address { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32) + 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[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) hash_buffer_offset += 2; // Data @@ -269,17 +239,17 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) { // Compute data hash { - uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) + uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8) uint16_t hash_buffer_offset = 0; - hash_buffer[0] = 0x00; // d1(1) - hash_buffer[1] = 0x50; // d2(1) + 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); + VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED); memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH); hash_buffer_offset += PUBLIC_KEY_LENGTH; @@ -295,11 +265,11 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) { // Compute address { - uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32) + 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[0] = 0x02; // d1(1) + hash_buffer[1] = 0x01; // d2(1) hash_buffer_offset += 2; // Data @@ -310,7 +280,9 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) { hash_buffer_offset += sizeof(uint32_t); // Code hash - memcpy(hash_buffer + hash_buffer_offset, ever_wallet_code_hash, sizeof(ever_wallet_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 @@ -322,17 +294,22 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) { } } -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) { +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); + ByteStream_init(&src, (uint8_t*) wallet, wallet_size); deserialize_cells_tree(&src); } BocContext_t* bc = &boc_context; VALIDATE(bc->cells_count != 0, ERR_INVALID_CONTRACT); - find_public_key_cell(); // sets public key cell index to boc_context + 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); @@ -341,12 +318,13 @@ void compute_multisig_address(uint32_t account_number, const uint8_t* wallet, ui VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, ERR_INVALID_CONTRACT); 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_CONTRACT); + VALIDATE(cell_data_size != 0 && cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, + ERR_INVALID_CONTRACT); 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); + VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED); uint8_t* data = bc->public_key_cell_data; SliceData_t slice; @@ -442,6 +420,7 @@ void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* ad #else -void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* address) {} +void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* address) { +} #endif diff --git a/src/contract.h b/src/contract.h index 80b8d2e..2f0be49 100644 --- a/src/contract.h +++ b/src/contract.h @@ -6,27 +6,27 @@ #include #include -#define SIGN_TRANSACTION_FLOW_ERROR -1 +#define SIGN_TRANSACTION_FLOW_ERROR -1 #define SIGN_TRANSACTION_FLOW_TRANSFER 0 -#define SIGN_TRANSACTION_FLOW_DEPLOY 1 -#define SIGN_TRANSACTION_FLOW_CONFIRM 2 -#define SIGN_TRANSACTION_FLOW_BURN 3 +#define SIGN_TRANSACTION_FLOW_DEPLOY 1 +#define SIGN_TRANSACTION_FLOW_CONFIRM 2 +#define SIGN_TRANSACTION_FLOW_BURN 3 enum { - 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, + 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, }; enum { MULTISIG_DEPLOY_TRANSACTION = 1813932348, - MULTISIG_SEND_TRANSACTION = 1290691692, + MULTISIG_SEND_TRANSACTION = 1290691692, MULTISIG_SUBMIT_TRANSACTION = 320701133, MULTISIG_CONFIRM_TRANSACTION = 447168749, @@ -40,11 +40,7 @@ enum { TOKEN_TRANSFER_TO_WALLET = 1185535980, // Ordinary transfer }; -enum { - NORMAL_FLAG = 3, - ALL_BALANCE_FLAG = 128, - ALL_BALANCE_AND_DELETE_FLAG = 160 -}; +enum { NORMAL_FLAG = 3, ALL_BALANCE_FLAG = 128, ALL_BALANCE_AND_DELETE_FLAG = 160 }; struct ByteStream_t; void deserialize_cells_tree(struct ByteStream_t* src); diff --git a/src/errors.h b/src/errors.h index b6b5ef9..06c5bd2 100644 --- a/src/errors.h +++ b/src/errors.h @@ -23,6 +23,17 @@ enum { ERR_INVALID_CELL = 0x6B17, ERR_INVALID_CONTRACT = 0x6B18, ERR_INVALID_MESSAGE = 0x6B19, + ERR_SIGNING_FAILED = 0x6B20, + ERR_GENERATE_PAIR_FAILED = 0x6B21, + ERR_INIT_PRIVATE_KEY_FAILED = 0x6B22, + ERR_DERIVE_PATH_FAILED = 0x6B23, + ERR_WRONG_DATA_LENGTH = 0x6B24, + ERR_CLA_NOT_SUPPORTED = 0x6B25, + ERR_WRONG_P1P2 = 0x6B26, + ERR_INS_NOT_SUPPORTED = 0x6B27, + ERR_NO_DATA = 0x6B28, + ERR_GET_PUBLIC_KEY_FAILED = 0x6B29, + ERR_USER_REJECTED = 0x6985, }; #endif diff --git a/src/get_address.c b/src/get_address.c deleted file mode 100644 index cef6b3c..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; - format_hex(context->address, sizeof(context->address), context->address_str, sizeof(context->address_str)); - ux_flow_init(0, ux_display_address_flow, NULL); - *flags |= IO_ASYNCH_REPLY; - return; - } - - THROW(ERR_INVALID_REQUEST); -} diff --git a/src/get_app_configuration.c b/src/get_app_configuration.c deleted file mode 100644 index d45dd60..0000000 --- a/src/get_app_configuration.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "apdu_constants.h" -#include "utils.h" -#include "errors.h" - -void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) { - UNUSED(dataBuffer); - 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); -} diff --git a/src/get_public_key.c b/src/get_public_key.c deleted file mode 100644 index 1617136..0000000 --- a/src/get_public_key.c +++ /dev/null @@ -1,71 +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; -} - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - -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 -); - -#endif - -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) { - format_hex(context->public_key, sizeof(context->public_key), context->public_key_str, sizeof(context->public_key_str)); -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - ux_flow_init(0, ux_display_public_flow, NULL); -#endif - *flags |= IO_ASYNCH_REPLY; - return; - } - - THROW(ERR_INVALID_REQUEST); -} diff --git a/src/globals.c b/src/globals.c deleted file mode 100644 index e8d7cc0..0000000 --- a/src/globals.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "globals.h" -#include "os.h" -#include "ux.h" - -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; - -// display stepped screens -unsigned int ux_step; -unsigned int ux_step_count; diff --git a/src/globals.h b/src/globals.h index ae82278..58338bb 100644 --- a/src/globals.h +++ b/src/globals.h @@ -8,40 +8,40 @@ #include "errors.h" #include "cell.h" -#define P1_CONFIRM 0x01 +#define P1_CONFIRM 0x01 #define P1_NON_CONFIRM 0x00 #define P2_EXTEND 0x01 -#define P2_MORE 0x02 +#define P2_MORE 0x02 -#define PUBLIC_KEY_LENGTH 32 -#define ADDRESS_LENGTH 32 +#define PUBLIC_KEY_LENGTH 32 +#define ADDRESS_LENGTH 32 #define TRANSACTION_ID_LENGTH 8 -#define BIP32_PATH 5 -#define AMOUNT_LENGHT 16 -#define TO_SIGN_LENGTH 32 -#define SIGN_MAGIC_LENGTH 4 -#define CHAIN_ID_LENGTH 4 -#define SIGNATURE_LENGTH 64 -#define HASH_SIZE 32 -#define MAX_ROOTS_COUNT 1 - -#define PRUNED_BRANCH_D1 0b00101000 +#define BIP32_PATH 5 +#define AMOUNT_LENGHT 16 +#define TO_SIGN_LENGTH 32 +#define SIGN_MAGIC_LENGTH 4 +#define CHAIN_ID_LENGTH 4 +#define SIGNATURE_LENGTH 64 +#define HASH_SIZE 32 +#define MAX_ROOTS_COUNT 1 + +#define PRUNED_BRANCH_D1 0b00101000 #define PRUNED_BRANCH_DATA_SIZE 36 #define MAX_TICKER_LEN 10 -#define MAX_DATA_LEN 1024 +#define MAX_DATA_LEN 1024 #define WALLET_ID 0x4BA92D8A -#define MAX_CONTRACT_CELLS_COUNT 7 -#define HASHES_BUFFER_SIZE (MAX_CONTRACT_CELLS_COUNT * HASH_SIZE) -#define MAX_PUBLIC_KEY_CELL_DATA_SIZE 36 // label(3) + public key(32) + tag(1) +#define MAX_CONTRACT_CELLS_COUNT 16 +#define HASHES_BUFFER_SIZE (MAX_CONTRACT_CELLS_COUNT * HASH_SIZE) +#define MAX_PUBLIC_KEY_CELL_DATA_SIZE 36 // label(3) + public key(32) + tag(1) -#define FLAG_WITH_WALLET_ID 0x01 +#define FLAG_WITH_WALLET_ID 0x01 #define FLAG_WITH_WORKCHAIN_ID 0x02 -#define FLAG_WITH_ADDRESS 0x04 -#define FLAG_WITH_CHAIN_ID 0x08 +#define FLAG_WITH_ADDRESS 0x04 +#define FLAG_WITH_CHAIN_ID 0x08 void reset_app_context(void); diff --git a/src/handler/get_address.c b/src/handler/get_address.c new file mode 100644 index 0000000..463269c --- /dev/null +++ b/src/handler/get_address.c @@ -0,0 +1,33 @@ +#include "format.h" +#include "read.h" +#include "apdu_constants.h" +#include "globals.h" +#include "utils.h" +#include "contract.h" +#include "slice_data.h" +#include "byte_stream.h" +#include "ui/display.h" +#include "errors.h" +#include "io.h" +#include "helper/send_response.h" + +int handleGetAddress(buffer_t* cdata, bool display, volatile unsigned int* flags) { + uint32_t account_number = read_u32_be(cdata->ptr, cdata->offset); + cdata->offset += sizeof(account_number); + + uint8_t wallet_type = cdata->ptr[cdata->offset++]; + + AddressContext_t* context = &data_context.addr_context; + get_address(account_number, wallet_type, context->address); + + if (display) { + format_hex(context->address, + sizeof(context->address), + context->address_str, + sizeof(context->address_str)); + ui_display_address(); + *flags |= IO_ASYNCH_REPLY; + return 0; + } + return helper_send_response_address(); +} diff --git a/src/handler/get_address.h b/src/handler/get_address.h new file mode 100644 index 0000000..74dbf4e --- /dev/null +++ b/src/handler/get_address.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +/** + * Handles the get address command + * @param cdata command data + * @param display display flag + * @param flags flags + * @return 0 on success, error code on failure + */ +int handleGetAddress(buffer_t* cdata, bool display, volatile unsigned int* flags); diff --git a/src/handler/get_app_configuration.c b/src/handler/get_app_configuration.c new file mode 100644 index 0000000..600a3dd --- /dev/null +++ b/src/handler/get_app_configuration.c @@ -0,0 +1,26 @@ + +#include // uint*_t +#include // UINT8_MAX +#include // _Static_assert + +#include "apdu_constants.h" +#include "utils.h" +#include "errors.h" +#include "io.h" + +int handleGetAppConfiguration() { + _Static_assert(APPVERSION_LEN == 3, "Length of (MAJOR || MINOR || PATCH) must be 3!"); + _Static_assert(MAJOR_VERSION >= 0 && MAJOR_VERSION <= UINT8_MAX, + "MAJOR version must be between 0 and 255!"); + _Static_assert(MINOR_VERSION >= 0 && MINOR_VERSION <= UINT8_MAX, + "MINOR version must be between 0 and 255!"); + _Static_assert(PATCH_VERSION >= 0 && PATCH_VERSION <= UINT8_MAX, + "PATCH version must be between 0 and 255!"); + + return io_send_response_pointer( + (const uint8_t*) &(uint8_t[APPVERSION_LEN]){(uint8_t) MAJOR_VERSION, + (uint8_t) MINOR_VERSION, + (uint8_t) PATCH_VERSION}, + APPVERSION_LEN, + SUCCESS); +} diff --git a/src/handler/get_app_configuration.h b/src/handler/get_app_configuration.h new file mode 100644 index 0000000..48b05a5 --- /dev/null +++ b/src/handler/get_app_configuration.h @@ -0,0 +1,3 @@ +#pragma once + +int handleGetAppConfiguration(); diff --git a/src/handler/get_public_key.c b/src/handler/get_public_key.c new file mode 100644 index 0000000..a4c47d1 --- /dev/null +++ b/src/handler/get_public_key.c @@ -0,0 +1,30 @@ +#include "os.h" +#include "ux.h" +#include "format.h" +#include "read.h" +#include "buffer.h" +#include "parser.h" +#include "utils.h" +#include "apdu_constants.h" +#include "errors.h" +#include "ui/display.h" +#include "helper/send_response.h" + +int handleGetPublicKey(buffer_t* cdata, bool display, volatile unsigned int* flags) { + uint32_t account_number = read_u32_be(cdata->ptr, cdata->offset); + PublicKeyContext_t* context = &data_context.pk_context; + if (get_public_key(account_number, context->public_key) != 0) { + return io_send_sw(ERR_GET_PUBLIC_KEY_FAILED); + } + + if (display) { + format_hex(context->public_key, + sizeof(context->public_key), + context->public_key_str, + sizeof(context->public_key_str)); + ui_display_public_key(); + *flags |= IO_ASYNCH_REPLY; + return 0; + } + return helper_send_response_public_key(); +} diff --git a/src/handler/get_public_key.h b/src/handler/get_public_key.h new file mode 100644 index 0000000..1cb0bb0 --- /dev/null +++ b/src/handler/get_public_key.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +/** + * Handles the get public key command + * @param cdata command data + * @param display display flag + * @param flags flags + */ +int handleGetPublicKey(buffer_t* cdata, bool display, volatile unsigned int* flags); diff --git a/src/handler/sign.c b/src/handler/sign.c new file mode 100644 index 0000000..8ccf25e --- /dev/null +++ b/src/handler/sign.c @@ -0,0 +1,30 @@ +#include "format.h" +#include "read.h" +#include "buffer.h" +#include "apdu_constants.h" +#include "utils.h" +#include "errors.h" +#include "ui/display.h" +#include "helper/send_response.h" + +static const char SIGN_MAGIC[] = {0xFF, 0xFF, 0xFF, 0xFF}; + +int handleSign(buffer_t* cdata, volatile unsigned int* flags) { + SignContext_t* context = &data_context.sign_context; + + VALIDATE(cdata->size >= sizeof(context->account_number), ERR_INVALID_REQUEST); + context->account_number = read_u32_be(cdata->ptr, cdata->offset); + cdata->offset += sizeof(context->account_number); + + VALIDATE(cdata->size >= cdata->offset + TO_SIGN_LENGTH, ERR_INVALID_REQUEST); + memcpy(context->to_sign, SIGN_MAGIC, SIGN_MAGIC_LENGTH); + memcpy(context->to_sign + SIGN_MAGIC_LENGTH, cdata->ptr + cdata->offset, TO_SIGN_LENGTH); + format_hex(context->to_sign, + SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, + context->to_sign_str, + sizeof(context->to_sign_str)); + + ui_display_sign(); + *flags |= IO_ASYNCH_REPLY; + return 0; +} diff --git a/src/handler/sign.h b/src/handler/sign.h new file mode 100644 index 0000000..79a13ae --- /dev/null +++ b/src/handler/sign.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "buffer.h" +/** + * Handles the sign command + * @param cdata input data buffer + * @param flags pointer to flags + */ +int handleSign(buffer_t* cdata, volatile unsigned int* flags); diff --git a/src/handler/sign_transaction.c b/src/handler/sign_transaction.c new file mode 100644 index 0000000..2a3acdf --- /dev/null +++ b/src/handler/sign_transaction.c @@ -0,0 +1,121 @@ +#include "apdu_constants.h" +#include "buffer.h" +#include "read.h" +#include "utils.h" +#include "io.h" +#include "errors.h" +#include "byte_stream.h" +#include "message.h" +#include "contract.h" +#include "ui/display.h" + +int handleSignTransaction(buffer_t* cdata, + bool is_first_chunk, + bool more, + volatile unsigned int* flags) { + if (is_first_chunk) { + reset_app_context(); + } + + SignTransactionContext_t* context = &data_context.sign_tr_context; + + if (is_first_chunk) { + VALIDATE(cdata->size >= cdata->offset + sizeof(context->account_number), + ERR_INVALID_REQUEST); + context->account_number = read_u32_be(cdata->ptr, cdata->offset); + cdata->offset += sizeof(context->account_number); + + VALIDATE(cdata->size >= cdata->offset + sizeof(context->origin_wallet_type), + ERR_INVALID_REQUEST); + context->origin_wallet_type = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(context->origin_wallet_type); + + VALIDATE(cdata->size >= cdata->offset + sizeof(context->decimals), ERR_INVALID_REQUEST); + context->decimals = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(context->decimals); + + VALIDATE(cdata->size >= cdata->offset + sizeof(uint8_t), ERR_INVALID_REQUEST); + uint8_t ticker_len = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(ticker_len); + + VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); + + VALIDATE(cdata->size >= cdata->offset + ticker_len, ERR_INVALID_REQUEST); + memcpy(context->ticker, cdata->ptr + cdata->offset, ticker_len); + cdata->offset += ticker_len; + + VALIDATE(cdata->size >= cdata->offset + sizeof(uint8_t), ERR_INVALID_REQUEST); + uint8_t metadata = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(metadata); + + // Read wallet type if present + if (metadata & FLAG_WITH_WALLET_ID) { + VALIDATE(cdata->size >= cdata->offset + sizeof(context->current_wallet_type), + ERR_INVALID_REQUEST); + context->current_wallet_type = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(context->current_wallet_type); + } else { + context->current_wallet_type = context->origin_wallet_type; + } + + // Get address + get_address(context->account_number, context->origin_wallet_type, context->address); + memset(&boc_context, 0, sizeof(boc_context)); + + // Read wc if present + context->wc = DEFAULT_WORKCHAIN_ID; + if (metadata & FLAG_WITH_WORKCHAIN_ID) { + VALIDATE(cdata->size >= cdata->offset + sizeof(context->wc), ERR_INVALID_REQUEST); + context->wc = cdata->ptr[cdata->offset]; + cdata->offset += sizeof(context->wc); + } + + // Read initial address if present + if (metadata & FLAG_WITH_ADDRESS) { + VALIDATE(cdata->size >= cdata->offset + sizeof(context->address), ERR_INVALID_REQUEST); + memcpy(context->prepend_address, cdata->ptr + cdata->offset, ADDRESS_LENGTH); + cdata->offset += sizeof(context->address); + } else { + memcpy(context->prepend_address, context->address, ADDRESS_LENGTH); + } + + // Read chain id if present + if (metadata & FLAG_WITH_CHAIN_ID) { + context->sign_with_chain_id = true; + + VALIDATE(cdata->size >= cdata->offset + sizeof(context->chain_id), ERR_INVALID_REQUEST); + memcpy(context->chain_id, cdata->ptr + cdata->offset, CHAIN_ID_LENGTH); + cdata->offset += sizeof(context->chain_id); + } else { + context->sign_with_chain_id = false; + } + } + // cdata->offset is a pointer to cdata->ptr, or the number of bytes we moved. here + + // cdata->offset means start of the message we need to save data to a context buffer and add + // msg_length to cdata->offset of this buffer + uint8_t* msg_begin = (uint8_t*) (cdata->ptr + cdata->offset); + + // Since we check LC cdata->size can not be manipulated + uint16_t msg_length = cdata->size - cdata->offset; + + if (msg_begin && msg_length > 0) { // if data exists + VALIDATE(context->data_offset + msg_length < sizeof(context->data), ERR_INVALID_DATA); + memcpy(context->data + context->data_offset, msg_begin, msg_length); + context->data_offset += msg_length; // add length of the new message to our context offset + } + + if (more) { + return io_send_sw(SUCCESS); + } + + // Handle transaction + ByteStream_t src; + ByteStream_init(&src, context->data, context->data_offset); + + int flow = prepare_to_sign(&src, context->wc, context->address, context->prepend_address); + + ui_display_sign_transaction(flow); + + *flags |= IO_ASYNCH_REPLY; + return 0; +} diff --git a/src/handler/sign_transaction.h b/src/handler/sign_transaction.h new file mode 100644 index 0000000..635cb6b --- /dev/null +++ b/src/handler/sign_transaction.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +/** + * Handles the sign transaction command + * @param cdata input data buffer + * @param is_first_chunk indicates if this is the first chunk of data + * @param more indicates if more chunks are expected + * @param flags pointer to flags + * @return 0 on success, -1 on error + */ +int handleSignTransaction(buffer_t* cdata, + bool is_first_chunk, + bool more, + volatile unsigned int* flags); diff --git a/src/hashmap_label.c b/src/hashmap_label.c index 84e5fe2..aaf85a5 100644 --- a/src/hashmap_label.c +++ b/src/hashmap_label.c @@ -10,15 +10,15 @@ uint8_t get_label_same(uint8_t max, struct SliceData_t* slice, struct SliceData_ VALIDATE(length <= 64, ERR_RANGE_CHECK); uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0); - SliceData_fill(label, value, length_bytes); + 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 + 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); } @@ -43,7 +43,7 @@ void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t* key) 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 + 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; @@ -51,10 +51,12 @@ void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t* key) // common prefix { - uint8_t max_prefix_len = MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key)); + 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)) { + while (i < max_prefix_len && + SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) { i += 1; } diff --git a/src/helper/send_response.c b/src/helper/send_response.c new file mode 100644 index 0000000..a5a211f --- /dev/null +++ b/src/helper/send_response.c @@ -0,0 +1,39 @@ +#include "helper/send_response.h" + +int helper_send_response_public_key() { + uint8_t resp[1 + PUBLIC_KEY_LENGTH] = {0}; + size_t offset = 0; + resp[offset++] = PUBLIC_KEY_LENGTH; + memmove(resp + offset, data_context.pk_context.public_key, PUBLIC_KEY_LENGTH); + offset += PUBLIC_KEY_LENGTH; + reset_app_context(); + return io_send_response_pointer(resp, offset, SUCCESS); +} + +int helper_send_response_address() { + uint8_t resp[1 + ADDRESS_LENGTH] = {0}; + size_t offset = 0; + resp[offset++] = ADDRESS_LENGTH; + memmove(resp + offset, data_context.addr_context.address, ADDRESS_LENGTH); + offset += ADDRESS_LENGTH; + reset_app_context(); + return io_send_response_pointer(resp, offset, SUCCESS); +} + +int helper_send_response_sign() { + uint8_t resp[1 + SIGNATURE_LENGTH] = {0}; + size_t offset = 0; + resp[offset++] = SIGNATURE_LENGTH; + memmove(resp + offset, data_context.sign_context.signature, SIGNATURE_LENGTH); + offset += SIGNATURE_LENGTH; + return io_send_response_pointer(resp, offset, SUCCESS); +} + +int helper_send_response_sign_transaction() { + uint8_t resp[1 + SIGNATURE_LENGTH] = {0}; + size_t offset = 0; + resp[offset++] = SIGNATURE_LENGTH; + memmove(resp + offset, data_context.sign_tr_context.signature, SIGNATURE_LENGTH); + offset += SIGNATURE_LENGTH; + return io_send_response_pointer(resp, offset, SUCCESS); +} diff --git a/src/helper/send_response.h b/src/helper/send_response.h new file mode 100644 index 0000000..5ca7d0a --- /dev/null +++ b/src/helper/send_response.h @@ -0,0 +1,9 @@ +#pragma once +#include "globals.h" +#include "utils.h" +#include "io.h" + +int helper_send_response_public_key(); +int helper_send_response_address(); +int helper_send_response_sign_transaction(); +int helper_send_response_sign(); diff --git a/src/main.c b/src/main.c index 040ca7f..7789413 100644 --- a/src/main.c +++ b/src/main.c @@ -1,25 +1,27 @@ /******************************************************************************* -* 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 "io.h" #include "apdu_constants.h" - -unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +#include "parser.h" +#include "errors.h" +#include "ui/menu.h" +#include "apdu/dispatcher.h" BocContext_t boc_context; DataContext_t data_context; @@ -29,352 +31,56 @@ void reset_app_context() { memset(&data_context, 0, sizeof(data_context)); } -void reset_spi_buffer() { - memset(&G_io_seproxyhal_spi_buffer, 0, sizeof(G_io_seproxyhal_spi_buffer)); -} - -void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) { - unsigned short sw = 0; - - if (!flags || !tx) { - THROW(0x6802); - } - - if (rx < 0) { - THROW(0x6813); - } - - BEGIN_TRY { - TRY { - if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { - THROW(0x6E00); - } - // must at least hold the class and instruction - if (rx <= OFFSET_INS) { - THROW(0x6b00); - } - PRINTF("command: %d\n", G_io_apdu_buffer[OFFSET_INS]); - switch (G_io_apdu_buffer[OFFSET_INS]) { - case INS_GET_APP_CONFIGURATION: { - if (G_io_apdu_buffer[OFFSET_P1] != 0 || G_io_apdu_buffer[OFFSET_P2] != 0) { - THROW(0x6802); - } - - 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: { - if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) { - // the length of the APDU should match what's in the 5-byte header. - // If not fail. Don't want to buffer overrun or anything. - THROW(0x6985); - } - - 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_GET_ADDRESS: { - if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) { - // the length of the APDU should match what's in the 5-byte header. - // If not fail. Don't want to buffer overrun or anything. - THROW(0x6985); - } - - 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: { - if (G_io_apdu_buffer[OFFSET_P1] != P1_CONFIRM || G_io_apdu_buffer[OFFSET_P2] != 0) { - THROW(0x6802); - } - - if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) { - // the length of the APDU should match what's in the 5-byte header. - // If not fail. Don't want to buffer overrun or anything. - THROW(0x6985); - } - - handleSign(G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags); - } break; - - case INS_SIGN_TRANSACTION: { - if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) { - // the length of the APDU should match what's in the 5-byte header. - // If not fail. Don't want to buffer overrun or anything. - THROW(0x6985); - } - - uint8_t p1 = G_io_apdu_buffer[OFFSET_P1]; - if (p1 == P1_NON_CONFIRM) { - // Don't allow blind signing. - THROW(0x6808); - } - - uint8_t p2 = G_io_apdu_buffer[OFFSET_P2]; - bool more = (bool) (p2 & P2_MORE); - - // P2_MORE is a signal for more apdu to receive in current chunk; - // P2_EXTEND is a signal for extended buffer and can't be in first chunk; - // P2_MORE && !P2_EXTEND = first chunk; - // P2_EXTEND && !P2_MORE = last chunk; - // P2_EXTEND && P2_MORE = ordinary request without chunks; - - // P2_EXTEND is set to signal that this APDU buffer extends, rather - // than replaces, the current message buffer - bool first_data_chunk = !(p2 & P2_EXTEND); - - handleSignTransaction(G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, first_data_chunk, more); - } break; - - default: - THROW(0x6D00); - break; - } - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); - } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - sw = e; - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - 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; - // Stores the information about the current command. Some commands expect - // multiple APDUs before they become complete and executed. - reset_app_context(); - reset_spi_buffer(); - - // 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, rx); - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); - } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - sw = e; - break; - case 0x9000: - // All is well - sw = e; - break; - default: - // Internal error - sw = 0x6800 | (e & 0x7FF); - 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 -} - -// override point, but nothing more to do -void io_seproxyhal_display(const 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 + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; + // Structured APDU command + command_t cmd; - // 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 - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; + io_init(); - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; + ui_main_menu(); - 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; -} - - -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); - } - return 0; -} + reset_app_context(); -/** - * Exit the application and go back to the dashboard. - */ -void app_exit() { - BEGIN_TRY_L(exit) { - TRY_L(exit) { - os_sched_exit(-1); + for (;;) { + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; } - FINALLY_L(exit) { + // Parse APDU command from G_io_apdu_buffer + if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { + PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); + io_send_sw(ERR_WRONG_DATA_LENGTH); + continue; } - } - END_TRY_L(exit); -} - -void nv_app_state_init() { - -} - -__attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); - - // ensure exception will work as planned - os_boot(); - - for (;;) { - UX_INIT(); - + PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", + cmd.cla, + cmd.ins, + cmd.p1, + cmd.p2, + cmd.lc, + cmd.lc, + cmd.data); BEGIN_TRY { TRY { - io_seproxyhal_init(); - - nv_app_state_init(); - - USB_power(0); - USB_power(1); - - 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; + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd, &flags) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } } - CATCH_ALL { - break; + CATCH_OTHER(e) { + PRINTF("=> exception: %d\n", e); + io_send_sw(e); + return; } FINALLY { } } END_TRY; } - app_exit(); - return 0; -} +} \ No newline at end of file diff --git a/src/menu.c b/src/menu.c deleted file mode 100644 index 45d143f..0000000 --- a/src/menu.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "menu.h" -#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 -); - -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); -} diff --git a/src/menu.h b/src/menu.h deleted file mode 100644 index e7a5c46..0000000 --- a/src/menu.h +++ /dev/null @@ -1,12 +0,0 @@ -#include "globals.h" - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -#include "glyphs.h" -#endif - -#ifndef _MENU_H_ -#define _MENU_H_ - -void ui_idle(void); - -#endif diff --git a/src/message.c b/src/message.c index e21de54..b2d9cc6 100644 --- a/src/message.c +++ b/src/message.c @@ -4,11 +4,16 @@ #include "slice_data.h" #include "byte_stream.h" #include "contract.h" +#include "format.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) { +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) { @@ -35,7 +40,7 @@ void deserialize_address(struct SliceData_t* slice, int8_t* wc, uint8_t* address 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); @@ -57,18 +62,25 @@ void deserialize_value(struct SliceData_t* slice, uint8_t* value, uint8_t value_ } 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); + 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; - format_hex(address, ADDRESS_LENGTH, address_str, sizeof(data_context.sign_tr_context.address_str)); + format_hex(address, + ADDRESS_LENGTH, + address_str, + sizeof(data_context.sign_tr_context.address_str)); } -void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uint8_t decimals, const char* ticker) { +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; size_t amount_str_size = sizeof(data_context.sign_tr_context.amount_str); @@ -77,8 +89,10 @@ void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uin switch (flags) { case NORMAL_FLAG: { const char* space = " "; - uint8_t text_size = convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str); - VALIDATE(amount_str_size >= text_size + strlen(space) + strlen(ticker), ERR_INVALID_MESSAGE); + uint8_t text_size = + convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str); + VALIDATE(amount_str_size >= text_size + strlen(space) + strlen(ticker), + ERR_INVALID_MESSAGE); strncpy(amount_str + text_size, space, strlen(space)); strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker)); @@ -106,10 +120,15 @@ void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uin 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)); - format_hex(transaction_id, TRANSACTION_ID_LENGTH, transaction_id_str, sizeof(data_context.sign_tr_context.transaction_id_str)); + format_hex(transaction_id, + TRANSACTION_ID_LENGTH, + transaction_id_str, + sizeof(data_context.sign_tr_context.transaction_id_str)); } -void deserialize_int_message_header(struct SliceData_t* slice, uint8_t flags, SignTransactionContext_t* ctx) { +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_MESSAGE); @@ -160,11 +179,13 @@ void deserialize_int_message_header(struct SliceData_t* slice, uint8_t flags, Si UNUSED(created_at); } - -int deserialize_token_body(struct SliceData_t* slice, struct SliceData_t* ref_slice, SignTransactionContext_t* ctx) { +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)) { + if (!ref_slice || !ref_slice->data || + (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) { // Empty payload is ok return SIGN_TRANSACTION_FLOW_TRANSFER; } @@ -235,7 +256,11 @@ int deserialize_token_body(struct SliceData_t* slice, struct SliceData_t* ref_sl 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 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) { @@ -331,10 +356,16 @@ void prepare_payload_hash(BocContext_t* bc) { } 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); + 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); + 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); } } @@ -372,9 +403,13 @@ uint32_t deserialize_contract_header(struct SliceData_t* slice) { 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) { +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) + 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); @@ -386,11 +421,11 @@ void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, st SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size); // Append prefix - uint8_t prefix[] = { 0x80 }; // $100 prefix AddrStd + uint8_t prefix[] = {0x80}; // $100 prefix AddrStd SliceData_append(&slice, prefix, 3, false); // Append workchain - uint8_t wc_buf[] = { wc }; + uint8_t wc_buf[] = {wc}; SliceData_append(&slice, wc_buf, 8, false); // Append address @@ -415,7 +450,10 @@ void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, st cell->cell_begin = cell_buffer; } -int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint8_t* prepend_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; @@ -465,7 +503,8 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint 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 @@ -494,7 +533,11 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint 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); @@ -508,7 +551,8 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint 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); + sign_transaction_flow = + deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context); } } @@ -530,7 +574,11 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint 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); @@ -544,13 +592,18 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint 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); + 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); + 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); diff --git a/src/message.h b/src/message.h index cd48c84..296f600 100644 --- a/src/message.h +++ b/src/message.h @@ -6,6 +6,9 @@ #define DEFAULT_WORKCHAIN_ID 0 struct ByteStream_t; -int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint8_t* prepend_address); +int prepare_to_sign(struct ByteStream_t* src, + uint8_t wc, + uint8_t* address, + uint8_t* prepend_address); #endif diff --git a/src/sign.c b/src/sign.c deleted file mode 100644 index 37d2c3e..0000000 --- a/src/sign.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "apdu_constants.h" -#include "utils.h" -#include "errors.h" - -static const char SIGN_MAGIC[] = {0xFF, 0xFF, 0xFF, 0xFF }; - -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); - cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL); - } FINALLY { - explicit_bzero(&privateKey, 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", - .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 *dataBuffer, __attribute__((unused)) uint16_t dataLength, volatile unsigned int *flags) { - SignContext_t* context = &data_context.sign_context; - - size_t offset = 0; - - VALIDATE(dataLength >= offset + sizeof(context->account_number), ERR_INVALID_REQUEST); - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); - - VALIDATE(dataLength >= offset + TO_SIGN_LENGTH, ERR_INVALID_REQUEST); - memcpy(context->to_sign, SIGN_MAGIC, SIGN_MAGIC_LENGTH); - memcpy(context->to_sign + SIGN_MAGIC_LENGTH, dataBuffer + offset, TO_SIGN_LENGTH); - format_hex(context->to_sign, SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, context->to_sign_str, sizeof(context->to_sign_str)); - - 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 6636886..0000000 --- a/src/sign_transaction.c +++ /dev/null @@ -1,259 +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 { - explicit_bzero(&privateKey, 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 -); - -int handleSignTransaction(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, bool is_first_chunk, bool more) { - if (is_first_chunk) { - reset_app_context(); - } - - SignTransactionContext_t *context = &data_context.sign_tr_context; - - size_t offset = 0; - - if (is_first_chunk) { - VALIDATE(dataLength >= offset + sizeof(context->account_number), ERR_INVALID_REQUEST); - context->account_number = readUint32BE(dataBuffer + offset); - offset += sizeof(context->account_number); - - VALIDATE(dataLength >= offset + sizeof(context->origin_wallet_type), ERR_INVALID_REQUEST); - context->origin_wallet_type = dataBuffer[offset]; - offset += sizeof(context->origin_wallet_type); - - VALIDATE(dataLength >= offset + sizeof(context->decimals), ERR_INVALID_REQUEST); - context->decimals = dataBuffer[offset]; - offset += sizeof(context->decimals); - - VALIDATE(dataLength >= offset + sizeof(uint8_t), ERR_INVALID_REQUEST); - uint8_t ticker_len = dataBuffer[offset]; - offset += sizeof(ticker_len); - - VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH); - - VALIDATE(dataLength >= offset + ticker_len, ERR_INVALID_REQUEST); - memcpy(context->ticker, dataBuffer + offset, ticker_len); - offset += ticker_len; - - VALIDATE(dataLength >= offset + sizeof(uint8_t), ERR_INVALID_REQUEST); - uint8_t metadata = dataBuffer[offset]; - offset += sizeof(metadata); - - // Read wallet type if present - if (metadata & FLAG_WITH_WALLET_ID) { - VALIDATE(dataLength >= offset + sizeof(context->current_wallet_type), ERR_INVALID_REQUEST); - context->current_wallet_type = dataBuffer[offset]; - offset += sizeof(context->current_wallet_type); - } else { - context->current_wallet_type = context->origin_wallet_type; - } - - // Get address - get_address(context->account_number, context->origin_wallet_type, context->address); - memset(&boc_context, 0, sizeof(boc_context)); - - // Read wc if present - context->wc = DEFAULT_WORKCHAIN_ID; - if (metadata & FLAG_WITH_WORKCHAIN_ID) { - VALIDATE(dataLength >= offset + sizeof(context->wc), ERR_INVALID_REQUEST); - context->wc = dataBuffer[offset]; - offset += sizeof(context->wc); - } - - // Read initial address if present - if (metadata & FLAG_WITH_ADDRESS) { - VALIDATE(dataLength >= offset + sizeof(context->address), ERR_INVALID_REQUEST); - memcpy(context->prepend_address, dataBuffer + offset, ADDRESS_LENGTH); - offset += sizeof(context->address); - } else { - memcpy(context->prepend_address, context->address, ADDRESS_LENGTH); - } - - // Read chain id if present - if (metadata & FLAG_WITH_CHAIN_ID) { - context->sign_with_chain_id = true; - - VALIDATE(dataLength >= offset + sizeof(context->chain_id), ERR_INVALID_REQUEST); - memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH); - offset += sizeof(context->chain_id); - } else { - context->sign_with_chain_id = false; - } - } - // offset is a pointer to dataBuffer, or the number of bytes we moved. here + offset means start of the message - // we need to save data to a context buffer and add msg_length to offset of this buffer - uint8_t* msg_begin = dataBuffer + offset; - - // Since we check LC dataLength can not be manipulated - uint16_t msg_length = dataLength - offset; - - if (msg_begin && msg_length > 0) { // if data exists - VALIDATE(context->data_offset + msg_length < sizeof(context->data) , ERR_INVALID_DATA); - memcpy(context->data + context->data_offset, msg_begin, msg_length); - context->data_offset += msg_length; // add length of the new message to our context offset - } - - if (more) { - THROW(SUCCESS); - } - - // Handle transaction - ByteStream_t src; - ByteStream_init(&src, context->data, context->data_offset); - - int flow = prepare_to_sign(&src, context->wc, context->address, context->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..6eb9f6e 100644 --- a/src/slice_data.c +++ b/src/slice_data.c @@ -66,7 +66,7 @@ uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint } ret = (ret >> (8 - r)) >> (8 - bits); - return (uint8_t)ret; + return (uint8_t) ret; } } @@ -161,8 +161,7 @@ void SliceData_append(struct SliceData_t* self, uint8_t* in, uint16_t bits, bool uint16_t offset = self->data_window_start; if (offset % 8 == 0 || bytes == 0) { memcpy(self->data + offset / 8, in, bytes ? bytes : 1); - } - else { + } else { uint8_t shift = offset % 8; uint8_t first_data_byte = offset / 8; uint8_t prev = 0; diff --git a/src/text b/src/text new file mode 100644 index 0000000..4b62c2e --- /dev/null +++ b/src/text @@ -0,0 +1,385 @@ +/usr/bin/docker run --name cf2912b6eda476ca142b2814c965c07_cbf8c6 --label 119993 --workdir /github/workspace --rm -e "INPUT_SOURCE" -e "INPUT_EXTENSIONS" -e "INPUT_CLANGFORMATVERSION" -e "INPUT_EXCLUDE" -e "INPUT_STYLE" -e "INPUT_INPLACE" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e "ACTIONS_RESULTS_URL" -e GITHUB_ACTIONS=true -e CI=true --network github_network_87a5535abc654fe98bcb659114df86d4 -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/app-everscale/app-everscale":"/github/workspace" 119993:0cf2912b6eda476ca142b2814c965c07 "--clang-format-executable" "/clang-format/clang-format12" "-r" "--color" "always" "--style" "file" "--inplace" "false" "--extensions" "h,c" "--exclude" "none" "./src" +Processing 26 files: ./src/menu.c, ./src/sign.c, ./src/main.c, ./src/contract.c, ./src/contract.h, ./src/hashmap_label.c, ./src/message.h, ./src/menu.h, ./src/apdu_constants.h, ./src/message.c, ./src/cell.h, ./src/slice_data.c, ./src/byte_stream.c, ./src/get_app_configuration.c, ./src/slice_data.h, ./src/get_public_key.c, ./src/globals.c, ./src/sign_transaction.c, ./src/globals.h, ./src/errors.h, ./src/cell.c, ./src/get_address.c, ./src/utils.c, ./src/byte_stream.h, ./src/hashmap_label.h, ./src/utils.h +--- ./src/message.h (original) ++++ ./src/message.h (reformatted) +@@ -6,6 +6,9 @@ +#define DEFAULT_WORKCHAIN_ID 0 + + struct ByteStream_t; +- + int + prepare_to_sign(struct ByteStream_t* src, + uint8_t wc, + uint8_t* address, + uint8_t* prepend_address); ++ + int + prepare_to_sign(struct ByteStream_t* src, + +uint8_t wc, + +uint8_t* address, + +uint8_t* prepend_address); + +#endif +-- -./ src / contract.h(original)++ +./ src / contract.h(reformatted) @ @-13, 21 + 13, + 21 @ @ +#define SIGN_TRANSACTION_FLOW_BURN 3 + + enum { + -WALLET_V3 = 0, + -EVER_WALLET = 1, + -SAFE_MULTISIG_WALLET = 2, + +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, + +SETCODE_MULTISIG_WALLET = 4, + +BRIDGE_MULTISIG_WALLET = 5, + +SURF_WALLET = 6, + +MULTISIG_2 = 7, + +MULTISIG_2_1 = 8, + }; + +enum { + -MULTISIG_DEPLOY_TRANSACTION = 1813932348, + -MULTISIG_SEND_TRANSACTION = 1290691692, + -MULTISIG_SUBMIT_TRANSACTION = 320701133, + +MULTISIG_DEPLOY_TRANSACTION = 1813932348, + +MULTISIG_SEND_TRANSACTION = 1290691692, + +MULTISIG_SUBMIT_TRANSACTION = 320701133, + MULTISIG_CONFIRM_TRANSACTION = 447168749, + + MULTISIG2_DEPLOY_TRANSACTION = 733015951, + @ @-35, + 16 + 35, + 12 @ @ +}; + +enum { + -TOKEN_BURN = 1445284013, // Burn + -TOKEN_TRANSFER = 1944199491, // Deploy + +TOKEN_BURN = 1445284013, // Burn + +TOKEN_TRANSFER = 1944199491, // Deploy + TOKEN_TRANSFER_TO_WALLET = 1185535980, // Ordinary transfer +}; + +- enum { -NORMAL_FLAG = 3, -ALL_BALANCE_FLAG = 128, -ALL_BALANCE_AND_DELETE_FLAG = 160 - }; ++ enum { NORMAL_FLAG = 3, ALL_BALANCE_FLAG = 128, ALL_BALANCE_AND_DELETE_FLAG = 160 }; + +struct ByteStream_t; +void deserialize_cells_tree(struct ByteStream_t* src); +-- -./ src / apdu_constants.h(original)++ +./ src / apdu_constants.h(reformatted) @ @-23, 29 + 23, + 29 @ @ +#define OFFSET_LC 4 +#define OFFSET_CDATA 5 + + -void handleGetAppConfiguration(uint8_t p1, + -uint8_t p2, + -uint8_t* dataBuffer, + -uint16_t dataLength, + -volatile unsigned int* flags, + -volatile unsigned int* tx); +- void +handleGetPublicKey(uint8_t p1, + -uint8_t p2, + -uint8_t* dataBuffer, + -uint16_t dataLength, + -volatile unsigned int* flags, + -volatile unsigned int* tx); +- void +handleGetAddress(uint8_t p1, + -uint8_t p2, + -uint8_t* dataBuffer, + -uint16_t dataLength, + -volatile unsigned int* flags, + -volatile unsigned int* tx); +- void handleSign(uint8_t* dataBuffer, uint16_t dataLength, volatile unsigned int* flags); +- void +handleSignTransaction(uint8_t* dataBuffer, + -uint16_t dataLength, + -volatile unsigned int* flags, + -bool is_first_chunk, + -bool more); ++ void +handleGetAppConfiguration(uint8_t p1, + +uint8_t p2, + +uint8_t* dataBuffer, + +uint16_t dataLength, + +volatile unsigned int* flags, + +volatile unsigned int* tx); ++ void +handleGetPublicKey(uint8_t p1, + +uint8_t p2, + +uint8_t* dataBuffer, + +uint16_t dataLength, + +volatile unsigned int* flags, + +volatile unsigned int* tx); ++ void +handleGetAddress(uint8_t p1, + +uint8_t p2, + +uint8_t* dataBuffer, + +uint16_t dataLength, + +volatile unsigned int* flags, + +volatile unsigned int* tx); ++ void handleSign(uint8_t* dataBuffer, uint16_t dataLength, volatile unsigned int* flags); ++ void +handleSignTransaction(uint8_t* dataBuffer, + +uint16_t dataLength, + +volatile unsigned int* flags, + +bool is_first_chunk, + +bool more); + +#endif +-- -./ src / cell.h(original)++ +./ src / cell.h(reformatted) @ @-12, 14 + 12, + 14 @ @uint16_t cell_length; +} +Cell_t; + +- void Cell_init(struct Cell_t* self, uint8_t* cell_begin, uint16_t cell_length); +- uint8_t Cell_get_d1(const struct Cell_t* self); +- uint8_t Cell_get_d2(const struct Cell_t* self); +- uint8_t Cell_get_data_size(const struct Cell_t* self); ++ void Cell_init(struct Cell_t* self, uint8_t* cell_begin, uint16_t cell_length); ++ uint8_t Cell_get_d1(const struct Cell_t* self); ++ uint8_t Cell_get_d2(const struct Cell_t* self); ++ uint8_t Cell_get_data_size(const struct Cell_t* self); +uint8_t* Cell_get_data(const struct Cell_t* self); +uint8_t* Cell_get_refs(const struct Cell_t* self, uint8_t* refs_count); +uint16_t Cell_bit_len(struct Cell_t* self); +uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const uint8_t cells_count); +- void calc_cell_hash(Cell_t* cell, const uint8_t cell_index); ++ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index); + +#endif +-- -./ src / slice_data.h(original)++ +./ src / slice_data.h(reformatted) @ @-13, 22 + 13, + 22 @ @ + + struct Cell_t; + +- void SliceData_init(struct SliceData_t* self, uint8_t* data, uint16_t data_size_bytes); +- void SliceData_from_cell(struct SliceData_t* self, struct Cell_t* cell); +- void SliceData_fill(struct SliceData_t* self, uint8_t value, uint16_t data_size_bytes); +- void SliceData_truncate(struct SliceData_t* self, uint16_t size); ++ void SliceData_init(struct SliceData_t* self, uint8_t* data, uint16_t data_size_bytes); ++ void SliceData_from_cell(struct SliceData_t* self, struct Cell_t* cell); ++ void SliceData_fill(struct SliceData_t* self, uint8_t value, uint16_t data_size_bytes); ++ void SliceData_truncate(struct SliceData_t* self, uint16_t size); +uint16_t SliceData_remaining_bits(const struct SliceData_t* self); +- void SliceData_move_by(struct SliceData_t* self, uint16_t offset); +- uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint8_t bits); +- uint8_t SliceData_get_next_bit(struct SliceData_t* self); +- uint8_t SliceData_get_next_byte(struct SliceData_t* self); ++ void SliceData_move_by(struct SliceData_t* self, uint16_t offset); ++ uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint8_t bits); ++ uint8_t SliceData_get_next_bit(struct SliceData_t* self); ++ uint8_t SliceData_get_next_byte(struct SliceData_t* self); +uint64_t SliceData_get_next_int(struct SliceData_t* self, uint8_t bits); +uint64_t SliceData_get_next_size(struct SliceData_t* self, uint16_t max_value); +- bool SliceData_is_empty(const struct SliceData_t* self); +- bool SliceData_equal(const struct SliceData_t* self, const struct SliceData_t* other); ++ bool SliceData_is_empty(const struct SliceData_t* self); ++ bool SliceData_equal(const struct SliceData_t* self, const struct SliceData_t* other); +uint16_t SliceData_get_cursor(const struct SliceData_t* self); +uint8_t* SliceData_begin(const struct SliceData_t* self); +uint16_t SliceData_data_size(const struct SliceData_t* self); +- void SliceData_append(struct SliceData_t* self, uint8_t* data, uint16_t bits, bool append_tag); ++ void SliceData_append(struct SliceData_t* self, uint8_t* data, uint16_t bits, bool append_tag); + +#endif +-- -./ src / globals.h(original)++ +./ src / globals.h(reformatted) @ @-46, 7 + 46, + 7 @ @ void reset_app_context(void); + +typedef struct BocContext_t { + - Cell_t cells[MAX_CONTRACT_CELLS_COUNT]; + + Cell_t cells[MAX_CONTRACT_CELLS_COUNT]; + uint8_t hashes[HASHES_BUFFER_SIZE]; + uint8_t cell_depth[MAX_CONTRACT_CELLS_COUNT]; + uint8_t public_key_cell_data[MAX_PUBLIC_KEY_CELL_DATA_SIZE]; + @ @-57, 46 + 57, + 46 @ @ + + typedef struct AddressContext_t { + uint8_t address[ADDRESS_LENGTH]; + - char address_str[65]; + + char address_str[65]; + } AddressContext_t; + + typedef struct PublicKeyContext_t { + uint8_t public_key[PUBLIC_KEY_LENGTH]; + - char public_key_str[65]; + + char public_key_str[65]; + } PublicKeyContext_t; + + typedef struct SignContext_t { + - uint8_t chain_id[CHAIN_ID_LENGTH]; + - uint8_t to_sign[SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH]; + - uint8_t signature[SIGNATURE_LENGTH]; + + uint8_t chain_id[CHAIN_ID_LENGTH]; + + uint8_t to_sign[SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH]; + + uint8_t signature[SIGNATURE_LENGTH]; + uint32_t account_number; + - char to_sign_str[73]; + + char to_sign_str[73]; + } SignContext_t; + + typedef struct SignTransactionContext_t { + - bool sign_with_chain_id; + - uint8_t chain_id[CHAIN_ID_LENGTH]; + - uint8_t to_sign[CHAIN_ID_LENGTH + TO_SIGN_LENGTH]; + - uint8_t signature[SIGNATURE_LENGTH]; + - char address_str[70]; + - char amount_str[40]; + - char transaction_id_str[20]; + + bool sign_with_chain_id; + + uint8_t chain_id[CHAIN_ID_LENGTH]; + + uint8_t to_sign[CHAIN_ID_LENGTH + TO_SIGN_LENGTH]; + + uint8_t signature[SIGNATURE_LENGTH]; + + char address_str[70]; + + char amount_str[40]; + + char transaction_id_str[20]; + uint32_t account_number; + - uint8_t origin_wallet_type; + - uint8_t current_wallet_type; + - uint8_t decimals; + - uint8_t address[ADDRESS_LENGTH]; + - uint8_t prepend_address[ADDRESS_LENGTH]; + - uint8_t wc; + - uint8_t data[MAX_DATA_LEN]; + + uint8_t origin_wallet_type; + + uint8_t current_wallet_type; + + uint8_t decimals; + + uint8_t address[ADDRESS_LENGTH]; + + uint8_t prepend_address[ADDRESS_LENGTH]; + + uint8_t wc; + + uint8_t data[MAX_DATA_LEN]; + uint16_t data_offset; + - char ticker[MAX_TICKER_LEN]; + + char ticker[MAX_TICKER_LEN]; + } SignTransactionContext_t; + + typedef union { + - PublicKeyContext_t pk_context; + - AddressContext_t addr_context; + - SignContext_t sign_context; + + PublicKeyContext_t pk_context; + + AddressContext_t addr_context; + + SignContext_t sign_context; + SignTransactionContext_t sign_tr_context; + } DataContext_t; + + @ @-104, 7 + 104, 7 @ @ extern unsigned int ux_step; + extern unsigned int ux_step_count; + + - extern BocContext_t boc_context; + + extern BocContext_t boc_context; + extern DataContext_t data_context; + +#endif + -- -./ src / byte_stream.h(original)++ +./ src / byte_stream.h(reformatted) @ @-9, 9 + 9, + 9 @ @uint8_t* data; +} ByteStream_t; + +- void ByteStream_init(struct ByteStream_t* self, uint8_t* data, uint16_t data_size); ++ void ByteStream_init(struct ByteStream_t* self, uint8_t* data, uint16_t data_size); +uint8_t* ByteStream_read_data(struct ByteStream_t* self, uint32_t data_size); +- uint8_t ByteStream_read_byte(struct ByteStream_t* self); ++ uint8_t ByteStream_read_byte(struct ByteStream_t* self); +uint32_t ByteStream_read_u32(struct ByteStream_t* self); +uint8_t* ByteStream_get_cursor(struct ByteStream_t* self); +uint16_t ByteStream_get_length(struct ByteStream_t* self); +-- -./ src / errors.h(original)++ +./ src / errors.h(reformatted) @ @-2, 28 + 2, + 28 @ @ +#define _ERRORS_H_ + + enum { + -SUCCESS = 0x9000, + -ERR_INVALID_DATA = 0x6B00, + -ERR_CELL_UNDERFLOW = 0x6B01, + -ERR_RANGE_CHECK = 0x6B02, + -ERR_WRONG_LABEL = 0x6B03, + -ERR_INVALID_FLAG = 0x6B04, + -ERR_END_OF_STREAM = 0x6B05, + -ERR_SLICE_IS_EMPTY = 0x6B06, + -ERR_INVALID_KEY = 0x6B07, + -ERR_CELL_IS_EMPTY = 0x6B08, + -ERR_INVALID_HASH = 0x6B09, + -ERR_INVALID_CELL_INDEX = 0x6B10, + -ERR_INVALID_REQUEST = 0x6B11, + +SUCCESS = 0x9000, + +ERR_INVALID_DATA = 0x6B00, + +ERR_CELL_UNDERFLOW = 0x6B01, + +ERR_RANGE_CHECK = 0x6B02, + +ERR_WRONG_LABEL = 0x6B03, + +ERR_INVALID_FLAG = 0x6B04, + +ERR_END_OF_STREAM = 0x6B05, + +ERR_SLICE_IS_EMPTY = 0x6B06, + +ERR_INVALID_KEY = 0x6B07, + +ERR_CELL_IS_EMPTY = 0x6B08, + +ERR_INVALID_HASH = 0x6B09, + +ERR_INVALID_CELL_INDEX = 0x6B10, + +ERR_INVALID_REQUEST = 0x6B11, + ERR_INVALID_FUNCTION_ID = 0x6B12, + ERR_INVALID_SRC_ADDRESS = 0x6B13, + -ERR_INVALID_WALLET_ID = 0x6B14, + +ERR_INVALID_WALLET_ID = 0x6B14, + ERR_INVALID_WALLET_TYPE = 0x6B15, + -ERR_TICKER_LENGTH = 0x6B16, + -ERR_INVALID_CELL = 0x6B17, + -ERR_INVALID_CONTRACT = 0x6B18, + -ERR_INVALID_MESSAGE = 0x6B19, + -ERR_SIGNING_FAILED = 0x6B20, + +ERR_TICKER_LENGTH = 0x6B16, + +ERR_INVALID_CELL = 0x6B17, + +ERR_INVALID_CONTRACT = 0x6B18, + +ERR_INVALID_MESSAGE = 0x6B19, + +ERR_SIGNING_FAILED = 0x6B20, + ERR_GENERATE_PAIR_FAILED = 0x6B21, + ERR_INIT_PRIVATE_KEY_FAILED = 0x6B22, + ERR_DERIVE_PATH_FAILED = 0x6B23, + -- -./ src / utils.h(original)++ +./ src / utils.h(reformatted) @ @-10, + 26 + 10, + 26 @ @ + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + + -unsigned int ui_prepro(const bagl_element_t* element); + -void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray); + -void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey); + -void send_response(uint8_t tx, bool approve); + +unsigned int ui_prepro(const bagl_element_t* element); + +void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray); + +void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey); + +void send_response(uint8_t tx, bool approve); + +#endif + + -void writeUint32BE(uint32_t val, uint8_t* bytes); + -void writeUint64BE(uint64_t val, uint8_t* bytes); + +void writeUint32BE(uint32_t val, uint8_t* bytes); + +void writeUint64BE(uint64_t val, uint8_t* bytes); + + -uint16_t readUint16BE(uint8_t * buffer); + -uint32_t readUint32BE(uint8_t * buffer); + -uint64_t readUint64BE(uint8_t * buffer); + -uint8_t leading_zeros(uint16_t value); + +uint16_t readUint16BE(uint8_t * buffer); + +uint32_t readUint32BE(uint8_t * buffer); + +uint64_t readUint64BE(uint8_t * buffer); + +uint8_t leading_zeros(uint16_t value); + + -uint16_t format_hex(const uint8_t* in, size_t in_len, char* out, size_t out_len); + -uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, + -uint8_t decimals, + -uint8_t amount_length, + -char* out); + +uint16_t format_hex(const uint8_t* in, size_t in_len, char* out, size_t out_len); + +uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, + +uint8_t decimals, + +uint8_t amount_length, + +char* out); + +#define VALIDATE(cond, error) do { \ No newline at end of file diff --git a/src/ui/action/validate.c b/src/ui/action/validate.c new file mode 100644 index 0000000..71e9a2a --- /dev/null +++ b/src/ui/action/validate.c @@ -0,0 +1,116 @@ +/***************************************************************************** + * Ledger App Everscale. + * (c) 2020 Ledger SAS. + * + * 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 "io.h" +#include "validate.h" +#include "errors.h" +#include "globals.h" +#include "utils.h" +#include "helper/send_response.h" + +void validate_pubkey(bool choice) { + if (choice) { + helper_send_response_public_key(); + } else { + io_send_sw(ERR_USER_REJECTED); + } +} + +void validate_address(bool choice) { + if (choice) { + helper_send_response_address(); + } else { + io_send_sw(ERR_USER_REJECTED); + } +} + +static int crypto_sign_message(void) { + cx_ecfp_private_key_t privateKey; + SignContext_t* context = &data_context.sign_context; + cx_err_t error; + + if (get_private_key(context->account_number, &privateKey) != 0) { + return -1; + } + error = cx_eddsa_sign_no_throw(&privateKey, + CX_SHA512, + context->to_sign, + SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, + context->signature, + SIGNATURE_LENGTH); + if (error != CX_OK) { + return -2; + } + + explicit_bzero(&privateKey, sizeof(privateKey)); + PRINTF("Signature: %.*H\n", SIGNATURE_LENGTH, context->signature); + return 0; +} + +void validate_message(bool choice) { + if (choice) { + if (crypto_sign_message() != 0) { + io_send_sw(ERR_SIGNING_FAILED); + } else { + helper_send_response_sign(); + } + } else { + io_send_sw(ERR_USER_REJECTED); + } +} + +static int crypto_sign_transaction(void) { + cx_ecfp_private_key_t privateKey; + SignTransactionContext_t* context = &data_context.sign_tr_context; + cx_err_t error; + + if (get_private_key(context->account_number, &privateKey) != 0) { + return -1; + } + if (!context->sign_with_chain_id) { + error = cx_eddsa_sign_no_throw(&privateKey, + CX_SHA512, + context->to_sign, + TO_SIGN_LENGTH, + context->signature, + SIGNATURE_LENGTH); + } else { + error = cx_eddsa_sign_no_throw(&privateKey, + CX_SHA512, + context->to_sign, + CHAIN_ID_LENGTH + TO_SIGN_LENGTH, + context->signature, + SIGNATURE_LENGTH); + } + if (error != CX_OK) { + return -2; + } + explicit_bzero(&privateKey, sizeof(privateKey)); + return 0; +} + +void validate_transaction(bool choice) { + if (choice) { + if (crypto_sign_transaction() != 0) { + io_send_sw(ERR_SIGNING_FAILED); + } else { + helper_send_response_sign_transaction(); + } + } else { + io_send_sw(ERR_USER_REJECTED); + } +} \ No newline at end of file diff --git a/src/ui/action/validate.h b/src/ui/action/validate.h new file mode 100644 index 0000000..f835f80 --- /dev/null +++ b/src/ui/action/validate.h @@ -0,0 +1,36 @@ +#pragma once + +#include // bool + +/** + * Action for public key validation and export. + * + * @param[in] choice + * User choice (either approved or rejected). + * + */ +void validate_pubkey(bool choice); + +/** + * Action for address validation and export. + * + * @param[in] choice + * User choice (either approved or rejectd). + * + */ +void validate_address(bool choice); +/** + * Action for transaction information validation. + * + * @param[in] choice + * User choice (either approved or rejectd). + * + */ +void validate_transaction(bool choice); + +/** + * Action for sign validation. + * + * @param[in] choice + */ +void validate_message(bool choice); \ No newline at end of file diff --git a/src/ui/display.h b/src/ui/display.h new file mode 100644 index 0000000..edcf3a2 --- /dev/null +++ b/src/ui/display.h @@ -0,0 +1,13 @@ +#pragma once + +#include // bool + +/** + * Callback to reuse action with approve/reject in step FLOW. + */ +typedef void (*action_validate_cb)(bool); + +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..f089265 --- /dev/null +++ b/src/ui/display_bagl.c @@ -0,0 +1,214 @@ +#ifdef HAVE_BAGL +#include "display.h" +#include "contract.h" +#include "ui/action/validate.h" +#include "ui/menu.h" + +static action_validate_cb g_validate_callback; + +static void ui_action_validate_pubkey(bool choice) { + validate_pubkey(choice); + ui_main_menu(); +} + +static void ui_action_validate_address(bool choice) { + validate_address(choice); + ui_main_menu(); +} + +static void ui_action_validate_message(bool choice) { + validate_message(choice); + ui_main_menu(); +} + +static void ui_action_validate_transaction(bool choice) { + validate_transaction(choice); + ui_main_menu(); +} + +// Screens and flows +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_reject_step, + pb, + (*g_validate_callback)(false), + { + &C_icon_crossmark, + "Reject", + }); +UX_STEP_CB(ux_display_approve_step, + pb, + (*g_validate_callback)(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_approve_step, + &ux_display_reject_step); + +UX_STEP_NOCB(ux_display_public_flow_1_step, + pnn, + { + &C_icon_eye, + "Verify", + "Public key", + }); +UX_STEP_NOCB(ux_display_public_flow_2_step, + bnnn_paging, + { + .title = "Public key", + .text = data_context.pk_context.public_key_str, + }); + +UX_FLOW(ux_display_public_flow, + &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, + &ux_display_approve_step, + &ux_display_reject_step); + +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", + .text = data_context.sign_context.to_sign_str, + }); +UX_STEP_CB(ux_sign_flow_4_step, + pbb, + (*g_validate_callback)(false), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); +UX_STEP_CB(ux_sign_flow_3_step, + pbb, + (*g_validate_callback)(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_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_FLOW(ux_sign_transaction_burn_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_burn, + &ux_sign_transaction_amount, + &ux_display_approve_step, + &ux_display_reject_step); + +UX_FLOW(ux_sign_transaction_deploy_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_deploy, + &ux_sign_transaction_address, + &ux_display_approve_step, + &ux_display_reject_step); + +UX_FLOW(ux_sign_transaction_confirm_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_confirm, + &ux_sign_transaction_transaction_id, + &ux_display_approve_step, + &ux_display_reject_step); + +UX_FLOW(ux_sign_transaction_transfer_flow, + &ux_sign_transaction_intro, + &ux_sign_transaction_transfer, + &ux_sign_transaction_amount, + &ux_sign_transaction_address, + &ux_display_approve_step, + &ux_display_reject_step); + +// Display functions +void ui_display_address() { + g_validate_callback = &ui_action_validate_address; + ux_flow_init(0, ux_display_address_flow, NULL); +} + +void ui_display_public_key() { + g_validate_callback = &ui_action_validate_pubkey; + ux_flow_init(0, ux_display_public_flow, NULL); +} + +void ui_display_sign() { + g_validate_callback = &ui_action_validate_message; + ux_flow_init(0, ux_sign_flow, NULL); +} + +void ui_display_sign_transaction(int flow) { + g_validate_callback = &ui_action_validate_transaction; + 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); + } +} +#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..5f810af --- /dev/null +++ b/src/ui/display_nbgl.c @@ -0,0 +1,181 @@ +#ifdef HAVE_NBGL +#include "display.h" +#include "contract.h" +#include "ui/action/validate.h" +#include "ui/menu.h" +#include "nbgl_use_case.h" + +static nbgl_contentTagValue_t pairs[10]; +static nbgl_contentTagValueList_t pairList; + +static void review_choice_pubkey(bool choice) { + // Answer, display a status page and go back to main + validate_pubkey(choice); + if (choice) { + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_main_menu); + } else { + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_main_menu); + } +} + +static void review_choice_address(bool choice) { + // Answer, display a status page and go back to main + validate_address(choice); + if (choice) { + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_main_menu); + } else { + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_main_menu); + } +} + +static void review_choice_transaction(bool choice) { + // Answer, display a status page and go back to main + validate_transaction(choice); + if (choice) { + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_main_menu); + } else { + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_main_menu); + } +} + +static void review_choice_message(bool choice) { + // Answer, display a status page and go back to main + validate_message(choice); + if (choice) { + nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_main_menu); + } else { + nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_main_menu); + } +} + +// TODO: Implement this +void ui_display_address() { + nbgl_useCaseAddressReview(data_context.addr_context.address_str, + NULL, + &C_app_everscale_64px, + "Verify Address", + NULL, + review_choice_address); +} + +// TODO: Implement this +void ui_display_public_key() { + // Create the page content + + uint8_t pairIndex = 0; + pairs[pairIndex].item = "Public Key"; + pairs[pairIndex].value = (char*) data_context.pk_context.public_key_str; + pairIndex++; + + nbgl_contentTagValueList_t content; + content.nbPairs = pairIndex; + content.pairs = pairs; + content.smallCaseForValue = false; + content.nbMaxLinesForValue = 0; + content.startIndex = 0; + + // to signing screens. + // Setup the review screen + nbgl_useCaseReviewLight(TYPE_OPERATION, + &content, + &C_app_everscale_64px, + "Verify Public Key", + NULL, // No subtitle + "Approve", + review_choice_pubkey); + + // nbgl_useCaseAddressReview(data_context.pk_context.public_key_str, + // NULL, + // &C_app_everscale_40px, + // "Verify Public Key", + // NULL, + // review_choice_pubkey); +} + +void ui_display_sign_transaction(int flow) { + uint8_t pairIndex = 0; + + // Action line + const char* action = NULL; + switch (flow) { + case SIGN_TRANSACTION_FLOW_TRANSFER: + action = "Transfer"; + break; + case SIGN_TRANSACTION_FLOW_DEPLOY: + action = "Deploy"; + break; + case SIGN_TRANSACTION_FLOW_CONFIRM: + action = "Confirm"; + break; + case SIGN_TRANSACTION_FLOW_BURN: + action = "Burn"; + break; + default: + THROW(ERR_INVALID_REQUEST); + break; + } + pairs[pairIndex].item = "Action"; + pairs[pairIndex].value = action; + pairIndex++; + + // Amount line + if (strcmp(action, "Transfer") == 0 || strcmp(action, "Burn") == 0) { + pairs[pairIndex].item = "Amount"; + pairs[pairIndex].value = (char*) data_context.sign_tr_context.amount_str; + pairIndex++; + } + + // Address line + if (strcmp(action, "Transfer") == 0 || strcmp(action, "Deploy") == 0) { + pairs[pairIndex].item = "Address"; + pairs[pairIndex].value = (char*) data_context.sign_tr_context.address_str; + pairIndex++; + } + + // Transaction id line + if (strcmp(action, "Confirm") == 0) { + pairs[pairIndex].item = "Transaction id"; + pairs[pairIndex].value = (char*) data_context.sign_tr_context.transaction_id_str; + pairIndex++; + } + + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.nbPairs = pairIndex; + pairList.pairs = pairs; + + // to signing screens. + // Setup the review screen + nbgl_useCaseReview(TYPE_TRANSACTION, + &pairList, + &C_app_everscale_64px, + "Review transaction", + NULL, // No subtitle + "Review transaction", + review_choice_transaction); +} + +void ui_display_sign() { + uint8_t pairIndex = 0; + + pairs[pairIndex].item = "Message"; + pairs[pairIndex].value = data_context.sign_context.to_sign_str; + pairIndex++; + + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.nbPairs = pairIndex; + pairList.pairs = pairs; + + // to signing screens. + // Setup the review screen + nbgl_useCaseReview(TYPE_MESSAGE, + &pairList, + &C_app_everscale_64px, + "Sign message", + NULL, // No subtitle + "Sign message.", + review_choice_message); +} + +#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..aa15b48 --- /dev/null +++ b/src/ui/menu.h @@ -0,0 +1,8 @@ +#pragma once + +#include "globals.h" +#include "glyphs.h" + +void ui_main_menu(void); + +void ui_about_menu(void); diff --git a/src/ui/menu_bagl.c b/src/ui/menu_bagl.c new file mode 100644 index 0000000..e33faa7 --- /dev/null +++ b/src/ui/menu_bagl.c @@ -0,0 +1,34 @@ +#ifdef HAVE_BAGL +#include "menu.h" +#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); + +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 diff --git a/src/ui/menu_nbgl.c b/src/ui/menu_nbgl.c new file mode 100644 index 0000000..d78643f --- /dev/null +++ b/src/ui/menu_nbgl.c @@ -0,0 +1,39 @@ +#ifdef HAVE_NBGL + +#include "os.h" +#include "nbgl_content.h" +#include "nbgl_use_case.h" +#include "menu.h" + +// ----------------------------------------------------------- +// --------------------- SETTINGS MENU ----------------------- +// ----------------------------------------------------------- +#define SETTING_INFO_NB 2 +static const char* const INFO_TYPES[SETTING_INFO_NB] = {"Version", "Developer"}; +static const char* const INFO_CONTENTS[SETTING_INFO_NB] = {APPVERSION, "Blooo"}; +static const nbgl_contentInfoList_t infoList = { + .nbInfos = SETTING_INFO_NB, + .infoTypes = INFO_TYPES, + .infoContents = INFO_CONTENTS, +}; + +// ----------------------------------------------------------- +// ----------------------- HOME PAGE ------------------------- +// ----------------------------------------------------------- +void app_quit(void) { + // exit app here + os_sched_exit(-1); +} + +void ui_main_menu(void) { + nbgl_useCaseHomeAndSettings(APPNAME, + &C_app_everscale_64px, + NULL, + INIT_HOME_PAGE, + NULL, + &infoList, + NULL, + app_quit); +} + +#endif \ No newline at end of file diff --git a/src/utils.c b/src/utils.c index 598b4b9..d8868b1 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,30 +1,20 @@ -#include "os.h" -#include "cx.h" #include "utils.h" -#include "menu.h" #include #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -void get_public_key(uint32_t account_number, uint8_t* publicKeyArray) { +int 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) { - explicit_bzero(&privateKey, sizeof(privateKey)); - THROW(e); - } - FINALLY { - explicit_bzero(&privateKey, sizeof(privateKey)); - } + if (get_private_key(account_number, &privateKey) != 0) { + return -1; + } + cx_err_t error = cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, &publicKey, &privateKey, 1); + if (error != CX_OK) { + return -2; } - END_TRY; + explicit_bzero(&privateKey, sizeof(privateKey)); for (int i = 0; i < 32; i++) { publicKeyArray[i] = publicKey.W[64 - i]; @@ -32,82 +22,58 @@ void get_public_key(uint32_t account_number, uint8_t* publicKeyArray) { if ((publicKey.W[32] & 1) != 0) { publicKeyArray[31] |= 0x80; } + return 0; } 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) { - explicit_bzero(&privateKeyData, sizeof(privateKeyData)); - THROW(e); - } - FINALLY { - explicit_bzero(&privateKeyData, sizeof(privateKeyData)); - } +/** + * @brief Get the private key object + * + * @param account_number + * @param privateKey + * @return 0 on success, -1 on error + */ +int 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[64]; + if (os_derive_bip32_with_seed_no_throw(HDW_ED25519_SLIP10, + CX_CURVE_Ed25519, + derivePath, + BIP32_PATH, + privateKeyData, + NULL, + NULL, + 0) != CX_OK) { + return -1; } - END_TRY; -} + cx_err_t error = + cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, privateKey); -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(); -} + explicit_bzero(&privateKeyData, sizeof(privateKeyData)); -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))); - } - } + if (error != CX_OK) { + return -1; } - return display; + + return 0; } #endif -void writeUint32BE(uint32_t val, uint8_t *bytes) { +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; } -void writeUint64BE(uint64_t val, uint8_t *bytes) { +void writeUint64BE(uint64_t val, uint8_t* bytes) { bytes[0] = (val >> 56) & 0xFF; bytes[1] = (val >> 48) & 0xFF; bytes[2] = (val >> 40) & 0xFF; @@ -118,15 +84,15 @@ void writeUint64BE(uint64_t val, uint8_t *bytes) { bytes[7] = val & 0xFF; } -uint16_t readUint16BE(uint8_t *buffer) { +uint16_t readUint16BE(uint8_t* buffer) { return (buffer[0] << 8) | (buffer[1]); } -uint32_t readUint32BE(uint8_t *buffer) { +uint32_t readUint32BE(uint8_t* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); } -uint64_t readUint64BE(uint8_t *buffer) { +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); @@ -145,35 +111,11 @@ uint8_t leading_zeros(uint16_t value) { return lz; } -uint16_t format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len) { - if (out_len < 2 * in_len + 1) { - return -1; - } - - const char hex[] = "0123456789abcdef"; - size_t i = 0; - int written = 0; - - while (i < in_len && (i * 2 + (2 + 1)) <= out_len) { - uint8_t high_nibble = (in[i] & 0xF0) >> 4; - *out = hex[high_nibble]; - out++; - - uint8_t low_nibble = in[i] & 0x0F; - *out = hex[low_nibble]; - out++; - - i++; - written += 2; - } - - *out = '\0'; - - return written + 1; -} - #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 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]; @@ -194,8 +136,7 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal for (j = 0; j < 8; j++) { uint8_t k; uint16_t shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 - : (short)0; + (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short) 1 : (short) 0; for (k = smin; k < nscratch; k++) { scratch[k] += ((scratch[k] >= 5) ? 3 : 0); } @@ -204,11 +145,10 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal smin -= 1; } for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); + 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); + scratch[nscratch - 1] = + ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0); } } diff --git a/src/utils.h b/src/utils.h index de58385..be9306d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,7 +2,6 @@ #define _UTILS_H_ #include "os.h" -#include "cx.h" #include "globals.h" #include @@ -10,31 +9,33 @@ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -unsigned int ui_prepro(const bagl_element_t *element); -void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray); -void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t *privateKey); -void send_response(uint8_t tx, bool approve); +#include "cx.h" + +int get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray); +int get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey); #endif -void writeUint32BE(uint32_t val, uint8_t *bytes); -void writeUint64BE(uint64_t val, uint8_t *bytes); +void writeUint32BE(uint32_t val, uint8_t* bytes); +void writeUint64BE(uint64_t val, uint8_t* bytes); -uint16_t readUint16BE(uint8_t *buffer); -uint32_t readUint32BE(uint8_t *buffer); -uint64_t readUint64BE(uint8_t *buffer); +uint16_t readUint16BE(uint8_t* buffer); +uint32_t readUint32BE(uint8_t* buffer); +uint64_t readUint64BE(uint8_t* buffer); uint8_t leading_zeros(uint16_t value); -uint16_t format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len); -uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimals, uint8_t amount_length, char* out); +uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, + uint8_t decimals, + uint8_t amount_length, + char* out); -#define VALIDATE(cond, error) \ - do {\ - if (!(cond)) { \ +#define VALIDATE(cond, error) \ + do { \ + if (!(cond)) { \ PRINTF("Validation Error in %s: %d\n", __FILE__, __LINE__); \ - THROW(error); \ - } \ - } while(0) + THROW(error); \ + } \ + } while (0) #define PRINT_LINE() PRINTF("Print line %s: %d\n", __FILE__, __LINE__) diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index b83d222..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/tests/Cargo.lock b/tests/Cargo.lock deleted file mode 100644 index 8bb05ac..0000000 --- a/tests/Cargo.lock +++ /dev/null @@ -1,2097 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -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 = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anstream" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "async-trait" -version = "0.1.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[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 = "base64" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" - -[[package]] -name = "base64ct" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" - -[[package]] -name = "bigdecimal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454bca3db10617b88b566f205ed190aedb0e0e6dd4cad61d3988a72e8c5594cb" -dependencies = [ - "autocfg", - "libm", - "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 = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[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.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" -dependencies = [ - "borsh-derive", - "hashbrown 0.13.2", -] - -[[package]] -name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bytecheck" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clap" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "console" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.45.0", -] - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" - -[[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.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.0", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "dialoguer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" -dependencies = [ - "console", - "shell-words", - "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.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" - -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -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.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "errno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[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-ledger-wallet" -version = "0.1.0" -source = "git+https://github.com/broxus/everscale-ledger-wallet.git#3e8b56fd9238c46b7da62bc8c58cb62c7d80fa8d" -dependencies = [ - "anyhow", - "console", - "dialoguer", - "ed25519-dalek", - "hex", - "hidapi", - "log", - "num-derive", - "num-traits", - "parking_lot", - "qstring", - "semver", - "thiserror", - "uriparse", -] - -[[package]] -name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-macro", - "futures-task", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hidapi" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723777263b0dcc5730aec947496bd8c3940ba63c15f5633b288cc615f4f6af79" -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 = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[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 0.21.4", - "bigdecimal", - "clap", - "ed25519-dalek", - "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.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "libm" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" - -[[package]] -name = "libsecp256k1" -version = "0.7.0" -source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2" -dependencies = [ - "arrayref", - "base64 0.13.1", - "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.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[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.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" - -[[package]] -name = "memzero" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "nekoton" -version = "0.13.1" -source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c" -dependencies = [ - "anyhow", - "async-trait", - "base64 0.13.1", - "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", - "quick_cache", - "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.13.0" -source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c" -dependencies = [ - "anyhow", - "base64 0.13.1", - "ed25519-dalek", - "hex", - "log", - "nekoton-derive", - "nekoton-utils", - "num-bigint", - "num-traits", - "once_cell", - "rustc-hash", - "serde", - "serde_json", - "smallvec", - "thiserror", - "ton_abi", - "ton_block", - "ton_executor", - "ton_types", - "ton_vm", -] - -[[package]] -name = "nekoton-contracts" -version = "0.13.0" -source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c" -dependencies = [ - "anyhow", - "nekoton-abi", - "once_cell", - "thiserror", - "ton_abi", - "ton_block", - "ton_types", -] - -[[package]] -name = "nekoton-derive" -version = "0.13.0" -source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c" -dependencies = [ - "either", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "nekoton-utils" -version = "0.13.0" -source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c" -dependencies = [ - "anyhow", - "base64 0.13.1", - "chacha20poly1305", - "ed25519-dalek", - "hex", - "hmac 0.11.0", - "pbkdf2", - "secstr", - "serde", - "sha2", - "thiserror", - "ton_block", - "ton_types", - "zeroize", -] - -[[package]] -name = "num" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" -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 1.0.109", -] - -[[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.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -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 = "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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[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.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[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.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[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-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -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 1.0.109", -] - -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "quick_cache" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5253a3a0d56548d5b0be25414171dc780cc6870727746d05bd2bde352eee96c5" -dependencies = [ - "ahash 0.8.3", - "hashbrown 0.13.2", - "parking_lot", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[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.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "rend" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "rkyv" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" -dependencies = [ - "bitvec", - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rust_decimal" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[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.38.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[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 = "semver" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[package]] -name = "serde_json" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" -dependencies = [ - "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 = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" - -[[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.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "thiserror" -version = "1.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" -dependencies = [ - "backtrace", - "num_cpus", - "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "ton_abi" -version = "2.1.0" -source = "git+https://github.com/broxus/ton-labs-abi#b8834529ef8fa121d534fca6554c0e95d4019998" -dependencies = [ - "anyhow", - "base64 0.13.1", - "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.9.73" -source = "git+https://github.com/broxus/ton-labs-block#66b3ccb8e6187e6d9f611f6541c0f59d3eb77cbf" -dependencies = [ - "anyhow", - "base64 0.13.1", - "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#2a38890d53f9c3dad84b3fb9a58e3bb62ba20f44" -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#3324562d7ff1ebec66d996128573966c1b53862b" -dependencies = [ - "anyhow", - "base64 0.13.1", - "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#497865fb3aabf02afea610f9c16f265b492c23a6" -dependencies = [ - "anyhow", - "ed25519", - "ed25519-dalek", - "hex", - "lazy_static", - "log", - "num", - "num-traits", - "rand", - "sha2", - "smallvec", - "thiserror", - "ton_block", - "ton_types", -] - -[[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.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[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 = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -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.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[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-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.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] diff --git a/tests/Cargo.toml b/tests/Cargo.toml deleted file mode 100644 index fe7989b..0000000 --- a/tests/Cargo.toml +++ /dev/null @@ -1,30 +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.21.3" -bigdecimal = "0.4.1" -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" } - -# 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/python/apps/__init__.py b/tests/application_client/__init__.py similarity index 100% rename from tests/python/apps/__init__.py rename to tests/application_client/__init__.py diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py new file mode 100644 index 0000000..b774bb6 --- /dev/null +++ b/tests/application_client/everscale_command_sender.py @@ -0,0 +1,176 @@ +from enum import IntEnum +from typing import Generator, List, Optional +from contextlib import contextmanager + +from ragger.backend.interface import BackendInterface, RAPDU + +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_APP_CONFIGURATION = 0x01 + GET_PUBLIC_KEY = 0x02 + SIGN_MESSAGE = 0x03 + 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 + 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 + # 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 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"", + ) + + 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"", + ) + + 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"), + ) + + @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: + 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_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: + yield response + + def get_async_response(self) -> Optional[RAPDU]: + return self.backend.last_async_response diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py new file mode 100644 index 0000000..9c6fed4 --- /dev/null +++ b/tests/application_client/everscale_response_unpacker.py @@ -0,0 +1,77 @@ +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) +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 + assert len(response) == 0 + + 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) +# 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/everscale_transaction.py b/tests/application_client/everscale_transaction.py new file mode 100644 index 0000000..31aa1d7 --- /dev/null +++ b/tests/application_client/everscale_transaction.py @@ -0,0 +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. + +# 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: + +# [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) + +# 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 +# ) diff --git a/tests/application_client/everscale_utils.py b/tests/application_client/everscale_utils.py new file mode 100644 index 0000000..fd96e62 --- /dev/null +++ b/tests/application_client/everscale_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/speculos/ledger_client/__init__.py b/tests/application_client/py.typed similarity index 100% rename from tests/speculos/ledger_client/__init__.py rename to tests/application_client/py.typed diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..76b5e0c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,24 @@ +from ragger.conftest import configuration + +########################### +### 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 + +# 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 ### +######################### + +# 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/speculos/setup.cfg b/tests/setup.cfg similarity index 66% rename from tests/speculos/setup.cfg rename to tests/setup.cfg index c79fd88..2d024b3 100644 --- a/tests/speculos/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 @@ -7,11 +7,14 @@ disable = C0114, # missing-module-docstring C0116, # missing-function-docstring C0103, # invalid-name R0801, # duplicate-code - R0913 # too-many-arguments + R0913, # too-many-arguments + R0917 # too-many-positional-arguments + +max-line-length=120 extension-pkg-whitelist=hid [pycodestyle] -max-line-length = 90 +max-line-length = 100 [mypy-hid.*] ignore_missing_imports = True diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png new file mode 100644 index 0000000..271e837 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png new file mode 100644 index 0000000..6b9235b Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png new file mode 100644 index 0000000..4321e60 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png new file mode 100644 index 0000000..271e837 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png new file mode 100644 index 0000000..6b9235b Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png new file mode 100644 index 0000000..45c08d4 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png differ diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png new file mode 100644 index 0000000..1a0afc1 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png new file mode 100644 index 0000000..7200206 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png new file mode 100644 index 0000000..7bc85c6 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png new file mode 100644 index 0000000..4321e60 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..1a0afc1 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..f8feb4c Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..45c08d4 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png new file mode 100644 index 0000000..f8feb4c Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png differ diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png new file mode 100644 index 0000000..45c08d4 Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png differ diff --git a/tests/snapshots/flex/test_sign_message/00000.png b/tests/snapshots/flex/test_sign_message/00000.png new file mode 100644 index 0000000..65ad8cb Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00000.png differ diff --git a/tests/snapshots/flex/test_sign_message/00001.png b/tests/snapshots/flex/test_sign_message/00001.png new file mode 100644 index 0000000..4842bfe Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00001.png differ diff --git a/tests/snapshots/flex/test_sign_message/00002.png b/tests/snapshots/flex/test_sign_message/00002.png new file mode 100644 index 0000000..b48c0c2 Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00002.png differ diff --git a/tests/snapshots/flex/test_sign_message/00003.png b/tests/snapshots/flex/test_sign_message/00003.png new file mode 100644 index 0000000..8b981d4 Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00003.png differ diff --git a/tests/snapshots/flex/test_sign_message/00004.png b/tests/snapshots/flex/test_sign_message/00004.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00004.png differ diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png new file mode 100644 index 0000000..ee3f74f Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png differ diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png new file mode 100644 index 0000000..a080152 Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png differ diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png new file mode 100644 index 0000000..f0c2eda Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png differ diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png new file mode 100644 index 0000000..be51a9d Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png differ diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png differ diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00000.png b/tests/snapshots/flex/test_sign_tx_confirm/00000.png new file mode 100644 index 0000000..ee3f74f Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00000.png differ diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00001.png b/tests/snapshots/flex/test_sign_tx_confirm/00001.png new file mode 100644 index 0000000..e4c5c68 Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00001.png differ diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00002.png b/tests/snapshots/flex/test_sign_tx_confirm/00002.png new file mode 100644 index 0000000..f0c2eda Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00002.png differ diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00003.png b/tests/snapshots/flex/test_sign_tx_confirm/00003.png new file mode 100644 index 0000000..be51a9d Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00003.png differ diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00004.png b/tests/snapshots/flex/test_sign_tx_confirm/00004.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00004.png differ diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00000.png b/tests/snapshots/flex/test_sign_tx_transfer/00000.png new file mode 100644 index 0000000..ee3f74f Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00000.png differ diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00001.png b/tests/snapshots/flex/test_sign_tx_transfer/00001.png new file mode 100644 index 0000000..f489d2e Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00001.png differ diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00002.png b/tests/snapshots/flex/test_sign_tx_transfer/00002.png new file mode 100644 index 0000000..f0c2eda Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00002.png differ diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00003.png b/tests/snapshots/flex/test_sign_tx_transfer/00003.png new file mode 100644 index 0000000..be51a9d Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00003.png differ diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00004.png b/tests/snapshots/flex/test_sign_tx_transfer/00004.png new file mode 100644 index 0000000..ed74cf1 Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00004.png differ 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 0000000..a487005 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png differ diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png new file mode 100644 index 0000000..b0fb95c Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png differ 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 0000000..79ec8e7 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png similarity index 100% rename from tests/speculos/screenshots/get_pubkey/approve/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00005.png similarity index 100% rename from tests/speculos/screenshots/get_pubkey/reject/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00005.png diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png new file mode 100644 index 0000000..a487005 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png differ diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png new file mode 100644 index 0000000..b0fb95c Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png differ 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 0000000..79ec8e7 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png differ 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 0000000..c4c84cf Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00005.png similarity index 100% rename from tests/speculos/screenshots/sign/sign_message/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00005.png 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 0000000..653262d Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png new file mode 100644 index 0000000..94681e7 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png new file mode 100644 index 0000000..9048fa4 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00004.png similarity index 100% rename from tests/speculos/screenshots/sign/sign_reject/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00004.png diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..653262d Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..94681e7 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..9048fa4 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png new file mode 100644 index 0000000..c4c84cf Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00000.png rename to tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png 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 0000000..1b27154 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00000.png differ 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 0000000..e17b3f6 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00001.png differ 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 0000000..64ae294 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00002.png differ 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 0000000..639625e Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00003.png differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_sign_message/00004.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00000.png rename to tests/snapshots/nanosp/test_sign_message/00004.png diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_sign_message/00005.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00000.png rename to tests/snapshots/nanosp/test_sign_message/00005.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 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00001.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00001.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00001.png rename to tests/snapshots/nanosp/test_sign_tx_burn_usdt/00001.png diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00002.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00002.png rename to tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00001.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00001.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00001.png rename to tests/snapshots/nanosp/test_sign_tx_confirm/00001.png diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png new file mode 100644 index 0000000..cc3d151 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png differ 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 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png new file mode 100644 index 0000000..3d8fac1 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png differ 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 0000000..79a7767 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png new file mode 100644 index 0000000..d7d0280 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png new file mode 100644 index 0000000..de482ce Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png new file mode 100644 index 0000000..a487005 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png new file mode 100644 index 0000000..b0fb95c Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png differ 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 0000000..79ec8e7 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png differ 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 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png new file mode 100644 index 0000000..a487005 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png new file mode 100644 index 0000000..b0fb95c Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png differ 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 0000000..79ec8e7 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png differ 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 0000000..c4c84cf Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png differ diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png new file mode 100644 index 0000000..653262d Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png new file mode 100644 index 0000000..94681e7 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png new file mode 100644 index 0000000..9048fa4 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..653262d Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..94681e7 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..9048fa4 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png differ 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 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png new file mode 100644 index 0000000..c4c84cf Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png differ diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png differ diff --git a/tests/snapshots/nanox/test_sign_message/00000.png b/tests/snapshots/nanox/test_sign_message/00000.png new file mode 100644 index 0000000..1b27154 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00000.png differ 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 0000000..e17b3f6 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00001.png differ 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 0000000..64ae294 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00002.png differ 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 0000000..639625e Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_message/00004.png b/tests/snapshots/nanox/test_sign_message/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_message/00005.png b/tests/snapshots/nanox/test_sign_message/00005.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00005.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00001.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00001.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_reject/nanox/00001.png rename to tests/snapshots/nanox/test_sign_tx_burn_usdt/00001.png diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00002.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/burn_reject/nanox/00002.png rename to tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00000.png b/tests/snapshots/nanox/test_sign_tx_confirm/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00000.png differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00001.png b/tests/snapshots/nanox/test_sign_tx_confirm/00001.png similarity index 100% rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00001.png rename to tests/snapshots/nanox/test_sign_tx_confirm/00001.png diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00002.png b/tests/snapshots/nanox/test_sign_tx_confirm/00002.png new file mode 100644 index 0000000..cc3d151 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00002.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00003.png b/tests/snapshots/nanox/test_sign_tx_confirm/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00004.png b/tests/snapshots/nanox/test_sign_tx_confirm/00004.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00000.png b/tests/snapshots/nanox/test_sign_tx_transfer/00000.png new file mode 100644 index 0000000..487ea10 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00000.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00001.png b/tests/snapshots/nanox/test_sign_tx_transfer/00001.png new file mode 100644 index 0000000..3d8fac1 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00001.png differ 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 0000000..79a7767 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00002.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00003.png b/tests/snapshots/nanox/test_sign_tx_transfer/00003.png new file mode 100644 index 0000000..d7d0280 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00004.png b/tests/snapshots/nanox/test_sign_tx_transfer/00004.png new file mode 100644 index 0000000..de482ce Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00005.png b/tests/snapshots/nanox/test_sign_tx_transfer/00005.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00005.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00006.png b/tests/snapshots/nanox/test_sign_tx_transfer/00006.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00006.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png new file mode 100644 index 0000000..a736b67 Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png new file mode 100644 index 0000000..73fb8df Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png new file mode 100644 index 0000000..7a49478 Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png new file mode 100644 index 0000000..a736b67 Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png new file mode 100644 index 0000000..73fb8df Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png new file mode 100644 index 0000000..94c91bb Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png differ diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png new file mode 100644 index 0000000..5bd92dd Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png new file mode 100644 index 0000000..1419977 Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png new file mode 100644 index 0000000..fd0228b Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png new file mode 100644 index 0000000..7a49478 Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png new file mode 100644 index 0000000..5bd92dd Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png new file mode 100644 index 0000000..3fd64e5 Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png new file mode 100644 index 0000000..94c91bb Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png new file mode 100644 index 0000000..3fd64e5 Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png differ diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png new file mode 100644 index 0000000..94c91bb Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png differ diff --git a/tests/snapshots/stax/test_sign_message/00000.png b/tests/snapshots/stax/test_sign_message/00000.png new file mode 100644 index 0000000..e25d920 Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00000.png differ diff --git a/tests/snapshots/stax/test_sign_message/00001.png b/tests/snapshots/stax/test_sign_message/00001.png new file mode 100644 index 0000000..4a1648e Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00001.png differ diff --git a/tests/snapshots/stax/test_sign_message/00002.png b/tests/snapshots/stax/test_sign_message/00002.png new file mode 100644 index 0000000..9dadee7 Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00002.png differ diff --git a/tests/snapshots/stax/test_sign_message/00003.png b/tests/snapshots/stax/test_sign_message/00003.png new file mode 100644 index 0000000..cfee3ae Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00003.png differ diff --git a/tests/snapshots/stax/test_sign_message/00004.png b/tests/snapshots/stax/test_sign_message/00004.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00004.png differ diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png new file mode 100644 index 0000000..5c40f61 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png differ diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png new file mode 100644 index 0000000..4321aca Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png differ diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png new file mode 100644 index 0000000..06e0ce9 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png differ diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png new file mode 100644 index 0000000..392165d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png differ diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png differ diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00000.png b/tests/snapshots/stax/test_sign_tx_confirm/00000.png new file mode 100644 index 0000000..5c40f61 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00000.png differ diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00001.png b/tests/snapshots/stax/test_sign_tx_confirm/00001.png new file mode 100644 index 0000000..f63f311 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00001.png differ diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00002.png b/tests/snapshots/stax/test_sign_tx_confirm/00002.png new file mode 100644 index 0000000..06e0ce9 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00002.png differ diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00003.png b/tests/snapshots/stax/test_sign_tx_confirm/00003.png new file mode 100644 index 0000000..392165d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00003.png differ diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00004.png b/tests/snapshots/stax/test_sign_tx_confirm/00004.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00004.png differ diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00000.png b/tests/snapshots/stax/test_sign_tx_transfer/00000.png new file mode 100644 index 0000000..5c40f61 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00000.png differ diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00001.png b/tests/snapshots/stax/test_sign_tx_transfer/00001.png new file mode 100644 index 0000000..7c1a8f7 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00001.png differ diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00002.png b/tests/snapshots/stax/test_sign_tx_transfer/00002.png new file mode 100644 index 0000000..06e0ce9 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00002.png differ diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00003.png b/tests/snapshots/stax/test_sign_tx_transfer/00003.png new file mode 100644 index 0000000..392165d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00003.png differ diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00004.png b/tests/snapshots/stax/test_sign_tx_transfer/00004.png new file mode 100644 index 0000000..f0e072d Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00004.png differ diff --git a/tests/speculos/conftest.py b/tests/speculos/conftest.py deleted file mode 100644 index 469d05b..0000000 --- a/tests/speculos/conftest.py +++ /dev/null @@ -1,40 +0,0 @@ -from pathlib import Path -import pytest - -from speculos.client import SpeculosClient - -from ledger_client.ledger_cmd import LedgerCommand - - -SCRIPT_DIR = Path(__file__).absolute().parent -API_URL = "http://127.0.0.1:5000" -#http://10.66.66.8:5000 - - -def pytest_addoption(parser): - # nanos, nanox, nanosp - parser.addoption("--model", action="store", default="nanos") - # qt: default, requires a X server - # headless: nothing is displayed - parser.addoption("--display", action="store", default="qt") - - path: str = SCRIPT_DIR.parent.parent / "bin" / "app.elf" - parser.addoption("--path", action="store", default=path) - -@pytest.fixture() -def client(pytestconfig): - file_path = pytestconfig.getoption("path") - model = pytestconfig.getoption("model") - - args = ['--log-level', 'speculos:DEBUG','--model', model, '--display', pytestconfig.getoption("display")] - with SpeculosClient(app=str(file_path), args=args) as client: - yield client - - -@pytest.fixture() -def cmd(client, pytestconfig): - yield LedgerCommand( - client=client, - debug=True, - model=pytestconfig.getoption("model"), - ) \ No newline at end of file diff --git a/tests/speculos/ledger_client/exception/__init__.py b/tests/speculos/ledger_client/exception/__init__.py deleted file mode 100644 index acb2bb8..0000000 --- a/tests/speculos/ledger_client/exception/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -from .device_exception import DeviceException -from .errors import (UnknownDeviceError, - DenyError, - WrongP1P2Error, - WrongDataLengthError, - InsNotSupportedError, - ClaNotSupportedError, - WrongResponseLengthError, - DisplayBip32PathFailError, - DisplayAddressFailError, - DisplayAmountFailError, - WrongTxLengthError, - TxParsingFailError, - TxHashFail, - BadStateError, - SignatureFailError) - -__all__ = [ - "DeviceException", - "DenyError", - "UnknownDeviceError", - "WrongP1P2Error", - "WrongDataLengthError", - "InsNotSupportedError", - "ClaNotSupportedError", - "WrongResponseLengthError", - "DisplayBip32PathFailError", - "DisplayAddressFailError", - "DisplayAmountFailError", - "WrongTxLengthError", - "TxParsingFailError", - "TxHashFail", - "BadStateError", - "SignatureFailError" -] diff --git a/tests/speculos/ledger_client/exception/device_exception.py b/tests/speculos/ledger_client/exception/device_exception.py deleted file mode 100644 index 7cd26f2..0000000 --- a/tests/speculos/ledger_client/exception/device_exception.py +++ /dev/null @@ -1,38 +0,0 @@ -import enum -from typing import Dict, Any, Union - -from .errors import * - - -class DeviceException(Exception): # pylint: disable=too-few-public-methods - exc: Dict[int, Any] = { - 0x6985: DenyError, - 0x6A86: WrongP1P2Error, - 0x6A87: WrongDataLengthError, - 0x6D00: InsNotSupportedError, - 0x6E00: ClaNotSupportedError, - 0xB000: WrongResponseLengthError, - 0xB001: DisplayBip32PathFailError, - 0xB002: DisplayAddressFailError, - 0xB003: DisplayAmountFailError, - 0xB004: WrongTxLengthError, - 0xB005: TxParsingFailError, - 0xB006: TxHashFail, - 0xB007: BadStateError, - 0xB008: SignatureFailError - } - - def __new__(cls, - error_code: int, - ins: Union[int, enum.IntEnum, None] = None, - message: str = "" - ) -> Any: - error_message: str = (f"Error in {ins!r} command" - if ins else "Error in command") - - if error_code in DeviceException.exc: - return DeviceException.exc[error_code](hex(error_code), - error_message, - message) - - return UnknownDeviceError(hex(error_code), error_message, message) diff --git a/tests/speculos/ledger_client/exception/errors.py b/tests/speculos/ledger_client/exception/errors.py deleted file mode 100644 index a9a853d..0000000 --- a/tests/speculos/ledger_client/exception/errors.py +++ /dev/null @@ -1,58 +0,0 @@ -class UnknownDeviceError(Exception): - pass - - -class DenyError(Exception): - pass - - -class WrongP1P2Error(Exception): - pass - - -class WrongDataLengthError(Exception): - pass - - -class InsNotSupportedError(Exception): - pass - - -class ClaNotSupportedError(Exception): - pass - - -class WrongResponseLengthError(Exception): - pass - - -class DisplayBip32PathFailError(Exception): - pass - - -class DisplayAddressFailError(Exception): - pass - - -class DisplayAmountFailError(Exception): - pass - - -class WrongTxLengthError(Exception): - pass - - -class TxParsingFailError(Exception): - pass - - -class TxHashFail(Exception): - pass - - -class BadStateError(Exception): - pass - - -class SignatureFailError(Exception): - pass diff --git a/tests/speculos/ledger_client/ledger_cmd.py b/tests/speculos/ledger_client/ledger_cmd.py deleted file mode 100644 index b732c32..0000000 --- a/tests/speculos/ledger_client/ledger_cmd.py +++ /dev/null @@ -1,155 +0,0 @@ -from ast import List -from contextlib import contextmanager -import struct -from time import sleep -from typing import Tuple - -from speculos.client import SpeculosClient, ApduException - -from ledger_client.ledger_cmd_builder import LedgerCommandBuilder, InsType, WalletType -from ledger_client.exception import DeviceException - - -class LedgerCommand: - def __init__(self, - client: SpeculosClient, - debug: bool = False, - model: str = "nanos") -> None: - self.client = client - self.builder = LedgerCommandBuilder(debug=debug) - self.debug = debug - self.model = model - - def get_configuration(self) -> Tuple[ int, int, int]: - try: - response = self.client._apdu_exchange( - self.builder.get_configuration() - ) # type: int, bytes - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_VERSION) - # response = MAJOR (1) || MINOR (1) || PATCH (1) - assert len(response) == 3 - major, minor, patch = struct.unpack( - "BBB", - response - ) # type: int, int, int - - return major, minor, patch - - def get_public_key(self, account: int, display: bool = False) -> str: - try: - response = self.client._apdu_exchange( - self.builder.get_public_key(account=account, display=display) - ) # type: bytes - - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_PUBLIC_KEY) - - # response = pub_key_len (1) || - # pub_key (var) - offset: int = 0 - - pub_key_len: int = response[offset] - - offset += 1 - pubkey = response[offset:].hex() - - assert len(response) == 1 + pub_key_len - - return pubkey - - @contextmanager - def get_public_key_with_display(self, account: int, result: List, display: bool = False) -> Tuple[bytes, bytes]: - - try: - chunk: bytes = self.builder.get_public_key(account=account, display=display) - - with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1], - p1=chunk[2], p2=chunk[3], - data=chunk[5:]) as exchange: - yield exchange - - response: bytes = exchange.receive() - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_PUBLIC_KEY) - offset: int = 0 - - pub_key_len: int = response[offset] - - offset += 1 - pubkey = response[offset:].hex() - assert len(response) == 1 + pub_key_len - print("PUBKEY", pubkey) - result.append(pubkey) - - def get_address(self, account: int, wallet_type: int, display: bool = False) -> str: - try: - response = self.client._apdu_exchange( - self.builder.get_address(account=account, wallet_type=wallet_type, display=display) - ) # type: bytes - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_ADDRESS) - - offset: int = 0 - - addr_len: int = response[offset] - - offset += 1 - address = response[offset:].hex() - - assert len(response) == 1 + addr_len - - return address - - @contextmanager - def sign_message(self, res: List, account: int, message: bytes) -> Tuple[bytes]: - try: - chunk: bytes = self.builder.sign_message(account=account, message=message) - - with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1], - p1=chunk[2], p2=chunk[3], - data=chunk[5:]) as exchange: - yield exchange - - response: bytes = exchange.receive() - - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN) - - offset: int = 0 - signature_len: int = response[offset] - assert signature_len == 64 - - offset += 1 - signature = response[offset:] - assert len(response) == 1 + signature_len - - res.append(signature) - - - @contextmanager - def sign_tx(self, res: List, account: int, wallet_type: int, decimals: int, ticker: str, meta: struct, data: bytes) -> Tuple[bytes]: - try: - chunk: bytes = self.builder.sign_tx( - account=account, wallet_type=wallet_type, decimals=decimals, ticker=ticker, meta=meta, data=data) - - with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1], - p1=chunk[2], p2=chunk[3], - data=chunk[5:]) as exchange: - yield exchange - - response: bytes = exchange.receive() - - except ApduException as error: - raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_TX) - - offset: int = 0 - signature_len: int = response[offset] - assert signature_len == 64 - - offset += 1 - signature = response[offset:] - assert len(response) == 1 + signature_len - - res.append(signature) - diff --git a/tests/speculos/ledger_client/ledger_cmd_builder.py b/tests/speculos/ledger_client/ledger_cmd_builder.py deleted file mode 100644 index 238acc6..0000000 --- a/tests/speculos/ledger_client/ledger_cmd_builder.py +++ /dev/null @@ -1,243 +0,0 @@ -import enum -import logging -import struct -from typing import List, Tuple, Union, Iterator, cast - -from ledger_client.transaction import EIP712, PersonalTransaction, Transaction -#from ethereum_client.plugin import ERC20Information, Plugin -from ledger_client.utils import packed_bip32_path_from_string - -MAX_APDU_LEN: int = 255 - -def chunked(size, source): - for i in range(0, len(source), size): - yield source[i:i+size] - -def chunkify(data: bytes, chunk_len: int) -> Iterator[Tuple[bool, bytes]]: - size: int = len(data) - - if size <= chunk_len: - yield True, data - return - - chunk: int = size // chunk_len - remaining: int = size % chunk_len - offset: int = 0 - - for i in range(chunk): - yield False, data[offset:offset + chunk_len] - offset += chunk_len - - if remaining: - yield True, data[offset:] - -class InsType(enum.IntEnum): - INS_GET_PUBLIC_KEY = 0x02 - INS_GET_CONFIGURATION = 0x01 - INS_SIGN = 0x03 - INS_GET_ADDRESS = 0x04 - INS_SIGN_TX = 0x05 - - -class WalletType(enum.IntEnum): - WalletV3 = 0, - EverWallet = 1, - SafeMultisig = 2, - SafeMultisig24h = 3, - SetcodeMultisig = 4, - BridgeMultisig = 5, - Surf = 6, - Multisig2 = 7, - Multisig2_1 = 8, - - -class LedgerCommandBuilder: - """APDU command builder for the Boilerplate application. - - Parameters - ---------- - debug: bool - Whether you want to see logging or not. - - Attributes - ---------- - debug: bool - Whether you want to see logging or not. - - """ - CLA: int = 0xE0 - - def __init__(self, debug: bool = False): - """Init constructor.""" - self.debug = debug - - def serialize(self, - cla: int, - ins: Union[int, enum.IntEnum], - p1: int = 0, - p2: int = 0, - cdata: bytes = b"") -> bytes: - """Serialize the whole APDU command (header + data). - - Parameters - ---------- - cla : int - Instruction class: CLA (1 byte) - ins : Union[int, IntEnum] - Instruction code: INS (1 byte) - p1 : int - Instruction parameter 1: P1 (1 byte). - p2 : int - Instruction parameter 2: P2 (1 byte). - cdata : bytes - Bytes of command data. - - Returns - ------- - bytes - Bytes of a complete APDU command. - - """ - ins = cast(int, ins.value) if isinstance(ins, enum.IntEnum) else cast(int, ins) - - header: bytes = struct.pack("BBBBB", - cla, - ins, - p1, - p2, - len(cdata)) # add Lc to APDU header - - if self.debug: - logging.info("header: %s", header.hex()) - logging.info("cdata: %s", cdata.hex()) - - print("serialize INS=", ins) - print("serialize DATA= ", cdata.hex()) - return header + cdata - - def get_configuration(self) -> bytes: - """Command builder for GET_CONFIGURATON - - Returns - ------- - bytes - APDU command for GET_CONFIGURATON - - """ - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_CONFIGURATION, - p1=0x00, - p2=0x00, - cdata=b"") - - - def get_public_key(self, account: int, display: bool = False) -> bytes: - """Command builder for GET_PUBLIC_KEY. - - Parameters - ---------- - bip32_path: str - String representation of BIP32 path. - display : bool - Whether you want to display the address on the device. - - Returns - ------- - bytes - APDU command for GET_PUBLIC_KEY. - - """ - cdata = account.to_bytes(4, byteorder='big') - print("cdata= ", cdata) - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_PUBLIC_KEY, - p1=0x01 if display else 0x00, - p2=0x00, - cdata=cdata) - - def get_address(self, account: int, wallet_type: int, display: bool) -> bytes: - """Command builder for GET_ADDRESS. - - Parameters - ---------- - account: int - Account identifier. - wallet_type: int - Wallet type. - display : bool - Whether you want to display the address on the device. - - Returns - ------- - bytes - APDU command for GET_ADDRESS. - - """ - - #account_num = account.to_bytes(4, byteorder='big') - - #wallet = wallet_type.to_bytes(1, byteorder='big') - - cdata = (account.to_bytes(4, byteorder='big') + wallet_type.to_bytes(1, byteorder='big')) - #cdata = (account_num + wallet) - - return self.serialize(cla=self.CLA, - ins=InsType.INS_GET_ADDRESS, - p1=0x01 if display else 0x00, - p2=0x00, - cdata=cdata) - - def sign_message(self, account: int, message: bytes) -> bytes: - """Command builder for SIGN_MESSAGE. - - Parameters - ---------- - account: int - Account identifier. - message: str - Message hash. - display : bool - Whether you want to display the address on the device. - - Returns - ------- - bytes - APDU command for SIGN_MESSAGE. - - """ - - cdata = (account.to_bytes(4, byteorder='big') + message) - - return self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN, - p1=0x01, - p2=0x00, - cdata=cdata) - - def sign_tx(self, account: int, wallet_type: int, decimals: int, ticker: str, meta: struct, data: bytes) -> bytes: - """Command builder for INS_SIGN_TX. - - Parameters - ---------- - bip32_path : str - String representation of BIP32 path. - transaction : Transaction - Representation of the transaction to be signed. - - Yields - ------- - bytes - APDU command chunk for INS_SIGN_TX. - - """ - meta_data = 0 - cdata = (account.to_bytes(4, byteorder='big') + wallet_type.to_bytes(1, byteorder='big') - + decimals.to_bytes(1, byteorder='big') + len(ticker).to_bytes(1, byteorder='big') - + bytes(ticker, 'UTF-8') + meta_data.to_bytes(1, byteorder='big') + data) - - return self.serialize(cla=self.CLA, - ins=InsType.INS_SIGN_TX, - p1=0x01, - p2=0x00, - cdata=cdata) - diff --git a/tests/speculos/ledger_client/transaction.py b/tests/speculos/ledger_client/transaction.py deleted file mode 100644 index 8186cec..0000000 --- a/tests/speculos/ledger_client/transaction.py +++ /dev/null @@ -1,96 +0,0 @@ -from typing import Union - -from ledger_client.utils import write_varint, UINT64_MAX - - -class TransactionError(Exception): - pass - -EIP2930 = 1 -EIP1559 = 2 - -class PersonalTransaction: - def __init__(self, msg: Union[str, bytes]) -> None: - # If you want to send bytes directly you have to put "0x" before the string - if msg[0:2] == "0x": - self.msg: bytes = bytes.fromhex(msg[2:]) - else: - self.msg: bytes = bytes(msg, "utf-8") - - def serialize(self) -> bytes: - return b"".join([ - len(self.msg).to_bytes(4, byteorder="big"), - self.msg, - ]) - -class Transaction: - def __init__(self, txType: int, nonce: int, gasPrice: int, gasLimit: int, to: Union[str, bytes], value: int, data: Union[str, bytes] = "", chainID: int = -1) -> None: - self.txType: int = txType - self.nonce: int = nonce - self.gasPrice: int = gasPrice - self.gasLimit: int = gasLimit - self.to: bytes = bytes.fromhex(to[2:]) if isinstance(to, str) else to - self.value: int = value - self.data: bytes = bytes(data, "utf-8") - self.chainID = b'' - - 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}'!") - - self.lenNonce = int((len(hex(self.nonce)) - 1) / 2) - self.lenGP = int((len(hex(self.gasPrice)) - 1) / 2) - self.lenGL = int((len(hex(self.gasLimit)) - 1) / 2) - self.lenValue = int((len(hex(self.value)) - 1) / 2) - - self.lenChainID = int((len(hex(chainID)) - 1) / 2) - - if chainID != -1: - self.chainID = b"".join([ - b'' if self.lenChainID == 1 else (self.lenChainID + 0x80).to_bytes(1, byteorder="big"), - chainID.to_bytes(self.lenChainID, byteorder="big"), - write_varint(0 + 0x80), - write_varint(0 + 0x80), - ]) - - def serialize(self) -> bytes: - return b"".join([ - self.txType.to_bytes(1, byteorder="big"), - - b'' if self.lenNonce == 1 else write_varint(self.lenNonce + 0x80), - self.nonce.to_bytes(self.lenNonce, byteorder="big"), - - write_varint(self.lenGP + 0x80), - self.gasPrice.to_bytes(self.lenGP, byteorder="big"), - - write_varint(self.lenGL + 0x80), - self.gasLimit.to_bytes(self.lenGL, byteorder="big"), - - write_varint(len(self.to) + 0x80), - self.to, - - write_varint(self.lenValue + 0x80), - self.value.to_bytes(self.lenValue, byteorder="big"), - - write_varint(len(self.data) + 0x80), - self.data, - - self.chainID, - - ]) - -class EIP712: - def __init__(self, domain_hash: str, msg_hash: str) -> None: - self.domain_hash = bytes.fromhex(domain_hash) - self.msg_hash = bytes.fromhex(msg_hash) - - def serialize(self) -> bytes: - return b"".join([ - self.domain_hash, - self.msg_hash - ]) \ No newline at end of file diff --git a/tests/speculos/ledger_client/utils.py b/tests/speculos/ledger_client/utils.py deleted file mode 100644 index aa7bd96..0000000 --- a/tests/speculos/ledger_client/utils.py +++ /dev/null @@ -1,115 +0,0 @@ -from io import BytesIO -from typing import List, Optional, Literal, Tuple -import PIL.Image as Image - -import speculos.client - -UINT64_MAX: int = 18446744073709551615 -UINT32_MAX: int = 4294967295 -UINT16_MAX: int = 65535 - -# Association tableau si écran nanos ou nanox -PATH_IMG = {"nanos": "nanos", "nanox": "nanox", "nanosp": "nanosp"} - -def save_screenshot(cmd, path: str): - screenshot = cmd.client.get_screenshot() - img = Image.open(BytesIO(screenshot)) - img.save(path) - - -def compare_screenshot(cmd, path: str): - screenshot = cmd.client.get_screenshot() - assert speculos.client.screenshot_equal(path, BytesIO(screenshot)) - - -def parse_sign_response(response : bytes) -> Tuple[bytes, bytes, bytes]: - assert len(response) == 65 - - offset: int = 0 - - v: bytes = response[offset] - offset += 1 - - r: bytes = response[offset:offset + 32] - offset += 32 - - s: bytes = response[offset:] - - return (v, r, s) - - -def bip32_path_from_string(path: str) -> List[bytes]: - splitted_path: List[str] = path.split("/") - - if not splitted_path: - raise Exception(f"BIP32 path format error: '{path}'") - - if "m" in splitted_path and splitted_path[0] == "m": - splitted_path = splitted_path[1:] - - return [int(p).to_bytes(4, byteorder="big") if "'" not in p - else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big") - for p in splitted_path] - - -def packed_bip32_path_from_string(path: str) -> bytes: - bip32_paths = bip32_path_from_string(path) - - return b"".join([ - len(bip32_paths).to_bytes(1, byteorder="big"), - *bip32_paths - ]) - - -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}'!") - - 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"Cant 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/speculos/requirements.txt b/tests/speculos/requirements.txt deleted file mode 100644 index 343948d..0000000 --- a/tests/speculos/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -speculos -ed25519 -pytest>=6.1.1,<7.0.0 -ledgercomm>=1.1.0,<1.2.0 -ecdsa>=0.16.1,<0.17.0 -pysha3>=1.0.0,<2.0.0 diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png deleted file mode 100644 index fdc04e7..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png deleted file mode 100644 index a1e51e9..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png deleted file mode 100644 index 7a7214c..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png deleted file mode 100644 index 660f665..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png deleted file mode 100644 index e7a5819..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png deleted file mode 100644 index 029ed0a..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png deleted file mode 100644 index 9dfa9f8..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png deleted file mode 100644 index 5fd127e..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png deleted file mode 100644 index f445d03..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png deleted file mode 100644 index 739d0b1..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png deleted file mode 100644 index 5fd127e..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png deleted file mode 100644 index fdc04e7..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png deleted file mode 100644 index a1e51e9..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png deleted file mode 100644 index 7a7214c..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png deleted file mode 100644 index 660f665..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png deleted file mode 100644 index 029ed0a..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png deleted file mode 100644 index 9dfa9f8..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png deleted file mode 100644 index f445d03..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png deleted file mode 100644 index 739d0b1..0000000 Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00000.png b/tests/speculos/screenshots/sign/sign_message/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00001.png b/tests/speculos/screenshots/sign/sign_message/nanos/00001.png deleted file mode 100644 index d369d6c..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00002.png b/tests/speculos/screenshots/sign/sign_message/nanos/00002.png deleted file mode 100644 index 1743761..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00003.png b/tests/speculos/screenshots/sign/sign_message/nanos/00003.png deleted file mode 100644 index 56201e2..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00004.png b/tests/speculos/screenshots/sign/sign_message/nanos/00004.png deleted file mode 100644 index 8ae711b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00005.png b/tests/speculos/screenshots/sign/sign_message/nanos/00005.png deleted file mode 100644 index f4fd25b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00005.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00006.png b/tests/speculos/screenshots/sign/sign_message/nanos/00006.png deleted file mode 100644 index 68927d6..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00006.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png deleted file mode 100644 index 4e2a997..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png deleted file mode 100644 index 7a4bd19..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png deleted file mode 100644 index e52854f..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png deleted file mode 100644 index fdc3d3b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png deleted file mode 100644 index fdc3d3b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png deleted file mode 100644 index fdc3d3b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00000.png b/tests/speculos/screenshots/sign/sign_message/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00001.png b/tests/speculos/screenshots/sign/sign_message/nanox/00001.png deleted file mode 100644 index 4e2a997..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00002.png b/tests/speculos/screenshots/sign/sign_message/nanox/00002.png deleted file mode 100644 index 7a4bd19..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00003.png b/tests/speculos/screenshots/sign/sign_message/nanox/00003.png deleted file mode 100644 index e52854f..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00004.png b/tests/speculos/screenshots/sign/sign_message/nanox/00004.png deleted file mode 100644 index 2cca50c..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00005.png b/tests/speculos/screenshots/sign/sign_message/nanox/00005.png deleted file mode 100644 index fdc3d3b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00005.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00006.png b/tests/speculos/screenshots/sign/sign_message/nanox/00006.png deleted file mode 100644 index fdc3d3b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00006.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png deleted file mode 100644 index d369d6c..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png deleted file mode 100644 index 1743761..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png deleted file mode 100644 index 56201e2..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png deleted file mode 100644 index 8ae711b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png deleted file mode 100644 index f4fd25b..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png deleted file mode 100644 index 4e2a997..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png deleted file mode 100644 index 7a4bd19..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png deleted file mode 100644 index e52854f..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png deleted file mode 100644 index 4e2a997..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png deleted file mode 100644 index 7a4bd19..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png deleted file mode 100644 index e52854f..0000000 Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png deleted file mode 100644 index 308a1ab..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png deleted file mode 100644 index 9ef8a57..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png deleted file mode 100644 index 1c9156c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png deleted file mode 100644 index 9c7e704..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png deleted file mode 100644 index c922246..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png deleted file mode 100644 index e90cd9d..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png deleted file mode 100644 index 308a1ab..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png deleted file mode 100644 index 9ef8a57..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png deleted file mode 100644 index 1c9156c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png deleted file mode 100644 index c26449c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png deleted file mode 100644 index 96a5cae..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png deleted file mode 100644 index c26449c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png deleted file mode 100644 index 96a5cae..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png deleted file mode 100644 index 235fddd..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png deleted file mode 100644 index 1370858..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png deleted file mode 100644 index 1c9156c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png deleted file mode 100644 index 24c4f84..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png deleted file mode 100644 index 24c4f84..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png deleted file mode 100644 index ce795f3..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png deleted file mode 100644 index 235fddd..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png deleted file mode 100644 index 1370858..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png deleted file mode 100644 index 1c9156c..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png deleted file mode 100644 index 9c7e704..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png deleted file mode 100644 index 0186ef4..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png deleted file mode 100644 index 24c4f84..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png deleted file mode 100644 index c922246..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png deleted file mode 100644 index 6578872..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png deleted file mode 100644 index 0186ef4..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png deleted file mode 100644 index 24c4f84..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png deleted file mode 100644 index 570ce28..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png and /dev/null differ diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png deleted file mode 100644 index e90cd9d..0000000 Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png and /dev/null differ diff --git a/tests/speculos/test_address.py b/tests/speculos/test_address.py deleted file mode 100644 index 0e7a1f5..0000000 --- a/tests/speculos/test_address.py +++ /dev/null @@ -1,34 +0,0 @@ -from time import sleep - -from ledger_client.ledger_cmd_builder import WalletType - -def test_address(cmd): - sleep(0.5) - # True = verify address, False = skip display verification - # Test with Wallet v3 - assert cmd.get_address(0, WalletType.WalletV3, False) == "7571b498e3fed7a0fffbe21377e50548c92da4a04842e1b163547d3e8980cf64" - # Test with Everwallet - assert cmd.get_address(0, WalletType.EverWallet, False) == "522a4cc774797f537c41b4853a9b83f359fe2802a5cf3bd9f31240c495e82358" - # Test with SafeMultisig - assert cmd.get_address(0, WalletType.SafeMultisig, False) == "ae990783e06a196ab03029fe4517dda0ea318c091cd49ff51cc0a40369b0aff5" - # Test with SafeMultisig24h - assert cmd.get_address(0, WalletType.SafeMultisig24h, False) == "98135fb68e91833e810122abfe00ff3b38c1d555bf773741f869dea8b87fb72d" - # Test with SetcodeMultisig - assert cmd.get_address(0, WalletType.SetcodeMultisig, False) == "23e76dee54e3f715e11cf374177e786878814ad2c7ac6e38bc06515efdb5fab3" - # Test with BridgeMultisig - assert cmd.get_address(0, WalletType.BridgeMultisig, False) == "0806dbe6c4581af1165879fd196d3e02404029540e818921edfedbffb46d3c65" - # Test with Surf - assert cmd.get_address(0, WalletType.Surf, False) == "ec03eb7af13d70083b9f3c8202b0321ede255edc624292c531106f50d9f005b3" - # Test with Multisig2 - assert cmd.get_address(0, WalletType.Multisig2, False) == "9760a1b7393cdbb389205f72ebf4d7e362b06b419fdac9aeccd83bf39ce0d05a" - # Test with Multisig2_1 - assert cmd.get_address(0, WalletType.Multisig2_1, False) == "1de569744cf341d8e2e35996f23cdf5d5f9226c1400c98100f480d89e70c6bcf" - - - - - - - - - diff --git a/tests/speculos/test_configuration.py b/tests/speculos/test_configuration.py deleted file mode 100644 index 3eb42e2..0000000 --- a/tests/speculos/test_configuration.py +++ /dev/null @@ -1,10 +0,0 @@ -from time import sleep - -def test_configuration(cmd): - sleep(0.5) - if cmd.model == "nanos": - assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch - if cmd.model == "nanox": - assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch - if cmd.model == "nanosp": - assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch \ No newline at end of file diff --git a/tests/speculos/test_pubkey.py b/tests/speculos/test_pubkey.py deleted file mode 100644 index 01c5123..0000000 --- a/tests/speculos/test_pubkey.py +++ /dev/null @@ -1,80 +0,0 @@ -from time import sleep - -import pytest - -import ledger_client -from ledger_client.utils import compare_screenshot, save_screenshot, PATH_IMG - - -def test_get_public_key_simple(cmd): - - # without display - public_key = cmd.get_public_key(account=0, display=False) - - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - -def test_get_public_key(cmd): - - # without display - result: list = [] - with cmd.get_public_key_with_display(account=0, display=False, result=result) as exchange: - pass - - public_key = result[0] - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - # with display - result: list = [] - with cmd.get_public_key_with_display(account=0, display=True, result=result) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00005.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox" or cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - public_key1 = result[0] - assert public_key1 == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - -def test_get_public_key_reject(cmd): - - result: list = [] - with pytest.raises(ledger_client.exception.errors.DenyError) as error: - with cmd.get_public_key_with_display(account=0, display=True, result=result) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - - if cmd.model == "nanox" or cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('both') - assert error.value.args[0] == '0x6985' \ No newline at end of file diff --git a/tests/speculos/test_sign_message.py b/tests/speculos/test_sign_message.py deleted file mode 100644 index 56b6e20..0000000 --- a/tests/speculos/test_sign_message.py +++ /dev/null @@ -1,144 +0,0 @@ -from time import sleep -import ed25519 -import pytest -import ledger_client -from ledger_client.utils import save_screenshot, compare_screenshot, PATH_IMG - -SIGN_MAGIC: [4] = [0xFF, 0xFF, 0xFF, 0xFF] - -SUCCESS = 0x9000 - - -def test_sign(cmd): - sleep(0.5) - - account = 0 - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - hash = "c617baa256c79192029d57bf8cce9a0dccd57923faf395e399fe04a4d05ed71d" - hash_in_bytes = bytes.fromhex(hash) - assert len(hash_in_bytes) == 32 - - prefix = bytes(SIGN_MAGIC) - assert len(prefix) == 4 - message = prefix + hash_in_bytes - - res: list = [] - # an acc num | bytes to sign - with cmd.sign_message(res, account, hash_in_bytes) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00005.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00006.png") - cmd.client.press_and_release('both') - - if cmd.model == "nanox": - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - - if cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00005.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00006.png") - cmd.client.press_and_release('both') - - signature = res[0] - assert len(signature) == 64 - - verifying_key = ed25519.VerifyingKey(public_key, encoding="hex") - result = 0 - try: - verifying_key.verify(signature, message) - result = SUCCESS - print("The signature is valid.") - except ed25519.BadSignatureError: - print("Invalid signature!") - - assert result == SUCCESS - -def test_sign_reject(cmd): - sleep(0.5) - account = 0 - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - hash = "c617baa256c79192029d57bf8cce9a0dccd57923faf395e399fe04a4d05ed71d" - hash_in_bytes = bytes.fromhex(hash) - assert len(hash_in_bytes) == 32 - - prefix = bytes(SIGN_MAGIC) - assert len(prefix) == 4 - message = prefix + hash_in_bytes - - res: list = [] - # an acc num | bytes to sign - with pytest.raises(ledger_client.exception.errors.DenyError) as error: - if cmd.model == "nanos": - with cmd.sign_message(res, account, hash_in_bytes) as exchange: - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00005.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox": - with cmd.sign_message(res, account, hash_in_bytes) as exchange: - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - if cmd.model == "nanosp": - with cmd.sign_message(res, account, hash_in_bytes) as exchange: - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - assert error.value.args[0] == '0x6985' - - diff --git a/tests/speculos/test_sign_tx.py b/tests/speculos/test_sign_tx.py deleted file mode 100644 index d4a8987..0000000 --- a/tests/speculos/test_sign_tx.py +++ /dev/null @@ -1,243 +0,0 @@ -from time import sleep -import ed25519 -import pytest -import ledger_client -from ledger_client.ledger_cmd_builder import WalletType -from dataclasses import dataclass -import base64 -from ledger_client.utils import save_screenshot, compare_screenshot, PATH_IMG - -SIGN_MAGIC: [4] = [0xFF, 0xFF, 0xFF, 0xFF] - -SUCCESS = 0x9000 - -EVER_DECIMALS: int = 9 -EVER_TICKER: str = "EVER" -USDT_DECIMALS: int = 9 -USDT_TICKER: str = "USDT" -WALLET_ID: int = 0x4BA92D8A -DEFAULT_EXPIRATION_TIMEOUT: int = 60 - -class SignTransactionMeta: - chain_id: int - workchain_id: int - current_wallet_type: WalletType - - -def test_sign_tx(cmd): - - account = 0 - wallet_type = WalletType.SafeMultisig - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - message = "te6ccgEBAQEAOwAAcfDmnGpQVUZxL24fHgfUfLGp2/wzR+YWmZukQraxETyqAAAAxHF5r4KyShssDVOgdrJKGvzpVh6gwA==" - boc = base64.b64decode(message) - hash = "1ce8d3bd135bdc9b5538e086643e06eb74ebf6aed06161a14b19bd6abcb602ec" - - sign_transaction_meta = SignTransactionMeta() - - res: list = [] - with cmd.sign_tx(res, account, wallet_type, EVER_DECIMALS, EVER_TICKER, 0, boc[4:]) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - if cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - signature = res[0] - - print("SIGNATURE =", signature) - verifying_key = ed25519.VerifyingKey(public_key, encoding="hex") - result = 0 - try: - verifying_key.verify(signature, bytes.fromhex(hash)) - result = SUCCESS - print("The signature is valid.") - except ed25519.BadSignatureError: - print("Invalid signature!") - - assert result == SUCCESS - - -def test_burn_tx(cmd): - sleep(0.5) - - account = 0 - wallet_type = WalletType.SafeMultisig - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - message = "te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA="; - boc = base64.b64decode(message) - hash = "1675cfae267250459cee3ccbc1f559322f24f6d0fde33b1b3141f9498a7e4b89" - - sign_transaction_meta = SignTransactionMeta() - - res: list = [] - with cmd.sign_tx(res, account, wallet_type, USDT_DECIMALS, USDT_TICKER, 0, boc[4:]) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - if cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('both') - signature = res[0] - verifying_key = ed25519.VerifyingKey(public_key, encoding="hex") - result = 0 - try: - verifying_key.verify(signature, bytes.fromhex(hash)) - result = SUCCESS - print("The signature is valid.") - except ed25519.BadSignatureError: - print("Invalid signature!") - - assert result == SUCCESS - - -def test_burn_tx_reject(cmd): - sleep(0.5) - account = 0 - wallet_type = WalletType.SafeMultisig - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - message = "te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA="; - boc = base64.b64decode(message) - res: list = [] - with pytest.raises(ledger_client.exception.errors.DenyError) as error: - - with cmd.sign_tx(res, account, wallet_type, USDT_DECIMALS, USDT_TICKER, 0, boc[4:]) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - if cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - assert error.value.args[0] == '0x6985' - - -def test_sign_tx_reject(cmd): - - account = 0 - wallet_type = WalletType.SafeMultisig - # # # getting pubkey - public_key = cmd.get_public_key(account=0, display=False) - assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84" - - message = "te6ccgEBAQEAOwAAcfDmnGpQVUZxL24fHgfUfLGp2/wzR+YWmZukQraxETyqAAAAxHF5r4KyShssDVOgdrJKGvzpVh6gwA==" - boc = base64.b64decode(message) - hash = "1ce8d3bd135bdc9b5538e086643e06eb74ebf6aed06161a14b19bd6abcb602ec" - - sign_transaction_meta = SignTransactionMeta() - - res: list = [] - with pytest.raises(ledger_client.exception.errors.DenyError) as error: - with cmd.sign_tx(res, account, wallet_type, EVER_DECIMALS, EVER_TICKER, 0, boc[4:]) as exchange: - if cmd.model == "nanos": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - if cmd.model == "nanox": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - if cmd.model == "nanosp": - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png") - cmd.client.press_and_release('right') - compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png") - cmd.client.press_and_release('both') - assert error.value.args[0] == '0x6985' - diff --git a/tests/test_address_cmd.py b/tests/test_address_cmd.py new file mode 100644 index 0000000..8bb9362 --- /dev/null +++ b/tests/test_address_cmd.py @@ -0,0 +1,64 @@ +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.everscale_command_sender import EverscaleCommandSender, Errors, WalletType +from application_client.everscale_response_unpacker import unpack_get_address_response + +HARDENED_OFFSET = 0x80000000 +PATH_PREFIX = "44'/396'/" +PATH_SUFFIX = "'/0'/0'" + # 9 types of wallets +EXPECTED_ADDRESSES = [ + '7571b498e3fed7a0fffbe21377e50548c92da4a04842e1b163547d3e8980cf64', '522a4cc774797f537c41b4853a9b83f359fe2802a5cf3bd9f31240c495e82358', 'ae990783e06a196ab03029fe4517dda0ea318c091cd49ff51cc0a40369b0aff5', '98135fb68e91833e810122abfe00ff3b38c1d555bf773741f869dea8b87fb72d', '23e76dee54e3f715e11cf374177e786878814ad2c7ac6e38bc06515efdb5fab3', '0806dbe6c4581af1165879fd196d3e02404029540e818921edfedbffb46d3c65', 'ec03eb7af13d70083b9f3c8202b0321ede255edc624292c531106f50d9f005b3', '9760a1b7393cdbb389205f72ebf4d7e362b06b419fdac9aeccd83bf39ce0d05a', '1de569744cf341d8e2e35996f23cdf5d5f9226c1400c98100f480d89e70c6bcf' +] + +# In this test we check that the GET_ADDRESS works in non-confirmation mode +@pytest.mark.active_test_scope +def test_get_address_all_types_no_confirm(backend: BackendInterface) -> 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 + + + + + diff --git a/tests/test_app_config_cmd.py b/tests/test_app_config_cmd.py new file mode 100644 index 0000000..b272b86 --- /dev/null +++ b/tests/test_app_config_cmd.py @@ -0,0 +1,18 @@ +import pytest +from ragger.backend.interface import BackendInterface + +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 +@pytest.mark.active_test_scope +def test_get_app_config(backend: BackendInterface) -> None: + # Use the app interface instead of raw interface + client = EverscaleCommandSender(backend) + # Send the GET_VERSION instruction + 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_pubkey_cmd.py b/tests/test_pubkey_cmd.py new file mode 100644 index 0000000..4082abe --- /dev/null +++ b/tests/test_pubkey_cmd.py @@ -0,0 +1,69 @@ +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 import NavInsID +from ragger.navigator.navigation_scenario import NavigateWithScenario + +from utils import navigate_until_text_and_compare + +from application_client.everscale_command_sender import EverscaleCommandSender, Errors +from application_client.everscale_response_unpacker import unpack_get_public_key_response + +HARDENED_OFFSET = 0x80000000 +PATH_PREFIX = "44'/396'/" +PATH_SUFFIX = "'/0'/0'" + +# In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode +@pytest.mark.active_test_scope +def test_get_public_key_no_confirm(backend: BackendInterface) -> None: + account_number_list = [ + 0, + 1, + 911, + 255, + 2147483647 + ] + for account_number in account_number_list: + client = EverscaleCommandSender(backend) + response = client.get_public_key(account_number=account_number).data + _, public_key = unpack_get_public_key_response(response) + + 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, firmware, navigator, default_screenshot_path, test_name) -> None: + client = EverscaleCommandSender(backend) + account_number = 0 + with client.get_public_key_with_confirmation(account_number=account_number): + navigate_until_text_and_compare(firmware, navigator, "Approve", default_screenshot_path, test_name, True, True, [NavInsID.USE_CASE_CHOICE_CONFIRM]) + + response = client.get_async_response().data + _, public_key = unpack_get_public_key_response(response) + + 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, firmware, navigator, default_screenshot_path, test_name, scenario_navigator) -> None: + client = EverscaleCommandSender(backend) + account_number = 0 + + confirm_instructions = [NavInsID.USE_CASE_CHOICE_REJECT, NavInsID.USE_CASE_CHOICE_CONFIRM] + + with pytest.raises(ExceptionRAPDU) as e: + with client.get_public_key_with_confirmation(account_number=account_number): + navigate_until_text_and_compare(firmware, navigator, "Reject", default_screenshot_path, test_name, True, True, confirm_instructions) + + # with client.get_public_key_with_confirmation(account_number=account_number): + # 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..faf8e57 --- /dev/null +++ b/tests/test_sign_cmd.py @@ -0,0 +1,220 @@ +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_command_sender import EverscaleCommandSender +from application_client.everscale_response_unpacker import unpack_sign_tx_response +from utils import navigate_until_text_and_compare + + +def run_test( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, + transaction: str, + expected_signature: str, + scenario_navigator: NavigateWithScenario, + firmware, +) -> None: + # Use the app interface instead of raw interface + client = EverscaleCommandSender(backend) + + # Raw transaction + 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_bytes): + # Validate the on-screen request by performing the navigation appropriate for this device + if firmware.is_nano: + navigate_until_text_and_compare( + backend.firmware, + navigator, + "Approve", + default_screenshot_path, + test_name, + ) + else: + 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() == 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, + scenario_navigator, + firmware, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "0000000001090455534454000101040100c9002161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e2c951fb3d692b2a677323640012165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d03802216b562548ad00000000000000000000000049504f808015e4256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ad00328480101c03bf4894e22cdd500e450cbe5838b9938fda1e4d3727fe3b5385c5114b0293f0001", # Transaction + "a8b3ee327f6a64945e875d59ec49b12bea553b30170be65c541176f052156035428f8a0180e9f8802622b4f3339f2161076790b822e55c0d46f01b919f6de005", # Expected_signature + scenario_navigator, + firmware, + ) + + +@pytest.mark.active_test_scope +def test_sign_tx_confirm( + backend: BackendInterface, + navigator: Navigator, + default_screenshot_path: str, + test_name: str, + scenario_navigator, + firmware, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "00000000020904455645520001010101003b000071b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e395aa2b3d695f78d53a076b24a0de621e6767fc0", # Transaction + "8a5a9435d8b85f37f0d0b6dd0cb39521c8acf3f04cff7d53a4fb83e05313baace8b63b0fc3d8e6d0f9dd1922bc65df11efbecb9c34e4c79ec2a7267d67613e0e", # Expected_signature + scenario_navigator, + firmware, + ) + + +# 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, + scenario_navigator, + firmware, +) -> None: + run_test( + backend, + navigator, + default_screenshot_path, + test_name, + "00000000010904455645520001010301006c000161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7cfb9642b3d6449ea677323640010165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d038020000", # Transaction + "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808", # Expected_signature + scenario_navigator, + firmware, + ) + + +# # 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..f92914f --- /dev/null +++ b/tests/test_sign_message_cmd.py @@ -0,0 +1,53 @@ +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_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 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 + +# TODO: Add a valid raw message and a valid expected signature +@pytest.mark.active_test_scope +def test_sign_message(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str, scenario_navigator, firmware) -> 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) + + # Message to sign + message_hash = "1111111111111111111111111111111111111111111111111111111111111111" + message_bytes = bytes.fromhex(message_hash) + payload = account_number.to_bytes(4, byteorder='big') + message_bytes + # 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(payload=payload): + # Validate the on-screen request by performing the navigation appropriate for this device + if firmware.is_nano: + navigate_until_text_and_compare( + backend.firmware, + navigator, + "message.", + default_screenshot_path, + test_name + ) + else: + 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() == "d4883fb9095f3610dfc0888917c8b5548c7074f0f010966c94a5c405ccabe8d320c90334786dbf2b34f10e75c5370ae151b0b11cb190a16d7509983964d6dd00" \ No newline at end of file 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..c8bdc35 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,129 @@ +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 +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: + 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 + + +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: List[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, + )