diff --git a/.clang-format b/.clang-format index b4abfa06..c76e9fc2 100644 --- a/.clang-format +++ b/.clang-format @@ -12,7 +12,6 @@ SortIncludes: false SpaceAfterCStyleCast: true AllowShortCaseLabelsOnASingleLine: false AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: Never AllowShortFunctionsOnASingleLine: None BinPackArguments: false diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 98931911..0a3c970a 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build run: | @@ -29,7 +29,7 @@ jobs: make BOLOS_SDK=${{ matrix.SDK }} DEBUG=1 - name: Upload app binary - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact }} path: bin @@ -43,7 +43,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build unit tests run: | @@ -64,14 +64,14 @@ jobs: lcov --directory . -b "$(realpath build/)" --remove coverage.info '*/unit-tests/*' -o coverage.info && \ genhtml coverage.info -o coverage - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: code-coverage path: unit-tests/coverage - name: Upload to codecov.io if: false - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./unit-tests/coverage.info @@ -89,12 +89,12 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: HTML documentation run: doxygen .doxygen/Doxyfile - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: documentation path: doc/html @@ -108,7 +108,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build with Clang Static Analyzer run: | @@ -116,7 +116,7 @@ jobs: scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default - name: Upload scan result - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: scan-build @@ -147,17 +147,17 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download app binary - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ergo-app-debug-${{matrix.model}} path: bin - name: Run test run: | - apt-get update && apt-get install -qy curl netcat + apt-get update && apt-get install -qy curl netcat-traditional curl -fsSL https://deb.nodesource.com/setup_18.x | bash - apt-get install -qy nodejs export SEED=`cat tests/seed.txt` diff --git a/.github/workflows/lint-workflow.yml b/.github/workflows/lint-workflow.yml index 91f0313c..e6133700 100644 --- a/.github/workflows/lint-workflow.yml +++ b/.github/workflows/lint-workflow.yml @@ -9,7 +9,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Lint uses: DoozyX/clang-format-lint-action@v0.12 @@ -24,7 +24,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index fdc2e33a..1ca6c0f8 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,19 +1,22 @@ { "env": { - "BOLOS_SDK": "~/.ledger/sdk/nanos-secure-sdk", - "BOLOS_ENV": "~/.ledger/env", - "GCC_COMPILER_NAME": "gcc-arm-none-eabi-10.3-2021.10" + "BOLOS_SDK": "~/.ledger/nanos-sdk", + "ARM_GCC": "~/.ledger/gcc-arm-none-eabi-13.2-2023.10" }, "configurations": [ { "name": "Nano S", "includePath": [ "${workspaceFolder}/src", - "${workspaceFolder}/build/**", - "${env:BOLOS_ENV}/${env:GCC_COMPILER_NAME}/arm-none-eabi/include", + "${workspaceFolder}/build/nanos/gen_src", + "${env:ARM_GCC}/arm-none-eabi/include/*", + "${env:ARM_GCC}/lib/gcc/arm-none-eabi/13.2.1/include/*", "${env:BOLOS_SDK}/include/*", + "${env:BOLOS_SDK}/target/nanos/include/*", + "${env:BOLOS_SDK}/lib_bagl/include/*", "${env:BOLOS_SDK}/lib_ux/include/*", - "${env:BOLOS_SDK}/lib_cxng/include/*" + "${env:BOLOS_SDK}/lib_cxng/include/*", + "${env:BOLOS_SDK}/lib_standard_app/*" ], "defines": [ "TARGET_NANOS", @@ -43,12 +46,14 @@ "PATCH_VERSION=0", "IO_SEPROXYHAL_BUFFER_SIZE_B=128", "HAVE_UX_FLOW", + "DEBUG=1", "DEBUG_BUILD=1", "HAVE_PRINTF", - "PRINTF=screen_printf" + "PRINTF=screen_printf", + "_DEFAULT_SOURCE" ], - "compilerPath": "${env:BOLOS_ENV}/${env:GCC_COMPILER_NAME}/bin/arm-none-eabi-gcc", - "cStandard": "c99", + "compilerPath": "${env:ARM_GCC}/bin/arm-none-eabi-gcc", + "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "gcc-arm", "browse": { diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..f044256a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-vscode.cpptools", + "LedgerHQ.ledger-dev-tools", + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 6b6ceecb..79469d37 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,11 +15,12 @@ "valuesFormatting": "parseText", "gdbpath": "gdb-multiarch", "autorun": [ + "set substitute-path /project ${workspaceFolder}", "set architecture arm", + "set backtrace limit 15", "handle SIGILL nostop pass noprint", "add-symbol-file ${workspaceFolder}/bin/app.elf 0x40000000", - "b *0x40000000", - "c" + "b *0x40000000" ] } ] diff --git a/.vscode/settings.json b/.vscode/settings.json index aef3d745..4be05ef5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,22 +1,9 @@ { "files.associations": { "*.h": "c", - "cstdio": "c", - "optional": "c", - "istream": "c", - "ostream": "c", - "ratio": "c", - "system_error": "c", - "array": "c", - "functional": "c", - "tuple": "c", - "type_traits": "c", - "utility": "c", - "limits": "c", - "numeric": "c", - "stop_token": "c" + "format": "c" }, - "C_Cpp.clang_format_path": "/usr/bin/clang-format", - "editor.formatOnSave": true, - "cmake.configureOnOpen": false + "editor.formatOnSave": false, + "python.terminal.activateEnvironment": false, + "git.ignoreLimitWarning": true, } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 7c430bc8..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "make", - "type": "shell", - "command": "make clean && make", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "[debug] make", - "type": "shell", - "command": "make clean && make DEBUG=1", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "make clean", - "type": "shell", - "command": "make clean", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "make load", - "type": "shell", - "command": "make load", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "run unit tests", - "type": "shell", - "command": "cd unit-tests && rm -rf build && cmake -Bbuild -H. && make -C build && CTEST_OUTPUT_ON_FAILURE=1 make -C build test", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "run Speculos", - "type": "shell", - "command": "python3 ~/.ledger/speculos/speculos.py ${workspaceFolder}/bin/app.elf --ontop --sdk 2.1 --apdu-port 9999 --api-port 5000 --seed \"`cat ${workspaceFolder}/tests/seed.txt`\"", - "group": { - "kind": "build", - "isDefault": true - }, - "dependsOn": [ - "make debug" - ], - "problemMatcher": [] - }, - { - "label": "[debug] run Speculos", - "type": "shell", - "command": "python3 ~/.ledger/speculos/speculos.py -d ${workspaceFolder}/bin/app.elf --ontop --sdk 2.1 --apdu-port 9999 --api-port 5000 --seed \"`cat ${workspaceFolder}/tests/seed.txt`\"", - "group": { - "kind": "build", - "isDefault": true - }, - "dependsOn": [ - "make debug" - ], - "problemMatcher": [] - }, - { - "label": "run tests", - "type": "shell", - "command": "cd tests && npm --model=nanos run test", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [] - }, - { - "label": "kill Speculos", - "type": "shell", - "command": "pkill -f speculos.py", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [] - } - ] -} \ No newline at end of file diff --git a/Makefile b/Makefile index 11fb0d14..b13c223f 100644 --- a/Makefile +++ b/Makefile @@ -19,108 +19,97 @@ ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif -include Makefile.env include $(BOLOS_SDK)/Makefile.defines -APP_LOAD_PARAMS = --curve secp256k1 -ifeq ($(TARGET_NAME), TARGET_NANOX) -APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS -else -APP_LOAD_PARAMS += --appFlags 0x000 -endif -APP_LOAD_PARAMS += --path "44'/429'" -APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) - -# Pending review parameters -APP_LOAD_PARAMS += --tlvraw 9F:01 -DEFINES += HAVE_PENDING_REVIEW_SCREEN +######################################## +# Mandatory configuration # +######################################## +# Application name +APPNAME = "Ergo" -APPNAME = "Ergo" +# Application version APPVERSION_M = 0 APPVERSION_N = 0 APPVERSION_P = 4 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -ifeq ($(TARGET_NAME),TARGET_NANOS) - ICONNAME=icons/nanos_app.gif -else - ICONNAME=icons/nanox_app.gif -endif - -all: default - -DEFINES += $(DEFINES_LIB) -DEFINES += APPNAME=\"$(APPNAME)\" -DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) 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 - -DEBUG = 0 -ifneq ($(DEBUG),0) - DEFINES += DEBUG_BUILD - DEFINES += HAVE_PRINTF - DEFINES += HAVE_BOLOS_APP_STACK_CANARY - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += PRINTF=screen_printf - else - DEFINES += PRINTF=mcu_usb_printf - endif -else - DEFINES += PRINTF\(...\)= -endif - -include Makefile.env - -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 - -include $(BOLOS_SDK)/Makefile.glyphs +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" +# Application source files 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 +# Application icons following guidelines: +# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon +ICON_NANOS = icons/app_16px.gif +ICON_NANOX = icons/app_14px.gif +ICON_NANOSP = icons/app_14px.gif +#ICON_STAX = icons/app_32px.gif + +# 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 = secp256k1 + +# 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'/429'" # purpose=coin(44) / coin_type=Ergo(429) + +# 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 +VARIANT_VALUES = ERGO + +# Enabling DEBUG flag will enable PRINTF and disable optimizations +#DEBUG = 1 + +# Enabling stack canary in debug mode and setting debug flag +ifeq ($(DEBUG), 1) + DEFINES += DEBUG_BUILD=1 HAVE_BOLOS_APP_STACK_CANARY=1 endif -load: all - 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) - -include $(BOLOS_SDK)/Makefile.rules - -dep/%.d: %.c Makefile - -listvariants: - @echo VARIANTS COIN ergo +######################################## +# 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 + +######################################## +# 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_STANDARD_BAGL_UX_FLOW = 1 +#DISABLE_DEBUG_LEDGER_ASSERT = 1 +#DISABLE_DEBUG_THROW = 1 + +include $(BOLOS_SDK)/Makefile.standard_app \ No newline at end of file diff --git a/Makefile.env b/Makefile.env deleted file mode 100644 index 96e8c37f..00000000 --- a/Makefile.env +++ /dev/null @@ -1,13 +0,0 @@ -ifneq ($(BOLOS_ENV),) -$(info BOLOS_ENV=$(BOLOS_ENV)) -CLANGPATH := $(BOLOS_ENV)/llvm-14-x86_64/bin/ -GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-10.3-2021.10/bin/ -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 \ No newline at end of file diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif deleted file mode 100644 index a2a7e6d4..00000000 Binary files a/glyphs/icon_back.gif and /dev/null differ diff --git a/glyphs/icon_back_x.gif b/glyphs/icon_back_x.gif deleted file mode 100644 index ff043615..00000000 Binary files a/glyphs/icon_back_x.gif and /dev/null differ diff --git a/glyphs/icon_certificate.gif b/glyphs/icon_certificate.gif deleted file mode 100644 index 89b529f7..00000000 Binary files a/glyphs/icon_certificate.gif and /dev/null differ diff --git a/glyphs/icon_coggle.gif b/glyphs/icon_coggle.gif deleted file mode 100644 index 01c43b28..00000000 Binary files a/glyphs/icon_coggle.gif and /dev/null differ diff --git a/glyphs/icon_crossmark.gif b/glyphs/icon_crossmark.gif deleted file mode 100644 index 2dcf9d9e..00000000 Binary files a/glyphs/icon_crossmark.gif and /dev/null differ diff --git a/glyphs/icon_dashboard.gif b/glyphs/icon_dashboard.gif deleted file mode 100644 index 5c305517..00000000 Binary files a/glyphs/icon_dashboard.gif and /dev/null differ diff --git a/glyphs/icon_dashboard_x.gif b/glyphs/icon_dashboard_x.gif deleted file mode 100644 index 33d9b0a7..00000000 Binary files a/glyphs/icon_dashboard_x.gif and /dev/null differ diff --git a/glyphs/icon_down.gif b/glyphs/icon_down.gif deleted file mode 100644 index 4f4e39ee..00000000 Binary files a/glyphs/icon_down.gif and /dev/null differ diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif deleted file mode 100644 index df4bb829..00000000 Binary files a/glyphs/icon_eye.gif and /dev/null differ diff --git a/glyphs/icon_left.gif b/glyphs/icon_left.gif deleted file mode 100644 index 524226ba..00000000 Binary files a/glyphs/icon_left.gif and /dev/null differ diff --git a/glyphs/icon_processing.gif b/glyphs/icon_processing.gif deleted file mode 100644 index 8fe937fa..00000000 Binary files a/glyphs/icon_processing.gif and /dev/null differ diff --git a/glyphs/icon_right.gif b/glyphs/icon_right.gif deleted file mode 100644 index 15ff3cf5..00000000 Binary files a/glyphs/icon_right.gif and /dev/null differ diff --git a/glyphs/icon_up.gif b/glyphs/icon_up.gif deleted file mode 100644 index 4e13c064..00000000 Binary files a/glyphs/icon_up.gif and /dev/null differ diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif deleted file mode 100644 index ccb5cabe..00000000 Binary files a/glyphs/icon_validate_14.gif and /dev/null differ diff --git a/glyphs/icon_warning.gif b/glyphs/icon_warning.gif deleted file mode 100644 index 08bd4a73..00000000 Binary files a/glyphs/icon_warning.gif and /dev/null differ diff --git a/icons/nanox_app.gif b/icons/app_14px.gif similarity index 100% rename from icons/nanox_app.gif rename to icons/app_14px.gif diff --git a/icons/nanos_app.gif b/icons/app_16px.gif similarity index 100% rename from icons/nanos_app.gif rename to icons/app_16px.gif diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..b223878c --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,8 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+"] + +[tests] +unit_directory = "./unit-tests/" +pytest_directory = "./tests/" diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h deleted file mode 100644 index c896ddfe..00000000 --- a/src/apdu/dispatcher.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "../types.h" - -/** - * Dispatch APDU command received to the right handler. - * - * @param[in] cmd - * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). - * - * @return zero or positive integer if success, negative integer otherwise. - * - */ -int apdu_dispatcher(const command_t *cmd); diff --git a/src/apdu/offsets.h b/src/apdu/offsets.h deleted file mode 100644 index 3db4bc14..00000000 --- a/src/apdu/offsets.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -/** - * Offset of instruction class. - */ -#define OFFSET_CLA 0 -/** - * Offset of instruction code. - */ -#define OFFSET_INS 1 -/** - * Offset of instruction parameter 1. - */ -#define OFFSET_P1 2 -/** - * Offset of instruction parameter 2. - */ -#define OFFSET_P2 3 -/** - * Offset of command data length. - */ -#define OFFSET_LC 4 -/** - * Offset of command data. - */ -#define OFFSET_CDATA 5 diff --git a/src/apdu/parser.c b/src/apdu/parser.c deleted file mode 100644 index 418d8357..00000000 --- a/src/apdu/parser.c +++ /dev/null @@ -1,39 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (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 // size_t -#include // uint*_t -#include // bool - -#include "parser.h" -#include "offsets.h" - -bool apdu_parser(command_t *cmd, uint8_t *buf, size_t buf_len) { - // Check minimum length and Lc field of APDU command - if (buf_len < OFFSET_CDATA || buf_len - OFFSET_CDATA != buf[OFFSET_LC]) { - return false; - } - - cmd->cla = buf[OFFSET_CLA]; - cmd->ins = (command_e) buf[OFFSET_INS]; - cmd->p1 = buf[OFFSET_P1]; - cmd->p2 = buf[OFFSET_P2]; - cmd->lc = buf[OFFSET_LC]; - cmd->data = (buf[OFFSET_LC] > 0) ? buf + OFFSET_CDATA : NULL; - - return true; -} diff --git a/src/apdu/parser.h b/src/apdu/parser.h deleted file mode 100644 index dfba3fd6..00000000 --- a/src/apdu/parser.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include // size_t -#include // uint*_t -#include // bool - -#include "../types.h" - -/** - * Parse APDU command from byte buffer. - * - * @param[out] cmd - * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). - * @param[in] buf - * Byte buffer with raw APDU command. - * @param[in] buf_len - * Length of byte buffer. - * - * @return true if success, false otherwise. - * - */ -bool apdu_parser(command_t *cmd, uint8_t *buf, size_t buf_len); diff --git a/src/apdu/dispatcher.c b/src/apdu_dispatcher.c similarity index 76% rename from src/apdu/dispatcher.c rename to src/apdu_dispatcher.c index c70a0153..b81a6654 100644 --- a/src/apdu/dispatcher.c +++ b/src/apdu_dispatcher.c @@ -1,19 +1,17 @@ #include #include -#include "dispatcher.h" -#include "../constants.h" -#include "../globals.h" -#include "../types.h" -#include "../sw.h" -#include "../helpers/io.h" -#include "../common/buffer.h" -#include "../commands/app_name.h" -#include "../commands/app_version.h" -#include "../commands/extpubkey/epk_handler.h" -#include "../commands/deriveaddress/da_handler.h" -#include "../commands/attestinput/ainpt_handler.h" -#include "../commands/signtx/stx_handler.h" +#include + +#include "apdu_dispatcher.h" +#include "constants.h" +#include "sw.h" +#include "commands/app_name.h" +#include "commands/app_version.h" +#include "commands/extpubkey/epk_handler.h" +#include "commands/deriveaddress/da_handler.h" +#include "commands/attestinput/ainpt_handler.h" +#include "commands/signtx/stx_handler.h" int apdu_dispatcher(const command_t *cmd) { if (cmd->cla != CLA) { @@ -21,7 +19,7 @@ int apdu_dispatcher(const command_t *cmd) { } buffer_t buf; - buffer_init(&buf, cmd->data, cmd->lc, cmd->lc); + buffer_init(&buf, cmd->data, cmd->lc); switch (cmd->ins) { case CMD_GET_APP_VERSION: diff --git a/src/types.h b/src/apdu_dispatcher.h similarity index 51% rename from src/types.h rename to src/apdu_dispatcher.h index 3c32d94f..adf0d075 100644 --- a/src/types.h +++ b/src/apdu_dispatcher.h @@ -1,18 +1,6 @@ #pragma once -#include // size_t -#include // uint*_t - -#include "constants.h" - -/** - * Enumeration for the status of IO. - */ -typedef enum { - READY, /// ready for new event - RECEIVED, /// data received - WAITING /// waiting -} io_state_e; +#include /** * Enumeration with expected INS of APDU commands. @@ -28,13 +16,12 @@ typedef enum { } command_e; /** - * Structure with fields of APDU command. + * Dispatch APDU command received to the right handler. + * + * @param[in] cmd + * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). + * + * @return zero or positive integer if success, negative integer otherwise. + * */ -typedef struct { - uint8_t cla; /// Instruction class - command_e ins; /// Instruction code - uint8_t p1; /// Instruction parameter 1 - uint8_t p2; /// Instruction parameter 2 - uint8_t lc; /// Length of command data - uint8_t *data; /// Command data -} command_t; +int apdu_dispatcher(const command_t *cmd); diff --git a/src/app_main.c b/src/app_main.c new file mode 100644 index 00000000..8acb7405 --- /dev/null +++ b/src/app_main.c @@ -0,0 +1,80 @@ +/***************************************************************************** + * Ledger App Boilerplate. + * (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 // uint*_t +#include // memset, explicit_bzero + +#include +#include +#include +#include +#include + +#include "context.h" +#include "sw.h" +#include "apdu_dispatcher.h" +#include "ui/ui_menu.h" +#include "common/macros_ext.h" + +/** + * Handle APDU command received and send back APDU response using handlers. + */ +void app_main() { + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; + // Structured APDU command + command_t cmd; + + // Initialize I/O + io_init(); + + // Initialize Global App Context + app_init(); + + // Show main menu + ui_menu_main(); + + for (;;) { + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; + } + + // 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(SW_WRONG_APDU_DATA_LENGTH); + continue; + } + + 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); + + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } + } +} diff --git a/src/commands/app_name.c b/src/commands/app_name.c index 6df643e6..474b4a69 100644 --- a/src/commands/app_name.c +++ b/src/commands/app_name.c @@ -4,14 +4,12 @@ #include "app_name.h" #include "../constants.h" -#include "../globals.h" -#include "../types.h" -#include "helpers/response.h" -#include "common/buffer.h" +#include "../helpers/response.h" +#include "../common/rwbuffer.h" int handler_get_app_name() { _Static_assert(APPNAME_LEN < MAX_APPNAME_LEN, "APPNAME must be at most 64 characters!"); - BUFFER_FROM_ARRAY_FULL(buf, (uint8_t *) PIC(APPNAME), APPNAME_LEN); + RW_BUFFER_FROM_ARRAY_FULL(buf, (uint8_t *) PIC(APPNAME), APPNAME_LEN); return res_ok_data(&buf); } diff --git a/src/commands/app_version.c b/src/commands/app_version.c index 44db447c..245d70e7 100644 --- a/src/commands/app_version.c +++ b/src/commands/app_version.c @@ -2,11 +2,9 @@ #include // UINT8_MAX #include // _Static_assert #include "app_version.h" -#include "../globals.h" #include "../constants.h" -#include "../types.h" -#include "helpers/response.h" -#include "common/buffer.h" +#include "../helpers/response.h" +#include "../common/rwbuffer.h" int handler_get_version() { _Static_assert(APPVERSION_LEN == 4, "Length of (MAJOR || MINOR || PATCH || DEBUG) must be 4!"); @@ -18,9 +16,9 @@ int handler_get_version() { "PATCH version must be between 0 and 255!"); uint8_t version[APPVERSION_LEN] = {MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0}; #ifdef DEBUG_BUILD - version[3] = 1; + version[APPVERSION_LEN - 1] = 1; #endif - BUFFER_FROM_ARRAY_FULL(buf, version, APPVERSION_LEN); + RW_BUFFER_FROM_ARRAY_FULL(buf, version, APPVERSION_LEN); return res_ok_data(&buf); } diff --git a/src/commands/attestinput/ainpt_context.h b/src/commands/attestinput/ainpt_context.h index b94e6f68..8082ed24 100755 --- a/src/commands/attestinput/ainpt_context.h +++ b/src/commands/attestinput/ainpt_context.h @@ -5,7 +5,6 @@ #include #include "../../constants.h" #include "../../ergo/tx_ser_box.h" -#include "../../common/buffer.h" #include "../../helpers/input_frame.h" #include "../../ui/ui_application_id.h" diff --git a/src/commands/attestinput/ainpt_handler.c b/src/commands/attestinput/ainpt_handler.c old mode 100755 new mode 100644 index df22a923..f3f946d1 --- a/src/commands/attestinput/ainpt_handler.c +++ b/src/commands/attestinput/ainpt_handler.c @@ -1,32 +1,16 @@ +#include + #include "ainpt_handler.h" #include "ainpt_response.h" #include "ainpt_ui.h" -#include "../../globals.h" #include "../../helpers/session_id.h" #include "../../helpers/response.h" #include "../../helpers/sw_result.h" -#include "../../common/int_ops.h" -#include "../../common/macros.h" - -#include - -#define CONTEXT(gctx) gctx.ctx.attest_input +#include "../../common/safeint.h" +#include "../../common/macros_ext.h" -#define CHECK_COMMAND(_cmd) \ - if (_cmd != G_context.current_command) return handler_err(&CONTEXT(G_context), SW_BAD_STATE) - -#define CHECK_SESSION(session_id) \ - if (session_id != CONTEXT(G_context).session) \ - return handler_err(&CONTEXT(G_context), SW_BAD_SESSION_ID) - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_READ_PARAM(_ctx, _call) \ - if (!_call) return handler_err(_ctx, SW_NOT_ENOUGH_DATA) - -#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ - if (buffer_can_read(_buffer, 1)) return handler_err(_ctx, SW_TOO_MUCH_DATA) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" #define CHECK_CALL_RESULT_OK(_ctx, _call) \ do { \ @@ -50,6 +34,7 @@ static inline int handler_err(attest_input_ctx_t *ctx, uint16_t err) { ctx->state = ATTEST_INPUT_STATE_ERROR; + app_set_current_command(CMD_NONE); return res_error(err); } @@ -150,7 +135,7 @@ static inline int handle_registers_chunk(attest_input_ctx_t *ctx, buffer_t *cdat } static inline int handle_get_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], buffer_t *cdata) { CHECK_PROPER_STATE(ctx, ATTEST_INPUT_STATE_FINISHED); uint8_t index; @@ -162,36 +147,35 @@ static inline int handle_get_frame(attest_input_ctx_t *ctx, int handler_attest_input(buffer_t *cdata, attest_input_subcommand_e subcommand, uint8_t session_or_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + + attest_input_ctx_t *ctx = app_attest_input_context(); switch (subcommand) { case ATTEST_INPUT_SUBCOMMAND_INIT: if (session_or_token != 0x01 && session_or_token != 0x02) { - return res_error(SW_WRONG_P1P2); + return handler_err(ctx, SW_WRONG_P1P2); } - clear_context(&G_context, CMD_ATTEST_INPUT_BOX); - return handle_init(&CONTEXT(G_context), - cdata, - session_or_token == 0x02, - G_context.app_session_id); + app_set_current_command(CMD_ATTEST_INPUT_BOX); + return handle_init(ctx, cdata, session_or_token == 0x02, app_connected_app_id()); case ATTEST_INPUT_SUBCOMMAND_TREE_CHUNK: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_tree_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_tree_chunk(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_TOKENS: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_tokens(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_REGISTERS: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_registers_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_registers_chunk(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_GET_RESPONSE_FRAME: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_get_frame(&CONTEXT(G_context), G_context.session_key, cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_get_frame(ctx, app_session_key(), cdata); default: - return res_error(SW_WRONG_SUBCOMMAND); + return handler_err(ctx, SW_WRONG_SUBCOMMAND); } } diff --git a/src/commands/attestinput/ainpt_handler.h b/src/commands/attestinput/ainpt_handler.h index 41124ad5..6905db75 100755 --- a/src/commands/attestinput/ainpt_handler.h +++ b/src/commands/attestinput/ainpt_handler.h @@ -4,8 +4,9 @@ #include // bool #include // uint*_t +#include + #include "ainpt_context.h" -#include "../../common/buffer.h" typedef enum { ATTEST_INPUT_SUBCOMMAND_INIT = 0x01, @@ -24,6 +25,8 @@ typedef enum { * Subcommand identifier. * @param[in] session_or_token * Whether data has access token or not, or session id (depends on subcommand) + * @param[in] app_context + * Whether data has access token or not, or session id (depends on subcommand) * * @return zero or positive integer if success, negative integer otherwise. * diff --git a/src/commands/attestinput/ainpt_response.c b/src/commands/attestinput/ainpt_response.c index 8be4d02f..23a063c5 100755 --- a/src/commands/attestinput/ainpt_response.c +++ b/src/commands/attestinput/ainpt_response.c @@ -1,78 +1,69 @@ +#include + #include "ainpt_response.h" #include "ainpt_context.h" -#include "../../globals.h" #include "../../helpers/response.h" #include "../../helpers/input_frame.h" -#include "../../helpers/io.h" + +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" static inline uint8_t get_frames_count(uint8_t tokens_count) { uint8_t frames_count = (tokens_count + (FRAME_MAX_TOKENS_COUNT - 1)) / FRAME_MAX_TOKENS_COUNT; return frames_count == 0 ? 1 : frames_count; } +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_attested_input_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], uint8_t index) { uint8_t frames_count = get_frames_count(ctx->tokens_table.count); if (index >= frames_count) { - return res_error(SW_BAD_FRAME_INDEX); + return send_error(SW_BAD_FRAME_INDEX); } - // Hack for stack overflow. Writing directly to the IO buffer. + // Hack for the stack overflow. Writing directly to the IO buffer. // Not elegant but works. - BUFFER_FROM_ARRAY_EMPTY(output, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + RW_BUFFER_FROM_ARRAY_EMPTY(output, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&output, ctx->box_id, ERGO_ID_LEN)); + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, frames_count)); + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, index)); + CHECK_WRITE_PARAM(rw_buffer_write_u64(&output, ctx->box.value, BE)); - if (!buffer_write_bytes(&output, ctx->box_id, ERGO_ID_LEN)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u8(&output, frames_count)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u8(&output, index)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u64(&output, ctx->box.value, BE)) { - return res_error(SW_BUFFER_ERROR); - } uint8_t tokens_count = (ctx->tokens_table.count - index * FRAME_MAX_TOKENS_COUNT); tokens_count = MIN(tokens_count, FRAME_MAX_TOKENS_COUNT); - if (!buffer_write_u8(&output, tokens_count)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, tokens_count)); uint8_t offset = index * FRAME_MAX_TOKENS_COUNT; for (uint8_t i = offset; i < offset + tokens_count; i++) { - if (!buffer_write_bytes(&output, ctx->tokens_table.tokens[i], ERGO_ID_LEN)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u64(&output, ctx->token_amounts[i], BE)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&output, ctx->tokens_table.tokens[i], ERGO_ID_LEN)); + CHECK_WRITE_PARAM(rw_buffer_write_u64(&output, ctx->token_amounts[i], BE)); } - if (!buffer_can_write(&output, CX_SHA256_SIZE)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_can_write(&output, CX_SHA256_SIZE)); cx_hmac_sha256(session_key, SESSION_KEY_LEN, - buffer_read_ptr(&output), - buffer_data_len(&output), - buffer_write_ptr(&output), + rw_buffer_read_ptr(&output), + rw_buffer_data_len(&output), + rw_buffer_write_ptr(&output), CX_SHA256_SIZE); - if (!buffer_seek_write_cur(&output, INPUT_FRAME_SIGNATURE_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_seek_write_cur(&output, INPUT_FRAME_SIGNATURE_LEN)); return res_ok_data(&output); } int send_response_attested_input_frame_count(uint8_t tokens_count) { uint8_t frames_count = get_frames_count(tokens_count); - BUFFER_FROM_VAR_FULL(buf, frames_count); + RW_BUFFER_FROM_VAR_FULL(buf, frames_count); return res_ok_data(&buf); } int send_response_attested_input_session_id(uint8_t session_id) { - BUFFER_FROM_VAR_FULL(buf, session_id); + RW_BUFFER_FROM_VAR_FULL(buf, session_id); return res_ok_data(&buf); } diff --git a/src/commands/attestinput/ainpt_response.h b/src/commands/attestinput/ainpt_response.h index 9967e80b..59292c77 100755 --- a/src/commands/attestinput/ainpt_response.h +++ b/src/commands/attestinput/ainpt_response.h @@ -13,7 +13,7 @@ * */ int send_response_attested_input_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], uint8_t index); /** diff --git a/src/commands/attestinput/ainpt_ui.c b/src/commands/attestinput/ainpt_ui.c index 47234d3b..7f99f07f 100644 --- a/src/commands/attestinput/ainpt_ui.c +++ b/src/commands/attestinput/ainpt_ui.c @@ -4,25 +4,27 @@ #include "ainpt_ui.h" #include "ainpt_response.h" -#include "../../globals.h" -#include "../../common/macros.h" +#include "../../context.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_ainpt_display_confirm_step, pn, {&C_icon_processing, "Confirm Attest Input"}); static NOINLINE void ui_action_attest_input(bool approved, void* context) { - G_context.is_ui_busy = false; attest_input_ctx_t* ctx = (attest_input_ctx_t*) context; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->ui.app_token_value; + app_set_connected_app_id(ctx->ui.app_token_value); ctx->state = ATTEST_INPUT_STATE_APPROVED; send_response_attested_input_session_id(ctx->session); } else { + app_set_current_command(CMD_NONE); res_deny(); } @@ -33,19 +35,17 @@ int ui_display_access_token(uint32_t app_access_token, attest_input_ctx_t* conte context->ui.app_token_value = app_access_token; uint8_t screen = 0; - G_ux_flow[screen++] = &ux_ainpt_display_confirm_step; + ui_add_screen(&ux_ainpt_display_confirm_step, &screen); + if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, context->ui.app_token); + ui_add_screen(ui_application_id_screen(app_access_token, context->ui.app_token), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_attest_input, context, approve, reject); - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; - - ux_flow_init(0, G_ux_flow, NULL); - G_context.is_ui_busy = true; + ui_approve_reject_screens(ui_action_attest_input, + context, + ui_next_sreen_ptr(&screen), + ui_next_sreen_ptr(&screen)); + ui_display_screens(&screen); return 0; } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_context.h b/src/commands/deriveaddress/da_context.h index a39abd51..7b689f9a 100644 --- a/src/commands/deriveaddress/da_context.h +++ b/src/commands/deriveaddress/da_context.h @@ -2,7 +2,6 @@ #include #include "../../constants.h" -#include "../../common/bip32.h" #include "../../ui/ui_application_id.h" #include "../../ergo/address.h" diff --git a/src/commands/deriveaddress/da_handler.c b/src/commands/deriveaddress/da_handler.c index 9c69dd02..75e32afb 100644 --- a/src/commands/deriveaddress/da_handler.c +++ b/src/commands/deriveaddress/da_handler.c @@ -10,25 +10,30 @@ #include "da_ui.h" #include "da_response.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../types.h" #include "../../helpers/crypto.h" -#include "../../common/buffer.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/rwbuffer.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../helpers/session_id.h" #include "../../ergo/address.h" -#define CONTEXT(gcxt) G_context.ctx.derive_address +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" + +static inline int handler_err(derive_address_ctx_t *_ctx, uint16_t err) { + UNUSED(_ctx); + app_set_current_command(CMD_NONE); + return res_error(err); +} int handler_derive_address(buffer_t *cdata, bool display, bool has_access_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + app_set_current_command(CMD_DERIVE_ADDRESS); - clear_context(&G_context, CMD_DERIVE_ADDRESS); + derive_address_ctx_t *ctx = app_derive_address_context(); uint8_t bip32_path_len; uint32_t bip32_path[MAX_BIP32_PATH]; @@ -37,47 +42,38 @@ int handler_derive_address(buffer_t *cdata, bool display, bool has_access_token) uint32_t access_token = 0; uint8_t network_type = 0; - if (!buffer_read_u8(cdata, &network_type)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (!buffer_read_u8(cdata, &bip32_path_len) || - !buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (has_access_token && !buffer_read_u32(cdata, &access_token, BE)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (buffer_can_read(cdata, 1)) { - return res_error(SW_TOO_MUCH_DATA); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &network_type)); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &bip32_path_len)); + CHECK_READ_PARAM(ctx, buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)); + if (has_access_token) { + CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &access_token, BE)); } + CHECK_PARAMS_FINISHED(ctx, cdata); if (!bip32_path_validate(bip32_path, bip32_path_len, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ADDRESS_GE5)) { - return res_error(SW_BIP32_BAD_PATH); + return handler_err(ctx, SW_BIP32_BAD_PATH); } if (crypto_generate_public_key(bip32_path, bip32_path_len, public_key, NULL) != 0) { - return res_error(SW_INTERNAL_CRYPTO_ERROR); + return handler_err(ctx, SW_INTERNAL_CRYPTO_ERROR); } - if (!ergo_address_from_pubkey(network_type, public_key, CONTEXT(G_context).raw_address)) { + if (!ergo_address_from_pubkey(network_type, public_key, ctx->raw_address)) { return res_error(SW_ADDRESS_GENERATION_FAILED); } - if (!display && is_known_application(access_token, G_context.app_session_id)) { - return send_response_address(CONTEXT(G_context).raw_address); + if (!display && is_known_application(access_token, app_connected_app_id())) { + return send_response_address(ctx->raw_address); } - return ui_display_address(&CONTEXT(G_context), + return ui_display_address(ctx, !display, access_token, bip32_path, bip32_path_len, - CONTEXT(G_context).raw_address); + ctx->raw_address); } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_handler.h b/src/commands/deriveaddress/da_handler.h index 4ae714a0..15d725cf 100644 --- a/src/commands/deriveaddress/da_handler.h +++ b/src/commands/deriveaddress/da_handler.h @@ -4,8 +4,7 @@ #include // bool #include // uint*_t -#include "../../types.h" -#include "../../common/buffer.h" +#include /** * Handler for CMD_DERIVE_ADDRESS command. If successfully parse BIP32 path, diff --git a/src/commands/deriveaddress/da_response.c b/src/commands/deriveaddress/da_response.c index 6b595017..27524546 100644 --- a/src/commands/deriveaddress/da_response.c +++ b/src/commands/deriveaddress/da_response.c @@ -6,19 +6,24 @@ #include "../../sw.h" #include "../../constants.h" #include "../../context.h" -#include "../../globals.h" -#include "../../common/buffer.h" +#include "../../common/rwbuffer.h" #include "../../helpers/response.h" #include "../../ergo/address.h" +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" + +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_address(uint8_t address[static P2PK_ADDRESS_LEN]) { - BUFFER_NEW_LOCAL_EMPTY(response, P2PK_ADDRESS_LEN); + RW_BUFFER_NEW_LOCAL_EMPTY(response, P2PK_ADDRESS_LEN); - if (!buffer_write_bytes(&response, address, P2PK_ADDRESS_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, address, P2PK_ADDRESS_LEN)); - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); return res_ok_data(&response); } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_ui.c b/src/commands/deriveaddress/da_ui.c index c0c53996..8218d36c 100644 --- a/src/commands/deriveaddress/da_ui.c +++ b/src/commands/deriveaddress/da_ui.c @@ -1,21 +1,21 @@ #include #include #include +#include #include "da_ui.h" #include "da_response.h" #include "da_context.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../common/base58.h" -#include "../../common/macros.h" +#include "../../common/macros_ext.h" #include "../../ergo/address.h" #include "../../helpers/response.h" #include "../../ui/ui_bip32_path.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_da_display_confirm_addr_step, pn, {&C_icon_eye, "Confirm Address"}); @@ -25,29 +25,35 @@ UX_STEP_NOCB(ux_da_display_address_step, bnnn_paging, { .title = "Address", - .text = G_context.ctx.derive_address.address, + .text = G_app_context.commands_ctx.derive_address.address, }); // Action static NOINLINE void ui_action_derive_address(bool approved, void* context) { derive_address_ctx_t* ctx = (derive_address_ctx_t*) context; - G_context.is_ui_busy = true; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); if (ctx->send) { send_response_address(ctx->raw_address); } else { - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); res_ok(); } } else { + app_set_current_command(CMD_NONE); res_deny(); } ui_menu_main(); } +static inline int send_error(uint16_t err) { + app_set_current_command(CMD_NONE); + return res_error(err); +} + // Display int ui_display_address(derive_address_ctx_t* ctx, bool send, @@ -60,27 +66,28 @@ int ui_display_address(derive_address_ctx_t* ctx, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ADDRESS_GE5)) { - return res_error(SW_BIP32_BAD_PATH); + return send_error(SW_BIP32_BAD_PATH); } ctx->app_token_value = app_access_token; ctx->send = send; uint8_t screen = 0; - G_ux_flow[screen++] = - send ? &ux_da_display_confirm_send_step : &ux_da_display_confirm_addr_step; + ui_add_screen(send ? &ux_da_display_confirm_send_step : &ux_da_display_confirm_addr_step, + &screen); const ux_flow_step_t* b32_screen = ui_bip32_path_screen(bip32_path, bip32_path_len, "Path", ctx->bip32_path, - MEMBER_SIZE(derive_address_ctx_t, bip32_path)); + MEMBER_SIZE(derive_address_ctx_t, bip32_path), + NULL, + NULL); if (b32_screen == NULL) { - return res_error(SW_BIP32_FORMATTING_FAILED); + return send_error(SW_BIP32_FORMATTING_FAILED); } - - G_ux_flow[screen++] = b32_screen; + ui_add_screen(b32_screen, &screen); memset(ctx->address, 0, MEMBER_SIZE(derive_address_ctx_t, address)); if (!send) { @@ -90,27 +97,23 @@ int ui_display_address(derive_address_ctx_t* ctx, MEMBER_SIZE(derive_address_ctx_t, address)); if (result == -1 || result >= P2PK_ADDRESS_STRING_MAX_LEN) { - return res_error(SW_ADDRESS_FORMATTING_FAILED); + return send_error(SW_ADDRESS_FORMATTING_FAILED); } - G_ux_flow[screen++] = &ux_da_display_address_step; + ui_add_screen(&ux_da_display_address_step, &screen); } if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, ctx->app_id); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_id), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_derive_address, ctx, approve, reject); - - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; + ui_approve_reject_screens(ui_action_derive_address, + ctx, + ui_next_sreen_ptr(&screen), + ui_next_sreen_ptr(&screen)); memmove(ctx->raw_address, raw_address, P2PK_ADDRESS_LEN); - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; + ui_display_screens(&screen); return 0; } diff --git a/src/commands/extpubkey/epk_context.h b/src/commands/extpubkey/epk_context.h index b87ee22e..07fe026f 100644 --- a/src/commands/extpubkey/epk_context.h +++ b/src/commands/extpubkey/epk_context.h @@ -2,7 +2,6 @@ #include #include "../../constants.h" -#include "../../common/bip32.h" #include "../../ui/ui_application_id.h" typedef struct { diff --git a/src/commands/extpubkey/epk_handler.c b/src/commands/extpubkey/epk_handler.c index 231480ec..17744b17 100644 --- a/src/commands/extpubkey/epk_handler.c +++ b/src/commands/extpubkey/epk_handler.c @@ -5,71 +5,69 @@ #include #include +#include #include "epk_handler.h" #include "epk_ui.h" #include "epk_response.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../types.h" #include "../../helpers/crypto.h" #include "../../helpers/response.h" -#include "../../common/buffer.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/macros_ext.h" #include "../../helpers/session_id.h" -#define CONTEXT(gctx) gctx.ctx.ext_pub_key +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" + +static inline int handler_err(extended_public_key_ctx_t *_ctx, uint16_t err) { + UNUSED(_ctx); + app_set_current_command(CMD_NONE); + return res_error(err); +} int handler_get_extended_public_key(buffer_t *cdata, bool has_access_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + app_set_current_command(CMD_GET_EXTENDED_PUBLIC_KEY); - clear_context(&G_context, CMD_GET_EXTENDED_PUBLIC_KEY); + extended_public_key_ctx_t *ctx = app_extended_public_key_context(); uint8_t bip32_path_len; uint32_t bip32_path[MAX_BIP32_PATH]; uint32_t access_token = 0; - if (!buffer_read_u8(cdata, &bip32_path_len) || - !buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (has_access_token && !buffer_read_u32(cdata, &access_token, BE)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (buffer_can_read(cdata, 1)) { - return res_error(SW_TOO_MUCH_DATA); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &bip32_path_len)); + CHECK_READ_PARAM(ctx, buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)); + if (has_access_token) { + CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &access_token, BE)); } + CHECK_PARAMS_FINISHED(ctx, cdata); if (!bip32_path_validate(bip32_path, bip32_path_len, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ACCOUNT_GE3)) { - return res_error(SW_BIP32_BAD_PATH); + return handler_err(ctx, SW_BIP32_BAD_PATH); } if (crypto_generate_public_key(bip32_path, bip32_path_len, - CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code) != 0) { - return res_error(SW_INTERNAL_CRYPTO_ERROR); + ctx->raw_public_key, + ctx->chain_code) != 0) { + return handler_err(ctx, SW_INTERNAL_CRYPTO_ERROR); } - if (is_known_application(access_token, G_context.app_session_id)) { - return send_response_extended_pubkey(CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code); + if (is_known_application(access_token, app_connected_app_id())) { + return send_response_extended_pubkey(ctx->raw_public_key, ctx->chain_code); } - return ui_display_account(&CONTEXT(G_context), + return ui_display_account(ctx, access_token, bip32_path, bip32_path_len, - CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code); + ctx->raw_public_key, + ctx->chain_code); } \ No newline at end of file diff --git a/src/commands/extpubkey/epk_handler.h b/src/commands/extpubkey/epk_handler.h index d63ccd6f..3ce9fc75 100644 --- a/src/commands/extpubkey/epk_handler.h +++ b/src/commands/extpubkey/epk_handler.h @@ -4,8 +4,7 @@ #include // bool #include // uint*_t -#include "../../types.h" -#include "../../common/buffer.h" +#include /** * Handler for CMD_GET_EXTENDED_PUBLIC_KEY command. If successfully parse BIP32 path, diff --git a/src/commands/extpubkey/epk_response.c b/src/commands/extpubkey/epk_response.c index 99b30786..f8473e45 100644 --- a/src/commands/extpubkey/epk_response.c +++ b/src/commands/extpubkey/epk_response.c @@ -6,27 +6,27 @@ #include "../../sw.h" #include "../../constants.h" #include "../../context.h" -#include "../../globals.h" -#include "../../common/buffer.h" +#include "../../common/rwbuffer.h" #include "../../helpers/response.h" +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" + +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_extended_pubkey(uint8_t raw_public_key[static PUBLIC_KEY_LEN], uint8_t chain_code[static CHAIN_CODE_LEN]) { - BUFFER_NEW_LOCAL_EMPTY(response, EXTENDED_PUBLIC_KEY_LEN); + RW_BUFFER_NEW_LOCAL_EMPTY(response, EXTENDED_PUBLIC_KEY_LEN); // Compressed pubkey - if (!buffer_write_u8(&response, ((raw_public_key[64] & 1) ? 0x03 : 0x02))) { - return false; - } - if (!buffer_write_bytes(&response, raw_public_key + 1, 32)) { - return false; - } - - if (!buffer_write_bytes(&response, chain_code, CHAIN_CODE_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_u8(&response, ((raw_public_key[64] & 1) ? 0x03 : 0x02))); + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, raw_public_key + 1, 32)); + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, chain_code, CHAIN_CODE_LEN)); - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); return res_ok_data(&response); } \ No newline at end of file diff --git a/src/commands/extpubkey/epk_ui.c b/src/commands/extpubkey/epk_ui.c index d7e82df8..c52f443b 100644 --- a/src/commands/extpubkey/epk_ui.c +++ b/src/commands/extpubkey/epk_ui.c @@ -6,26 +6,26 @@ #include "epk_ui.h" #include "epk_response.h" -#include "../../globals.h" #include "../../context.h" #include "../../sw.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/bip32_ext.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../ui/ui_bip32_path.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_epk_display_confirm_ext_pubkey_step, pn, {&C_icon_warning, "Ext PubKey Export"}); static NOINLINE void ui_action_get_extended_pubkey(bool approved, void* context) { extended_public_key_ctx_t* ctx = (extended_public_key_ctx_t*) context; - G_context.is_ui_busy = false; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); send_response_extended_pubkey(ctx->raw_public_key, ctx->chain_code); explicit_bzero(ctx, sizeof(extended_public_key_ctx_t)); } else { @@ -33,6 +33,8 @@ static NOINLINE void ui_action_get_extended_pubkey(bool approved, void* context) res_deny(); } + app_set_current_command(CMD_NONE); + ui_menu_main(); } @@ -51,37 +53,36 @@ int ui_display_account(extended_public_key_ctx_t* ctx, } uint8_t screen = 0; - G_ux_flow[screen++] = &ux_epk_display_confirm_ext_pubkey_step; + ui_add_screen(&ux_epk_display_confirm_ext_pubkey_step, &screen); const ux_flow_step_t* b32_step = ui_bip32_path_screen(bip32_path, bip32_path_len, "Path", ctx->bip32_path, - MEMBER_SIZE(extended_public_key_ctx_t, bip32_path)); + MEMBER_SIZE(extended_public_key_ctx_t, bip32_path), + NULL, + NULL); if (b32_step == NULL) { + app_set_current_command(CMD_NONE); return res_error(SW_BIP32_FORMATTING_FAILED); } - G_ux_flow[screen++] = b32_step; + ui_add_screen(b32_step, &screen); if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, ctx->app_token); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_token), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_get_extended_pubkey, ctx, approve, reject); - - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; + ui_approve_reject_screens(ui_action_get_extended_pubkey, + ctx, + ui_next_sreen_ptr(&screen), + ui_next_sreen_ptr(&screen)); ctx->app_token_value = app_access_token; memmove(ctx->raw_public_key, raw_pub_key, PUBLIC_KEY_LEN); memmove(ctx->chain_code, chain_code, CHAIN_CODE_LEN); - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; + ui_display_screens(&screen); return 0; } diff --git a/src/commands/signtx/operations/stx_op_p2pk.c b/src/commands/signtx/operations/stx_op_p2pk.c index 376dd9dc..bc858917 100644 --- a/src/commands/signtx/operations/stx_op_p2pk.c +++ b/src/commands/signtx/operations/stx_op_p2pk.c @@ -1,28 +1,21 @@ +#include + #include "stx_op_p2pk.h" -#include "../../../common/macros.h" +#include "../../../context.h" +#include "../../../common/macros_ext.h" #include "../../../helpers/crypto.h" #include "../../../helpers/response.h" #include "../../../helpers/sw_result.h" #include "../../../ergo/schnorr.h" #include "../../../ergo/network_id.h" #include "../stx_ui.h" +#include "../../../ui/ui_main.h" -#include - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ - if (_ctx->state != _state1 && _ctx->state != _state2) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_SW_CALL_RESULT_OK(_ctx, _call) \ - do { \ - uint16_t res = _call; \ - if (res != SW_OK) return handler_err(_ctx, res); \ - } while (0) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../../helpers/cmd_macros.h" #define CHECK_TX_CALL_RESULT_OK(_tctx, _tcall) \ - CHECK_SW_CALL_RESULT_OK(_tctx, sw_from_tx_full_result(_tcall)) + CHECK_CALL_RESULT_SW_OK(_tctx, sw_from_tx_full_result(_tcall)) #define CHECK_TX_FINISHED(ctx) \ if (ergo_tx_serializer_full_is_finished(&ctx->transaction.tx)) { \ @@ -31,6 +24,7 @@ static inline uint16_t handler_err(sign_transaction_operation_p2pk_ctx_t *ctx, uint16_t err) { ctx->state = SIGN_TRANSACTION_OPERATION_P2PK_STATE_ERROR; + app_set_current_command(CMD_NONE); return err; } @@ -150,7 +144,7 @@ uint16_t stx_operation_p2pk_add_input(sign_transaction_operation_p2pk_ctx_t *ctx &p2pk_input_token_cb, (void *) ctx)); // Add input value to the amounts - CHECK_SW_CALL_RESULT_OK(ctx, stx_amounts_add_input(&ctx->amounts, erg_amount)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_amounts_add_input(&ctx->amounts, erg_amount)); // Switch state ctx->state = SIGN_TRANSACTION_OPERATION_P2PK_STATE_INPUTS_STARTED; return SW_OK; @@ -242,7 +236,7 @@ uint16_t stx_operation_p2pk_add_output_tree_chunk(sign_transaction_operation_p2p return handler_err(ctx, sw_from_tx_full_result(res)); } // Add chunk to the output info. Uses copied pointers. - CHECK_SW_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_output_info_add_tree_chunk(&ctx->transaction.ui.output, chunk, chunk_len, is_finished)); CHECK_TX_FINISHED(ctx); @@ -255,7 +249,7 @@ uint16_t stx_operation_p2pk_add_output_tree_fee(sign_transaction_operation_p2pk_ ctx, ergo_tx_serializer_full_add_box_miners_fee_tree(&ctx->transaction.tx, network_id_is_mainnet(ctx->network_id))); - CHECK_SW_CALL_RESULT_OK(ctx, stx_output_info_set_fee(&ctx->transaction.ui.output)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_output_info_set_fee(&ctx->transaction.ui.output)); CHECK_TX_FINISHED(ctx); return SW_OK; } @@ -268,7 +262,7 @@ uint16_t stx_operation_p2pk_add_output_tree_change(sign_transaction_operation_p2 CHECK_TX_CALL_RESULT_OK( ctx, ergo_tx_serializer_full_add_box_change_tree(&ctx->transaction.tx, pub_key)); - CHECK_SW_CALL_RESULT_OK(ctx, + CHECK_CALL_RESULT_SW_OK(ctx, stx_output_info_set_bip32(&ctx->transaction.ui.output, path, path_len)); CHECK_TX_FINISHED(ctx); return SW_OK; @@ -302,11 +296,38 @@ bool stx_operation_p2pk_should_show_output_confirm_screen( SIGN_TRANSACTION_OUTPUT_INFO_TYPE_MINERS_FEE) { return stx_output_info_used_tokens_count(&ctx->transaction.ui.output) > 0; } + // Change address + if (stx_output_info_type(&ctx->transaction.ui.output) == + SIGN_TRANSACTION_OUTPUT_INFO_TYPE_BIP32) { + // if path length is not 5 or wrong type then we should ask to confirm + if (!bip32_path_validate(ctx->transaction.ui.output.bip32_path.path, + ctx->transaction.ui.output.bip32_path.len, + BIP32_HARDENED(44), + BIP32_HARDENED(BIP32_ERGO_COIN), + BIP32_PATH_VALIDATE_ADDRESS_E5)) + return true; + // Check was it already approved then approve automatically + if (stx_bip32_path_is_equal(&ctx->transaction.ui.output.bip32_path, + &ctx->transaction.last_approved_change)) + return false; + // if account is the same and change index is < current + 20 then we approve it + // automatically + if (stx_bip32_path_same_account(&ctx->transaction.ui.output.bip32_path, &ctx->bip32) && + ctx->transaction.ui.output.bip32_path.path[3] == ctx->bip32.path[3] && + ctx->transaction.ui.output.bip32_path.path[4] < ctx->bip32.path[4] + 20) + return false; + } return true; } // =========================== // UI + +static NOINLINE void ui_stx_operation_p2pk_approve_action(void *context) { + sign_transaction_ui_aprove_ctx_t *ctx = (sign_transaction_ui_aprove_ctx_t *) context; + ui_stx_operation_approve_reject(true, ctx); +} + uint16_t ui_stx_operation_p2pk_show_token_and_path(sign_transaction_operation_p2pk_ctx_t *ctx, uint32_t app_access_token, bool is_known_application, @@ -317,11 +338,13 @@ uint16_t ui_stx_operation_p2pk_show_token_and_path(sign_transaction_operation_p2 ctx->bip32.len, "P2PK Signing", ctx->ui_approve.bip32_path, - MEMBER_SIZE(sign_transaction_operation_p2pk_ui_approve_data_ctx_t, bip32_path)); + MEMBER_SIZE(sign_transaction_operation_p2pk_ui_approve_data_ctx_t, bip32_path), + ui_stx_operation_p2pk_approve_action, + &ctx->ui_approve.ui_approve); if (b32_step == NULL) { return SW_BIP32_FORMATTING_FAILED; } - G_ux_flow[screen++] = b32_step; + ui_add_screen(b32_step, &screen); if (!ui_stx_add_operation_approve_screens(&ctx->ui_approve.ui_approve, &screen, @@ -345,6 +368,7 @@ uint16_t ui_stx_operation_p2pk_show_output_confirm_screen( if (!ui_stx_add_output_screens(&ctx->transaction.ui.ui, &screen, &ctx->transaction.ui.output, + &ctx->transaction.last_approved_change, ctx->network_id)) { return SW_SCREENS_BUFFER_OVERFLOW; } @@ -360,15 +384,17 @@ static NOINLINE void ui_stx_operation_p2pk_send_response(void *cb_context) { uint8_t secret[PRIVATE_KEY_LEN]; uint8_t signature[ERGO_SIGNATURE_LEN]; - BUFFER_FROM_ARRAY_FULL(res_sig, signature, ERGO_SIGNATURE_LEN); + RW_BUFFER_FROM_ARRAY_FULL(res_sig, signature, ERGO_SIGNATURE_LEN); if (ctx->state != SIGN_TRANSACTION_OPERATION_P2PK_STATE_FINALIZED) { + app_set_current_command(CMD_NONE); res_error(SW_BAD_STATE); return; } if (crypto_generate_private_key(ctx->bip32.path, ctx->bip32.len, secret) != 0) { explicit_bzero(ctx->schnorr_key, PRIVATE_KEY_LEN); + app_set_current_command(CMD_NONE); res_error(SW_INTERNAL_CRYPTO_ERROR); return; } @@ -381,6 +407,7 @@ static NOINLINE void ui_stx_operation_p2pk_send_response(void *cb_context) { if (finished) { res_ok_data(&res_sig); } else { + app_set_current_command(CMD_NONE); res_error(SW_SCHNORR_SIGNING_FAILED); } } diff --git a/src/commands/signtx/operations/stx_op_p2pk.h b/src/commands/signtx/operations/stx_op_p2pk.h index 611719b3..02d39a2c 100644 --- a/src/commands/signtx/operations/stx_op_p2pk.h +++ b/src/commands/signtx/operations/stx_op_p2pk.h @@ -3,7 +3,7 @@ #include "../stx_types.h" #include "../stx_amounts.h" #include "../stx_output.h" -#include "../../../common/bip32.h" +#include "../../../common/bip32_ext.h" #include "../../../ui/ui_application_id.h" #include "../../../ui/ui_bip32_path.h" @@ -30,6 +30,7 @@ typedef enum { typedef struct { ergo_tx_serializer_full_context_t tx; sign_transaction_operation_p2pk_ui_output_info_ctx_t ui; + sign_transaction_bip32_path_t last_approved_change; } sign_transaction_operation_p2pk_transaction_ctx_t; typedef struct { diff --git a/src/commands/signtx/stx_amounts.c b/src/commands/signtx/stx_amounts.c index d071f604..316ec552 100644 --- a/src/commands/signtx/stx_amounts.c +++ b/src/commands/signtx/stx_amounts.c @@ -1,24 +1,18 @@ #include "stx_amounts.h" -#include "../../common/macros.h" - -static inline uint8_t find_token_index(const token_table_t *table, - const uint8_t id[static ERGO_ID_LEN]) { - for (uint8_t i = 0; i < table->count; i++) { - if (memcmp(table->tokens[i], id, ERGO_ID_LEN) == 0) return i; - } - return INDEX_NOT_EXIST; -} +#include "../../common/macros_ext.h" ergo_tx_serializer_input_result_e stx_amounts_add_input_token( sign_transaction_amounts_ctx_t *ctx, const uint8_t box_id[static ERGO_ID_LEN], const uint8_t tn_id[static ERGO_ID_LEN], uint64_t value) { - (void) (box_id); + UNUSED(box_id); // searching for token in table - uint8_t index = 0; - if (!IS_ELEMENT_FOUND(index = find_token_index(&ctx->tokens_table, tn_id))) { - return ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_ID; + uint8_t index = token_table_find_token_index(&ctx->tokens_table, tn_id); + if (!IS_ELEMENT_FOUND(index)) { + index = token_table_add_token(&ctx->tokens_table, tn_id); + if (!IS_ELEMENT_FOUND(index)) return ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MANY_TOKENS; + ctx->tokens[index] = 0; } // calculating proper token sum if (!checked_add_i64(ctx->tokens[index], value, &ctx->tokens[index])) { @@ -57,8 +51,8 @@ ergo_tx_serializer_box_result_e stx_amounts_add_output_token(sign_transaction_am const uint8_t id[static ERGO_ID_LEN], uint64_t value) { UNUSED(type); - uint8_t index = 0; - if (!IS_ELEMENT_FOUND(index = find_token_index(&ctx->tokens_table, id))) { + uint8_t index = token_table_find_token_index(&ctx->tokens_table, id); + if (!IS_ELEMENT_FOUND(index)) { return ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_ID; } if (!checked_sub_i64(ctx->tokens[index], diff --git a/src/commands/signtx/stx_amounts.h b/src/commands/signtx/stx_amounts.h index 75c9c69d..04e82380 100644 --- a/src/commands/signtx/stx_amounts.h +++ b/src/commands/signtx/stx_amounts.h @@ -5,7 +5,7 @@ #include #include "../../constants.h" #include "../../ergo/tx_ser_full.h" -#include "../../common/int_ops.h" +#include "../../common/safeint.h" #include "../../sw.h" typedef struct { diff --git a/src/commands/signtx/stx_handler.c b/src/commands/signtx/stx_handler.c old mode 100755 new mode 100644 index 2c0ec73f..0a273026 --- a/src/commands/signtx/stx_handler.c +++ b/src/commands/signtx/stx_handler.c @@ -1,48 +1,24 @@ +#include + #include "stx_handler.h" #include "stx_response.h" #include "stx_ui.h" -#include "../../globals.h" #include "../../helpers/session_id.h" #include "../../helpers/response.h" -#include "../../common/int_ops.h" -#include "../../common/macros.h" +#include "../../common/safeint.h" +#include "../../common/macros_ext.h" #include "../../helpers/crypto.h" #include "../../helpers/input_frame.h" #include "../../ergo/schnorr.h" #include "./operations/stx_op_p2pk.h" -#include - -#define CONTEXT(gctx) gctx.ctx.sign_tx - -#define CHECK_COMMAND(_cmd) \ - if (_cmd != G_context.current_command) return handler_err(&CONTEXT(G_context), SW_BAD_STATE) - -#define CHECK_SESSION(_session) \ - if (_session != CONTEXT(G_context).session) \ - return handler_err(&CONTEXT(G_context), SW_BAD_SESSION_ID) - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ - if (_ctx->state != _state1 && _ctx->state != _state2) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_READ_PARAM(_ctx, _call) \ - if (!_call) return handler_err(_ctx, SW_NOT_ENOUGH_DATA) - -#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ - if (buffer_can_read(_buffer, 1)) return handler_err(_ctx, SW_TOO_MUCH_DATA) - -#define CHECK_CALL_RESULT_OK(_ctx, _call) \ - do { \ - uint16_t res = _call; \ - if (res != SW_OK) return handler_err(_ctx, res); \ - } while (0) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" static inline int handler_err(sign_transaction_ctx_t *ctx, uint16_t err) { ctx->state = SIGN_TRANSACTION_STATE_ERROR; + app_set_current_command(CMD_NONE); return res_error(err); } @@ -75,7 +51,7 @@ static inline int show_output_screen_if_needed(sign_transaction_ctx_t *ctx) { // Check if we have to show screen if (stx_operation_p2pk_should_show_output_confirm_screen(&ctx->p2pk)) { // Show it - CHECK_CALL_RESULT_OK(ctx, ui_stx_operation_p2pk_show_output_confirm_screen(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, ui_stx_operation_p2pk_show_output_confirm_screen(&ctx->p2pk)); return 0; } // We don't need to show confirm screen @@ -89,11 +65,12 @@ static inline int handle_init_p2pk(sign_transaction_ctx_t *ctx, uint32_t app_session_id_in = 0; uint8_t network_id = 0; CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &network_id)); - CHECK_CALL_RESULT_OK(ctx, read_bip32_path(cdata, ctx->p2pk.bip32.path, &ctx->p2pk.bip32.len)); + CHECK_CALL_RESULT_SW_OK(ctx, + read_bip32_path(cdata, ctx->p2pk.bip32.path, &ctx->p2pk.bip32.len)); CHECK_READ_PARAM(ctx, !(has_token && !buffer_read_u32(cdata, &app_session_id_in, BE))); CHECK_PARAMS_FINISHED(ctx, cdata); - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_init(&ctx->p2pk, ctx->p2pk.bip32.path, ctx->p2pk.bip32.len, network_id)); @@ -102,12 +79,12 @@ static inline int handle_init_p2pk(sign_transaction_ctx_t *ctx, ctx->session = session_id_new_random(ctx->session); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, - ui_stx_operation_p2pk_show_token_and_path( - &ctx->p2pk, - app_session_id_in, - is_known_application(app_session_id, app_session_id_in), - ctx)); + CHECK_CALL_RESULT_SW_OK(ctx, + ui_stx_operation_p2pk_show_token_and_path( + &ctx->p2pk, + app_session_id_in, + is_known_application(app_session_id, app_session_id_in), + ctx)); return 0; } @@ -123,24 +100,24 @@ static inline int handle_tx_start(sign_transaction_ctx_t *ctx, buffer_t *cdata) CHECK_PARAMS_FINISHED(ctx, cdata); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_start_tx(&ctx->p2pk, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_start_tx(&ctx->p2pk, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count)); return res_ok(); } static inline int handle_tokens(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_tokens(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_tokens(&ctx->p2pk, cdata)); return res_ok(); } static inline int handle_input_frame(sign_transaction_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); uint8_t id_buffer[ERGO_ID_LEN]; @@ -175,9 +152,9 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, // Tokens sub buffer uint8_t tokens_len = tokens_count * FRAME_TOKEN_VALUE_PAIR_SIZE; - buffer_init(&tokens, buffer_read_ptr(cdata), tokens_len, tokens_len); + buffer_init(&tokens, buffer_read_ptr(cdata), tokens_len); // Seek to the frame end - if (!buffer_seek_read_cur(cdata, tokens_len + INPUT_FRAME_SIGNATURE_LEN)) { + if (!buffer_seek_cur(cdata, tokens_len + INPUT_FRAME_SIGNATURE_LEN)) { return handler_err(ctx, SW_NOT_ENOUGH_DATA); } // New input @@ -187,15 +164,15 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &extension_len, BE)); // Add new input. Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_add_input(&ctx->p2pk, - id_buffer, - value, - frames_count, - extension_len)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_add_input(&ctx->p2pk, + id_buffer, + value, + frames_count, + extension_len)); } // Add tokens to the input. Swould be switch if more ops added - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_add_input_tokens(&ctx->p2pk, id_buffer, frame_index, &tokens)); @@ -205,14 +182,14 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, static inline int handle_input_context_extension(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_input_context_extension(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_input_context_extension(&ctx->p2pk, cdata)); return res_ok(); } static inline int handle_data_inputs(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_data_inputs(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_data_inputs(&ctx->p2pk, cdata)); return res_ok(); } @@ -230,20 +207,20 @@ static inline int handle_output_init(sign_transaction_ctx_t *ctx, buffer_t *cdat CHECK_PARAMS_FINISHED(ctx, cdata); // Add box. Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_add_output(&ctx->p2pk, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_add_output(&ctx->p2pk, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size)); return res_ok(); } static inline int handle_output_tree_chunk(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tree_chunk(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tree_chunk(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } @@ -251,7 +228,7 @@ static inline int handle_output_tree_fee(sign_transaction_ctx_t *ctx, buffer_t * CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); CHECK_PARAMS_FINISHED(ctx, cdata); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tree_fee(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tree_fee(&ctx->p2pk)); return show_output_screen_if_needed(ctx); } @@ -259,15 +236,15 @@ static inline int handle_output_tree_change(sign_transaction_ctx_t *ctx, buffer_ CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); uint8_t public_key[PUBLIC_KEY_LEN]; // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - read_bip32_path(cdata, - ctx->p2pk.transaction.ui.output.bip32_path.path, - &ctx->p2pk.transaction.ui.output.bip32_path.len)); - CHECK_CALL_RESULT_OK(ctx, - bip32_public_key(ctx->p2pk.transaction.ui.output.bip32_path.path, - ctx->p2pk.transaction.ui.output.bip32_path.len, - public_key)); - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK(ctx, + read_bip32_path(cdata, + ctx->p2pk.transaction.ui.output.bip32_path.path, + &ctx->p2pk.transaction.ui.output.bip32_path.len)); + CHECK_CALL_RESULT_SW_OK(ctx, + bip32_public_key(ctx->p2pk.transaction.ui.output.bip32_path.path, + ctx->p2pk.transaction.ui.output.bip32_path.len, + public_key)); + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_add_output_tree_change(&ctx->p2pk, ctx->p2pk.transaction.ui.output.bip32_path.path, @@ -279,89 +256,88 @@ static inline int handle_output_tree_change(sign_transaction_ctx_t *ctx, buffer_ static inline int handle_output_tokens(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tokens(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tokens(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } static inline int handle_output_registers(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_registers(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_registers(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } static inline int handle_sign_confirm(sign_transaction_ctx_t *ctx) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, ui_stx_operation_p2pk_show_confirm_screen(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, ui_stx_operation_p2pk_show_confirm_screen(&ctx->p2pk)); return 0; } int handler_sign_transaction(buffer_t *cdata, sign_transaction_subcommand_e subcommand, uint8_t session_or_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + sign_transaction_ctx_t *ctx = app_sign_transaction_context(); switch (subcommand) { case SIGN_TRANSACTION_SUBCOMMAND_SIGN_PK: if (session_or_token != 0x01 && session_or_token != 0x02) { return res_error(SW_WRONG_P1P2); } - clear_context(&G_context, CMD_SIGN_TRANSACTION); - return handle_init_p2pk(&CONTEXT(G_context), - cdata, - session_or_token == 0x02, - G_context.app_session_id); + app_set_current_command(CMD_SIGN_TRANSACTION); + + return handle_init_p2pk(ctx, cdata, session_or_token == 0x02, app_connected_app_id()); case SIGN_TRANSACTION_SUBCOMMAND_START_TX: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_tx_start(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_tx_start(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_TOKEN_IDS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_tokens(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_INPUT_FRAME: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_input_frame(&CONTEXT(G_context), G_context.session_key, cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_input_frame(ctx, app_session_key(), cdata); case SIGN_TRANSACTION_SUBCOMMAND_INPUT_CONTEXT_EXTENSION: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_input_context_extension(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_input_context_extension(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_DATA_INPUT: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_data_inputs(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_data_inputs(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_init(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_init(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_TREE_CHUNK: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_chunk(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_MINERS_FEE_TREE: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_fee(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_fee(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_CHANGE_TREE: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_change(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_change(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_TOKENS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tokens(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_REGISTERS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_registers(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_registers(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_CONFIRM: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_sign_confirm(&CONTEXT(G_context)); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_sign_confirm(ctx); default: - return res_error(SW_WRONG_SUBCOMMAND); + return handler_err(ctx, SW_WRONG_SUBCOMMAND); } } diff --git a/src/commands/signtx/stx_handler.h b/src/commands/signtx/stx_handler.h index ff4076bb..28bf5eb7 100755 --- a/src/commands/signtx/stx_handler.h +++ b/src/commands/signtx/stx_handler.h @@ -4,8 +4,9 @@ #include // bool #include // uint*_t +#include + #include "stx_context.h" -#include "../../common/buffer.h" typedef enum { SIGN_TRANSACTION_SUBCOMMAND_SIGN_PK = 0x01, diff --git a/src/commands/signtx/stx_output.c b/src/commands/signtx/stx_output.c index d3f4fa86..750a1f18 100644 --- a/src/commands/signtx/stx_output.c +++ b/src/commands/signtx/stx_output.c @@ -1,7 +1,6 @@ #include "stx_output.h" #include "../../sw.h" -#include "../../common/macros.h" -#include "../../common/base58.h" +#include "../../common/macros_ext.h" #include "../../ergo/ergo_tree.h" #include "../../ergo/address.h" #include "../../helpers/sw_result.h" @@ -24,11 +23,11 @@ static inline ergo_tx_serializer_box_result_e maybe_finished( sign_transaction_output_info_ctx_t* ctx) { if (stx_output_info_is_finished(ctx)) { if (STX_OUTPUT_INFO_TYPE(ctx) == SIGN_TRANSACTION_OUTPUT_INFO_TYPE_SCRIPT) { - uint8_t hash[BLAKE2B_256_DIGEST_LEN]; + uint8_t hash[CX_BLAKE2B_256_SIZE]; if (!blake2b_256_finalize(&ctx->tree_hash_ctx, hash)) { return ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER; } - memmove(ctx->tree_hash, hash, BLAKE2B_256_DIGEST_LEN); + memmove(ctx->tree_hash, hash, CX_BLAKE2B_256_SIZE); } } return ERGO_TX_SERIALIZER_BOX_RES_OK; diff --git a/src/commands/signtx/stx_output.h b/src/commands/signtx/stx_output.h index 18ec74d7..8f83b111 100644 --- a/src/commands/signtx/stx_output.h +++ b/src/commands/signtx/stx_output.h @@ -5,7 +5,7 @@ #include // uint*_t #include // memset -#include "../../common/bip32.h" +#include "../../common/bip32_ext.h" #include "../../constants.h" #include "../../helpers/blake2b.h" #include "../../ergo/tx_ser_full.h" @@ -31,7 +31,7 @@ typedef struct { union { cx_blake2b_t tree_hash_ctx; uint8_t public_key[COMPRESSED_PUBLIC_KEY_LEN]; - uint8_t tree_hash[BLAKE2B_256_DIGEST_LEN]; + uint8_t tree_hash[CX_BLAKE2B_256_SIZE]; sign_transaction_bip32_path_t bip32_path; }; const token_table_t* tokens_table; @@ -82,4 +82,14 @@ static inline sign_transaction_output_info_type_e stx_output_info_type( static inline bool stx_output_info_is_finished(const sign_transaction_output_info_ctx_t* ctx) { return STX_OUTPUT_INFO_IS_TREE_SET(ctx) && STX_OUTPUT_INFO_IS_BOX_FINISHED(ctx); +} + +static inline bool stx_bip32_path_is_equal(const sign_transaction_bip32_path_t* p1, + const sign_transaction_bip32_path_t* p2) { + return bip32_path_is_equal(p1->path, p1->len, p2->path, p2->len); +} + +static inline bool stx_bip32_path_same_account(const sign_transaction_bip32_path_t* p1, + const sign_transaction_bip32_path_t* p2) { + return bip32_path_same_account(p1->path, p1->len, p2->path, p2->len); } \ No newline at end of file diff --git a/src/commands/signtx/stx_response.c b/src/commands/signtx/stx_response.c index 7c98445b..8f0ab3f8 100755 --- a/src/commands/signtx/stx_response.c +++ b/src/commands/signtx/stx_response.c @@ -1,8 +1,7 @@ #include "stx_response.h" -#include "../../globals.h" #include "../../helpers/response.h" int send_response_sign_transaction_session_id(uint8_t session_id) { - BUFFER_FROM_VAR_FULL(buf, session_id); + RW_BUFFER_FROM_VAR_FULL(buf, session_id); return res_ok_data(&buf); } diff --git a/src/commands/signtx/stx_types.h b/src/commands/signtx/stx_types.h index 58ad0a96..58ea112d 100644 --- a/src/commands/signtx/stx_types.h +++ b/src/commands/signtx/stx_types.h @@ -45,6 +45,7 @@ typedef struct { char text[70]; // dynamic screen text uint8_t network_id; const sign_transaction_output_info_ctx_t *output; + sign_transaction_bip32_path_t *last_approved_change; } sign_transaction_ui_output_confirm_ctx_t; // Show screen callback: (index, title, title_len, text, text_len, cb_context) diff --git a/src/commands/signtx/stx_ui.c b/src/commands/signtx/stx_ui.c index 9b4f035b..a8e26def 100644 --- a/src/commands/signtx/stx_ui.c +++ b/src/commands/signtx/stx_ui.c @@ -1,21 +1,22 @@ #include #include #include +#include +#include #include "stx_ui.h" #include "stx_response.h" -#include "../../globals.h" -#include "../../common/macros.h" +#include "../../context.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" -#include "../../common/int_ops.h" -#include "../../common/base58.h" -#include "../../common/format.h" +#include "../../common/safeint.h" #include "../../ergo/address.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_dynamic_flow.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" #ifdef TARGET_NANOS #define ERGO_ID_UI_CHARACTERS_HALF 7 @@ -41,7 +42,7 @@ static inline void id_string_remove_middle(char* str, size_t len) { static inline bool format_hex_id(const uint8_t* id, size_t id_len, char* out, size_t out_len) { int len = format_hex(id, id_len, out, out_len); if (len <= 0) return false; - id_string_remove_middle(out, len); + id_string_remove_middle(out, len - 1); return true; } @@ -52,8 +53,11 @@ static inline bool format_b58_id(const uint8_t* id, size_t id_len, char* out, si } static inline bool format_erg_amount(uint64_t amount, char* out, size_t out_len) { - int out_bytes = format_fpu64(out, out_len, amount, ERGO_ERG_FRACTION_DIGIT_COUNT); - if (out_bytes <= 0 || out_len < 5 || (size_t) out_bytes > out_len - 5) return false; + if (!format_fpu64(out, out_len, amount, ERGO_ERG_FRACTION_DIGIT_COUNT)) { + return false; + } + size_t out_bytes = strlen(out); + if (out_len < 5 || out_bytes > out_len - 5) return false; out_len -= out_bytes; out += out_bytes; STRING_ADD_STATIC_TEXT(out, out_len, " ERG"); @@ -62,23 +66,28 @@ static inline bool format_erg_amount(uint64_t amount, char* out, size_t out_len) // ----- OPERATION APPROVE / REJECT FLOW -static NOINLINE void ui_stx_operation_approve_action(bool approved, void* context) { - sign_transaction_ui_aprove_ctx_t* ctx = (sign_transaction_ui_aprove_ctx_t*) context; +void ui_stx_operation_approve_reject(bool approved, sign_transaction_ui_aprove_ctx_t* ctx) { sign_transaction_ctx_t* sign_tx = (sign_transaction_ctx_t*) ctx->sign_tx_context; - G_context.is_ui_busy = false; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); sign_tx->state = SIGN_TRANSACTION_STATE_APPROVED; send_response_sign_transaction_session_id(sign_tx->session); } else { + app_set_current_command(CMD_NONE); res_deny(); } ui_menu_main(); } +static NOINLINE void ui_stx_operation_approve_action(bool approved, void* context) { + sign_transaction_ui_aprove_ctx_t* ctx = (sign_transaction_ui_aprove_ctx_t*) context; + ui_stx_operation_approve_reject(approved, ctx); +} + bool ui_stx_add_operation_approve_screens(sign_transaction_ui_aprove_ctx_t* ctx, uint8_t* screen, uint32_t app_access_token, @@ -87,15 +96,16 @@ bool ui_stx_add_operation_approve_screens(sign_transaction_ui_aprove_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 3) return false; if (!is_known_application) { - G_ux_flow[(*screen)++] = ui_application_id_screen(app_access_token, ctx->app_token); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_token), screen); } ctx->app_token_value = app_access_token; ctx->sign_tx_context = sign_tx; ctx->is_known_application = is_known_application; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_approve_action, ctx, approve, reject); + ui_approve_reject_screens(ui_stx_operation_approve_action, + ctx, + ui_next_sreen_ptr(screen), + ui_next_sreen_ptr(screen)); return true; } @@ -208,25 +218,39 @@ static NOINLINE uint16_t ui_stx_display_output_state(uint8_t screen, } static NOINLINE void ui_stx_operation_output_confirm_action(bool approved, void* context) { - UNUSED(context); - G_context.is_ui_busy = false; + sign_transaction_ui_output_confirm_ctx_t* ctx = + (sign_transaction_ui_output_confirm_ctx_t*) context; + app_set_ui_busy(false); + + explicit_bzero(ctx->last_approved_change, sizeof(sign_transaction_bip32_path_t)); + if (approved) { + // store last approved change address + if (stx_output_info_type(ctx->output) == SIGN_TRANSACTION_OUTPUT_INFO_TYPE_BIP32) { + memmove(ctx->last_approved_change, + &ctx->output->bip32_path, + sizeof(sign_transaction_bip32_path_t)); + } res_ok(); } else { + app_set_current_command(CMD_NONE); res_deny(); } + ui_menu_main(); } bool ui_stx_add_output_screens(sign_transaction_ui_output_confirm_ctx_t* ctx, uint8_t* screen, const sign_transaction_output_info_ctx_t* output, + sign_transaction_bip32_path_t* last_approved_change, uint8_t network_id) { if (MAX_NUMBER_OF_SCREENS - *screen < 6) return false; memset(ctx, 0, sizeof(sign_transaction_ui_output_confirm_ctx_t)); + memset(last_approved_change, 0, sizeof(sign_transaction_bip32_path_t)); - G_ux_flow[(*screen)++] = &ux_stx_display_output_confirm_step; + ui_add_screen(&ux_stx_display_output_confirm_step, screen); uint8_t info_screen_count = 1; // Address screen if (stx_output_info_type(output) != SIGN_TRANSACTION_OUTPUT_INFO_TYPE_BIP32) { @@ -244,12 +268,14 @@ bool ui_stx_add_output_screens(sign_transaction_ui_output_confirm_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 2) return false; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_output_confirm_action, NULL, approve, reject); + ui_approve_reject_screens(ui_stx_operation_output_confirm_action, + (void*) ctx, + ui_next_sreen_ptr(screen), + ui_next_sreen_ptr(screen)); ctx->network_id = network_id; ctx->output = output; + ctx->last_approved_change = last_approved_change; return true; } @@ -322,14 +348,16 @@ static NOINLINE uint16_t ui_stx_display_tx_state(uint8_t screen, // TX approve/reject callback static NOINLINE void ui_stx_operation_execute_action(bool approved, void* context) { - G_context.is_ui_busy = false; + app_set_ui_busy(false); + sign_transaction_ui_sign_confirm_ctx_t* ctx = (sign_transaction_ui_sign_confirm_ctx_t*) context; if (approved) { ctx->op_response_cb(ctx->op_cb_context); } else { res_deny(); } - clear_context(&G_context, CMD_NONE); + + app_set_current_command(CMD_NONE); ui_menu_main(); } @@ -346,7 +374,7 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, uint8_t tokens_count = stx_amounts_non_zero_tokens_count(amounts); - G_ux_flow[(*screen)++] = &ux_stx_display_sign_confirm_step; + ui_add_screen(&ux_stx_display_sign_confirm_step, screen); if (!ui_add_dynamic_flow_screens(screen, op_screen_count + 2 + (2 * tokens_count), @@ -358,9 +386,10 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 2) return false; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_execute_action, ctx, approve, reject); + ui_approve_reject_screens(ui_stx_operation_execute_action, + ctx, + ui_next_sreen_ptr(screen), + ui_next_sreen_ptr(screen)); ctx->op_screen_count = op_screen_count; ctx->op_screen_cb = screen_cb; @@ -372,14 +401,5 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, } bool ui_stx_display_screens(uint8_t screen_count) { - if (MAX_NUMBER_OF_SCREENS - screen_count < 2) return false; - - G_ux_flow[screen_count++] = FLOW_LOOP; - G_ux_flow[screen_count++] = FLOW_END_STEP; - - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; - - return true; + return ui_display_screens(&screen_count); } diff --git a/src/commands/signtx/stx_ui.h b/src/commands/signtx/stx_ui.h index 2bd7c068..6b632a7f 100644 --- a/src/commands/signtx/stx_ui.h +++ b/src/commands/signtx/stx_ui.h @@ -29,6 +29,7 @@ bool ui_stx_add_operation_approve_screens(sign_transaction_ui_aprove_ctx_t* ctx, bool ui_stx_add_output_screens(sign_transaction_ui_output_confirm_ctx_t* ctx, uint8_t* screen, const sign_transaction_output_info_ctx_t* output, + sign_transaction_bip32_path_t* last_approved_change, uint8_t network_id); /** @@ -51,4 +52,10 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, * @return true if success, false if screens buffer is full. * */ -bool ui_stx_display_screens(uint8_t screen_count); \ No newline at end of file +bool ui_stx_display_screens(uint8_t screen_count); + +/** + * Approve or reject operation programmatically. + * + */ +void ui_stx_operation_approve_reject(bool approved, sign_transaction_ui_aprove_ctx_t* ctx); \ No newline at end of file diff --git a/src/common/bip32.c b/src/common/bip32_ext.c similarity index 60% rename from src/common/bip32.c rename to src/common/bip32_ext.c index 286483e4..261e6dc7 100644 --- a/src/common/bip32.c +++ b/src/common/bip32_ext.c @@ -20,74 +20,9 @@ #include // uint*_t #include // bool -#include "bip32.h" -#include "read.h" +#include -bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, uint8_t out_len) { - if (out_len == 0 || out_len > MAX_BIP32_PATH) { - return false; - } - - uint8_t offset = 0; - - for (uint8_t i = 0; i < out_len; i++) { - if (offset + 4 > in_len) { - return false; - } - out[i] = read_u32_be(in, offset); - offset += 4; - } - - return true; -} - -bool bip32_path_format(const uint32_t *bip32_path, - size_t bip32_path_len, - char *out, - size_t out_len) { - if (bip32_path_len == 0 || bip32_path_len > MAX_BIP32_PATH) { - return false; - } - - size_t offset = 0; - - for (uint16_t i = 0; i < bip32_path_len; i++) { - size_t written; - - snprintf(out + offset, - out_len - offset, - "%d", - bip32_path[i] & (BIP32_HARDENED_CONSTANT - 1)); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - - if ((bip32_path[i] & BIP32_HARDENED_CONSTANT) != 0) { - snprintf(out + offset, out_len - offset, "'"); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - } - - if (i != bip32_path_len - 1) { - snprintf(out + offset, out_len - offset, "/"); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - } - } - - return true; -} +#include "bip32_ext.h" bool bip32_path_validate(const uint32_t *bip32_path, uint8_t bip32_path_len, @@ -140,4 +75,5 @@ bool bip32_path_validate(const uint32_t *bip32_path, } return true; } + LEDGER_ASSERT(false, "Bip32 validation type isn't handled properly"); } \ No newline at end of file diff --git a/src/common/bip32_ext.h b/src/common/bip32_ext.h new file mode 100644 index 00000000..9436c997 --- /dev/null +++ b/src/common/bip32_ext.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#define BIP32_HARDENED_CONSTANT 0x80000000u + +#define BIP32_HARDENED(x) (BIP32_HARDENED_CONSTANT + x) + +typedef enum { + BIP32_PATH_VALIDATE_COIN, + BIP32_PATH_VALIDATE_COIN_GE2_HARD, + BIP32_PATH_VALIDATE_ACCOUNT_E3, + BIP32_PATH_VALIDATE_ACCOUNT_GE3, + BIP32_PATH_VALIDATE_ADDRESS_E5, + BIP32_PATH_VALIDATE_ADDRESS_GE5 +} bip32_path_validation_type_e; + +bool bip32_path_validate(const uint32_t *bip32_path, + uint8_t bip32_path_len, + uint32_t type, + uint32_t coin, + bip32_path_validation_type_e vtype); + +static inline bool bip32_path_is_equal(const uint32_t *bip32_path_1, + uint8_t bip32_path_1_len, + const uint32_t *bip32_path_2, + uint8_t bip32_path_2_len) { + return bip32_path_1_len == bip32_path_2_len && + memcmp(bip32_path_1, bip32_path_2, bip32_path_1_len) == 0; +} + +static inline bool bip32_path_same_account(const uint32_t *bip32_path_1, + uint8_t bip32_path_1_len, + const uint32_t *bip32_path_2, + uint8_t bip32_path_2_len) { + return bip32_path_1_len >= 3 && bip32_path_2_len >= 3 && + memcmp(bip32_path_1, bip32_path_2, 3) == 0; +} \ No newline at end of file diff --git a/src/common/buffer.c b/src/common/buffer.c deleted file mode 100755 index 8a936e48..00000000 --- a/src/common/buffer.c +++ /dev/null @@ -1,241 +0,0 @@ -#include // uint*_t -#include // size_t -#include // bool -#include // memmove - -#include "buffer.h" -#include "read.h" -#include "write.h" -#include "bip32.h" - -bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->write_offset) { - return false; - } - - buffer->read_offset = offset; - - return true; -} - -bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset) { - if (buffer->read_offset + offset < buffer->read_offset || // overflow - buffer->read_offset + offset > buffer->write_offset) { // exceed buffer size - return false; - } - - buffer->read_offset += offset; - - return true; -} - -bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->write_offset) { - return false; - } - - buffer->read_offset = buffer->write_offset - offset; - - return true; -} - -bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->write_offset = offset; - - return true; -} - -bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset) { - if (buffer->write_offset + offset < buffer->write_offset || // overflow - buffer->write_offset + offset > buffer->size) { // exceed buffer size - return false; - } - - buffer->write_offset += offset; - - return true; -} - -bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->write_offset = buffer->size - offset; - - return true; -} - -bool buffer_read_u8(buffer_t *buffer, uint8_t *value) { - if (!buffer_can_read(buffer, 1)) { - *value = 0; - - return false; - } - - *value = buffer->ptr[buffer->read_offset]; - buffer_seek_read_cur(buffer, 1); - - return true; -} - -bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 2)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u16_be(buffer->ptr, buffer->read_offset) - : read_u16_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_cur(buffer, 2); - - return true; -} - -bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 4)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u32_be(buffer->ptr, buffer->read_offset) - : read_u32_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_cur(buffer, 4); - - return true; -} - -bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 8)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u64_be(buffer->ptr, buffer->read_offset) - : read_u64_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_cur(buffer, 8); - - return true; -} - -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len) { - if (!bip32_path_read(buffer->ptr + buffer->read_offset, - buffer->write_offset - buffer->read_offset, - out, - out_len)) { - return false; - } - - buffer_seek_read_cur(buffer, sizeof(*out) * out_len); - - return true; -} - -bool buffer_write_u8(buffer_t *buffer, uint8_t value) { - if (!buffer_can_write(buffer, 1)) { - return false; - } - - buffer->ptr[buffer->write_offset] = value; - buffer_seek_write_cur(buffer, 1); - - return true; -} - -bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 2)) { - return false; - } - - if (endianness == BE) { - write_u16_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u16_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 2); - - return true; -} - -bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 4)) { - return false; - } - - if (endianness == BE) { - write_u32_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u32_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 4); - - return true; -} - -bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 8)) { - return false; - } - - if (endianness == BE) { - write_u64_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u64_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 8); - - return true; -} - -bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len) { - if (buffer_data_len(buffer) < out_len) { - return false; - } - - memmove(out, buffer->ptr + buffer->read_offset, out_len); - - buffer_seek_read_cur(buffer, out_len); - - return true; -} - -bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len) { - if (buffer_data_len(buffer) > out_len) { - return false; - } - memmove(out, buffer->ptr + buffer->read_offset, buffer_data_len(buffer)); - return true; -} - -bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len) { - if (!buffer_can_write(buffer, from_len)) { - return false; - } - - memcpy(buffer->ptr + buffer->write_offset, from, from_len); - - buffer_seek_write_cur(buffer, from_len); - - return true; -} - -void buffer_shift_data(buffer_t *buffer) { - if (buffer->read_offset == 0) return; - size_t data_len = buffer_data_len(buffer); - memmove(buffer->ptr, buffer->ptr + buffer->read_offset, data_len); - buffer->write_offset = data_len; - buffer->read_offset = 0; -} diff --git a/src/common/buffer_ext.c b/src/common/buffer_ext.c new file mode 100644 index 00000000..2ecf8f72 --- /dev/null +++ b/src/common/buffer_ext.c @@ -0,0 +1,19 @@ +#include // uint*_t +#include // size_t +#include // bool +#include // memmove + +#include "buffer_ext.h" + +bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, size_t count) { + if (!buffer_can_read(buffer, count)) return false; + memmove(out, buffer_read_ptr(buffer), count); + return true; +} + +bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, size_t count) { + if (!buffer_copy_bytes(buffer, out, count)) { + return false; + } + return buffer_seek_cur(buffer, count); +} \ No newline at end of file diff --git a/src/common/buffer_ext.h b/src/common/buffer_ext.h new file mode 100644 index 00000000..cd194fd1 --- /dev/null +++ b/src/common/buffer_ext.h @@ -0,0 +1,74 @@ +#pragma once + +#include + +/** + * Initialize buffer. + * + * @param[out] buffer + * Pointer to input buffer struct. + * @param[in] ptr + * Pointer to byte buffert. + * @param[in] data_size + * Data size of the buffer. + * + */ +static inline void buffer_init(buffer_t *buffer, const uint8_t *ptr, size_t data_size) { + buffer->ptr = ptr; + buffer->offset = 0; + buffer->size = data_size; +} + +/** + * Return read pointer to the start of the data. + * + * @param[in] buffer + * Pointer to input buffer struct. + * + */ +static inline const uint8_t *buffer_read_ptr(const buffer_t *buffer) { + return buffer->ptr + buffer->offset; +} + +/** + * Tell whether buffer has bytes to read or not. + * + * @param[in] buffer + * Pointer to input buffer struct. + * + * @return length of the data in buffer. + * + */ +static inline size_t buffer_data_len(const buffer_t *buffer) { + return buffer->size - buffer->offset; +} + +/** + * Copy bytes from buffer without its modification. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] out + * Pointer to output byte buffer. + * @param[in] count + * Amount of bytes to copy. + * + * @return true if success, false otherwise. + * + */ +bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, size_t count); + +/** + * Read bytes from buffer. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] out + * Pointer to output byte buffer. + * @param[in] count + * Amount of bytes to copy. + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, size_t count); \ No newline at end of file diff --git a/src/common/format.c b/src/common/format.c deleted file mode 100644 index ede55c44..00000000 --- a/src/common/format.c +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * (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 // size_t -#include // int*_t, uint*_t -#include // strncpy, memmove -#include // bool - -#include "format.h" - -int format_i64(char *dst, size_t dst_len, const int64_t value) { - char temp[] = "-9223372036854775808"; - - char *ptr = temp; - int64_t num = value; - int sign = 1; - - if (value < 0) { - sign = -1; - } - - while (num != 0) { - *ptr++ = '0' + (num % 10) * sign; - num /= 10; - } - - if (value < 0) { - *ptr++ = '-'; - } else if (value == 0) { - *ptr++ = '0'; - } - - int distance = (ptr - temp) + 1; - - if ((int) dst_len < distance) { - return -1; - } - - size_t index = 0; - - while (--ptr >= temp) { - dst[index++] = *ptr; - } - - dst[index] = '\0'; - - return index; -} - -int format_u64(char *out, size_t outLen, uint64_t in) { - uint8_t i = 0; - - if (outLen == 0) { - return false; - } - outLen--; - - while (in > 9) { - out[i] = in % 10 + '0'; - in /= 10; - i++; - if (i + 1 > outLen) { - return -1; - } - } - out[i] = in + '0'; - out[i + 1] = '\0'; - - uint8_t j = 0, count = i + 1; - char tmp; - - // revert the string - while (j < i) { - // swap out[j] and out[i] - tmp = out[j]; - out[j] = out[i]; - out[i] = tmp; - - i--; - j++; - } - return count; -} - -int format_fpu64(char *dst, size_t dst_len, const uint64_t value, uint8_t decimals) { - char buffer[21] = {0}; - - if (format_u64(buffer, sizeof(buffer), value) <= 0) { - return -1; - } - - size_t digits = strlen(buffer); - - if (digits <= decimals) { - if (dst_len <= 2 + decimals - digits) { - return -1; - } - *dst++ = '0'; - *dst++ = '.'; - for (uint16_t i = 0; i < decimals - digits; i++, dst++) { - *dst = '0'; - } - dst_len -= 2 + decimals - digits; - strncpy(dst, buffer, dst_len); - return 2 + decimals; - } else { - if (dst_len <= digits + 1 + decimals) { - return -1; - } - - const size_t shift = digits - decimals; - memmove(dst, buffer, shift); - dst[shift] = '.'; - strncpy(dst + shift + 1, buffer + shift, decimals); - return digits + 1; - } -} - -int 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; -} diff --git a/src/common/format.h b/src/common/format.h deleted file mode 100644 index 1dc5c55f..00000000 --- a/src/common/format.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include // size_t -#include // int*_t, uint*_t -#include // bool - -/** - * Format 64-bit signed integer as string. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit signed integer to format. - * - * @return number of bytes written if success, -1 otherwise. - * - */ -int format_i64(char *dst, size_t dst_len, const int64_t value); - -/** - * Format 64-bit unsigned integer as string. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit unsigned integer to format. - * - * @return number of bytes written if success, -1 otherwise. - * - */ -int format_u64(char *dst, size_t dst_len, uint64_t value); - -/** - * Format 64-bit unsigned integer as string with decimals. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit unsigned integer to format. - * @param[in] decimals - * Number of digits after decimal separator. - * - * @return number of bytes written if success, -1 otherwise. - * - */ -int format_fpu64(char *dst, size_t dst_len, const uint64_t value, uint8_t decimals); - -/** - * Format byte buffer to lowercase hexadecimal string. - * - * @param[in] in - * Pointer to input byte buffer. - * @param[in] in_len - * Length of input byte buffer. - * @param[out] out - * Pointer to output string. - * @param[in] out_len - * Length of output string. - * - * @return number of bytes written if success, -1 otherwise. - * - */ -int format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len); diff --git a/src/common/varint.c b/src/common/gve.c similarity index 92% rename from src/common/varint.c rename to src/common/gve.c index a1222fee..5e604690 100644 --- a/src/common/varint.c +++ b/src/common/gve.c @@ -5,7 +5,7 @@ // Created by Yehor Popovych on 11.08.2021. // -#include "varint.h" +#include "gve.h" gve_result_e gve_get_i16(buffer_t *buffer, int16_t *val) { int32_t i32; @@ -73,7 +73,7 @@ gve_result_e gve_get_u64(buffer_t *buffer, uint64_t *val) { return res; } -gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val) { +gve_result_e gve_put_u64(rw_buffer_t *buffer, uint64_t val) { uint8_t out[10]; size_t i = 0; do { @@ -82,6 +82,5 @@ gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val) { if (val) byte |= 0x80U; out[i++] = byte; } while (val); - return buffer_write_bytes(buffer, out, i) ? GVE_OK : GVE_ERR_DATA_SIZE; - ; + return rw_buffer_write_bytes(buffer, out, i) ? GVE_OK : GVE_ERR_DATA_SIZE; } diff --git a/src/common/varint.h b/src/common/gve.h similarity index 63% rename from src/common/varint.h rename to src/common/gve.h index ce8e6fd4..308ac5e3 100755 --- a/src/common/varint.h +++ b/src/common/gve.h @@ -9,8 +9,8 @@ #include #include +#include "rwbuffer.h" #include "zigzag.h" -#include "buffer.h" typedef enum { GVE_OK = 0, GVE_ERR_INT_TO_BIG, GVE_ERR_DATA_SIZE } gve_result_e; @@ -29,32 +29,32 @@ gve_result_e gve_get_u32(buffer_t *buffer, uint32_t *val); gve_result_e gve_get_i64(buffer_t *buffer, int64_t *val); gve_result_e gve_get_u64(buffer_t *buffer, uint64_t *val); -gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val); +gve_result_e gve_put_u64(rw_buffer_t *buffer, uint64_t val); -static inline gve_result_e gve_put_i64(buffer_t *buffer, int64_t val) { +static inline gve_result_e gve_put_i64(rw_buffer_t *buffer, int64_t val) { return gve_put_u64(buffer, zigzag_encode_i64(val)); } -static inline gve_result_e gve_put_u32(buffer_t *buffer, uint32_t val) { +static inline gve_result_e gve_put_u32(rw_buffer_t *buffer, uint32_t val) { return gve_put_u64(buffer, val); } -static inline gve_result_e gve_put_i32(buffer_t *buffer, int32_t val) { +static inline gve_result_e gve_put_i32(rw_buffer_t *buffer, int32_t val) { return gve_put_u64(buffer, zigzag_encode_i32(val)); } -static inline gve_result_e gve_put_u8(buffer_t *buffer, uint8_t val) { - return buffer_write_bytes(buffer, &val, 1) ? GVE_OK : GVE_ERR_DATA_SIZE; +static inline gve_result_e gve_put_u8(rw_buffer_t *buffer, uint8_t val) { + return rw_buffer_write_u8(buffer, val) ? GVE_OK : GVE_ERR_DATA_SIZE; } -static inline gve_result_e gve_put_i8(buffer_t *buffer, int8_t val) { +static inline gve_result_e gve_put_i8(rw_buffer_t *buffer, int8_t val) { return gve_put_u8(buffer, (uint8_t) val); } -static inline gve_result_e gve_put_i16(buffer_t *buffer, int16_t val) { +static inline gve_result_e gve_put_i16(rw_buffer_t *buffer, int16_t val) { return gve_put_u32(buffer, (uint32_t) zigzag_encode_i32(val)); } -static inline gve_result_e gve_put_u16(buffer_t *buffer, uint16_t val) { +static inline gve_result_e gve_put_u16(rw_buffer_t *buffer, uint16_t val) { return gve_put_u64(buffer, val); } diff --git a/src/common/macros.h b/src/common/macros_ext.h similarity index 69% rename from src/common/macros.h rename to src/common/macros_ext.h index 4a6f4000..f4d085d3 100644 --- a/src/common/macros.h +++ b/src/common/macros_ext.h @@ -1,9 +1,6 @@ #pragma once -/** - * Macro for the size of a specific structure field. - */ -#define MEMBER_SIZE(type, member) (sizeof(((type *) 0)->member)) +#include /** * Macro for disabling inlining for function (GCC & Clang) diff --git a/src/common/rwbuffer.c b/src/common/rwbuffer.c new file mode 100644 index 00000000..686efe9a --- /dev/null +++ b/src/common/rwbuffer.c @@ -0,0 +1,111 @@ +#include // uint*_t +#include // size_t +#include // bool +#include // memmove + +#include +#include "rwbuffer.h" + +bool rw_buffer_seek_write_set(rw_buffer_t *buffer, size_t offset) { + if (offset > buffer->size) { + return false; + } + buffer->read.size = offset; + return true; +} + +bool rw_buffer_seek_write_cur(rw_buffer_t *buffer, size_t offset) { + if (buffer->read.size + offset < buffer->read.size || // overflow + buffer->read.size + offset > buffer->size) { // exceed buffer size + return false; + } + buffer->read.size += offset; + return true; +} + +bool rw_buffer_seek_write_end(rw_buffer_t *buffer, size_t offset) { + if (offset > buffer->size) { + return false; + } + buffer->read.size = buffer->size - offset; + return true; +} + +bool rw_buffer_write_u8(rw_buffer_t *buffer, uint8_t value) { + if (!rw_buffer_can_write(buffer, 1)) { + return false; + } + + ((uint8_t *) buffer->read.ptr)[buffer->read.size] = value; + + rw_buffer_seek_write_cur(buffer, 1); + return true; +} + +bool rw_buffer_write_u16(rw_buffer_t *buffer, uint16_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 2)) { + return false; + } + + if (endianness == BE) { + write_u16_be((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } else { + write_u16_le((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } + + rw_buffer_seek_write_cur(buffer, 2); + + return true; +} + +bool rw_buffer_write_u32(rw_buffer_t *buffer, uint32_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 4)) { + return false; + } + + if (endianness == BE) { + write_u32_be((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } else { + write_u32_le((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } + + rw_buffer_seek_write_cur(buffer, 4); + + return true; +} + +bool rw_buffer_write_u64(rw_buffer_t *buffer, uint64_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 8)) { + return false; + } + + if (endianness == BE) { + write_u64_be((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } else { + write_u64_le((uint8_t *) buffer->read.ptr, buffer->read.size, value); + } + + rw_buffer_seek_write_cur(buffer, 8); + + return true; +} + +bool rw_buffer_write_bytes(rw_buffer_t *buffer, const uint8_t *from, size_t from_len) { + if (!rw_buffer_can_write(buffer, from_len)) { + return false; + } + + memmove(rw_buffer_write_ptr(buffer), from, from_len); + + rw_buffer_seek_write_cur(buffer, from_len); + + return true; +} + +void rw_buffer_shift_data(rw_buffer_t *buffer) { + if (rw_buffer_read_position(buffer) == 0) return; + size_t data_len = rw_buffer_data_len(buffer); + memmove((uint8_t *) buffer->read.ptr, rw_buffer_read_ptr(buffer), data_len); + rw_buffer_seek_read_set(buffer, 0); + rw_buffer_seek_write_set(buffer, data_len); +} diff --git a/src/common/buffer.h b/src/common/rwbuffer.h old mode 100755 new mode 100644 similarity index 58% rename from src/common/buffer.h rename to src/common/rwbuffer.h index 70dd4fcf..36793961 --- a/src/common/buffer.h +++ b/src/common/rwbuffer.h @@ -1,47 +1,35 @@ #pragma once -#include // uint*_t -#include // size_t -#include // bool +#include "buffer_ext.h" -#define BUFFER_FROM_ARRAY_FULL(name, array, size) \ - buffer_t name; \ - buffer_init(&name, array, size, size) +#define RW_BUFFER_FROM_ARRAY_FULL(_name, _array, _size) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, _array, _size, _size) -#define BUFFER_FROM_ARRAY_EMPTY(name, array, size) \ - buffer_t name; \ - buffer_init(&name, array, size, 0) +#define RW_BUFFER_FROM_ARRAY_EMPTY(_name, _array, _size) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, _array, _size, 0) -#define BUFFER_FROM_VAR_FULL(name, var) \ - buffer_t name; \ - buffer_init(&name, &var, sizeof(var), sizeof(var)) +#define RW_BUFFER_FROM_VAR_FULL(_name, _var) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, &_var, sizeof(_var), sizeof(_var)) -#define BUFFER_FROM_VAR_EMPTY(name, var) \ - buffer_t name; \ - buffer_init(&name, &var, sizeof(var), 0) +#define RW_BUFFER_FROM_VAR_EMPTY(_name, _var) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, &_var, sizeof(_var), 0) -#define BUFFER_NEW_LOCAL_EMPTY(name, size) \ - uint8_t __##name[size]; \ - buffer_t name; \ - buffer_init(&name, __##name, size, 0) - -/** - * Enumeration for endianness. - */ -typedef enum { - BE, /// Big Endian - LE /// Little Endian -} endianness_t; +#define RW_BUFFER_NEW_LOCAL_EMPTY(_name, _size) \ + uint8_t __##_name[_size]; \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, __##_name, _size, 0) /** * Struct for buffer with size and read+write offset. */ typedef struct { - uint8_t *ptr; /// Pointer to byte buffer - uint16_t size; /// Size of byte buffer - uint16_t read_offset; /// Read offset in byte buffer - uint16_t write_offset; /// Write offset in byte buffer -} buffer_t; + buffer_t read; /// read buffer. size is a write offset. + size_t size; /// full allocated size of the buffer +} rw_buffer_t; /** * Initialize buffer. @@ -56,14 +44,12 @@ typedef struct { * Data size of the buffer. * */ -static inline void buffer_init(buffer_t *buffer, - uint8_t *ptr, - uint16_t buf_size, - uint16_t data_size) { - buffer->ptr = ptr; +static inline void rw_buffer_init(rw_buffer_t *buffer, + uint8_t *ptr, + size_t buf_size, + size_t data_size) { + buffer_init(&buffer->read, ptr, data_size); buffer->size = buf_size; - buffer->read_offset = 0; - buffer->write_offset = data_size; } /** @@ -73,87 +59,87 @@ static inline void buffer_init(buffer_t *buffer, * Pointer to input buffer struct. * */ -static inline void buffer_empty(buffer_t *buffer) { - buffer->read_offset = 0; - buffer->write_offset = 0; +static inline void rw_buffer_empty(rw_buffer_t *buffer) { + buffer->read.offset = 0; + buffer->read.size = 0; } /** - * Return read pointer to the start of the data. + * Tell whether buffer has bytes to read or not. * * @param[in] buffer * Pointer to input buffer struct. * + * @return length of the data in buffer. + * */ -static inline uint8_t *buffer_read_ptr(const buffer_t *buffer) { - return buffer->ptr + buffer->read_offset; +static inline size_t rw_buffer_data_len(const rw_buffer_t *buffer) { + return buffer_data_len(&buffer->read); } /** - * Return write pointer to the start of the empty space. + * Tell whether buffer can write bytes or not. * * @param[in] buffer * Pointer to input buffer struct. * + * @return length of the empty space in buffer. + * */ -static inline uint8_t *buffer_write_ptr(const buffer_t *buffer) { - return buffer->ptr + buffer->write_offset; +static inline size_t rw_buffer_empty_space_len(const rw_buffer_t *buffer) { + return buffer->size - buffer->read.size; } /** - * Tell whether buffer can read bytes or not. + * Return read pointer to the start of the data. * * @param[in] buffer * Pointer to input buffer struct. - * @param[in] n - * Number of bytes to read in buffer. - * - * @return true if success, false otherwise. * */ -static inline bool buffer_can_read(const buffer_t *buffer, uint16_t n) { - return (buffer->write_offset - buffer->read_offset) >= n; +static inline const uint8_t *rw_buffer_read_ptr(const rw_buffer_t *buffer) { + return buffer_read_ptr(&buffer->read); } /** - * Tell whether buffer can write bytes or not. + * Return write pointer to the start of the empty space. * * @param[in] buffer * Pointer to input buffer struct. - * @param[in] n - * Number of bytes to write in buffer. - * - * @return true if success, false otherwise. * */ -static inline bool buffer_can_write(const buffer_t *buffer, uint16_t n) { - return (buffer->size - buffer->write_offset) >= n; +static inline uint8_t *rw_buffer_write_ptr(rw_buffer_t *buffer) { + return ((uint8_t *) buffer->read.ptr) + buffer->read.size; } /** - * Tell whether buffer can write bytes or not. + * Tell whether buffer can read bytes or not. * * @param[in] buffer * Pointer to input buffer struct. + * @param[in] n + * Number of bytes to read in buffer. * - * @return length of the empty space in buffer. + * @return true if success, false otherwise. * */ -static inline uint16_t buffer_empty_space_len(const buffer_t *buffer) { - return buffer->size - buffer->write_offset; +static inline bool rw_buffer_can_read(const rw_buffer_t *buffer, size_t n) { + return buffer_can_read(&buffer->read, n); } /** - * Tell whether buffer has bytes to read or not. + * Tell whether buffer can write bytes or not. * * @param[in] buffer * Pointer to input buffer struct. + * @param[in] n + * Number of bytes to write in buffer. * - * @return length of the data in buffer. + * @return true if success, false otherwise. * */ -static inline uint16_t buffer_data_len(const buffer_t *buffer) { - return buffer->write_offset - buffer->read_offset; +static inline bool rw_buffer_can_write(const rw_buffer_t *buffer, size_t n) { + return rw_buffer_empty_space_len(buffer) >= n; } /** @@ -165,8 +151,8 @@ static inline uint16_t buffer_data_len(const buffer_t *buffer) { * @return current read position in the buffer. * */ -static inline uint16_t buffer_read_position(const buffer_t *buffer) { - return buffer->read_offset; +static inline size_t rw_buffer_read_position(const rw_buffer_t *buffer) { + return buffer->read.offset; } /** @@ -178,8 +164,8 @@ static inline uint16_t buffer_read_position(const buffer_t *buffer) { * @return current write position in the buffer. * */ -static inline uint16_t buffer_write_position(const buffer_t *buffer) { - return buffer->write_offset; +static inline size_t rw_buffer_write_position(const rw_buffer_t *buffer) { + return buffer->read.size; } /** @@ -193,7 +179,9 @@ static inline uint16_t buffer_write_position(const buffer_t *buffer) { * @return true if success, false otherwise. * */ -bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_set(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_set(&buffer->read, offset); +} /** * Seek the buffer read position relatively to current offset. @@ -201,12 +189,14 @@ bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset); * @param[in,out] buffer * Pointer to input buffer struct. * @param[in] offset - * Offset to seek relatively to `buffer->read_offset`. + * Offset to seek relatively to `buffer->read.offset`. * * @return true if success, false otherwise. * */ -bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_cur(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_cur(&buffer->read, offset); +} /** * Seek the buffer read position relatively to the end of the data. @@ -214,12 +204,14 @@ bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset); * @param[in,out] buffer * Pointer to input buffer struct. * @param[in] offset - * Offset to seek relatively to `buffer->write_offset`. + * Offset to seek relatively to `buffer->read.size`. * * @return true if success, false otherwise. * */ -bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_end(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_end(&buffer->read, offset); +} /** * Seek the buffer write position to specific offset. @@ -232,7 +224,7 @@ bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_set(rw_buffer_t *buffer, size_t offset); /** * Seek the buffer write position relatively to current offset. @@ -245,7 +237,7 @@ bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_cur(rw_buffer_t *buffer, size_t offset); /** * Seek the buffer write position relatively to the buffer end. @@ -258,7 +250,7 @@ bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_end(rw_buffer_t *buffer, size_t offset); /** * Read 1 byte from buffer into uint8_t. @@ -271,7 +263,9 @@ bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_read_u8(buffer_t *buffer, uint8_t *value); +static inline bool rw_buffer_read_u8(rw_buffer_t *buffer, uint8_t *value) { + return buffer_read_u8(&buffer->read, value); +} /** * Read 2 bytes from buffer into uint16_t. @@ -286,7 +280,11 @@ bool buffer_read_u8(buffer_t *buffer, uint8_t *value); * @return true if success, false otherwise. * */ -bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u16(rw_buffer_t *buffer, + uint16_t *value, + endianness_t endianness) { + return buffer_read_u16(&buffer->read, value, endianness); +} /** * Read 4 bytes from buffer into uint32_t. @@ -301,7 +299,11 @@ bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u32(rw_buffer_t *buffer, + uint32_t *value, + endianness_t endianness) { + return buffer_read_u32(&buffer->read, value, endianness); +} /** * Read 8 bytes from buffer into uint64_t. @@ -316,7 +318,11 @@ bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u64(rw_buffer_t *buffer, + uint64_t *value, + endianness_t endianness) { + return buffer_read_u64(&buffer->read, value, endianness); +} /** * Read BIP32 path from buffer. @@ -331,7 +337,9 @@ bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len); +static inline bool rw_buffer_read_bip32_path(rw_buffer_t *buffer, uint32_t *out, size_t out_len) { + return buffer_read_bip32_path(&buffer->read, out, out_len); +} /** * Move bytes from buffer. @@ -340,13 +348,15 @@ bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len); * Pointer to input buffer struct. * @param[out] out * Pointer to output byte buffer. - * @param[in] out_len - * Length of output byte buffer. + * @param[in] count + * Amount bytes to read. * * @return true if success, false otherwise. * */ -bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len); +static inline bool rw_buffer_read_bytes(rw_buffer_t *buffer, uint8_t *out, size_t count) { + return buffer_read_bytes(&buffer->read, out, count); +} /** * Copy bytes from buffer without its modification. @@ -355,13 +365,15 @@ bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len); * Pointer to input buffer struct. * @param[out] out * Pointer to output byte buffer. - * @param[in] out_len + * @param[in] count * Length of output byte buffer. * * @return true if success, false otherwise. * */ -bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len); +static inline bool rw_buffer_copy_bytes(const rw_buffer_t *buffer, uint8_t *out, size_t count) { + return buffer_copy_bytes(&buffer->read, out, count); +} /** * Write 1 byte to buffer from uint8_t. @@ -374,7 +386,7 @@ bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len); * @return true if success, false otherwise. * */ -bool buffer_write_u8(buffer_t *buffer, uint8_t value); +bool rw_buffer_write_u8(rw_buffer_t *buffer, uint8_t value); /** * Write 2 bytes to buffer from uint16_t. @@ -389,7 +401,7 @@ bool buffer_write_u8(buffer_t *buffer, uint8_t value); * @return true if success, false otherwise. * */ -bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness); +bool rw_buffer_write_u16(rw_buffer_t *buffer, uint16_t value, endianness_t endianness); /** * Write 4 bytes to buffer from uint32_t. @@ -404,7 +416,7 @@ bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness); +bool rw_buffer_write_u32(rw_buffer_t *buffer, uint32_t value, endianness_t endianness); /** * Write 8 bytes to buffer from uint64_t. @@ -419,7 +431,7 @@ bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness); +bool rw_buffer_write_u64(rw_buffer_t *buffer, uint64_t value, endianness_t endianness); /** * Write bytes to buffer. @@ -434,7 +446,7 @@ bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len); +bool rw_buffer_write_bytes(rw_buffer_t *buffer, const uint8_t *from, size_t from_len); /** * Move all data to the start of the buffer. @@ -443,4 +455,4 @@ bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len * Pointer to input buffer struct. * */ -void buffer_shift_data(buffer_t *buffer); +void rw_buffer_shift_data(rw_buffer_t *buffer); diff --git a/src/common/int_ops.h b/src/common/safeint.h similarity index 100% rename from src/common/int_ops.h rename to src/common/safeint.h diff --git a/src/context.c b/src/context.c index 7eba075b..60411743 100644 --- a/src/context.c +++ b/src/context.c @@ -1,15 +1,26 @@ #include // uint*_t #include // memset, explicit_bzero +#include #include "context.h" +#include "./common/macros_ext.h" -void clear_context(global_ctx_t* context, command_e current_command) { - uint8_t session_key[SESSION_KEY_LEN] = {0}; - uint32_t app_session = context->app_session_id; - memcpy(session_key, context->session_key, SESSION_KEY_LEN); - explicit_bzero(context, sizeof(global_ctx_t)); - memcpy(context->session_key, session_key, SESSION_KEY_LEN); - context->app_session_id = app_session; - context->current_command = current_command; - context->is_ui_busy = false; +// Saved here to store it outside of the stack +app_ctx_t G_app_context; + +void app_init(void) { + // Clear context + explicit_bzero(&G_app_context, sizeof(app_ctx_t)); + + // Generate random key for session + cx_rng(G_app_context.session_key, MEMBER_SIZE(app_ctx_t, session_key)); + + // Reset context to default values + app_set_current_command(CMD_NONE); +} + +void app_set_current_command(command_e current_command) { + explicit_bzero(&G_app_context.commands_ctx, MEMBER_SIZE(app_ctx_t, commands_ctx)); + app_set_ui_busy(false); + G_app_context.current_command = current_command; } \ No newline at end of file diff --git a/src/context.h b/src/context.h index f802f7c5..88cda123 100644 --- a/src/context.h +++ b/src/context.h @@ -1,16 +1,16 @@ #pragma once -#include "types.h" +#include "apdu_dispatcher.h" #include "commands/extpubkey/epk_context.h" #include "commands/deriveaddress/da_context.h" #include "commands/attestinput/ainpt_context.h" #include "commands/signtx/stx_context.h" /** - * Structure for global context. + * Structure for application context. */ typedef struct { - uint32_t app_session_id; + uint32_t connected_app_id; uint8_t session_key[SESSION_KEY_LEN]; command_e current_command; /// current command bool is_ui_busy; @@ -19,10 +19,90 @@ typedef struct { sign_transaction_ctx_t sign_tx; derive_address_ctx_t derive_address; extended_public_key_ctx_t ext_pub_key; - } ctx; -} global_ctx_t; + } commands_ctx; +} app_ctx_t; /** - * Clear context saving app token and session key + * Global application context */ -void clear_context(global_ctx_t* context, command_e current_command); \ No newline at end of file +extern app_ctx_t G_app_context; + +/** + * Check is ui busy + */ +static inline bool app_is_ui_busy() { + return G_app_context.is_ui_busy; +} + +/** + * Set UI busy + */ +static inline void app_set_ui_busy(bool is_busy) { + G_app_context.is_ui_busy = is_busy; +} + +/** + * Get connected application id. + */ +static inline uint32_t app_connected_app_id(void) { + return G_app_context.connected_app_id; +} + +/** + * Set connected application id. + */ +static inline void app_set_connected_app_id(uint32_t id) { + G_app_context.connected_app_id = id; +} + +/** + * Get session key. + */ +static inline const uint8_t* app_session_key(void) { + return G_app_context.session_key; +} + +/** + * Get current command key. + */ +static inline command_e app_current_command(void) { + return G_app_context.current_command; +} + +/** + * Attest Input command context + */ +static inline attest_input_ctx_t* app_attest_input_context(void) { + return &G_app_context.commands_ctx.attest_input; +} + +/** + * Sign Transaction command context + */ +static inline sign_transaction_ctx_t* app_sign_transaction_context(void) { + return &G_app_context.commands_ctx.sign_tx; +} + +/** + * Derive Address command context + */ +static inline derive_address_ctx_t* app_derive_address_context(void) { + return &G_app_context.commands_ctx.derive_address; +} + +/** + * Extended Public Key command context + */ +static inline extended_public_key_ctx_t* app_extended_public_key_context(void) { + return &G_app_context.commands_ctx.ext_pub_key; +} + +/** + * Init application context + */ +void app_init(void); + +/** + * Switch context state to the command + */ +void app_set_current_command(command_e current_command); \ No newline at end of file diff --git a/src/ergo/address.c b/src/ergo/address.c index 02e46f10..b4be68c9 100644 --- a/src/ergo/address.c +++ b/src/ergo/address.c @@ -6,47 +6,48 @@ #include #include +#include + #include "address.h" #include "network_id.h" -#include "../common/base58.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" #include "../helpers/blake2b.h" static inline bool _ergo_address_from_pubkey(uint8_t network, const uint8_t* public_key, uint8_t address[static P2PK_ADDRESS_LEN], bool is_compressed) { - BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2PK_ADDRESS_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2PK_ADDRESS_LEN); if (!network_id_is_valid(network)) { return false; } // P2PK + network id - if (!buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2PK + network)) { + if (!rw_buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2PK + network)) { return false; } if (is_compressed) { - if (!buffer_write_bytes(&buffer, public_key, COMPRESSED_PUBLIC_KEY_LEN)) { + if (!rw_buffer_write_bytes(&buffer, public_key, COMPRESSED_PUBLIC_KEY_LEN)) { return false; } } else { // Compress pubkey - if (!buffer_write_u8(&buffer, ((public_key[64] & 1) ? 0x03 : 0x02))) { + if (!rw_buffer_write_u8(&buffer, ((public_key[64] & 1) ? 0x03 : 0x02))) { return false; } - if (!buffer_write_bytes(&buffer, public_key + 1, COMPRESSED_PUBLIC_KEY_LEN - 1)) { + if (!rw_buffer_write_bytes(&buffer, public_key + 1, COMPRESSED_PUBLIC_KEY_LEN - 1)) { return false; } } - uint8_t hash[BLAKE2B_256_DIGEST_LEN] = {0}; + uint8_t hash[CX_BLAKE2B_256_SIZE] = {0}; - if (!blake2b_256(buffer_read_ptr(&buffer), buffer_data_len(&buffer), hash)) { + if (!blake2b_256(rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer), hash)) { return false; } // Checksum - if (!buffer_write_bytes(&buffer, hash, ADDRESS_CHECKSUM_LEN)) { + if (!rw_buffer_write_bytes(&buffer, hash, ADDRESS_CHECKSUM_LEN)) { return false; } @@ -68,23 +69,23 @@ bool ergo_address_from_compressed_pubkey(uint8_t network, bool ergo_address_from_script_hash(uint8_t network, const uint8_t hash[static P2SH_HASH_LEN], uint8_t address[static P2SH_ADDRESS_LEN]) { - BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2SH_ADDRESS_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2SH_ADDRESS_LEN); if (!network_id_is_valid(network)) { return false; } // P2SH + network id - if (!buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2SH + network)) { + if (!rw_buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2SH + network)) { return false; } - if (!buffer_write_bytes(&buffer, hash, P2SH_HASH_LEN)) { + if (!rw_buffer_write_bytes(&buffer, hash, P2SH_HASH_LEN)) { return false; } - uint8_t checksum[BLAKE2B_256_DIGEST_LEN] = {0}; - if (!blake2b_256(buffer_read_ptr(&buffer), buffer_data_len(&buffer), checksum)) { + uint8_t checksum[CX_BLAKE2B_256_SIZE] = {0}; + if (!blake2b_256(rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer), checksum)) { return false; } // Checksum - if (!buffer_write_bytes(&buffer, checksum, ADDRESS_CHECKSUM_LEN)) { + if (!rw_buffer_write_bytes(&buffer, checksum, ADDRESS_CHECKSUM_LEN)) { return false; } return true; diff --git a/src/ergo/ergo_tree.c b/src/ergo/ergo_tree.c index d75910ec..1416c449 100644 --- a/src/ergo/ergo_tree.c +++ b/src/ergo/ergo_tree.c @@ -2,7 +2,7 @@ #include #include #include "address.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" static const uint8_t C_ERGO_TREE_P2PK_PREFIX[ERGO_TREE_P2PK_PREFIX_LEN] = {0x00, 0x08, 0xcd}; @@ -35,14 +35,14 @@ static const uint8_t C_ERGO_TREE_MINERS_HASH_FEE_MAINNET[105] = { void ergo_tree_generate_p2pk(const uint8_t raw_public_key[static PUBLIC_KEY_LEN], uint8_t tree[ERGO_TREE_P2PK_LEN]) { - BUFFER_FROM_ARRAY_EMPTY(out, tree, ERGO_TREE_P2PK_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(out, tree, ERGO_TREE_P2PK_LEN); // Prefix - buffer_write_bytes(&out, PIC(C_ERGO_TREE_P2PK_PREFIX), ERGO_TREE_P2PK_PREFIX_LEN); + rw_buffer_write_bytes(&out, PIC(C_ERGO_TREE_P2PK_PREFIX), ERGO_TREE_P2PK_PREFIX_LEN); // Compressed pubkey - buffer_write_u8(&out, ((raw_public_key[64] & 1) ? 0x03 : 0x02)); - buffer_write_bytes(&out, raw_public_key + 1, 32); + rw_buffer_write_u8(&out, ((raw_public_key[64] & 1) ? 0x03 : 0x02)); + rw_buffer_write_bytes(&out, raw_public_key + 1, 32); } bool ergo_tree_parse_p2pk(const uint8_t tree[ERGO_TREE_P2PK_LEN], diff --git a/src/ergo/schnorr.c b/src/ergo/schnorr.c index 48651ff2..b703311d 100644 --- a/src/ergo/schnorr.c +++ b/src/ergo/schnorr.c @@ -97,10 +97,10 @@ bool ergo_secp256k1_schnorr_p2pk_sign_finish(uint8_t signature[static ERGO_SIGNA // build c // important: we only use the first 24 bytes of the hash output! - memset(buf, 0, BLAKE2B_256_DIGEST_LEN - ERGO_SOUNDNESS_BYTES); - memcpy(buf + BLAKE2B_256_DIGEST_LEN - ERGO_SOUNDNESS_BYTES, signature, ERGO_SOUNDNESS_BYTES); + memset(buf, 0, CX_BLAKE2B_256_SIZE - ERGO_SOUNDNESS_BYTES); + memcpy(buf + CX_BLAKE2B_256_SIZE - ERGO_SOUNDNESS_BYTES, signature, ERGO_SOUNDNESS_BYTES); - if (cx_math_is_zero(buf, BLAKE2B_256_DIGEST_LEN)) return false; + if (cx_math_is_zero(buf, CX_BLAKE2B_256_SIZE)) return false; // z = c * secret + key if (cx_math_multm_no_throw(buf, buf, secret, PIC(SECP256K1_N), PRIVATE_KEY_LEN) != 0) diff --git a/src/ergo/tx_ser_box.c b/src/ergo/tx_ser_box.c old mode 100755 new mode 100644 index b2366157..656ddf65 --- a/src/ergo/tx_ser_box.c +++ b/src/ergo/tx_ser_box.c @@ -1,8 +1,8 @@ #include "tx_ser_box.h" #include #include "ergo_tree.h" -#include "../common/varint.h" -#include "../common/macros.h" +#include "../common/gve.h" +#include "../common/macros_ext.h" #define CHECK_PROPER_STATE(_ctx, _state) \ if (_ctx->state != _state) return res_error(_ctx, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE) @@ -22,19 +22,19 @@ static inline ergo_tx_serializer_box_result_e res_error(ergo_tx_serializer_box_c static inline ergo_tx_serializer_box_result_e add_height_and_token_count( ergo_tx_serializer_box_context_t* context) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); if (gve_put_u32(&buffer, context->creation_height) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u8(&buffer, context->tokens_count) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } return ERGO_TX_SERIALIZER_BOX_RES_OK; @@ -42,11 +42,11 @@ static inline ergo_tx_serializer_box_result_e add_height_and_token_count( static NOINLINE ergo_tx_serializer_box_result_e add_empty_registers_count(ergo_tx_serializer_box_context_t* context) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 1); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 1); if (gve_put_u8(&buffer, 0) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } return ERGO_TX_SERIALIZER_BOX_RES_OK; @@ -105,11 +105,11 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_init( return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA); } - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); if (gve_put_u64(&buffer, value) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } @@ -139,7 +139,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tree( if (!blake2b_update(context->hash, buffer_read_ptr(tree_chunk), len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - if (!buffer_seek_read_cur(tree_chunk, len)) { + if (!buffer_seek_cur(tree_chunk, len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } context->ergo_tree_size -= len; @@ -181,9 +181,9 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_change_tree( ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( ergo_tx_serializer_box_context_t* context, buffer_t* input, - const token_table_t* table) { + const ergo_tx_serializer_table_context_t* table) { CHECK_PROPER_STATE(context, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); while (buffer_data_len(input) > 0) { union { @@ -209,17 +209,17 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( return ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_INDEX; } // index should be inside table - if (token_id.index >= table->count) { + if (token_id.index >= table->distinct_tokens_count) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_INDEX); } // hashing index - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u32(&buffer, token_id.index) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } if (!blake2b_update(context->hash, - buffer_read_ptr(&buffer), - buffer_data_len(&buffer))) { + rw_buffer_read_ptr(&buffer), + rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } } @@ -228,16 +228,19 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( if (!buffer_read_u64(input, &value, BE)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_VALUE); } - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u64(&buffer, value) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, + rw_buffer_read_ptr(&buffer), + rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } if (context->callbacks.on_token != NULL) { - const uint8_t* tid = table == NULL ? token_id.id : table->tokens[token_id.index]; + const uint8_t* tid = + table == NULL ? token_id.id : table->tokens_table->tokens[token_id.index]; CHECK_CALL_RESULT_OK( context, context->callbacks.on_token(context->type, tid, value, context->callbacks.context)); @@ -267,7 +270,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_registers( if (!blake2b_update(context->hash, buffer_read_ptr(registers_chunk), len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - if (!buffer_seek_read_cur(registers_chunk, len)) { + if (!buffer_seek_cur(registers_chunk, len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } context->registers_size -= len; @@ -292,11 +295,11 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_id_hash( return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - BUFFER_NEW_LOCAL_EMPTY(buffer, 4); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 4); if (gve_put_u16(&buffer, box_index) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } diff --git a/src/ergo/tx_ser_box.h b/src/ergo/tx_ser_box.h index e3239662..19045022 100755 --- a/src/ergo/tx_ser_box.h +++ b/src/ergo/tx_ser_box.h @@ -2,8 +2,10 @@ #include #include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" #include "tx_ser_table.h" @@ -90,7 +92,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_change_tree( ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( ergo_tx_serializer_box_context_t* context, buffer_t* tokens, - const token_table_t* table); + const ergo_tx_serializer_table_context_t* table); ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_registers( ergo_tx_serializer_box_context_t* context, diff --git a/src/ergo/tx_ser_full.c b/src/ergo/tx_ser_full.c old mode 100755 new mode 100644 index e4d59fa1..fea38893 --- a/src/ergo/tx_ser_full.c +++ b/src/ergo/tx_ser_full.c @@ -1,6 +1,7 @@ #include "tx_ser_full.h" -#include "../common/varint.h" -#include "../common/macros.h" +#include "../common/gve.h" +#include "../common/macros_ext.h" +#include #include #define CHECK_PROPER_STATE(_ctx, _state) \ @@ -49,6 +50,7 @@ static inline ergo_tx_serializer_full_result_e map_table_result( case ERGO_TX_SERIALIZER_TABLE_RES_ERR_BUFFER: return ERGO_TX_SERIALIZER_FULL_RES_ERR_BUFFER; } + LEDGER_ASSERT(false, "Unknown table response: %d", (int) res); } static inline ergo_tx_serializer_full_result_e map_input_result( @@ -80,7 +82,10 @@ static inline ergo_tx_serializer_full_result_e map_input_result( return ERGO_TX_SERIALIZER_FULL_RES_ERR_BUFFER; case ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE: return ERGO_TX_SERIALIZER_FULL_RES_ERR_BAD_STATE; + case ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MANY_TOKENS: + return ERGO_TX_SERIALIZER_FULL_RES_ERR_TOO_MANY_TOKENS; } + LEDGER_ASSERT(false, "Unknown input response: %d", (int) res); } static inline ergo_tx_serializer_full_result_e map_box_result(ergo_tx_serializer_box_result_e res) { @@ -110,20 +115,17 @@ static inline ergo_tx_serializer_full_result_e map_box_result(ergo_tx_serializer case ERGO_TX_SERIALIZER_BOX_RES_ERR_SMALL_CHUNK: return ERGO_TX_SERIALIZER_FULL_RES_ERR_SMALL_CHUNK; } + LEDGER_ASSERT(false, "Unknown box response: %d", (int) res); } static inline bool hash_u16(cx_blake2b_t* hash, uint16_t u16) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 4); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 4); if (gve_put_u16(&buffer, u16) != GVE_OK) return false; - return blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer)); + return blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer)); } static NOINLINE ergo_tx_serializer_full_result_e data_inputs_finished(ergo_tx_serializer_full_context_t* context) { - CHECK_CALL_RESULT_OK( - context, - map_table_result( - ergo_tx_serializer_table_init(&context->table_ctx, 0, context->tokens_table))); CHECK_CALL_RESULT_OK( context, map_table_result(ergo_tx_serializer_table_hash(&context->table_ctx, context->hash))); @@ -180,15 +182,11 @@ ergo_tx_serializer_full_result_e ergo_tx_serializer_full_init( context->inputs_count = inputs_count; context->data_inputs_count = data_inputs_count; context->outputs_count = outputs_count; - context->tokens_table = tokens_table; - tokens_table->count = 0; - + CHECK_CALL_RESULT_OK( + context, + map_table_result( + ergo_tx_serializer_table_init(&context->table_ctx, tokens_count, tokens_table))); if (tokens_count != 0) { - CHECK_CALL_RESULT_OK( - context, - map_table_result(ergo_tx_serializer_table_init(&context->table_ctx, - tokens_count, - context->tokens_table))); context->state = ERGO_TX_SERIALIZER_FULL_STATE_TOKENS_STARTED; } else { context->state = ERGO_TX_SERIALIZER_FULL_STATE_INPUTS_STARTED; @@ -226,13 +224,14 @@ ergo_tx_serializer_full_result_e ergo_tx_serializer_full_add_input( return res_error(context, ERGO_TX_SERIALIZER_FULL_RES_ERR_TOO_MANY_INPUTS); } - CHECK_CALL_RESULT_OK(context, - map_input_result(ergo_tx_serializer_input_init(&context->input_ctx, - box_id, - frames_count, - context_extension_data_size, - context->tokens_table, - context->hash))); + CHECK_CALL_RESULT_OK( + context, + map_input_result(ergo_tx_serializer_input_init(&context->input_ctx, + box_id, + frames_count, + context_extension_data_size, + context->table_ctx.tokens_table, + context->hash))); return ERGO_TX_SERIALIZER_FULL_RES_OK; } @@ -366,7 +365,7 @@ ergo_tx_serializer_full_result_e ergo_tx_serializer_full_add_box_tokens( CHECK_CALL_DATA_IS_FINISHED( context, map_box_result( - ergo_tx_serializer_box_add_tokens(&context->box_ctx, tokens, context->tokens_table)), + ergo_tx_serializer_box_add_tokens(&context->box_ctx, tokens, &context->table_ctx)), { if (ergo_tx_serializer_box_is_finished(&context->box_ctx)) { return output_finished(context); diff --git a/src/ergo/tx_ser_full.h b/src/ergo/tx_ser_full.h index 1e81e884..bf4e8923 100755 --- a/src/ergo/tx_ser_full.h +++ b/src/ergo/tx_ser_full.h @@ -2,11 +2,13 @@ #include #include + +#include + #include "../constants.h" #include "tx_ser_table.h" #include "tx_ser_box.h" #include "tx_ser_input.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" typedef enum { @@ -49,9 +51,8 @@ typedef struct { uint16_t data_inputs_count; uint16_t outputs_count; cx_blake2b_t* hash; - token_table_t* tokens_table; + ergo_tx_serializer_table_context_t table_ctx; union { - ergo_tx_serializer_table_context_t table_ctx; ergo_tx_serializer_box_context_t box_ctx; ergo_tx_serializer_input_context_t input_ctx; }; diff --git a/src/ergo/tx_ser_input.c b/src/ergo/tx_ser_input.c index 95c32988..5f548a1d 100644 --- a/src/ergo/tx_ser_input.c +++ b/src/ergo/tx_ser_input.c @@ -1,5 +1,6 @@ #include "tx_ser_input.h" #include +#include "../common/buffer_ext.h" #define CHECK_PROPER_STATE(_ctx, _state) \ if (_ctx->state != _state) return res_error(_ctx, ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE) diff --git a/src/ergo/tx_ser_input.h b/src/ergo/tx_ser_input.h index b1d7e56f..33f7bb23 100644 --- a/src/ergo/tx_ser_input.h +++ b/src/ergo/tx_ser_input.h @@ -2,8 +2,10 @@ #include #include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" #include "tx_ser_table.h" @@ -20,7 +22,8 @@ typedef enum { ERGO_TX_SERIALIZER_INPUT_RES_ERR_HASHER = 0x08, ERGO_TX_SERIALIZER_INPUT_RES_ERR_BUFFER = 0x09, ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE = 0x0A, - ERGO_TX_SERIALIZER_INPUT_RES_ERR_U64_OVERFLOW = 0x0B + ERGO_TX_SERIALIZER_INPUT_RES_ERR_U64_OVERFLOW = 0x0B, + ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MANY_TOKENS = 0x0C } ergo_tx_serializer_input_result_e; typedef enum { diff --git a/src/ergo/tx_ser_table.c b/src/ergo/tx_ser_table.c old mode 100755 new mode 100644 index da64d581..bf9648b1 --- a/src/ergo/tx_ser_table.c +++ b/src/ergo/tx_ser_table.c @@ -1,5 +1,5 @@ #include "tx_ser_table.h" -#include "../common/varint.h" +#include "../common/gve.h" static inline ergo_tx_serializer_table_result_e parse_token(buffer_t* tokens, token_table_t* table, @@ -17,10 +17,15 @@ ergo_tx_serializer_table_result_e ergo_tx_serializer_table_init( ergo_tx_serializer_table_context_t* context, uint8_t tokens_count, token_table_t* tokens_table) { - if (tokens_count + tokens_table->count > TOKEN_MAX_COUNT) { + // tokens table should be empty. + // we add distinct tokens to the start of the table + if (tokens_table->count != 0 || tokens_count > TOKEN_MAX_COUNT) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS; } - context->tokens_count = tokens_count; + // clean tokens area (we will search) + memset(&tokens_table->tokens, 0, MEMBER_SIZE(token_table_t, tokens)); + // save in context + context->distinct_tokens_count = tokens_count; context->tokens_table = tokens_table; return ERGO_TX_SERIALIZER_TABLE_RES_OK; } @@ -30,7 +35,7 @@ ergo_tx_serializer_table_result_e ergo_tx_serializer_table_add( buffer_t* tokens) { while (buffer_data_len(tokens) > 0) { ergo_tx_serializer_table_result_e res = - parse_token(tokens, context->tokens_table, context->tokens_count); + parse_token(tokens, context->tokens_table, context->distinct_tokens_count); if (res != ERGO_TX_SERIALIZER_TABLE_RES_OK) { return res; } @@ -44,14 +49,14 @@ ergo_tx_serializer_table_result_e ergo_tx_serializer_table_add( ergo_tx_serializer_table_result_e ergo_tx_serializer_table_hash( const ergo_tx_serializer_table_context_t* context, cx_blake2b_t* hash) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); - if (gve_put_u32(&buffer, context->tokens_table->count) != GVE_OK) { + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + if (gve_put_u32(&buffer, context->distinct_tokens_count) != GVE_OK) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_BUFFER; } - if (!blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_HASHER; } - for (uint8_t i = 0; i < context->tokens_table->count; i++) { + for (uint8_t i = 0; i < context->distinct_tokens_count; i++) { if (!blake2b_update(hash, context->tokens_table->tokens[i], ERGO_ID_LEN)) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_HASHER; } diff --git a/src/ergo/tx_ser_table.h b/src/ergo/tx_ser_table.h index da23d87d..8552e490 100755 --- a/src/ergo/tx_ser_table.h +++ b/src/ergo/tx_ser_table.h @@ -2,9 +2,13 @@ #include #include +#include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" +#include "../common/macros_ext.h" typedef struct { uint8_t count; @@ -22,9 +26,25 @@ typedef enum { typedef struct { token_table_t* tokens_table; - uint8_t tokens_count; + uint8_t distinct_tokens_count; } ergo_tx_serializer_table_context_t; +static inline uint8_t token_table_find_token_index(const token_table_t* table, + const uint8_t id[static ERGO_ID_LEN]) { + for (uint8_t i = 0; i < table->count; i++) { + if (memcmp(table->tokens[i], id, ERGO_ID_LEN) == 0) return i; + } + return INDEX_NOT_EXIST; +} + +static inline uint8_t token_table_add_token(token_table_t* table, + const uint8_t id[static ERGO_ID_LEN]) { + if (table->count >= TOKEN_MAX_COUNT) return INDEX_NOT_EXIST; + uint8_t index = table->count++; + memmove(table->tokens[index], id, ERGO_ID_LEN); + return index; +} + ergo_tx_serializer_table_result_e ergo_tx_serializer_table_init( ergo_tx_serializer_table_context_t* context, uint8_t tokens_count, @@ -40,5 +60,5 @@ ergo_tx_serializer_table_result_e ergo_tx_serializer_table_hash( static inline bool ergo_tx_serializer_table_is_finished( const ergo_tx_serializer_table_context_t* context) { - return context->tokens_table->count >= context->tokens_count; + return context->tokens_table->count >= context->distinct_tokens_count; } diff --git a/src/globals.h b/src/globals.h deleted file mode 100644 index 29d1f529..00000000 --- a/src/globals.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include - -#include "types.h" -#include "constants.h" -#include "context.h" -#include "helpers/io.h" - -/** - * Global buffer for interactions between SE and MCU. - */ -extern uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; - -/** - * Global structure to perform asynchronous UX aside IO operations. - */ -extern ux_state_t G_ux; - -/** - * Global structure with the parameters to exchange with the BOLOS UX application. - */ -extern bolos_ux_params_t G_ux_params; - -/** - * Global context for user requests. - */ -extern global_ctx_t G_context; - -/** - * Global array for UI screen flow - */ -extern ux_flow_step_t const *G_ux_flow[MAX_NUMBER_OF_SCREENS + 1]; \ No newline at end of file diff --git a/src/helpers/blake2b.c b/src/helpers/blake2b.c index 84ec8a65..ffa608b9 100644 --- a/src/helpers/blake2b.c +++ b/src/helpers/blake2b.c @@ -1,29 +1,22 @@ #include "blake2b.h" bool blake2b_256_init(cx_blake2b_t* ctx) { - return cx_blake2b_init_no_throw(ctx, 256) == 0; + return cx_blake2b_init_no_throw(ctx, 256) == CX_OK; } bool blake2b_update(cx_blake2b_t* ctx, const uint8_t* data, size_t len) { - return cx_hash_no_throw((cx_hash_t*) ctx, 0, data, len, NULL, 0) == 0; + return cx_hash_no_throw((cx_hash_t*) ctx, 0, data, len, NULL, 0) == CX_OK; } -bool blake2b_256_finalize(cx_blake2b_t* ctx, uint8_t out[static BLAKE2B_256_DIGEST_LEN]) { +bool blake2b_256_finalize(cx_blake2b_t* ctx, uint8_t out[static CX_BLAKE2B_256_SIZE]) { return cx_hash_no_throw((cx_hash_t*) ctx, CX_LAST | CX_NO_REINIT, NULL, 0, out, - BLAKE2B_256_DIGEST_LEN) == 0; + CX_BLAKE2B_256_SIZE) == CX_OK; } -bool blake2b_256(const uint8_t* data, size_t len, uint8_t out[static BLAKE2B_256_DIGEST_LEN]) { - cx_blake2b_t ctx; - if (!blake2b_256_init(&ctx)) return false; - return cx_hash_no_throw((cx_hash_t*) &ctx, - CX_LAST | CX_NO_REINIT, - data, - len, - out, - BLAKE2B_256_DIGEST_LEN) == 0; +bool blake2b_256(const uint8_t* data, size_t len, uint8_t out[static CX_BLAKE2B_256_SIZE]) { + return cx_blake2b_256_hash(data, len, out) == CX_OK; } \ No newline at end of file diff --git a/src/helpers/blake2b.h b/src/helpers/blake2b.h index a109bc44..b42ffcff 100644 --- a/src/helpers/blake2b.h +++ b/src/helpers/blake2b.h @@ -5,9 +5,7 @@ #include #include -#define BLAKE2B_256_DIGEST_LEN 32 - bool blake2b_256_init(cx_blake2b_t* ctx); bool blake2b_update(cx_blake2b_t* ctx, const uint8_t* data, size_t len); -bool blake2b_256_finalize(cx_blake2b_t* ctx, uint8_t out[static BLAKE2B_256_DIGEST_LEN]); -bool blake2b_256(const uint8_t* data, size_t len, uint8_t out[static BLAKE2B_256_DIGEST_LEN]); \ No newline at end of file +bool blake2b_256_finalize(cx_blake2b_t* ctx, uint8_t out[static CX_BLAKE2B_256_SIZE]); +bool blake2b_256(const uint8_t* data, size_t len, uint8_t out[static CX_BLAKE2B_256_SIZE]); \ No newline at end of file diff --git a/src/helpers/cmd_macros.h b/src/helpers/cmd_macros.h new file mode 100644 index 00000000..edd5d0c1 --- /dev/null +++ b/src/helpers/cmd_macros.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "../context.h" +#include "../sw.h" + +#define CHECK_COMMAND(_ctx, _cmd) \ + if (_cmd != app_current_command()) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_SESSION(_ctx, _session_id) \ + if (_session_id != _ctx->session) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_SESSION_ID) + +#define CHECK_PROPER_STATE(_ctx, _state) \ + if (_ctx->state != _state) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ + if (_ctx->state != _state1 && _ctx->state != _state2) \ + return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_READ_PARAM(_ctx, _call) \ + if (!_call) return COMMAND_ERROR_HANDLER(_ctx, SW_NOT_ENOUGH_DATA) + +#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ + if (buffer_can_read(_buffer, 1)) return COMMAND_ERROR_HANDLER(_ctx, SW_TOO_MUCH_DATA) + +#define CHECK_CALL_RESULT_SW_OK(_ctx, _call) \ + do { \ + uint16_t _res = _call; \ + if (_res != SW_OK) return COMMAND_ERROR_HANDLER(_ctx, _res); \ + } while (0) + +#define CHECK_WRITE_PARAM(_call) \ + if (!_call) return WRITE_ERROR_HANDLER(SW_BUFFER_ERROR) \ No newline at end of file diff --git a/src/helpers/crypto.c b/src/helpers/crypto.c index a1dce889..c2744c92 100644 --- a/src/helpers/crypto.c +++ b/src/helpers/crypto.c @@ -20,46 +20,37 @@ #include // bool #include "crypto.h" -#include "globals.h" -#define PRIVATE_KEY_SIZE 32 - -uint16_t crypto_derive_private_key(cx_ecfp_private_key_t *private_key, +uint16_t crypto_derive_private_key(cx_ecfp_256_private_key_t *private_key, uint8_t chain_code[static CHAIN_CODE_LEN], const uint32_t *bip32_path, uint8_t bip32_path_len) { - uint8_t raw_private_key[PRIVATE_KEY_SIZE] = {0}; - uint16_t result = 0; - BEGIN_TRY { - TRY { - // derive the seed with bip32_path - os_perso_derive_node_bip32(CX_CURVE_256K1, - bip32_path, - bip32_path_len, - raw_private_key, - chain_code); - // new private_key from raw - cx_ecfp_init_private_key(CX_CURVE_256K1, - raw_private_key, - sizeof(raw_private_key), - private_key); - } - CATCH_OTHER(e) { - result = e; - } - FINALLY { - explicit_bzero(raw_private_key, sizeof(raw_private_key)); - } + uint8_t raw_private_key[64] = {0}; + + // derive the seed with bip32_path + cx_err_t result = os_derive_bip32_no_throw(CX_CURVE_256K1, + bip32_path, + bip32_path_len, + raw_private_key, + chain_code); + if (result != CX_OK) { + return (uint16_t) result; } - END_TRY; - return result; + + // new private_key from raw + result = cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, + raw_private_key, + PRIVATE_KEY_LEN, + private_key); + explicit_bzero(raw_private_key, sizeof(raw_private_key)); + return (uint16_t) result; } uint16_t crypto_generate_private_key(const uint32_t *bip32_path, uint8_t bip32_path_len, uint8_t private_key[static PRIVATE_KEY_LEN]) { uint8_t chain_code[CHAIN_CODE_LEN]; - cx_ecfp_private_key_t ecfp_private_key = {0}; + cx_ecfp_256_private_key_t ecfp_private_key = {0}; // derive private key according to BIP32 path uint16_t result = @@ -73,12 +64,15 @@ uint16_t crypto_generate_private_key(const uint32_t *bip32_path, return result; } -uint16_t crypto_init_public_key(cx_ecfp_private_key_t *private_key, - cx_ecfp_public_key_t *public_key, +uint16_t crypto_init_public_key(const cx_ecfp_256_private_key_t *private_key, + cx_ecfp_256_public_key_t *public_key, uint8_t raw_public_key[static PUBLIC_KEY_LEN]) { // generate corresponding public key - cx_err_t result = cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, public_key, private_key, 1); - if (result == 0) { + cx_err_t result = cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, + public_key, + (cx_ecfp_256_private_key_t *) private_key, + true); + if (result == CX_OK) { memmove(raw_public_key, public_key->W, PUBLIC_KEY_LEN); } return (uint16_t) result; @@ -93,8 +87,8 @@ uint16_t crypto_generate_public_key(const uint32_t *bip32_path, if (!has_chain_code) { chain_code = temp_chain_code; } - cx_ecfp_private_key_t private_key = {0}; - cx_ecfp_public_key_t public_key = {0}; + cx_ecfp_256_private_key_t private_key = {0}; + cx_ecfp_256_public_key_t public_key = {0}; // derive private key according to BIP32 path uint16_t result = diff --git a/src/helpers/crypto.h b/src/helpers/crypto.h index abad6137..b1d07daa 100644 --- a/src/helpers/crypto.h +++ b/src/helpers/crypto.h @@ -22,7 +22,7 @@ * @returns 0 if ok, error_code on error * */ -uint16_t crypto_derive_private_key(cx_ecfp_private_key_t *private_key, +uint16_t crypto_derive_private_key(cx_ecfp_256_private_key_t *private_key, uint8_t chain_code[static CHAIN_CODE_LEN], const uint32_t *bip32_path, uint8_t bip32_path_len); @@ -40,8 +40,8 @@ uint16_t crypto_derive_private_key(cx_ecfp_private_key_t *private_key, * @returns 0 if ok, error_code on error. * */ -uint16_t crypto_init_public_key(cx_ecfp_private_key_t *private_key, - cx_ecfp_public_key_t *public_key, +uint16_t crypto_init_public_key(const cx_ecfp_256_private_key_t *private_key, + cx_ecfp_256_public_key_t *public_key, uint8_t raw_public_key[static PUBLIC_KEY_LEN]); uint16_t crypto_generate_private_key(const uint32_t *bip32_path, diff --git a/src/helpers/input_frame.c b/src/helpers/input_frame.c index 96f44556..51d39228 100644 --- a/src/helpers/input_frame.c +++ b/src/helpers/input_frame.c @@ -1,4 +1,5 @@ #include "input_frame.h" +#include "../common/buffer_ext.h" uint8_t input_frame_data_length(const buffer_t* input) { if (!buffer_can_read(input, FRAME_MIN_SIZE)) { @@ -12,7 +13,7 @@ uint8_t input_frame_data_length(const buffer_t* input) { return data_len; } -uint8_t* input_frame_signature_ptr(const buffer_t* input) { +const uint8_t* input_frame_signature_ptr(const buffer_t* input) { uint8_t data_len = input_frame_data_length(input); if (data_len == 0) return NULL; return buffer_read_ptr(input) + data_len; diff --git a/src/helpers/input_frame.h b/src/helpers/input_frame.h index b4017079..7699d291 100644 --- a/src/helpers/input_frame.h +++ b/src/helpers/input_frame.h @@ -2,9 +2,11 @@ #include #include + #include + #include "../constants.h" -#include "../common/buffer.h" +#include "../common/buffer_ext.h" #include "../ergo/tx_ser_table.h" #define FRAME_MAX_TOKENS_COUNT 4 @@ -15,4 +17,4 @@ #define FRAME_MAX_SIZE (FRAME_MIN_SIZE + FRAME_MAX_TOKENS_COUNT * FRAME_TOKEN_VALUE_PAIR_SIZE) uint8_t input_frame_data_length(const buffer_t* input); -uint8_t* input_frame_signature_ptr(const buffer_t* input); \ No newline at end of file +const uint8_t* input_frame_signature_ptr(const buffer_t* input); \ No newline at end of file diff --git a/src/helpers/io.c b/src/helpers/io.c deleted file mode 100644 index 03a7cb40..00000000 --- a/src/helpers/io.c +++ /dev/null @@ -1,161 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (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 - -#include "io.h" -#include "../globals.h" -#include "../sw.h" -#include "../common/buffer.h" -#include "../common/write.h" - -void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t *) element); -} - -uint8_t io_event(__attribute__((unused)) uint8_t channel) { - switch (G_io_seproxyhal_spi_buffer[0]) { - 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); - } - /* fallthrough */ - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - default: - UX_DEFAULT_EVENT(); - break; - } - - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - return 1; -} - -uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - halt(); - } - - return 0; - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); - } - default: - THROW(INVALID_PARAMETER); - } - - return 0; -} - -/** - * Variable containing the length of the APDU response to send back. - */ -static uint32_t G_output_len = 0; - -/** - * IO state (READY, RECEIVING, WAITING). - */ -static io_state_e G_io_state = READY; - -void io_init() { - // Reset length of APDU response - G_output_len = 0; - G_io_state = READY; -} - -int io_recv_command() { - int ret = -1; - - switch (G_io_state) { - case READY: - G_io_state = RECEIVED; - ret = io_exchange(CHANNEL_APDU, G_output_len); - break; - case RECEIVED: - G_io_state = WAITING; - ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, G_output_len); - G_io_state = RECEIVED; - break; - case WAITING: - G_io_state = READY; - ret = -1; - break; - } - - return ret; -} - -int io_send_response(const buffer_t *rdata, uint16_t sw) { - int ret = -1; - - if (rdata != NULL) { - size_t len = buffer_data_len(rdata); - if (len > IO_APDU_BUFFER_SIZE - 2 || // - !buffer_copy_bytes(rdata, G_io_apdu_buffer, sizeof(G_io_apdu_buffer))) { - return io_send_sw(SW_WRONG_RESPONSE_LENGTH); - } - G_output_len = len; - } else { - G_output_len = 0; - } - - write_u16_be(G_io_apdu_buffer, G_output_len, sw); - G_output_len += 2; - - switch (G_io_state) { - case READY: - ret = -1; - break; - case RECEIVED: - G_io_state = READY; - ret = 0; - break; - case WAITING: - ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len); - G_output_len = 0; - G_io_state = READY; - break; - } - - return ret; -} - -int io_send_sw(uint16_t sw) { - return io_send_response(NULL, sw); -} diff --git a/src/helpers/io.h b/src/helpers/io.h deleted file mode 100644 index 7859289a..00000000 --- a/src/helpers/io.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "../types.h" -#include "../common/buffer.h" - -void io_seproxyhal_display(const bagl_element_t *element); - -/** - * IO callback called when an interrupt based channel has received - * data to be processed. - * - * @return 1 if success, 0 otherwise. - * - */ -uint8_t io_event(uint8_t channel); - -uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len); - -/** - * Initialize the APDU I/O state. - * - * This function must be called before calling any other I/O function. - */ -void io_init(void); - -/** - * Receive APDU command in G_io_apdu_buffer and update G_output_len. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_recv_command(void); - -/** - * Send APDU response (response data + status word) by filling - * G_io_apdu_buffer. - * - * @param[in] rdata - * Buffer with APDU response data. - * @param[in] sw - * Status word of APDU response. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_send_response(const buffer_t *rdata, uint16_t sw); - -/** - * Send APDU response (only status word) by filling - * G_io_apdu_buffer. - * - * @param[in] sw - * Status word of APDU response. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_send_sw(uint16_t sw); diff --git a/src/helpers/response.h b/src/helpers/response.h index 8031c64e..587b8235 100644 --- a/src/helpers/response.h +++ b/src/helpers/response.h @@ -2,31 +2,26 @@ #include -#include "io.h" +#include #include "../sw.h" -#include "../types.h" -#include "../context.h" -#include "../globals.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" static inline int res_ok() { return io_send_sw(SW_OK); } +static inline int res_ok_data(const rw_buffer_t* data) { + return io_send_response_buffer(&data->read, SW_OK); +} + static inline int res_ui_busy() { return io_send_sw(SW_BUSY); } static inline int res_deny() { - clear_context(&G_context, CMD_NONE); return io_send_sw(SW_DENY); } -static inline int res_ok_data(const buffer_t* data) { - return io_send_response(data, SW_OK); -} - static inline int res_error(uint16_t code) { - clear_context(&G_context, CMD_NONE); return io_send_sw(code); } \ No newline at end of file diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 837d2432..00000000 --- a/src/main.c +++ /dev/null @@ -1,160 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (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 // uint*_t -#include // memset, explicit_bzero - -#include -#include -#include - -#include "types.h" -#include "globals.h" -#include "sw.h" -#include "ui/ui_menu.h" -#include "apdu/parser.h" -#include "apdu/dispatcher.h" -#include "common/macros.h" - -uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; -global_ctx_t G_context; -ux_flow_step_t const *G_ux_flow[MAX_NUMBER_OF_SCREENS + 1]; - -/** - * Handle APDU command received and send back APDU response using handlers. - */ -void app_main() { - // Length of APDU command received in G_io_apdu_buffer - int input_len = 0; - // Structured APDU command - command_t cmd; - - io_init(); - - // Reset context - clear_context(&G_context, CMD_NONE); - - // Set zero session id - G_context.app_session_id = 0; - - // Generate random key for session - cx_rng(G_context.session_key, MEMBER_SIZE(global_ctx_t, session_key)); - - for (;;) { - BEGIN_TRY { - TRY { - // Reset structured APDU command - memset(&cmd, 0, sizeof(cmd)); - - // Receive command bytes in G_io_apdu_buffer - if ((input_len = io_recv_command()) < 0) { - CLOSE_TRY; - return; - } - - // Parse APDU command from G_io_apdu_buffer - if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { - io_send_sw(SW_WRONG_APDU_DATA_LENGTH); - CLOSE_TRY; - continue; - } - - // Dispatch structured APDU command to handler - if (apdu_dispatcher(&cmd) < 0) { - CLOSE_TRY; - return; - } - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); - } - CATCH_OTHER(e) { - clear_context(&G_context, CMD_NONE); - io_send_sw(e); - } - FINALLY { - } - END_TRY; - } - } -} - -/** - * Exit the application and go back to the dashboard. - */ -void app_exit() { - BEGIN_TRY_L(exit) { - TRY_L(exit) { - os_sched_exit(-1); - } - FINALLY_L(exit) { - } - } - END_TRY_L(exit); -} - -/** - * Main loop to setup USB, Bluetooth, UI and launch app_main(). - */ -__attribute__((section(".boot"))) int main() { - __asm volatile("cpsie i"); - - os_boot(); - - for (;;) { - // Reset UI - memset(&G_ux, 0, sizeof(G_ux)); - - BEGIN_TRY { - TRY { - io_seproxyhal_init(); - -#ifdef TARGET_NANOX - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX - - USB_power(0); - USB_power(1); - - ui_menu_main(); - -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); -#endif // HAVE_BLE - app_main(); - } - CATCH(EXCEPTION_IO_RESET) { - CLOSE_TRY; - continue; - } - CATCH_ALL { - CLOSE_TRY; - break; - } - FINALLY { - } - } - END_TRY; - } - - app_exit(); - - return 0; -} diff --git a/src/ui/ui_bip32_path.c b/src/ui/ui_bip32_path.c index 8d68ec8d..f00a50d4 100644 --- a/src/ui/ui_bip32_path.c +++ b/src/ui/ui_bip32_path.c @@ -1,12 +1,28 @@ #include "ui_bip32_path.h" -#include "../common/bip32.h" +#include "../common/bip32_ext.h" static ux_layout_bnnn_paging_params_t G_ui_path_params[1]; +static ui_bip32_approve_callback G_ui_bip32_approve_callback; +static void* G_ui_bip32_approve_callback_context; + +void ux_bip32_path_validate_init(unsigned int stack_slot) { + UNUSED(stack_slot); + if (G_ui_bip32_approve_callback != NULL) { + G_ui_bip32_approve_callback(G_ui_bip32_approve_callback_context); + } else { + ux_flow_next(); + } +} + +const ux_flow_step_t ux_bip32_path_validate_step = {ux_bip32_path_validate_init, NULL, NULL, NULL}; + +const ux_flow_step_t* const ux_bip32_path_validate[] = {&ux_bip32_path_validate_step, + FLOW_END_STEP}; const ux_flow_step_t ux_bip32_path_step = { ux_layout_bnnn_paging_init, G_ui_path_params, - NULL, + ux_bip32_path_validate, NULL, }; @@ -14,12 +30,16 @@ const ux_flow_step_t* ui_bip32_path_screen(uint32_t* path, uint8_t path_len, const char* title, char* buffer, - uint8_t buffer_len) { + uint8_t buffer_len, + ui_bip32_approve_callback cb, + void* cb_context) { G_ui_path_params[0].title = title; G_ui_path_params[0].text = buffer; memset(buffer, 0, buffer_len); if (!bip32_path_format(path, path_len, buffer, buffer_len)) { return NULL; } + G_ui_bip32_approve_callback = cb; + G_ui_bip32_approve_callback_context = cb_context; return &ux_bip32_path_step; } \ No newline at end of file diff --git a/src/ui/ui_bip32_path.h b/src/ui/ui_bip32_path.h index d7e149e0..88a61ed8 100644 --- a/src/ui/ui_bip32_path.h +++ b/src/ui/ui_bip32_path.h @@ -3,8 +3,12 @@ #include #include +typedef void (*ui_bip32_approve_callback)(void*); + const ux_flow_step_t* ui_bip32_path_screen(uint32_t* path, uint8_t path_len, const char* title, char* buffer, - uint8_t buffer_len); \ No newline at end of file + uint8_t buffer_len, + ui_bip32_approve_callback cb, + void* cb_context); \ No newline at end of file diff --git a/src/ui/ui_dynamic_flow.c b/src/ui/ui_dynamic_flow.c index c1c1962f..25b7b9ee 100644 --- a/src/ui/ui_dynamic_flow.c +++ b/src/ui/ui_dynamic_flow.c @@ -1,10 +1,11 @@ #include "ui_dynamic_flow.h" -#include "../globals.h" #include "../constants.h" +#include "../context.h" #include "../helpers/response.h" -#include "../common/macros.h" +#include "../common/macros_ext.h" #include "ui_menu.h" +#include "ui_main.h" #include @@ -37,8 +38,8 @@ void bnnn_paging_edgecase() { if (res == SW_OK) { \ switch_method(); \ } else { \ + app_set_current_command(CMD_NONE); \ res_error(res); \ - clear_context(&G_context, CMD_NONE); \ ui_menu_main(); \ } \ } while (0) @@ -100,9 +101,9 @@ bool ui_add_dynamic_flow_screens(uint8_t *screen, G_dynamic_flow_context.current_screen = INDEX_NOT_EXIST; G_dynamic_flow_context.show_cb = show_cb; - G_ux_flow[(*screen)++] = &ux_dynamic_upper_delimiter_step; - G_ux_flow[(*screen)++] = &ux_dynamic_step; - G_ux_flow[(*screen)++] = &ux_dynamic_lower_delimiter_step; + ui_add_screen(&ux_dynamic_upper_delimiter_step, screen); + ui_add_screen(&ux_dynamic_step, screen); + ui_add_screen(&ux_dynamic_lower_delimiter_step, screen); return true; } diff --git a/src/ui/ui_dynamic_flow.h b/src/ui/ui_dynamic_flow.h index 66b8abe1..01e869c6 100644 --- a/src/ui/ui_dynamic_flow.h +++ b/src/ui/ui_dynamic_flow.h @@ -3,7 +3,6 @@ #include #include #include -#include "../globals.h" typedef uint16_t (*ui_dynamic_flow_show_screen_cb)(uint8_t, char *, char *, void *); diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c new file mode 100644 index 00000000..d5150766 --- /dev/null +++ b/src/ui/ui_main.c @@ -0,0 +1,5 @@ +#include "ui_main.h" + +#ifdef HAVE_BAGL +ux_flow_step_t const *G_ux_flow_steps[MAX_NUMBER_OF_SCREENS + 1]; +#endif \ No newline at end of file diff --git a/src/ui/ui_main.h b/src/ui/ui_main.h new file mode 100644 index 00000000..14b3fdeb --- /dev/null +++ b/src/ui/ui_main.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "../constants.h" +#include "../context.h" + +#ifdef HAVE_BAGL +/** + * Global array for UI screen flow + */ +extern ux_flow_step_t const* G_ux_flow_steps[MAX_NUMBER_OF_SCREENS + 1]; + +static inline const ux_flow_step_t** ui_next_sreen_ptr(uint8_t* position) { + if (*position >= MAX_NUMBER_OF_SCREENS) return NULL; + return &G_ux_flow_steps[(*position)++]; +} + +static inline bool ui_add_screen(const ux_flow_step_t* screen, uint8_t* position) { + if (*position >= MAX_NUMBER_OF_SCREENS) return false; + G_ux_flow_steps[(*position)++] = screen; + return true; +} + +static inline bool ui_display_screens(uint8_t* position) { + if (MAX_NUMBER_OF_SCREENS - *position < 2) return false; + + G_ux_flow_steps[(*position)++] = FLOW_LOOP; + G_ux_flow_steps[(*position)++] = FLOW_END_STEP; + + ux_flow_init(0, G_ux_flow_steps, NULL); + + app_set_ui_busy(true); + + return true; +} + +#endif diff --git a/src/ui/ui_menu.c b/src/ui/ui_menu.c index 6c621e6f..c11aaa5f 100644 --- a/src/ui/ui_menu.c +++ b/src/ui/ui_menu.c @@ -19,8 +19,8 @@ #include #include -#include "../globals.h" #include "ui_menu.h" +#include "ui_main.h" UX_STEP_NOCB(ux_menu_ready_step, pnn, {&C_app_logo, APPNAME, "is ready"}); UX_STEP_CB(ux_menu_about_step, pb, ui_menu_about(), {&C_icon_certificate, "About"}); @@ -31,25 +31,25 @@ void ui_menu_main() { ux_stack_push(); } - G_ux_flow[0] = &ux_menu_ready_step; - G_ux_flow[1] = &ux_menu_about_step; - G_ux_flow[2] = &ux_menu_exit_step; - G_ux_flow[3] = FLOW_LOOP; - G_ux_flow[4] = FLOW_END_STEP; + uint8_t screen = 0; + ui_add_screen(&ux_menu_ready_step, &screen); + ui_add_screen(&ux_menu_about_step, &screen); + ui_add_screen(&ux_menu_exit_step, &screen); + ui_display_screens(&screen); - ux_flow_init(0, G_ux_flow, NULL); + app_set_ui_busy(false); } -UX_STEP_NOCB(ux_menu_info_step, bn, {APPNAME " App", "(c) 2023 Ergo"}); +UX_STEP_NOCB(ux_menu_info_step, bn, {APPNAME " App", "(c) 2024 Ergo"}); UX_STEP_NOCB(ux_menu_version_step, bn, {"Version", APPVERSION}); UX_STEP_CB(ux_menu_back_step, pb, ui_menu_main(), {&C_icon_back, "Back"}); void ui_menu_about() { - G_ux_flow[0] = &ux_menu_info_step; - G_ux_flow[1] = &ux_menu_version_step; - G_ux_flow[2] = &ux_menu_back_step; - G_ux_flow[3] = FLOW_LOOP; - G_ux_flow[4] = FLOW_END_STEP; + uint8_t screen = 0; + ui_add_screen(&ux_menu_info_step, &screen); + ui_add_screen(&ux_menu_version_step, &screen); + ui_add_screen(&ux_menu_back_step, &screen); + ui_display_screens(&screen); - ux_flow_init(0, G_ux_flow, NULL); + app_set_ui_busy(false); } diff --git a/tests/address-tests.js b/tests/address-tests.js index a3188a78..d0171412 100644 --- a/tests/address-tests.js +++ b/tests/address-tests.js @@ -3,49 +3,45 @@ const { expect } = require('chai') const { toHex, getApplication, removeMasterNode } = require('./helpers/common'); const { TEST_DATA } = require('./helpers/data'); const { mergePagedScreens } = require("./helpers/screen"); -const { AuthTokenFlows } = require('./helpers/flow'); +const { authTokenFlows } = require('./helpers/flow'); describe("Address Tests", function () { context("Address Commands", function () { - new AuthTokenFlows("can derive address", () => { return { address: TEST_DATA.address0 }; }).do( - function () { - return this.test.device.deriveAddress(this.address.path.toString()); - }, - function (derivedAddress) { - const deriveAddressFlow = [ - { header: null, body: 'Confirm Send Address' }, - { header: 'Path', body: removeMasterNode(this.address.path.toString()) }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ]; - if (this.auth) { - deriveAddressFlow.splice(2, 0, { header: 'Application', body: getApplication(this.test.device) }); + authTokenFlows("can derive address") + .init(async ({test, auth}) => { + const address = TEST_DATA.address0; + const flow = [{ header: null, body: 'Confirm Send Address' }, + { header: 'Path', body: removeMasterNode(address.path.toString()) }]; + if (auth) { + flow.push({ header: 'Application', body: getApplication(test.device) }) } - expect(this.flows[0]).to.be.deep.equal(deriveAddressFlow); - expect(derivedAddress).to.be.deep.equal({ - addressHex: toHex(this.address.toBytes()) + flow.push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + return { address, flow, flowsCount: 1 }; + }) + .shouldSucceed(({flow, flows, address}, derived) => { + expect(flows[0]).to.be.deep.equal(flow); + expect(derived).to.be.deep.equal({ + addressHex: toHex(address.toBytes()) }); - } - ); + }) + .run(({test, address}) => test.device.deriveAddress(address.path.toString())); - new AuthTokenFlows("can show address", () => { return { address: TEST_DATA.address0 }; }).do( - function () { - return this.test.device.showAddress(this.address.path.toString()); - }, - function (show) { - const addressFlow = [ - { header: null, body: 'Confirm Address' }, - { header: 'Path', body: removeMasterNode(this.address.path.toString()) }, - { header: 'Address', body: this.address.toBase58() }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ]; - if (this.auth) { - addressFlow.splice(3, 0, { header: 'Application', body: getApplication(this.test.device) }); + authTokenFlows("can show address") + .init(async ({test, auth}) => { + const address = TEST_DATA.address0; + const flow = [{ header: null, body: 'Confirm Address' }, + { header: 'Path', body: removeMasterNode(address.path.toString()) }, + { header: 'Address', body: address.toBase58() }]; + if (auth) { + flow.push({ header: 'Application', body: getApplication(test.device) }) } - expect(mergePagedScreens(this.flows[0])).to.be.deep.equal(addressFlow); + flow.push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + return { address, flow, flowsCount: 1 }; + }) + .shouldSucceed(({flow, flows}, show) => { + expect(mergePagedScreens(flows[0])).to.be.deep.equal(flow); expect(show).to.be.true; - } - ); + }) + .run(({test, address}) => test.device.showAddress(address.path.toString())); }); }); diff --git a/tests/helpers/data.js b/tests/helpers/data.js index 82479b15..a6b71dcc 100644 --- a/tests/helpers/data.js +++ b/tests/helpers/data.js @@ -13,6 +13,8 @@ class ExtendedAddress { this.network = network; this.address = address; this.path = DerivationPath.new(path[0], [path[1]]); + this.acc_index = path[0]; + this.addr_index = path[1]; } toBase58() { @@ -47,6 +49,11 @@ class TestData { Address.from_base58("9eo8hALVQTaAuu8m95JhR8rhXuAMsLacaxM8X4omp724Smt8ior"), [0, 2] ); + this.changeAddress22 = new ExtendedAddress( + network, + Address.from_base58("9fRejXDJxxdJ1KVRH6HdxDj1S1duKmUNGG7CjztN2YjHnooxYAX"), + [0, 22] + ); } } diff --git a/tests/helpers/flow.js b/tests/helpers/flow.js index e9c75c88..3311fd6c 100644 --- a/tests/helpers/flow.js +++ b/tests/helpers/flow.js @@ -14,55 +14,83 @@ function restorePromiseError(promise) { } class AuthTokenFlows { - constructor(name, before, count = [1, 1]) { - this.name = name; - this.before = before; - this.count = count; + constructor(name) { + this._name = name; + this._before = null; + this.shouldSucceed(null); + this.shouldFail(null); } - do(action, success, failure) { - const count = this.count; - const before = this.before; + init(before) { + this._before = before; + return this; + } - success = success ?? (function (result) { + shouldSucceed(success) { + this._success = success ?? (function (_, result) { throw new Error(`Success called: ${JSON.stringify(result)}`); }); - failure = failure ?? (function (error) { + return this; + } + + shouldFail(failure) { + this._failure = failure ?? (function (_, error) { throw new Error(`Failure called: ${error}`); }); + return this; + } - const run = auth => { - it(`${this.name}${auth ? ' (with auth token)' : ''}`, async function () { - this.timeout(30_000); - const params = before(); - Object.assign(params, { test: this, auth }); - this.device.useAuthToken(auth); - this.screens.removeCurrentScreen(); // Wait for new screen in the readFlow - const promise = suppressPomiseError(action.call(params)); - const flows = []; - for (let i = 0; i < count[auth]; i++) { - let flow = await this.screens.readFlow(); - flows.push(mergePagedScreens(flow)); - await this.screens.clickOn('Approve'); - if (i != count[auth] - 1 && await this.screens.isReadyMainScreen()) { // we have more flows - this.screens.removeCurrentScreen(); // Wait for new screen in the readFlow - } - } - Object.assign(params, { flows }); - let result; - try { - result = await restorePromiseError(promise); - } catch (error) { - failure.call(params, error); - return; - } - success.call(params, result); - }); - } + run(action) { + this.__run(false, action); + this.__run(true, action); + } + + __run(auth, action) { + const before = this._before; + const success = this._success; + const failure = this._failure; - run(0); - run(1); + it(`${this._name}${auth ? ' (with auth token)' : ''}`, async function() { + this.timeout(30_000); + this.device.useAuthToken(auth); + const params = { test: this, auth }; + if (before) { + Object.assign(params, await before(params)); + } + const flowsCount = params.flowsCount; + if (typeof flowsCount !== "number") { + throw new Error("flowsCount should be defined and to be a number"); + } + this.screens.removeCurrentScreen(); // Wait for new screen in the readFlow + // Call action + const promise = suppressPomiseError(action(params)); + // Read flows + const flows = []; + for (let i = 0; i < flowsCount; i++) { + let flow = await this.screens.readFlow(); + flows.push(mergePagedScreens(flow)); + await this.screens.clickOn('Approve'); + if (i != flowsCount - 1 && await this.screens.isReadyMainScreen()) { // we have more flows + this.screens.removeCurrentScreen(); // Wait for new screen in the readFlow + } + } + params.flows = flows; + // Call success or error + let result; + try { + result = await restorePromiseError(promise); + } catch (error) { + failure(params, error); + return; + } + success(params, result); + }); + return null; } } +exports.authTokenFlows = function(name) { + return new AuthTokenFlows(name); +}; + exports.AuthTokenFlows = AuthTokenFlows; diff --git a/tests/helpers/screen.js b/tests/helpers/screen.js index d7cf1a0e..77c05d09 100644 --- a/tests/helpers/screen.js +++ b/tests/helpers/screen.js @@ -7,7 +7,7 @@ const MAIN_FLOW = [ ]; const ABOUT_FLOW = [ - { header: makefile.appName + " App", body: "(c) 2023 Ergo" }, + { header: makefile.appName + " App", body: "(c) 2024 Ergo" }, { header: "Version", body: makefile.version }, { header: null, body: "Back" } ]; diff --git a/tests/helpers/transaction.js b/tests/helpers/transaction.js index 93b6f163..9823a2e2 100644 --- a/tests/helpers/transaction.js +++ b/tests/helpers/transaction.js @@ -3,9 +3,9 @@ const Buffer = require('buffer').Buffer; const common = require('./common'); const { TEST_DATA } = require('./data'); -function createErgoBox(recipient, txId, index, tokens = new ergo.Tokens()) { +function createErgoBox(recipient, txId, index, amount, tokens) { const ergoBox = new ergo.ErgoBox( - ergo.BoxValue.from_i64(ergo.I64.from_str('1000000000')), + ergo.BoxValue.from_i64(ergo.I64.from_str(amount)), 0, ergo.Contract.pay_to_address(recipient), txId, @@ -40,6 +40,11 @@ function toToken(token) { }; } +function isTokensEqual(t1, t2) { + return t1.id().to_str() === t2.id().to_str() && + t1.amount().as_i64().to_str() === t2.amount().as_i64().to_str(); +} + function toBoxCandidate(output) { return { value: output.value().as_i64().to_str(), @@ -50,128 +55,90 @@ function toBoxCandidate(output) { }; } -class ErgoUnsignedTransactionBuilder { +class ErgoTxBuilder { constructor() { this.amount = ergo.I64.from_str('0'); - this.inputs = ergo.ErgoBoxes.empty(); - this.dataInputs = new ergo.DataInputs(); - this.outputs = ergo.ErgoBoxCandidates.empty(); - this.feeAmount = ergo.TxBuilder.SUGGESTED_TX_FEE(); - this.changeAddress = null; - } - - input(ergoBox) { - this.inputs.add(ergoBox); - return this; - } - - dataInput(ergoBox) { - this.dataInputs.add(new ergo.DataInput(ergoBox.box_id())); - return this; - } - - output(boxCandidate) { - this.amount = this.amount.checked_add(boxCandidate.value().as_i64()); - this.outputs.add(boxCandidate); - return this; - } - - fee(amount) { - this.feeAmount = amount; - } - - change(address) { - this.changeAddress = address; - return this; - } - - build() { - const targetBalance = ergo.BoxValue.from_i64(this.amount.checked_add(this.feeAmount.as_i64())); - const targetTokens = new ergo.Tokens(); - common.toArray(this.outputs) - .flatMap(output => common.toArray(output.tokens())) - .forEach(token => targetTokens.add(token)); - const boxSelection = new ergo.SimpleBoxSelector().select(this.inputs, targetBalance, targetTokens); - const txBuilder = ergo.TxBuilder.new( - boxSelection, - this.outputs, - 0, - this.feeAmount, - this.changeAddress - ); - txBuilder.set_data_inputs(this.dataInputs); - return txBuilder.build(); - } -} - -class UnsignedTransactionBuilder { - constructor() { - this.network = TEST_DATA.network; - this.ergoBuilder = new ErgoUnsignedTransactionBuilder(); this.inputs = []; this.dataInputs = []; this.outputs = []; - this.distinctTokenIds = []; + this.feeAmount = ergo.TxBuilder.SUGGESTED_TX_FEE(); + this.burningTokens = []; + this.mintingOutputs = []; + this.changeAddress = null; this.changeMap = null; - this.ergoTransaction = null; } - inputFrom(ergoBox, path) { - const contextExtension = new ergo.ContextExtension(); - const unsignedBox = toUnsignedBox(ergoBox, contextExtension, path.toString()); - this.inputs.push(unsignedBox); - this.ergoBuilder.input(ergoBox); - return this; + input(extendedAddress, txId, index, amount, tokens) { + const ergoTokens = new ergo.Tokens(); + if (tokens) { + tokens.forEach(t => { + const token = new ergo.Token( + ergo.TokenId.from_str(t.id), + ergo.TokenAmount.from_i64(ergo.I64.from_str(t.amount)) + ); + ergoTokens.add(token); + }); + } + const eTxId = ergo.TxId.from_str(txId); + const ergoBox = createErgoBox(extendedAddress.address, eTxId, index, amount, ergoTokens); + return this.boxInput(ergoBox, extendedAddress.path); } - input(extendedAddress, txId, index, tokens = new ergo.Tokens()) { - const ergoBox = createErgoBox(extendedAddress.address, txId, index, tokens); + boxInput(ergoBox, path) { const contextExtension = new ergo.ContextExtension(); - const unsignedBox = toUnsignedBox(ergoBox, contextExtension, extendedAddress.path.toString()); - this.inputs.push(unsignedBox); - this.ergoBuilder.input(ergoBox); + const box = toUnsignedBox(ergoBox, contextExtension, path.toString()); + this.inputs.push({box, ergo: ergoBox}); return this; } dataInput(address, txId, index) { - const ergoBox = createErgoBox(address, txId, index); - const dataInput = ergoBox.box_id().to_str(); - this.dataInputs.push(dataInput); - this.ergoBuilder.dataInput(ergoBox); + const eTxId = ergo.TxId.from_str(txId); + const ergoBox = createErgoBox( + address, eTxId, index, '100000000', new ergo.Tokens() + ); + this.dataInputs.push(new ergo.DataInput(ergoBox.box_id())); return this; } - output(value, address, tokens = new ergo.Tokens()) { + output(address, value, send_tokens, mint_token_amount) { const builder = new ergo.ErgoBoxCandidateBuilder( ergo.BoxValue.from_i64(ergo.I64.from_str(value)), ergo.Contract.pay_to_address(address), 0 ); - common.toArray(tokens) - .forEach(token => builder.add_token(token.id(), token.amount())); + if (send_tokens) { + send_tokens.forEach(t => { + builder.add_token( + ergo.TokenId.from_str(t.id), + ergo.TokenAmount.from_i64(ergo.I64.from_str(t.amount)) + ); + }); + } + if (mint_token_amount) { + const id = ergo.TokenId.from_str(this.inputs[0].ergo.box_id().to_str()); + const amount = ergo.TokenAmount.from_i64(ergo.I64.from_str(mint_token_amount)); + builder.add_token(id, amount); + this.mintingOutputs.push(new ergo.Token(id, amount)); + } else { + this.mintingOutputs.push(null); + } const output = builder.build(); - const boxCandidate = toBoxCandidate(output); - this.outputs.push(boxCandidate); - this.ergoBuilder.output(output); + this.amount = this.amount.checked_add(output.value().as_i64()); + this.outputs.push(output); return this; } - fee(value) { - const amount = ergo.BoxValue.from_i64(ergo.I64.from_str(value)); - const builder = new ergo.ErgoBoxCandidateBuilder( - amount, - ergo.Contract.pay_to_address(common.getMinerAddress(this.network)), - 0 - ); - const output = builder.build(); - const boxCandidate = toBoxCandidate(output); - this.outputs.push(boxCandidate); - this.ergoBuilder.fee(amount); + burn(tokens) { + const ergoTokens = tokens.map(t => new ergo.Token( + ergo.TokenId.from_str(t.id), + ergo.TokenAmount.from_i64(ergo.I64.from_str(t.amount)) + )); + this.burningTokens.push(...ergoTokens); return this; } - tokenIds(tokenIds) { - this.distinctTokenIds = tokenIds; + fee(amount) { + this.feeAmount = amount ? ergo.BoxValue.from_i64(ergo.I64.from_str(amount)) : null; return this; } @@ -180,37 +147,120 @@ class UnsignedTransactionBuilder { address: extendedAddress.toBase58(), path: extendedAddress.path.toString(), }; - const sum = array => array - .map(e => ergo.I64.from_str(e.value)) - .reduce((a, b) => a.checked_add(b), ergo.I64.from_str('0')); - const amount = sum(this.inputs).as_num() - sum(this.outputs).as_num(); - const builder = new ergo.ErgoBoxCandidateBuilder( - ergo.BoxValue.from_i64(ergo.I64.from_str(amount.toString())), - ergo.Contract.pay_to_address(extendedAddress.address), - 0 - ); - const output = builder.build(); - const boxCandidate = toBoxCandidate(output); - this.outputs.push(boxCandidate); - this.ergoBuilder.change(extendedAddress.address); + this.changeAddress = extendedAddress.address; return this; } - build(buildErgo = true) { - if (buildErgo) { - this.ergoTransaction = this.ergoBuilder.build(); - this.dataInputs = common.toArray(this.ergoTransaction.data_inputs()).map(toDataInput); - this.outputs = common.toArray(this.ergoTransaction.output_candidates()).map(toBoxCandidate); - this.distinctTokenIds = this.ergoTransaction.distinct_token_ids(); + build() { + const targetBalance = ergo.BoxValue.from_i64(this.amount.checked_add(this.feeAmount.as_i64())); + + const targetTokens = new ergo.Tokens(); + this.outputs.flatMap((output, idx) => { + const minting = this.mintingOutputs[idx]; + return common.toArray(output.tokens()).filter( + token => minting ? !isTokensEqual(token, minting) : true + ) + }).forEach(token => targetTokens.add(token)); + this.burningTokens.forEach(token => targetTokens.add(token)); + + const inputs = ergo.ErgoBoxes.empty(); + this.inputs.forEach(input => inputs.add(input.ergo)); + + const outputs = ergo.ErgoBoxCandidates.empty(); + this.outputs.forEach(output => outputs.add(output)); + + const dataInputs = new ergo.DataInputs(); + this.dataInputs.forEach(input => dataInputs.add(input)); + + const boxSelection = new ergo.SimpleBoxSelector().select(inputs, targetBalance, targetTokens); + + const txBuilder = ergo.TxBuilder.new( + boxSelection, + outputs, + 0, + this.feeAmount, + this.changeAddress + ); + if (this.burningTokens.length > 0) { + const burn = new ergo.Tokens(); + this.burningTokens.forEach(token => burn.add(token)); + txBuilder.set_token_burn_permit(burn); + } + txBuilder.set_data_inputs(dataInputs); + const ergoTx = txBuilder.build(); + + const txInputs = common.toArray(ergoTx.inputs()).map( + txinp => this.inputs.find( + i => txinp.box_id().to_str() === i.ergo.box_id().to_str() + ) + ); + + const appTx = { + inputs: txInputs.map(i => i.box), + dataInputs: common.toArray(ergoTx.data_inputs()).map(toDataInput), + outputs: common.toArray(ergoTx.output_candidates()).map(toBoxCandidate), + distinctTokenIds: ergoTx.distinct_token_ids(), + changeMap: this.changeMap, + }; + return { appTx, ergoTx, uInputs: txInputs.map(i => i.ergo) }; + } +} + +class TxBuilder extends ErgoTxBuilder { + constructor(network = TEST_DATA.network) { + super() + this.network = network + } + + buildAppTx() { + const inputs = this.inputs.map(i => i.box); + const outputs = this.outputs.map(toBoxCandidate); + + // add fee output + if (this.feeAmount) { + const feeBuilder = new ergo.ErgoBoxCandidateBuilder( + this.feeAmount, + ergo.Contract.pay_to_address(common.getMinerAddress(this.network)), + 0 + ); + outputs.push(toBoxCandidate(feeBuilder.build())); + } + + // add change output + if (this.changeAddress) { + const sum = array => array + .map(e => ergo.I64.from_str(e.value)) + .reduce((a, b) => a.checked_add(b), ergo.I64.from_str('0')); + const amount = sum(inputs).as_num() - sum(outputs).as_num(); + + const changeBuilder = new ergo.ErgoBoxCandidateBuilder( + ergo.BoxValue.from_i64(ergo.I64.from_str(amount.toString())), + ergo.Contract.pay_to_address(this.changeAddress.address), + 0 + ); + outputs.push(toBoxCandidate(changeBuilder.build())); } + + let distinctTokenIds = [] + outputs.forEach(output => { + output.tokens.forEach(({id}) => { + if (!distinctTokenIds.includes(id)) { + distinctTokenIds.push(id); + } + }); + }); + distinctTokenIds = distinctTokenIds.map( + id => ergo.TokenId.from_str(id).as_bytes() + ); + return { - inputs: this.inputs, - dataInputs: this.dataInputs, - outputs: this.outputs, - distinctTokenIds: this.distinctTokenIds, + inputs: inputs, + dataInputs: this.dataInputs.map(toDataInput), + outputs: outputs, changeMap: this.changeMap, + distinctTokenIds: distinctTokenIds }; } } -exports.UnsignedTransactionBuilder = UnsignedTransactionBuilder; +exports.TxBuilder = TxBuilder; \ No newline at end of file diff --git a/tests/package.json b/tests/package.json index fd112e47..096e40c9 100644 --- a/tests/package.json +++ b/tests/package.json @@ -13,9 +13,9 @@ "mocha": "^10.1.0" }, "dependencies": { - "@ledgerhq/hw-transport-node-hid": "6.27.8", - "@ledgerhq/hw-transport-node-speculos-http": "6.27.8", - "ergo-lib-wasm-nodejs": "v0.21.1", + "@ledgerhq/hw-transport-node-hid": "6.28.5", + "@ledgerhq/hw-transport-node-speculos-http": "6.28.5", + "ergo-lib-wasm-nodejs": "v0.26.0", "ledger-ergo-js": "^0.1.14" } } diff --git a/tests/public-key-tests.js b/tests/public-key-tests.js index 653714fd..7b7abf86 100644 --- a/tests/public-key-tests.js +++ b/tests/public-key-tests.js @@ -2,30 +2,28 @@ const { expect } = require('chai') .use(require('chai-bytes')); const { toHex, getApplication, removeMasterNode } = require('./helpers/common'); const { TEST_DATA } = require('./helpers/data'); -const { AuthTokenFlows } = require('./helpers/flow'); +const { authTokenFlows } = require('./helpers/flow'); describe("Public Key Tests", function () { context("Public Key Commands", function () { - new AuthTokenFlows("can get extended public key", () => { return { account: TEST_DATA.account }; }).do( - function () { - return this.test.device.getExtendedPublicKey(this.account.path.toString()) - }, - function (extendedPublicKey) { - const getExtendedPublicKeyFlow = [ - { header: null, body: 'Ext PubKey Export' }, - { header: 'Path', body: removeMasterNode(this.account.path.toString()) }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ]; - if (this.auth) { - getExtendedPublicKeyFlow.splice(2, 0, { header: 'Application', body: getApplication(this.test.device) }); + authTokenFlows("can get extended public key") + .init(async ({test, auth}) => { + const account = TEST_DATA.account; + const flow = [{ header: null, body: 'Ext PubKey Export' }, + { header: 'Path', body: removeMasterNode(account.path.toString()) }]; + if (auth) { + flow.push({ header: 'Application', body: getApplication(test.device) }); } - expect(this.flows[0]).to.be.deep.equal(getExtendedPublicKeyFlow); - expect(extendedPublicKey).to.be.deep.equal({ - publicKey: toHex(this.account.publicKey.pub_key_bytes()), - chainCode: toHex(this.account.publicKey.chain_code()), + flow.push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + return { account, flow, flowsCount: 1 }; + }) + .shouldSucceed(({flow, flows, account}, extPubKey) => { + expect(flows[0]).to.be.deep.equal(flow); + expect(extPubKey).to.be.deep.equal({ + publicKey: toHex(account.publicKey.pub_key_bytes()), + chainCode: toHex(account.publicKey.chain_code()), }); - } - ); + }) + .run(({test, account}) => test.device.getExtendedPublicKey(account.path.toString())); }); }); diff --git a/tests/transaction-tests.js b/tests/transaction-tests.js index f63a8872..88f3cd2d 100644 --- a/tests/transaction-tests.js +++ b/tests/transaction-tests.js @@ -1,57 +1,52 @@ -const { expect } = require('chai') - .use(require('chai-bytes')); -const { Transaction, TxId, Tokens, Token, TokenId, TokenAmount, I64, ErgoBox } = require('ergo-lib-wasm-nodejs'); +const { expect } = require('chai').use(require('chai-bytes')); +const { Transaction, ErgoBox } = require('ergo-lib-wasm-nodejs'); const { toNetwork, getApplication, removeMasterNode, ellipsize } = require('./helpers/common'); const { TEST_DATA } = require('./helpers/data'); -const { AuthTokenFlows } = require('./helpers/flow'); -const { UnsignedTransactionBuilder } = require('./helpers/transaction'); +const { authTokenFlows } = require('./helpers/flow'); +const { TxBuilder } = require('./helpers/transaction'); -const signTxFlowCount = [5, 5]; +const txId = "0000000000000000000000000000000000000000000000000000000000000000"; -function signTxFlows({ model, device }, auth, from, to, change, tokens = undefined) { - const flows = [ - [ - { header: null, body: 'Confirm Attest Input' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ], - [ - { header: 'P2PK Signing', body: removeMasterNode(from.path.toString()) }, - { header: 'Application', body: '0x00000000' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ], - [ - { header: null, body: 'Confirm Output' }, - { header: 'Address', body: to.toBase58() }, - { header: 'Output Value', body: '0.100000000 ERG' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ], - [ - { header: null, body: 'Confirm Output' }, - { header: 'Change', body: removeMasterNode(change.path.toString()) }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ], - [ - { header: null, body: 'Approve Signing' }, - { header: 'P2PK Path', body: removeMasterNode(from.path.toString()) }, - { header: 'Transaction Amount', body: '0.100000000 ERG' }, - { header: 'Transaction Fee', body: '0.001000000 ERG' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ] - ]; - if (tokens) { - flows[2].splice(3, 0, ...tokens); - } +function signTxFlows({ device }, auth, from, to, change, tokens_to = undefined, tokens_tx = undefined) { + let i = 0; + const flows = []; + // attest input screen + flows[i] = [{ header: null, body: 'Confirm Attest Input' }]; if (auth) { - flows[0].splice(1, 0, { header: 'Application', body: getApplication(device) }); - flows[1].splice(1, 1); + flows[i].push({ header: 'Application', body: getApplication(device) }); + } + flows[i++].push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + // accept tx screen + flows[i] = [{ header: 'P2PK Signing', body: removeMasterNode(from.path.toString()) }]; + if (!auth) { + flows[i].push({ header: 'Application', body: '0x00000000' }); + } + flows[i++].push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + // output screen + if (to) { + flows[i] = [{ header: null, body: 'Confirm Output' }, + { header: 'Address', body: to.toBase58() }, + { header: 'Output Value', body: '0.100000000 ERG' }]; + if (tokens_to) { flows[i].push(...tokens_to); } + flows[i++].push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + } + // change screen + if (change && (from.acc_index != change.acc_index || change.addr_index >= 19)) { + flows[i++] = [{ header: null, body: 'Confirm Output' }, + { header: 'Change', body: removeMasterNode(change.path.toString()) }, + { header: null, body: 'Approve' }, + { header: null, body: 'Reject' }]; + } + if (to && change) { + flows[i] = [{ header: null, body: 'Approve Signing' }, + { header: 'P2PK Path', body: removeMasterNode(from.path.toString()) }, + { header: 'Transaction Amount', body: '0.100000000 ERG' }, + { header: 'Transaction Fee', body: '0.001000000 ERG' }]; + if (tokens_tx) { flows[i].push(...tokens_tx); } + flows[i++].push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); } return flows; -}; +} function verifySignatures(unsigned, signatures, ergoBox) { const signed = Transaction.from_unsigned_tx(unsigned, signatures); @@ -61,31 +56,22 @@ function verifySignatures(unsigned, signatures, ergoBox) { describe("Transaction Tests", function () { context("Transaction Commands", function () { - new AuthTokenFlows("can attest input", () => { - return { - unsignedBox: new UnsignedTransactionBuilder() - .input(TEST_DATA.address0, TxId.zero(), 0) - .output('100000000', TEST_DATA.address1.address) - .change(TEST_DATA.changeAddress) - .build() - .inputs[0] - }; - }).do( - function () { - return this.test.device.attestInput(this.unsignedBox); - }, - function (attestedBox) { - const attestInputFlow = [ - { header: null, body: 'Confirm Attest Input' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ]; - if (this.auth) { - attestInputFlow.splice(1, 0, { header: 'Application', body: getApplication(this.test.device) }); + authTokenFlows("can attest input") + .init(async ({test, auth}) => { + const unsignedBox = new TxBuilder() + .input(TEST_DATA.address0, txId, 0, '1000000000') + .inputs[0].box; + const flow = [{ header: null, body: 'Confirm Attest Input' }]; + if (auth) { + flow.push({ header: 'Application', body: getApplication(test.device) }); } - expect(this.flows[0]).to.be.deep.equal(attestInputFlow); + flow.push({ header: null, body: 'Approve' }, { header: null, body: 'Reject' }); + return { unsignedBox, flow, flowsCount: 1 }; + }) + .shouldSucceed(({flow, flows, unsignedBox}, attestedBox) => { + expect(flows[0]).to.be.deep.equal(flow); expect(attestedBox).to.have.property('box'); - expect(attestedBox.box).to.be.deep.equal(this.unsignedBox); + expect(attestedBox.box).to.be.deep.equal(unsignedBox); expect(attestedBox).to.have.property('frames'); expect(attestedBox.frames).to.have.length(1); const frame = attestedBox.frames[0]; @@ -96,291 +82,274 @@ describe("Transaction Tests", function () { expect(frame.tokens).to.be.empty; expect(frame.attestation).to.exist; expect(frame.buffer).to.exist; - } - ); + }) + .run(({test, unsignedBox}) => test.device.attestInput(unsignedBox)); - new AuthTokenFlows("can sign tx", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const builder = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0) - .dataInput(from.address, TxId.zero(), 0) - .output('100000000', to.address) - .fee('1000000') - .change(change); - return { from, to, change, builder }; - }, signTxFlowCount).do( - function () { - const unsignedTransaction = this.builder.build(); - return this.test.device.signTx(unsignedTransaction, toNetwork(TEST_DATA.network)) - }, - function (signatures) { - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change); - expect(this.flows).to.be.deep.equal(flows); + authTokenFlows("can sign tx") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000') + .dataInput(from.address, txId, 1) + .output(to.address, '100000000') + .fee('1000000') + .change(change) + .build(); + const expectedFlows = signTxFlows(test, auth, from, to, change); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length, + network: TEST_DATA.network }; + }) + .shouldSucceed(({ergoTx, input, expectedFlows, flows}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - const ergoBox = this.builder.ergoBuilder.inputs.get(0); - verifySignatures(this.builder.ergoTransaction, signatures, ergoBox); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx, network}) => test.device.signTx(appTx, toNetwork(network))); - new AuthTokenFlows("can sign tx with additional registers", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const ergoBox = ErgoBox.from_json(`{ - "boxId": "ef16f4a6db61a1c31aea55d3bf10e1fb6443cf08cff4a1cf2e3a4780e1312dba", - "value": 1000000000, - "ergoTree": "${from.address.to_ergo_tree().to_base16_bytes()}", - "assets": [], - "additionalRegisters": { - "R5": "0e050102030405", - "R4": "04f601" - }, - "creationHeight": 0, - "transactionId": "0000000000000000000000000000000000000000000000000000000000000000", - "index": 0 - }`); - const builder = new UnsignedTransactionBuilder() - .inputFrom(ergoBox, from.path) - .output('100000000', to.address) - .fee('1000000') - .change(change); - return { from, to, change, builder }; - }, signTxFlowCount).do( - function () { - const unsignedTransaction = this.builder.build(); - return this.test.device.signTx(unsignedTransaction, toNetwork(TEST_DATA.network)) - }, - function (signatures) { - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change); - expect(this.flows).to.be.deep.equal(flows); + authTokenFlows("can sign tx change 22") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress22; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000') + .dataInput(from.address, txId, 1) + .output(to.address, '100000000') + .fee('1000000') + .change(change) + .build(); + const expectedFlows = signTxFlows(test, auth, from, to, change); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({ergoTx, input, expectedFlows, flows}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - const ergoBox = this.builder.ergoBuilder.inputs.get(0); - verifySignatures(this.builder.ergoTransaction, signatures, ergoBox); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can sign tx with zero data inputs", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const builder = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0) - .output('100000000', to.address) - .fee('1000000') - .change(change); - return { from, to, change, builder }; - }, signTxFlowCount).do( - function () { - const unsignedTransaction = this.builder.build(); - return this.test.device.signTx(unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - function (signatures) { - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change); - expect(this.flows).to.be.deep.equal(flows); + authTokenFlows("can sign tx with additional registers") + .init(({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const ergoBox = ErgoBox.from_json(`{ + "boxId": "ef16f4a6db61a1c31aea55d3bf10e1fb6443cf08cff4a1cf2e3a4780e1312dba", + "value": 1000000000, + "ergoTree": "${from.address.to_ergo_tree().to_base16_bytes()}", + "assets": [], + "additionalRegisters": { + "R5": "0e050102030405", + "R4": "04f601" + }, + "creationHeight": 0, + "transactionId": "0000000000000000000000000000000000000000000000000000000000000000", + "index": 0 + }`); + const {appTx, ergoTx, uInputs} = new TxBuilder() + .boxInput(ergoBox, from.path) + .output(to.address, '100000000') + .fee('1000000') + .change(change) + .build(); + const expectedFlows = signTxFlows(test, auth, from, to, change); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({ergoTx, input, expectedFlows, flows}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - const ergoBox = this.builder.ergoBuilder.inputs.get(0); - verifySignatures(this.builder.ergoTransaction, signatures, ergoBox); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can not sign tx with zero inputs", () => { - return { - unsignedTransaction: new UnsignedTransactionBuilder() - .dataInput(TEST_DATA.address0.address, TxId.zero(), 0) - .output('100000000', TEST_DATA.address1.address) - .build(false) - }; - }, [0, 0]).do( - function () { - return this.test.device.signTx(this.unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - null, - function (error) { + authTokenFlows("can sign tx with zero data inputs") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000') + .output(to.address, '100000000') + .fee('1000000') + .change(change) + .build(); + const expectedFlows = signTxFlows(test, auth, from, to, change); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({ergoTx, input, expectedFlows, flows}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); + expect(signatures).to.have.length(1); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); + + authTokenFlows("can not sign tx with zero inputs") + .init(async () => { + const tx = new TxBuilder() + .dataInput(TEST_DATA.address0.address, txId, 0) + .output(TEST_DATA.address1.address, '100000000') + .fee(null) + .buildAppTx(); + return { tx, flowsCount: 0 }; + }) + .shouldFail((_, error) => { expect(error).to.be.an('error'); expect(error.name).to.be.equal('DeviceError'); expect(error.message).to.be.equal('Bad input count'); - } - ); + }) + .run(({test, tx}) => test.device.signTx(tx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can not sign tx with zero outputs", () => { - const address = TEST_DATA.address0; - const unsignedTransaction = new UnsignedTransactionBuilder() - .input(address, TxId.zero(), 0) - .dataInput(address.address, TxId.zero(), 0) - .build(false); - return { address, unsignedTransaction }; - }, [2, 2]).do( - function () { - return this.test.device.signTx(this.unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - null, - function (error) { - const signTxNoOutputsFlows = [ - [ - { header: null, body: 'Confirm Attest Input' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ], - [ - { header: 'P2PK Signing', body: removeMasterNode(this.address.path.toString()) }, - { header: 'Application', body: '0x00000000' }, - { header: null, body: 'Approve' }, - { header: null, body: 'Reject' } - ] - ]; - if (this.auth) { - signTxNoOutputsFlows[0].splice(1, 0, { header: 'Application', body: getApplication(this.test.device) }); - signTxNoOutputsFlows[1].splice(1, 1); - } - expect(this.flows).to.be.deep.equal(signTxNoOutputsFlows); + authTokenFlows("can not sign tx with zero outputs") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const tx = new TxBuilder() + .input(from, txId, 0, '1000000000') + .dataInput(from.address, txId, 0) + .fee(null) + .buildAppTx(); + const expectedFlows = signTxFlows(test, auth, from, null, null); + return { tx, expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldFail(({flows, expectedFlows}, error) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(error).to.be.an('error'); expect(error.name).to.be.equal('DeviceError'); expect(error.message).to.be.equal('Bad output count'); - } - ); + }) + .run(({test, tx}) => test.device.signTx(tx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can sign tx with tokens", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const tokens = new Tokens(); - const tokenId = TokenId.from_str('1111111111111111111111111111111111111111111111111111111111111111'); - tokens.add(new Token(tokenId, TokenAmount.from_i64(I64.from_str('1000')))); - const builder = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0, tokens) - .dataInput(from.address, TxId.zero(), 0) - .output('100000000', to.address, tokens) - .fee('1000000') - .change(change); - return { from, to, change, builder, tokenId }; - }, signTxFlowCount).do( - function () { - const unsignedTransaction = this.builder.build(); - return this.test.device.signTx(unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - function (signatures) { - const tokens = [ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId.to_str()) }, + authTokenFlows("can sign tx with tokens") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const tokenId = '1111111111111111111111111111111111111111111111111111111111111111'; + const tokens = [{id: tokenId, amount: '1000'}]; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000', tokens) + .dataInput(from.address, txId, 0) + .output(to.address, '100000000', tokens) + .fee('1000000') + .change(change) + .build(); + const tokensFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, tokenId) }, { header: 'Token [1] Value', body: '1000' } ]; - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change, tokens); - expect(this.flows).to.be.deep.equal(flows); + const expectedFlows = signTxFlows(test, auth, from, to, change, tokensFlow); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({ergoTx, input, flows, expectedFlows}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - const ergoBox = this.builder.ergoBuilder.inputs.get(0); - verifySignatures(this.builder.ergoTransaction, signatures, ergoBox); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can sign tx with burned tokens", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const tokens = new Tokens(); - const tokenId = TokenId.from_str('1111111111111111111111111111111111111111111111111111111111111111'); - tokens.add(new Token(tokenId, TokenAmount.from_i64(I64.from_str('1000')))); - const unsignedTransaction = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0, tokens) - .dataInput(from.address, TxId.zero(), 0) - .output('100000000', to.address) - .fee('1000000') - .change(change) - .tokenIds([tokenId.as_bytes()]) - .build(false); - return { from, to, change, unsignedTransaction, tokenId }; - }, signTxFlowCount).do( - function () { - return this.test.device.signTx(this.unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - function (signatures) { - const tokens = [ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId.to_str()) }, + authTokenFlows("can sign tx with burned tokens") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const tokenId = '1111111111111111111111111111111111111111111111111111111111111111'; + const tokens = [{id: tokenId, amount: '1000'}]; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000', tokens) + .dataInput(from.address, txId, 0) + .output(to.address, '100000000') + .fee('1000000') + .change(change) + .burn(tokens) + .build(); + const tokensFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, tokenId) }, { header: 'Token [1] Value', body: 'Burning: 1000' } ]; - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change); - flows[4].splice(4, 0, ...tokens); - expect(this.flows).to.be.deep.equal(flows); + const expectedFlows = signTxFlows(test, auth, from, to, change, null, tokensFlow); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length };; + }) + .shouldSucceed(({flows, expectedFlows, ergoTx, input}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can sign tx with minted tokens", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const tokens = new Tokens(); - const tokenId = TokenId.from_str('1111111111111111111111111111111111111111111111111111111111111111'); - tokens.add(new Token(tokenId, TokenAmount.from_i64(I64.from_str('1000')))); - const unsignedTransaction = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0) - .dataInput(from.address, TxId.zero(), 0) - .output('100000000', to.address, tokens) - .fee('1000000') - .change(change) - .tokenIds([tokenId.as_bytes()]) - .build(false); - return { from, to, change, unsignedTransaction, tokenId }; - }, signTxFlowCount).do( - function () { - return this.test.device.signTx(this.unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - function (signatures) { - const tokens = [ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId.to_str()) }, + authTokenFlows("can sign tx with minted tokens") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000') + .dataInput(from.address, txId, 0) + .output(to.address, '100000000', null, '1000') + .fee('1000000') + .change(change) + .build(); + const tokenId = uInputs[0].box_id().to_str().toUpperCase(); + const tokensOutFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, tokenId) }, { header: 'Token [1] Value', body: '1000' } ]; - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change, tokens); - flows[4].splice(4, 0, ...[ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId.to_str()) }, + const tokensTxFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, tokenId) }, { header: 'Token [1] Value', body: 'Minting: 1000' } - ]); - expect(this.flows).to.be.deep.equal(flows); + ]; + const expectedFlows = signTxFlows(test, auth, from, to, change, tokensOutFlow, tokensTxFlow); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({flows, expectedFlows, ergoTx, input}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); - new AuthTokenFlows("can sign tx with few token ids", () => { - const from = TEST_DATA.address0; - const to = TEST_DATA.address1; - const change = TEST_DATA.changeAddress; - const tokens = new Tokens(); - const tokenId = TokenId.from_str('1111111111111111111111111111111111111111111111111111111111111111'); - tokens.add(new Token(tokenId, TokenAmount.from_i64(I64.from_str('1000')))); - const tokens2 = new Tokens(); - const tokenId2 = TokenId.from_str('0000000000000000000000000000000000000000000000000000000000000000'); - tokens2.add(new Token(tokenId2, TokenAmount.from_i64(I64.from_str('1000')))); - const unsignedTransaction = new UnsignedTransactionBuilder() - .input(from, TxId.zero(), 0, tokens) - .dataInput(from.address, TxId.zero(), 0) - .output('100000000', to.address, tokens2) - .fee('1000000') - .change(change) - .tokenIds([ - tokenId.as_bytes(), - tokenId2.as_bytes() - ]) - .build(false); - return { from, to, change, unsignedTransaction, tokenId, tokenId2 }; - }, signTxFlowCount).do( - function () { - return this.test.device.signTx(this.unsignedTransaction, toNetwork(TEST_DATA.network)); - }, - function (signatures) { - const tokens = [ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId2.to_str()) }, - { header: 'Token [1] Value', body: '1000' } + authTokenFlows("can sign tx with few token ids") + .init(async ({test, auth}) => { + const from = TEST_DATA.address0; + const to = TEST_DATA.address1; + const change = TEST_DATA.changeAddress; + const iTokenId = '1111111111111111111111111111111111111111111111111111111111111111'; + const iTokens = [{id: iTokenId, amount: '1234'}]; + const {appTx, ergoTx, uInputs} = new TxBuilder() + .input(from, txId, 0, '1000000000', iTokens) + .dataInput(from.address, txId, 0) + .output(to.address, '100000000', null, '5678') + .fee('1000000') + .change(change) + .burn(iTokens) + .build(); + const oTokenId = uInputs[0].box_id().to_str().toUpperCase(); + const tokensOutFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, oTokenId) }, + { header: 'Token [1] Value', body: '5678' } + ]; + const tokensTxFlow = [ + { header: 'Token [1]', body: ellipsize(test.model, oTokenId) }, + { header: 'Token [1] Value', body: 'Minting: 5678' }, + { header: 'Token [2]', body: ellipsize(test.model, iTokenId) }, + { header: 'Token [2] Value', body: 'Burning: 1234' } ]; - let flows = signTxFlows(this.test, this.auth, this.from, this.to, this.change, tokens); - flows[4].splice(4, 0, ...[ - { header: 'Token [1]', body: ellipsize(this.test.model, this.tokenId.to_str()) }, - { header: 'Token [1] Value', body: 'Burning: 1000' }, - { header: 'Token [2]', body: ellipsize(this.test.model, this.tokenId2.to_str()) }, - { header: 'Token [2] Value', body: 'Minting: 1000' } - ]); - expect(this.flows).to.be.deep.equal(flows); + const expectedFlows = signTxFlows(test, auth, from, to, change, tokensOutFlow, tokensTxFlow); + return { appTx, ergoTx, input: uInputs[0], + expectedFlows, flowsCount: expectedFlows.length }; + }) + .shouldSucceed(({flows, expectedFlows, ergoTx, input}, signatures) => { + expect(flows).to.be.deep.equal(expectedFlows); expect(signatures).to.have.length(1); - } - ); + verifySignatures(ergoTx, signatures, input); + }) + .run(({test, appTx}) => test.device.signTx(appTx, toNetwork(TEST_DATA.network))); }); }); diff --git a/unit-tests/.vscode/c_cpp_properties.json b/unit-tests/.vscode/c_cpp_properties.json index cc65eae9..dc48e5c9 100644 --- a/unit-tests/.vscode/c_cpp_properties.json +++ b/unit-tests/.vscode/c_cpp_properties.json @@ -3,6 +3,7 @@ { "name": "Linux-Clang", "includePath": [ + "/usr/include", "${workspaceFolder}/utils", "${workspaceFolder}/../src" ], diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 7f6c4e8b..12aba4e2 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -40,35 +40,14 @@ add_definitions(-include macro_helpers.h) include_directories(BEFORE SYSTEM ../src utils) -# CX lirary shim for testing -add_library(cx SHARED utils/cx.c utils/blake2b-ref.c) +file(GLOB SHIMS_SRC utils/*.c) -add_executable(test_base58 test_base58.c) -add_executable(test_bip32 test_bip32.c) -add_executable(test_buffer test_buffer.c) -add_executable(test_format test_format.c) -add_executable(test_write test_write.c) -add_executable(test_apdu_parser test_apdu_parser.c) -add_executable(test_full_tx test_full_tx.c) -add_executable(test_int_ops test_int_ops.c) -add_executable(test_read test_read.c) -add_executable(test_varint test_varint.c) -add_executable(test_zigzag test_zigzag.c) -add_executable(test_address test_address.c) -add_executable(test_ergo_tree test_ergo_tree.c) -add_executable(test_tx_ser_box test_tx_ser_box.c) -add_executable(test_tx_ser_input test_tx_ser_input.c) -add_executable(test_tx_ser_table test_tx_ser_table.c) -add_executable(test_input_frame test_input_frame.c) +# CX library shim for testing +add_library(sdk_shims SHARED ${SHIMS_SRC}) -add_library(base58 SHARED ../src/common/base58.c) -add_library(bip32 SHARED ../src/common/bip32.c) -add_library(buffer SHARED ../src/common/buffer.c) -add_library(read SHARED ../src/common/read.c) -add_library(write SHARED ../src/common/write.c) -add_library(format SHARED ../src/common/format.c) -add_library(varint SHARED ../src/common/varint.c) -add_library(apdu_parser SHARED ../src/apdu/parser.c) +add_library(bip32_ext SHARED ../src/common/bip32_ext.c) +add_library(rwbuffer SHARED ../src/common/buffer_ext.c ../src/common/rwbuffer.c) +add_library(gve SHARED ../src/common/gve.c) add_library(blake2b SHARED ../src/helpers/blake2b.c) add_library(ergo_tree SHARED ../src/ergo/ergo_tree.c) add_library(tx_ser_box SHARED ../src/ergo/tx_ser_box.c) @@ -78,49 +57,53 @@ add_library(tx_ser_table SHARED ../src/ergo/tx_ser_table.c) add_library(address SHARED ../src/ergo/address.c) add_library(input_frame SHARED ../src/helpers/input_frame.c) -target_link_libraries(varint PUBLIC buffer) -target_link_libraries(bip32 PUBLIC read) -target_link_libraries(blake2b PUBLIC cx) -target_link_libraries(buffer PUBLIC read write bip32) -target_link_libraries(ergo_tree PUBLIC buffer) -target_link_libraries(tx_ser_table PUBLIC blake2b buffer varint) -target_link_libraries(tx_ser_input PUBLIC buffer blake2b tx_ser_table) -target_link_libraries(tx_ser_box PUBLIC blake2b buffer tx_ser_table varint ergo_tree) -target_link_libraries(tx_ser_full PUBLIC blake2b buffer varint tx_ser_box tx_ser_input tx_ser_table) -target_link_libraries(address PUBLIC buffer blake2b) - -target_link_libraries(test_base58 PUBLIC cmocka gcov base58) -target_link_libraries(test_bip32 PUBLIC cmocka gcov bip32) -target_link_libraries(test_buffer PUBLIC cmocka gcov buffer) -target_link_libraries(test_format PUBLIC cmocka gcov format) -target_link_libraries(test_write PUBLIC cmocka gcov write) -target_link_libraries(test_apdu_parser PUBLIC cmocka gcov apdu_parser) -target_link_libraries(test_full_tx PUBLIC cmocka gcov blake2b tx_ser_full) -target_link_libraries(test_int_ops PUBLIC cmocka gcov) -target_link_libraries(test_read PUBLIC cmocka gcov read) -target_link_libraries(test_varint PUBLIC cmocka gcov varint) -target_link_libraries(test_zigzag PUBLIC cmocka gcov) +target_link_libraries(bip32_ext PUBLIC sdk_shims) +target_link_libraries(blake2b PUBLIC sdk_shims) +target_link_libraries(rwbuffer PUBLIC bip32_ext) +target_link_libraries(gve PUBLIC rwbuffer) +target_link_libraries(address PUBLIC rwbuffer blake2b) +target_link_libraries(input_frame PUBLIC rwbuffer) +target_link_libraries(ergo_tree PUBLIC rwbuffer) +target_link_libraries(tx_ser_table PUBLIC blake2b rwbuffer gve) +target_link_libraries(tx_ser_input PUBLIC rwbuffer blake2b tx_ser_table) +target_link_libraries(tx_ser_box PUBLIC blake2b rwbuffer tx_ser_table gve ergo_tree) +target_link_libraries(tx_ser_full PUBLIC blake2b rwbuffer gve tx_ser_box tx_ser_input tx_ser_table) + +add_executable(test_address test_address.c) +add_executable(test_bip32 test_bip32.c) +add_executable(test_buffer test_buffer.c) +add_executable(test_ergo_tree test_ergo_tree.c) +add_executable(test_full_tx test_full_tx.c) +add_executable(test_gve test_gve.c) +add_executable(test_input_frame test_input_frame.c) +add_executable(test_safeint test_safeint.c) +add_executable(test_tx_ser_box test_tx_ser_box.c) +add_executable(test_tx_ser_input test_tx_ser_input.c) +add_executable(test_tx_ser_table test_tx_ser_table.c) +add_executable(test_zigzag test_zigzag.c) + target_link_libraries(test_address PUBLIC cmocka gcov address) +target_link_libraries(test_bip32 PUBLIC cmocka gcov bip32_ext) +target_link_libraries(test_buffer PUBLIC cmocka gcov rwbuffer) target_link_libraries(test_ergo_tree PUBLIC cmocka gcov ergo_tree) +target_link_libraries(test_full_tx PUBLIC cmocka gcov blake2b tx_ser_full) +target_link_libraries(test_gve PUBLIC cmocka gcov gve) +target_link_libraries(test_input_frame PUBLIC cmocka gcov input_frame) +target_link_libraries(test_safeint PUBLIC cmocka gcov) target_link_libraries(test_tx_ser_box PUBLIC cmocka gcov tx_ser_box) target_link_libraries(test_tx_ser_input PUBLIC cmocka gcov tx_ser_input) target_link_libraries(test_tx_ser_table PUBLIC cmocka gcov tx_ser_table) -target_link_libraries(test_input_frame PUBLIC cmocka gcov input_frame) +target_link_libraries(test_zigzag PUBLIC cmocka gcov) -add_test(test_base58 test_base58) +add_test(test_address test_address) add_test(test_bip32 test_bip32) add_test(test_buffer test_buffer) -add_test(test_format test_format) -add_test(test_write test_write) -add_test(test_apdu_parser test_apdu_parser) -add_test(test_full_tx test_full_tx) -add_test(test_int_ops test_int_ops) -add_test(test_read test_read) -add_test(test_varint test_varint) -add_test(test_zigzag test_zigzag) -add_test(test_address test_address) add_test(test_ergo_tree test_ergo_tree) +add_test(test_full_tx test_full_tx) +add_test(test_gve test_gve) +add_test(test_input_frame test_input_frame) +add_test(test_safeint test_safeint) add_test(test_tx_ser_box test_tx_ser_box) add_test(test_tx_ser_input test_tx_ser_input) add_test(test_tx_ser_table test_tx_ser_table) -add_test(test_input_frame test_input_frame) \ No newline at end of file +add_test(test_zigzag test_zigzag) diff --git a/unit-tests/test_address.c b/unit-tests/test_address.c index e790b013..8dca0f62 100644 --- a/unit-tests/test_address.c +++ b/unit-tests/test_address.c @@ -13,21 +13,16 @@ static void test_ergo_address_from_pubkey(void **state) { uint8_t network = 0; const uint8_t public_key[65] = { - 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, - 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, - 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, - 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, 0x59, - 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, - 0x1a, 0x60, 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, - 0xe5, 0xcf, 0xf1, 0x0a, 0xe7 - }; + 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, + 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, + 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, + 0x59, 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, 0x1a, 0x60, + 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, 0xe5, 0xcf, 0xf1, 0x0a, 0xe7}; uint8_t address[38]; - uint8_t expected[38] = { - 0x01, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, - 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, - 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, - 0x5a, 0xbd, 0xcb, 0x2a, 0xb5, 0x2d, 0xca, 0xce - }; + uint8_t expected[38] = {0x01, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, + 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, + 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, + 0x5a, 0xbd, 0xcb, 0x2a, 0xb5, 0x2d, 0xca, 0xce}; assert_true(ergo_address_from_pubkey(network, public_key, address)); assert_memory_equal(address, expected, sizeof(expected)); } diff --git a/unit-tests/test_apdu_parser.c b/unit-tests/test_apdu_parser.c deleted file mode 100644 index 99ee07d5..00000000 --- a/unit-tests/test_apdu_parser.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "types.h" -#include "apdu/parser.h" - -static void test_apdu_parser(void **state) { - (void) state; - uint8_t apdu_bad_min_len[] = {0xE0, 0x03, 0x00, 0x00}; // less than 5 bytes - uint8_t apdu_bad_lc[] = {0xE0, 0x03, 0x00, 0x00, 0x01}; // Lc = 1 but no data - uint8_t apdu[] = {0xE0, 0x03, 0x01, 0x02, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04}; - - command_t cmd; - - memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_min_len, sizeof(apdu_bad_min_len))); - - memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_lc, sizeof(apdu_bad_min_len))); - - memset(&cmd, 0, sizeof(cmd)); - assert_true(apdu_parser(&cmd, apdu, sizeof(apdu))); - assert_int_equal(cmd.cla, 0xE0); - assert_int_equal(cmd.ins, 0x03); - assert_int_equal(cmd.p1, 0x01); - assert_int_equal(cmd.p2, 0x02); - assert_int_equal(cmd.lc, 5); - assert_memory_equal(cmd.data, ((uint8_t[]){0x00, 0x01, 0x02, 0x03, 0x04}), cmd.lc); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_apdu_parser)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_base58.c b/unit-tests/test_base58.c deleted file mode 100644 index 91602f70..00000000 --- a/unit-tests/test_base58.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/base58.h" - -#define VERIFY_BAD_BASE58_ENCODE(in) \ - char out[165] = {0}; \ - int out_len = base58_encode((uint8_t *) in, strlen(in), out, sizeof(out)); \ - assert_int_equal(out_len, -1); - -#define VERIFY_BASE58_ENCODE(in, expected_out) \ - char out[165] = {0}; \ - int out_len = base58_encode((uint8_t *) in, strlen(in), out, sizeof(out)); \ - assert_int_equal(out_len, strlen(expected_out)); \ - assert_string_equal((char *) out, expected_out); - -#define VERIFY_BAD_BASE58_DECODE(in) \ - uint8_t out[121] = {0}; \ - int out_len = base58_decode(in, strlen(in), out, sizeof(out)); \ - assert_int_equal(out_len, -1); - -#define VERIFY_BASE58_DECODE(in, expected_out) \ - uint8_t out[121] = {0}; \ - int out_len = base58_decode(in, strlen(in), out, sizeof(out)); \ - assert_int_equal(out_len, strlen(expected_out)); \ - assert_string_equal((char *) out, expected_out); - -static void test_base58(void **state) { - (void) state; - - const char in[] = "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z"; - const char expected_out[] = "The quick brown fox jumps over the lazy dog."; - uint8_t out[100] = {0}; - int out_len = base58_decode(in, sizeof(in) - 1, out, sizeof(out)); - assert_int_equal(out_len, strlen(expected_out)); - assert_string_equal((char *) out, expected_out); - - const char in2[] = "The quick brown fox jumps over the lazy dog."; - const char expected_out2[] = "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z"; - char out2[100] = {0}; - int out_len2 = base58_encode((uint8_t *) in2, sizeof(in2) - 1, out2, sizeof(out2)); - assert_int_equal(out_len2, strlen(expected_out2)); - assert_string_equal((char *) out2, expected_out2); -} - -static void test_bad_base58_encode_out_of_range(void **state) { - (void) state; - VERIFY_BAD_BASE58_ENCODE("1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "11111111111111111111111111111111111111111"); -} - -static void test_base58_encode_zero_characters(void **state) { - (void) state; - VERIFY_BASE58_ENCODE("", ""); -} - -static void test_base58_encode_one_character(void **state) { - (void) state; - VERIFY_BASE58_ENCODE("!", "a"); -} - -static void test_base58_encode_max_number_of_characters(void **state) { - (void) state; - VERIFY_BASE58_ENCODE("1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111", - "7pURzZxewQxq8JBWyAdgyj3h3xxhjY1cWcyv2GYQ" - "tophYQA4CpLhMJpjKVW8conmkFmRwDd8Ut4XKWiK" - "SbKZ8BqEfXxANAne3kugUNtKHy2S6RKLb9rhCbTq" - "DJFLEwmK7izZWSCbeBU6hph56skH6xcc2DU8B3MWr3Zr"); -} - -static void test_bad_base58_decode_zero_characters(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE(""); -} - -static void test_bad_base58_decode_0_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("0a"); -} - -static void test_bad_base58_decode_I_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("Ia"); -} - -static void test_bad_base58_decode_O_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("Oa"); -} - -static void test_bad_base58_decode_l_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("la"); -} - -static void test_bad_base58_decode_plus_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("+a"); -} - -static void test_bad_base58_decode_slash_symbol(void **state) { - (void) state; - VERIFY_BAD_BASE58_DECODE("/a"); -} - -static void test_base58_decode_max_number_of_characters(void **state) { - (void) state; - VERIFY_BASE58_DECODE("7pURzZxewQxq8JBWyAdgyj3h3xxhjY1cWcyv2GYQ" - "tophYQA4CpLhMJpjKVW8conmkFmRwDd8Ut4XKWiK" - "SbKZ8BqEfXxANAne3kugUNtKHy2S6RKLb9rhCbTq" - "DJFLEwmK7izZWSCbeBU6hph56skH6xcc2DU8B3MWr3Zr", - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111"); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_base58), - cmocka_unit_test(test_bad_base58_encode_out_of_range), - cmocka_unit_test(test_base58_encode_zero_characters), - cmocka_unit_test(test_base58_encode_one_character), - cmocka_unit_test(test_base58_encode_max_number_of_characters), - cmocka_unit_test(test_bad_base58_decode_zero_characters), - cmocka_unit_test(test_bad_base58_decode_0_symbol), - cmocka_unit_test(test_bad_base58_decode_I_symbol), - cmocka_unit_test(test_bad_base58_decode_O_symbol), - cmocka_unit_test(test_bad_base58_decode_l_symbol), - cmocka_unit_test(test_bad_base58_decode_plus_symbol), - cmocka_unit_test(test_bad_base58_decode_slash_symbol), - cmocka_unit_test(test_base58_decode_max_number_of_characters)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_bip32.c b/unit-tests/test_bip32.c index 71c11ead..5daa5cc9 100644 --- a/unit-tests/test_bip32.c +++ b/unit-tests/test_bip32.c @@ -8,138 +8,18 @@ #include -#include "common/bip32.h" +#include "common/bip32_ext.h" #define ARRAYLEN(array) (sizeof(array) / sizeof(array[0])) -#define BIP32_VALIDATE_OK(tvar, type) \ - b = bip32_path_validate(tvar, \ - ARRAYLEN(tvar), \ - BIP32_HARDENED(44), \ - BIP32_HARDENED(429), \ - type); \ +#define BIP32_VALIDATE_OK(tvar, type) \ + b = bip32_path_validate(tvar, ARRAYLEN(tvar), BIP32_HARDENED(44), BIP32_HARDENED(429), type); \ assert_true(b); -#define BIP32_VALIDATE_ERR(tvar, type) \ - b = bip32_path_validate(tvar, \ - ARRAYLEN(tvar), \ - BIP32_HARDENED(44), \ - BIP32_HARDENED(429), \ - type); \ +#define BIP32_VALIDATE_ERR(tvar, type) \ + b = bip32_path_validate(tvar, ARRAYLEN(tvar), BIP32_HARDENED(44), BIP32_HARDENED(429), type); \ assert_false(b); -#define VERIFY_BIP32_PATH_READ(input, expected, n) \ - uint32_t output[n] = {0}; \ - assert_true(bip32_path_read(input, sizeof(input), output, n)); \ - assert_memory_equal(output, expected, n); - -#define VERIFY_BAD_BIP32_PATH_READ(input, n) \ - uint32_t output[n] = {0}; \ - assert_false(bip32_path_read(input, sizeof(input), output, n)); - -static void test_bip32_format(void **state) { - (void) state; - - char output[30]; - bool b = false; - - b = bip32_path_format((const uint32_t[5]){0x8000002C, 0x80000000, 0x80000000, 0, 0}, - 5, - output, - sizeof(output)); - assert_true(b); - assert_string_equal(output, "44'/0'/0'/0/0"); - - b = bip32_path_format((const uint32_t[5]){0x8000002C, 0x80000001, 0x80000000, 0, 0}, - 5, - output, - sizeof(output)); - assert_true(b); - assert_string_equal(output, "44'/1'/0'/0/0"); -} - -static void test_bad_bip32_format(void **state) { - (void) state; - - char output[30]; - bool b = true; - - // More than MAX_BIP32_PATH (=10) - b = bip32_path_format( - (const uint32_t[11]){0x8000002C, 0x80000000, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0}, - 11, - output, - sizeof(output)); - assert_false(b); - - // No BIP32 path (=0) - b = bip32_path_format(NULL, 0, output, sizeof(output)); - assert_false(b); -} - -static void test_bip32_read(void **state) { - (void) state; - - // clang-format off - uint8_t input[20] = { - 0x80, 0x00, 0x00, 0x2C, - 0x80, 0x00, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - uint32_t expected[5] = {0x8000002C, 0x80000001, 0x80000000, 0, 0}; - uint32_t output[5] = {0}; - bool b = false; - - b = bip32_path_read(input, sizeof(input), output, 5); - assert_true(b); - assert_memory_equal(output, expected, 5); -} - -static void test_bip32_read_bigger_buffer(void **state) { - (void) state; - - uint8_t input[8] = { - 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02 - }; - uint32_t expected[1] = {0x01010101}; - VERIFY_BIP32_PATH_READ(input, expected, 1); -} - -static void test_bad_bip32_read(void **state) { - (void) state; - - // clang-format off - uint8_t input[20] = { - 0x80, 0x00, 0x00, 0x2C, - 0x80, 0x00, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - uint32_t output[10] = {0}; - - // buffer too small (5 BIP32 paths instead of 10) - assert_false(bip32_path_read(input, sizeof(input), output, 10)); - - // No BIP32 path - assert_false(bip32_path_read(input, sizeof(input), output, 0)); - - // More than MAX_BIP32_PATH (=10) - assert_false(bip32_path_read(input, sizeof(input), output, 20)); -} - -static void test_bad_bip32_read_smaller_buffer(void **state) { - (void) state; - - uint8_t input[4] = { - 0x01, 0x01, 0x01, 0x01 - }; - VERIFY_BAD_BIP32_PATH_READ(input, 2); -} - static void test_bip32_validate_account(void **state) { (void) state; @@ -237,13 +117,7 @@ static void test_bad_bip32_validate_address(void **state) { } int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_bip32_format), - cmocka_unit_test(test_bad_bip32_format), - cmocka_unit_test(test_bip32_read), - cmocka_unit_test(test_bip32_read_bigger_buffer), - cmocka_unit_test(test_bad_bip32_read), - cmocka_unit_test(test_bad_bip32_read_smaller_buffer), - cmocka_unit_test(test_bip32_validate_account), + const struct CMUnitTest tests[] = {cmocka_unit_test(test_bip32_validate_account), cmocka_unit_test(test_bip32_validate_address), cmocka_unit_test(test_bad_bip32_validate_account), cmocka_unit_test(test_bad_bip32_validate_address)}; diff --git a/unit-tests/test_buffer.c b/unit-tests/test_buffer.c index 0bd3c2a8..773ae225 100644 --- a/unit-tests/test_buffer.c +++ b/unit-tests/test_buffer.c @@ -6,211 +6,211 @@ #include -#include "common/buffer.h" +#include "common/rwbuffer.h" static void test_buffer_init(void **state) { (void) state; - uint8_t data[1] = {0x01}; - uint16_t buf_size = 1; - uint16_t data_size = sizeof(data); - buffer_t buf; - buffer_init(&buf, data, buf_size, data_size); - assert_ptr_equal(data, buf.ptr); + uint8_t data[3] = {0x01, 0x02, 0x00}; + uint16_t data_size = 2; + uint16_t buf_size = sizeof(data); + rw_buffer_t buf; + rw_buffer_init(&buf, data, buf_size, data_size); + assert_ptr_equal(data, buf.read.ptr); assert_int_equal(buf.size, buf_size); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, data_size); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, data_size); } static void test_buffer_from_array_full(void **state) { (void) state; uint8_t array[1] = {0x01}; - BUFFER_FROM_ARRAY_FULL(buf, array, 1); - assert_ptr_equal(array, buf.ptr); + RW_BUFFER_FROM_ARRAY_FULL(buf, array, 1); + assert_ptr_equal(array, buf.read.ptr); assert_int_equal(buf.size, 1); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, 1); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, 1); } static void test_buffer_from_array_empty(void **state) { (void) state; uint8_t array[1] = {0x01}; - BUFFER_FROM_ARRAY_EMPTY(buf, array, 1); - assert_ptr_equal(array, buf.ptr); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, array, 1); + assert_ptr_equal(array, buf.read.ptr); assert_int_equal(buf.size, 1); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, 0); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, 0); } static void test_buffer_from_var_full(void **state) { (void) state; uint8_t var = 0x01; - BUFFER_FROM_VAR_FULL(buf, var); - assert_ptr_equal(&var, buf.ptr); + RW_BUFFER_FROM_VAR_FULL(buf, var); + assert_ptr_equal(&var, buf.read.ptr); assert_int_equal(buf.size, sizeof(var)); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, sizeof(var)); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, sizeof(var)); } static void test_buffer_from_var_empty(void **state) { (void) state; uint8_t var = 0x01; - BUFFER_FROM_VAR_EMPTY(buf, var); - assert_ptr_equal(&var, buf.ptr); + RW_BUFFER_FROM_VAR_EMPTY(buf, var); + assert_ptr_equal(&var, buf.read.ptr); assert_int_equal(buf.size, sizeof(var)); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, 0); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, 0); } static void test_buffer_new_local_empty(void **state) { (void) state; uint16_t size = 1; - BUFFER_NEW_LOCAL_EMPTY(buf, size); + RW_BUFFER_NEW_LOCAL_EMPTY(buf, size); assert_int_equal(buf.size, size); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, 0); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, 0); } static void test_buffer_empty(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - buf.read_offset = 1; - buffer_empty(&buf); - assert_int_equal(buf.read_offset, 0); - assert_int_equal(buf.write_offset, 0); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + buf.read.offset = 1; + rw_buffer_empty(&buf); + assert_int_equal(buf.read.offset, 0); + assert_int_equal(buf.read.size, 0); } static void test_buffer_read_ptr(void **state) { (void) state; uint8_t temp[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - buf.read_offset = 1; - uint8_t *ptr = buffer_read_ptr(&buf); - assert_ptr_equal(ptr, buf.ptr + buf.read_offset); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + buf.read.offset = 1; + const uint8_t *ptr = rw_buffer_read_ptr(&buf); + assert_ptr_equal(ptr, buf.read.ptr + buf.read.offset); } static void test_buffer_write_ptr(void **state) { (void) state; uint8_t temp[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - uint8_t *ptr = buffer_write_ptr(&buf); - assert_ptr_equal(ptr, buf.ptr + buf.write_offset); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + uint8_t *ptr = rw_buffer_write_ptr(&buf); + assert_ptr_equal(ptr, buf.read.ptr + buf.read.size); } static void test_buffer_can_read(void **state) { (void) state; uint8_t temp[20] = {0}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_can_read(&buf, 20)); + assert_true(rw_buffer_can_read(&buf, 20)); - assert_true(buffer_seek_read_cur(&buf, 20)); - assert_false(buffer_can_read(&buf, 1)); + assert_true(rw_buffer_seek_read_cur(&buf, 20)); + assert_false(rw_buffer_can_read(&buf, 1)); } static void test_buffer_can_write(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_true(buffer_can_write(&buf, 1)); - assert_false(buffer_can_write(&buf, sizeof(temp) + 1)); - assert_true(buffer_seek_write_cur(&buf, 1)); - assert_false(buffer_can_write(&buf, 1)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + assert_true(rw_buffer_can_write(&buf, 1)); + assert_false(rw_buffer_can_write(&buf, sizeof(temp) + 1)); + assert_true(rw_buffer_seek_write_cur(&buf, 1)); + assert_false(rw_buffer_can_write(&buf, 1)); } static void test_buffer_empty_space_len(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_int_equal(buffer_empty_space_len(&buf), 1); - assert_true(buffer_seek_write_cur(&buf, 1)); - assert_int_equal(buffer_empty_space_len(&buf), 0); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + assert_int_equal(rw_buffer_empty_space_len(&buf), 1); + assert_true(rw_buffer_seek_write_cur(&buf, 1)); + assert_int_equal(rw_buffer_empty_space_len(&buf), 0); } static void test_buffer_data_len(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_int_equal(buffer_data_len(&buf), 0); - assert_true(buffer_seek_write_cur(&buf, 1)); - assert_int_equal(buffer_data_len(&buf), 1); - assert_true(buffer_seek_read_cur(&buf, 1)); - assert_int_equal(buffer_data_len(&buf), 0); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + assert_int_equal(rw_buffer_data_len(&buf), 0); + assert_true(rw_buffer_seek_write_cur(&buf, 1)); + assert_int_equal(rw_buffer_data_len(&buf), 1); + assert_true(rw_buffer_seek_read_cur(&buf, 1)); + assert_int_equal(rw_buffer_data_len(&buf), 0); } static void test_buffer_read_position(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_int_equal(buffer_read_position(&buf), 0); - assert_true(buffer_seek_read_cur(&buf, 1)); - assert_int_equal(buffer_read_position(&buf), 1); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + assert_int_equal(rw_buffer_read_position(&buf), 0); + assert_true(rw_buffer_seek_read_cur(&buf, 1)); + assert_int_equal(rw_buffer_read_position(&buf), 1); } static void test_buffer_write_position(void **state) { (void) state; uint8_t temp[1] = {0x01}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_int_equal(buffer_write_position(&buf), 0); - assert_true(buffer_seek_write_cur(&buf, 1)); - assert_int_equal(buffer_write_position(&buf), 1); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + assert_int_equal(rw_buffer_write_position(&buf), 0); + assert_true(rw_buffer_seek_write_cur(&buf, 1)); + assert_int_equal(rw_buffer_write_position(&buf), 1); } static void test_buffer_seek_read(void **state) { (void) state; uint8_t temp[20] = {0}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_can_read(&buf, 20)); + assert_true(rw_buffer_can_read(&buf, 20)); - assert_true(buffer_seek_read_cur(&buf, 20)); // seek at offset 20 - assert_false(buffer_can_read(&buf, 1)); // can't read 1 byte - assert_false(buffer_seek_read_cur(&buf, 1)); // can't move at offset 21 + assert_true(rw_buffer_seek_read_cur(&buf, 20)); // seek at offset 20 + assert_false(rw_buffer_can_read(&buf, 1)); // can't read 1 byte + assert_false(rw_buffer_seek_read_cur(&buf, 1)); // can't move at offset 21 - assert_true(buffer_seek_read_end(&buf, 19)); - assert_int_equal(buf.read_offset, 1); - assert_false(buffer_seek_read_end(&buf, 21)); // can't seek at offset -1 + assert_true(rw_buffer_seek_read_end(&buf, 19)); + assert_int_equal(buf.read.offset, 1); + assert_false(rw_buffer_seek_read_end(&buf, 21)); // can't seek at offset -1 - assert_true(buffer_seek_read_set(&buf, 10)); - assert_int_equal(buf.read_offset, 10); - assert_false(buffer_seek_read_set(&buf, 21)); // can't seek at offset 21 + assert_true(rw_buffer_seek_read_set(&buf, 10)); + assert_int_equal(buf.read.offset, 10); + assert_false(rw_buffer_seek_read_set(&buf, 21)); // can't seek at offset 21 } static void test_buffer_seek_write(void **state) { (void) state; uint8_t temp[20] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_true(buffer_can_write(&buf, 20)); + assert_true(rw_buffer_can_write(&buf, 20)); - assert_true(buffer_seek_write_cur(&buf, 20)); // seek at offset 20 - assert_false(buffer_can_write(&buf, 1)); // can't write 1 byte - assert_false(buffer_seek_write_cur(&buf, 1)); // can't move at offset 21 + assert_true(rw_buffer_seek_write_cur(&buf, 20)); // seek at offset 20 + assert_false(rw_buffer_can_write(&buf, 1)); // can't write 1 byte + assert_false(rw_buffer_seek_write_cur(&buf, 1)); // can't move at offset 21 - assert_true(buffer_seek_write_end(&buf, 19)); - assert_int_equal(buf.write_offset, 1); - assert_false(buffer_seek_write_end(&buf, 21)); // can't seek at offset -1 + assert_true(rw_buffer_seek_write_end(&buf, 19)); + assert_int_equal(buf.read.size, 1); + assert_false(rw_buffer_seek_write_end(&buf, 21)); // can't seek at offset -1 - assert_true(buffer_seek_write_set(&buf, 10)); - assert_int_equal(buf.write_offset, 10); - assert_false(buffer_seek_write_set(&buf, 21)); // can't seek at offset 21 + assert_true(rw_buffer_seek_write_set(&buf, 10)); + assert_int_equal(buf.read.size, 10); + assert_false(rw_buffer_seek_write_set(&buf, 21)); // can't seek at offset 21 } static void test_buffer_read(void **state) { @@ -223,43 +223,43 @@ static void test_buffer_read(void **state) { 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E }; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); uint8_t first = 0; - assert_true(buffer_read_u8(&buf, &first)); + assert_true(rw_buffer_read_u8(&buf, &first)); assert_int_equal(first, 255); // 0xFF - assert_true(buffer_seek_read_end(&buf, 0)); // seek at offset 19 - assert_false(buffer_read_u8(&buf, &first)); // can't read 1 byte + assert_true(rw_buffer_seek_read_end(&buf, 0)); // seek at offset 19 + assert_false(rw_buffer_read_u8(&buf, &first)); // can't read 1 byte uint16_t second = 0; - assert_true(buffer_seek_read_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_read_u16(&buf, &second, BE)); // big endian + assert_true(rw_buffer_seek_read_set(&buf, 1)); // set back to offset 1 + assert_true(rw_buffer_read_u16(&buf, &second, BE)); // big endian assert_int_equal(second, 258); // 0x01 0x02 - assert_true(buffer_seek_read_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_read_u16(&buf, &second, LE)); // little endian + assert_true(rw_buffer_seek_read_set(&buf, 1)); // set back to offset 1 + assert_true(rw_buffer_read_u16(&buf, &second, LE)); // little endian assert_int_equal(second, 513); // 0x02 0x01 - assert_true(buffer_seek_read_set(&buf, 14)); // seek at offset 14 - assert_false(buffer_read_u16(&buf, &second, BE)); // can't read 2 bytes + assert_true(rw_buffer_seek_read_set(&buf, 14)); // seek at offset 14 + assert_false(rw_buffer_read_u16(&buf, &second, BE)); // can't read 2 bytes uint32_t third = 0; - assert_true(buffer_seek_read_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_read_u32(&buf, &third, BE)); // big endian + assert_true(rw_buffer_seek_read_set(&buf, 3)); // set back to offset 3 + assert_true(rw_buffer_read_u32(&buf, &third, BE)); // big endian assert_int_equal(third, 50595078); // 0x03 0x04 0x05 0x06 - assert_true(buffer_seek_read_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_read_u32(&buf, &third, LE)); // little endian + assert_true(rw_buffer_seek_read_set(&buf, 3)); // set back to offset 3 + assert_true(rw_buffer_read_u32(&buf, &third, LE)); // little endian assert_int_equal(third, 100992003); // 0x06 0x05 0x04 0x03 - assert_true(buffer_seek_read_set(&buf, 12)); // seek at offset 12 - assert_false(buffer_read_u32(&buf, &third, BE)); // can't read 4 bytes + assert_true(rw_buffer_seek_read_set(&buf, 12)); // seek at offset 12 + assert_false(rw_buffer_read_u32(&buf, &third, BE)); // can't read 4 bytes uint64_t fourth = 0; - assert_true(buffer_seek_read_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_read_u64(&buf, &fourth, BE)); // big endian + assert_true(rw_buffer_seek_read_set(&buf, 7)); // set back to offset 7 + assert_true(rw_buffer_read_u64(&buf, &fourth, BE)); // big endian assert_int_equal(fourth, 506664896818842894); // 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E - assert_true(buffer_seek_read_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_read_u64(&buf, &fourth, LE)); // little endian + assert_true(rw_buffer_seek_read_set(&buf, 7)); // set back to offset 7 + assert_true(rw_buffer_read_u64(&buf, &fourth, LE)); // little endian assert_int_equal(fourth, 1012478732780767239); // 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 - assert_true(buffer_seek_read_set(&buf, 8)); // seek at offset 8 - assert_false(buffer_read_u64(&buf, &fourth, BE)); // can't read 8 bytes + assert_true(rw_buffer_seek_read_set(&buf, 8)); // seek at offset 8 + assert_false(rw_buffer_read_u64(&buf, &fourth, BE)); // can't read 8 bytes } static void test_buffer_read_bip32_path(void **state) { @@ -274,63 +274,61 @@ static void test_buffer_read_bip32_path(void **state) { }; uint32_t expected[5] = {0x8000002C, 0x80000001, 0x80000000, 0, 0}; uint32_t out[5] = {0}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_read_bip32_path(&buf, out, 5)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + assert_true(rw_buffer_read_bip32_path(&buf, out, 5)); assert_memory_equal(out, expected, 5); - assert_int_equal(buf.read_offset, sizeof(expected)); - assert_false(buffer_read_bip32_path(&buf, out, 6)); + assert_int_equal(buf.read.offset, sizeof(expected)); + assert_false(rw_buffer_read_bip32_path(&buf, out, 6)); } static void test_buffer_write(void **state) { (void) state; // clang-format off - uint8_t temp[15] = { - 0xFF, - 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E - }; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + uint8_t temp[8] = {0x0}; + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); uint8_t first = 0xFF; - assert_true(buffer_write_u8(&buf, first)); - assert_int_equal(first, 255); // 0xFF - assert_true(buffer_seek_write_end(&buf, 0)); // seek at offset 19 - assert_false(buffer_write_u8(&buf, first)); // can't write 1 byte - - uint16_t second_be = 0x0102; - uint16_t second_le = 0x0201; - assert_true(buffer_seek_write_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_write_u16(&buf, second_be, BE)); // big endian - assert_int_equal(second_be, 258); // 0x01 0x02 - assert_true(buffer_seek_write_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_write_u16(&buf, second_le, LE)); // little endian - assert_int_equal(second_le, 513); // 0x02 0x01 - assert_true(buffer_seek_write_set(&buf, 14)); // seek at offset 14 - assert_false(buffer_write_u16(&buf, second_be, BE)); // can't write 2 bytes - - uint32_t third_be = 0x03040506; - uint32_t third_le = 0x06050403; - assert_true(buffer_seek_write_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_write_u32(&buf, third_be, BE)); // big endian - assert_int_equal(third_be, 50595078); // 0x03 0x04 0x05 0x06 - assert_true(buffer_seek_write_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_write_u32(&buf, third_le, LE)); // little endian - assert_int_equal(third_le, 100992003); // 0x06 0x05 0x04 0x03 - assert_true(buffer_seek_write_set(&buf, 12)); // seek at offset 12 - assert_false(buffer_write_u32(&buf, third_be, BE)); // can't write 4 bytes - - uint64_t fourth_be = 0x0708090A0B0C0D0E; - uint64_t fourth_le = 0x0E0D0C0B0A090807; - assert_true(buffer_seek_write_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_write_u64(&buf, fourth_be, BE)); // big endian - assert_int_equal(fourth_be, 506664896818842894); // 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E - assert_true(buffer_seek_write_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_write_u64(&buf, fourth_le, LE)); // little endian - assert_int_equal(fourth_le, 1012478732780767239); // 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 - assert_true(buffer_seek_write_set(&buf, 8)); // seek at offset 8 - assert_false(buffer_write_u64(&buf, fourth_be, BE)); // can't write 8 bytes + assert_true(rw_buffer_write_u8(&buf, first)); + assert_int_equal(temp[0], 255); // 0xFF + assert_true(rw_buffer_seek_write_end(&buf, 0)); // seek at offset 19 + assert_false(rw_buffer_write_u8(&buf, first)); // can't write 1 byte + + uint16_t second = 0x0102; + uint8_t second_be[] = {0x01, 0x02}; + uint8_t second_le[] = {0x02, 0x01}; + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u16(&buf, second, BE)); // big endian + assert_memory_equal(temp, second_be, 2); // 0x01 0x02 + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u16(&buf, second, LE)); // little endian + assert_memory_equal(temp, second_le, 2); // 0x02 0x01 + assert_true(rw_buffer_seek_write_set(&buf, 7)); // seek at offset 7 + assert_false(rw_buffer_write_u16(&buf, second, BE)); // can't write 2 bytes + + uint32_t third = 0x03040506; + uint8_t third_be[] = {0x03, 0x04, 0x05, 0x06}; + uint8_t third_le[] = {0x06, 0x05, 0x04, 0x03}; + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u32(&buf, third, BE)); // big endian + assert_memory_equal(temp, third_be, 4); // 0x03 0x04 0x05 0x06 + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u32(&buf, third, LE)); // little endian + assert_memory_equal(temp, third_le, 4); // 0x06 0x05 0x04 0x03 + assert_true(rw_buffer_seek_write_set(&buf, 5)); // seek at offset 5 + assert_false(rw_buffer_write_u32(&buf, third, BE)); // can't write 4 bytes + + uint64_t fourth = 0x0708090A0B0C0D0E; + uint8_t fourth_be[] = {0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E}; + uint8_t fourth_le[] = {0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07}; + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u64(&buf, fourth, BE)); // big endian + assert_memory_equal(temp, fourth_be, 8); // 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E + assert_true(rw_buffer_seek_write_set(&buf, 0)); // set back to offset 0 + assert_true(rw_buffer_write_u64(&buf, fourth, LE)); // little endian + assert_memory_equal(temp, fourth_le, 8); // 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 + assert_true(rw_buffer_seek_write_set(&buf, 1)); // seek at offset 1 + assert_false(rw_buffer_write_u64(&buf, fourth, BE)); // can't write 8 bytes } static void test_buffer_read_bytes(void **state) { @@ -338,14 +336,14 @@ static void test_buffer_read_bytes(void **state) { uint8_t output[5] = {0}; uint8_t temp[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_read_bytes(&buf, output, sizeof(output))); + assert_true(rw_buffer_read_bytes(&buf, output, sizeof(output))); assert_memory_equal(output, temp, sizeof(output)); - assert_int_equal(buf.read_offset, sizeof(output)); + assert_int_equal(buf.read.offset, sizeof(output)); uint8_t output2[3] = {0}; - assert_false(buffer_read_bytes(&buf, output2, sizeof(output2))); // can't read 3 bytes + assert_false(rw_buffer_read_bytes(&buf, output2, sizeof(output2))); // can't read 3 bytes } static void test_buffer_copy_bytes(void **state) { @@ -353,17 +351,17 @@ static void test_buffer_copy_bytes(void **state) { uint8_t output[5] = {0}; uint8_t temp[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_copy_bytes(&buf, output, sizeof(output))); + assert_true(rw_buffer_copy_bytes(&buf, output, sizeof(output))); assert_memory_equal(output, temp, sizeof(output)); uint8_t output2[3] = {0}; - assert_true(buffer_seek_read_set(&buf, 2)); - assert_true(buffer_copy_bytes(&buf, output2, sizeof(output2))); + assert_true(rw_buffer_seek_read_set(&buf, 2)); + assert_true(rw_buffer_copy_bytes(&buf, output2, sizeof(output2))); assert_memory_equal(output2, ((uint8_t[3]){0x03, 0x04, 0x05}), 3); - assert_true(buffer_seek_read_set(&buf, 0)); // seek at offset 0 - assert_false(buffer_copy_bytes(&buf, output2, sizeof(output2))); // can't read 5 bytes + assert_true(rw_buffer_seek_read_set(&buf, 3)); // seek at offset 3 + assert_false(rw_buffer_copy_bytes(&buf, output2, sizeof(output2))); // can't read 3 bytes } static void test_buffer_write_bytes(void **state) { @@ -371,21 +369,21 @@ static void test_buffer_write_bytes(void **state) { uint8_t input[2] = {0x01, 0x02}; uint8_t temp[5] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, temp, sizeof(temp)); - assert_true(buffer_write_bytes(&buf, input, sizeof(input))); + assert_true(rw_buffer_write_bytes(&buf, input, sizeof(input))); assert_memory_equal(input, temp, sizeof(input)); - assert_int_equal(buf.write_offset, sizeof(input)); + assert_int_equal(buf.read.size, sizeof(input)); uint8_t input2[3] = {0x03, 0x04, 0x05}; - assert_true(buffer_write_bytes(&buf, input2, sizeof(input2))); - assert_int_equal(buf.write_offset, sizeof(temp)); + assert_true(rw_buffer_write_bytes(&buf, input2, sizeof(input2))); + assert_int_equal(buf.read.size, sizeof(temp)); uint8_t expected[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; assert_memory_equal(expected, temp, sizeof(expected)); uint8_t input3[1] = {0x01}; - assert_false(buffer_write_bytes(&buf, input3, sizeof(input3))); // can't write bytes - assert_int_equal(buf.write_offset, sizeof(temp)); // nothing is changed + assert_false(rw_buffer_write_bytes(&buf, input3, sizeof(input3))); // can't write bytes + assert_int_equal(buf.read.size, sizeof(temp)); // nothing is changed assert_memory_equal(expected, temp, sizeof(expected)); // nothing is changed } @@ -394,11 +392,11 @@ static void test_buffer_shift_data(void **state) { uint8_t temp[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; uint16_t shift = 2; - BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); - assert_true(buffer_seek_read_cur(&buf, shift)); - buffer_shift_data(&buf); - assert_int_equal(buf.write_offset, sizeof(temp) - shift); - assert_int_equal(buf.read_offset, 0); + RW_BUFFER_FROM_ARRAY_FULL(buf, temp, sizeof(temp)); + assert_true(rw_buffer_seek_read_cur(&buf, shift)); + rw_buffer_shift_data(&buf); + assert_int_equal(buf.read.size, sizeof(temp) - shift); + assert_int_equal(buf.read.offset, 0); uint8_t expected[3] = {0x03, 0x04, 0x05}; assert_memory_equal(expected, temp, sizeof(expected)); } diff --git a/unit-tests/test_ergo_tree.c b/unit-tests/test_ergo_tree.c index 87f7e1da..d8c0331e 100644 --- a/unit-tests/test_ergo_tree.c +++ b/unit-tests/test_ergo_tree.c @@ -12,22 +12,17 @@ static void test_ergo_tree_generate_p2pk(void **state) { (void) state; const uint8_t raw_public_key[PUBLIC_KEY_LEN] = { - 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, - 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, - 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, - 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, 0x59, - 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, - 0x1a, 0x60, 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, - 0xe5, 0xcf, 0xf1, 0x0a, 0xe7 - }; + 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, + 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, + 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, + 0x59, 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, 0x1a, 0x60, + 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, 0xe5, 0xcf, 0xf1, 0x0a, 0xe7}; uint8_t tree[ERGO_TREE_P2PK_LEN] = {0}; ergo_tree_generate_p2pk(raw_public_key, tree); - uint8_t expected[ERGO_TREE_P2PK_LEN] = { - 0x00, 0x08, 0xcd, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, - 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, - 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, - 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a - }; + uint8_t expected[ERGO_TREE_P2PK_LEN] = {0x00, 0x08, 0xcd, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, + 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, + 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, + 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a}; assert_memory_equal(tree, expected, sizeof(expected)); } @@ -45,8 +40,7 @@ static void test_ergo_tree_miners_fee_tree_mainnet(void **state) { 0xf8, 0x17, 0x98, 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, 0x8c, 0xc7, 0xa7, 0x01, 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, 0x73, 0x00, 0x00, 0x01, 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, 0x00, 0x74, - 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04 - }; + 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04}; assert_int_equal(size, sizeof(expected)); assert_memory_equal(tree, expected, sizeof(expected)); } @@ -65,8 +59,7 @@ static void test_ergo_tree_miners_fee_tree_testnet(void **state) { 0xf8, 0x17, 0x98, 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, 0x8c, 0xc7, 0xa7, 0x01, 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, 0x73, 0x00, 0x00, 0x01, 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, 0x00, 0x74, - 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04 - }; + 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04}; assert_int_equal(size, sizeof(expected)); assert_memory_equal(tree, expected, sizeof(expected)); } diff --git a/unit-tests/test_format.c b/unit-tests/test_format.c deleted file mode 100644 index 5ce969cd..00000000 --- a/unit-tests/test_format.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/format.h" - -static void test_format_i64(void **state) { - (void) state; - - char temp[22] = {0}; - - int64_t value = 0; - assert_int_equal(format_i64(temp, sizeof(temp), value), 1); - assert_string_equal(temp, "0"); - - value = (int64_t) 9223372036854775807ull; // MAX_INT64 - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_i64(temp, sizeof(temp), value), 19); - assert_string_equal(temp, "9223372036854775807"); - - // buffer too small - assert_int_equal(format_i64(temp, sizeof(temp) - 5, value), -1); - - value = (int64_t) -9223372036854775808ull; // MIN_INT64 - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_i64(temp, sizeof(temp), value), 20); - assert_string_equal(temp, "-9223372036854775808"); -} - -static void test_format_u64(void **state) { - (void) state; - - char temp[21] = {0}; - - uint64_t value = 0; - assert_int_equal(format_u64(temp, sizeof(temp), value), 1); - assert_string_equal(temp, "0"); - - value = (uint64_t) 18446744073709551615ull; // MAX_UNT64 - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_u64(temp, sizeof(temp), value), 20); - assert_string_equal(temp, "18446744073709551615"); - - // buffer too small - assert_int_equal(format_u64(temp, sizeof(temp) - 5, value), -1); -} - -static void test_format_fpu64(void **state) { - (void) state; - - char temp[22] = {0}; - - uint64_t amount = 0ull; - assert_int_equal(format_fpu64(temp, sizeof(temp), amount, 0), 2); - assert_string_equal(temp, "0."); - - amount = 0ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_fpu64(temp, sizeof(temp), amount, 8), 10); - assert_string_equal(temp, "0.00000000"); - - amount = 100000000ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_fpu64(temp, sizeof(temp), amount, 8), 10); - assert_string_equal(temp, "1.00000000"); // BTC - - amount = 24964823ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_fpu64(temp, sizeof(temp), amount, 8), 10); - assert_string_equal(temp, "0.24964823"); // BTC - - amount = 100ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_int_equal(format_fpu64(temp, sizeof(temp), amount, 8), 10); - assert_string_equal(temp, "0.00000100"); // BTC - // buffer too small - assert_int_equal(format_fpu64(temp, sizeof(temp) - 16, amount, 8), -1); - - char temp2[50] = {0}; - - amount = 1000000000000000000ull; // wei - assert_int_equal(format_fpu64(temp2, sizeof(temp2), amount, 18), 20); - assert_string_equal(temp2, "1.000000000000000000"); // ETH - - // buffer too small - assert_int_equal(format_fpu64(temp2, sizeof(temp2) - 20, amount, 18), -1); -} - -static void test_format_hex(void **state) { - (void) state; - - uint8_t input1[1] = {0x00}; - char output1[2 * sizeof(input1) + 1] = {0}; - assert_int_equal(2 * sizeof(input1), - format_hex(input1, sizeof(input1), output1, sizeof(output1))); - assert_string_equal(output1, "00"); - - uint8_t address[] = {0xde, 0xb, 0x29, 0x56, 0x69, 0xa9, 0xfd, 0x93, 0xd5, 0xf2, - 0x8d, 0x9e, 0xc8, 0x5e, 0x40, 0xf4, 0xcb, 0x69, 0x7b, 0xae}; - char output[2 * sizeof(address) + 1] = {0}; - - assert_int_equal(2 * sizeof(address), - format_hex(address, sizeof(address), output, sizeof(output))); - assert_string_equal(output, "de0b295669a9fd93d5f28d9ec85e40f4cb697bae"); - assert_int_equal(-1, format_hex(address, sizeof(address), output, sizeof(address))); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_format_i64), - cmocka_unit_test(test_format_u64), - cmocka_unit_test(test_format_fpu64), - cmocka_unit_test(test_format_hex)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_full_tx.c b/unit-tests/test_full_tx.c index 78c2e549..86678b56 100644 --- a/unit-tests/test_full_tx.c +++ b/unit-tests/test_full_tx.c @@ -7,6 +7,8 @@ #include #include "ergo/tx_ser_full.h" +#include "common/rwbuffer.h" +#include "macro_helpers.h" #include @@ -48,7 +50,7 @@ static void test_simple_send_tx(void** state) { ERGO_TX_SERIALIZER_FULL_RES_OK); // Adding address tree. - BUFFER_FROM_ARRAY_FULL(OUT_ERGO_TREE_BUF, OUT_ERGO_TREE, sizeof(OUT_ERGO_TREE)); + BUFFER_FROM_ARRAY(OUT_ERGO_TREE_BUF, OUT_ERGO_TREE, sizeof(OUT_ERGO_TREE)); assert_int_equal(ergo_tx_serializer_full_add_box_ergo_tree(&ctx, &OUT_ERGO_TREE_BUF), ERGO_TX_SERIALIZER_FULL_RES_OK); @@ -74,7 +76,7 @@ static void test_simple_send_tx(void** state) { ERGO_TX_SERIALIZER_FULL_RES_OK); // Adding tree. - BUFFER_FROM_ARRAY_FULL(CHANGE_ERGO_TREE_BUF, CHANGE_ERGO_TREE, sizeof(CHANGE_ERGO_TREE)); + BUFFER_FROM_ARRAY(CHANGE_ERGO_TREE_BUF, CHANGE_ERGO_TREE, sizeof(CHANGE_ERGO_TREE)); assert_int_equal(ergo_tx_serializer_full_add_box_ergo_tree(&ctx, &CHANGE_ERGO_TREE_BUF), ERGO_TX_SERIALIZER_FULL_RES_OK); @@ -87,8 +89,6 @@ static void test_simple_send_tx(void** state) { 0xc7, 0x18, 0x6d, 0x8d, 0x41, 0x78, 0x01, 0x58, 0xd5, 0xb3, 0xbe, 0x56, 0x45, 0x56, 0x4a, 0x5d}; - - // Calculating hash assert_true(blake2b_256_finalize(&hash, tx_id)); @@ -114,31 +114,17 @@ static void test_ergo_tx_serializer_full_init(void** state) { uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - assert_int_equal( - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + token_table_t tokens_table = {0}; + assert_int_equal(ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table), + ERGO_TX_SERIALIZER_FULL_RES_OK); uint8_t expected_hash[] = {0x01}; - uint8_t *data; + uint8_t* data; size_t data_len; _cx_blake2b_get_data(context.hash, &data, &data_len); assert_int_equal(data_len, sizeof(expected_hash)); @@ -148,9 +134,8 @@ static void test_ergo_tx_serializer_full_init(void** state) { assert_int_equal(context.data_inputs_count, data_inputs_count); assert_int_equal(context.outputs_count, outputs_count); assert_int_equal(tokens_table.count, 0); - assert_memory_equal(context.tokens_table, &tokens_table, sizeof(tokens_table)); - assert_int_equal(context.table_ctx.tokens_count, tokens_count); - assert_memory_equal(context.table_ctx.tokens_table, &tokens_table, sizeof(tokens_table)); + assert_int_equal(context.table_ctx.distinct_tokens_count, tokens_count); + assert_ptr_equal(context.table_ctx.tokens_table, &tokens_table); assert_int_equal(context.state, ERGO_TX_SERIALIZER_FULL_STATE_TOKENS_STARTED); } @@ -164,31 +149,17 @@ static void test_ergo_tx_serializer_full_init_zero_tokens(void** state) { uint8_t tokens_count = 0; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - assert_int_equal( - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + token_table_t tokens_table = {0}; + assert_int_equal(ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table), + ERGO_TX_SERIALIZER_FULL_RES_OK); uint8_t expected_hash[] = {0x01}; - uint8_t *data; + uint8_t* data; size_t data_len; _cx_blake2b_get_data(context.hash, &data, &data_len); assert_int_equal(data_len, sizeof(expected_hash)); @@ -198,8 +169,8 @@ static void test_ergo_tx_serializer_full_init_zero_tokens(void** state) { assert_int_equal(context.data_inputs_count, data_inputs_count); assert_int_equal(context.outputs_count, outputs_count); assert_int_equal(tokens_table.count, 0); - assert_memory_equal(context.tokens_table, &tokens_table, sizeof(tokens_table)); - assert_int_equal(context.table_ctx.tokens_count, tokens_count); + assert_ptr_equal(context.table_ctx.tokens_table, &tokens_table); + assert_int_equal(context.table_ctx.distinct_tokens_count, tokens_count); assert_int_equal(context.state, ERGO_TX_SERIALIZER_FULL_STATE_INPUTS_STARTED); assert_int_equal(context.input_ctx.state, ERGO_TX_SERIALIZER_INPUT_STATE_FINISHED); } @@ -214,40 +185,21 @@ static void test_ergo_tx_serializer_full_add_tokens(void** state) { uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - assert_int_equal( - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - assert_int_equal( - ergo_tx_serializer_full_add_tokens(&context, &tokens), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + token_table_t tokens_table = {0}; + assert_int_equal(ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table), + ERGO_TX_SERIALIZER_FULL_RES_OK); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_full_add_tokens(&context, &tokens), + ERGO_TX_SERIALIZER_FULL_RES_OK); assert_int_equal(context.state, ERGO_TX_SERIALIZER_FULL_STATE_INPUTS_STARTED); assert_int_equal(context.input_ctx.state, ERGO_TX_SERIALIZER_INPUT_STATE_FINISHED); } @@ -262,51 +214,29 @@ static void test_ergo_tx_serializer_full_add_input(void** state) { uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + token_table_t tokens_table = {0}; + ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); ergo_tx_serializer_full_add_tokens(&context, &tokens); - uint8_t box_id[32] = { - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03 - }; + uint8_t box_id[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; uint8_t token_frames_count = 1; uint32_t context_extension_data_size = 2; - assert_int_equal( - ergo_tx_serializer_full_add_input( - &context, - box_id, - token_frames_count, - context_extension_data_size - ), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + assert_int_equal(ergo_tx_serializer_full_add_input(&context, + box_id, + token_frames_count, + context_extension_data_size), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_input_tokens(void** state) { @@ -319,61 +249,39 @@ static void test_ergo_tx_serializer_full_add_input_tokens(void** state) { uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + token_table_t tokens_table = {0}; + ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); ergo_tx_serializer_full_add_tokens(&context, &tokens); - uint8_t box_id[32] = { - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03 - }; + uint8_t box_id[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; uint8_t token_frames_count = 1; uint32_t context_extension_data_size = 2; - ergo_tx_serializer_full_add_input( - &context, - box_id, - token_frames_count, - context_extension_data_size - ); + ergo_tx_serializer_full_add_input(&context, + box_id, + token_frames_count, + context_extension_data_size); uint8_t token_frame_index = 0; - uint8_t input_tokens_array[40] = { - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 - }; - BUFFER_FROM_ARRAY_FULL(input_tokens, input_tokens_array, sizeof(input_tokens_array)); - assert_int_equal( - ergo_tx_serializer_full_add_input_tokens(&context, box_id, token_frame_index, &input_tokens), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + uint8_t input_tokens_array[] = {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + BUFFER_FROM_ARRAY(input_tokens, input_tokens_array, sizeof(input_tokens_array)); + assert_int_equal(ergo_tx_serializer_full_add_input_tokens(&context, + box_id, + token_frame_index, + &input_tokens), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_input_context_extension(void** state) { @@ -386,66 +294,40 @@ static void test_ergo_tx_serializer_full_add_input_context_extension(void** stat uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + token_table_t tokens_table = {0}; + ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); ergo_tx_serializer_full_add_tokens(&context, &tokens); - uint8_t box_id[32] = { - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03 - }; + uint8_t box_id[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; uint8_t token_frames_count = 1; uint32_t context_extension_data_size = 2; - ergo_tx_serializer_full_add_input( - &context, - box_id, - token_frames_count, - context_extension_data_size - ); + ergo_tx_serializer_full_add_input(&context, + box_id, + token_frames_count, + context_extension_data_size); uint8_t token_frame_index = 0; - uint8_t input_tokens_array[40] = { - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 - }; - BUFFER_FROM_ARRAY_FULL(input_tokens, input_tokens_array, sizeof(input_tokens_array)); + uint8_t input_tokens_array[] = {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + BUFFER_FROM_ARRAY(input_tokens, input_tokens_array, sizeof(input_tokens_array)); ergo_tx_serializer_full_add_input_tokens(&context, box_id, token_frame_index, &input_tokens); - uint8_t extension_chunk_array[2] = { - 0x01, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); + uint8_t extension_chunk_array[2] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); assert_int_equal( ergo_tx_serializer_full_add_input_context_extension(&context, &extension_chunk), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_data_inputs(void** state) { @@ -458,164 +340,102 @@ static void test_ergo_tx_serializer_full_add_data_inputs(void** state) { uint8_t tokens_count = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - ergo_tx_serializer_full_init( - &context, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count, - &hash, - &tokens_table - ); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + token_table_t tokens_table = {0}; + ergo_tx_serializer_full_init(&context, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count, + &hash, + &tokens_table); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); ergo_tx_serializer_full_add_tokens(&context, &tokens); - uint8_t box_id[32] = { - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03 - }; + uint8_t box_id[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; uint8_t token_frames_count = 1; uint32_t context_extension_data_size = 2; - ergo_tx_serializer_full_add_input( - &context, - box_id, - token_frames_count, - context_extension_data_size - ); + ergo_tx_serializer_full_add_input(&context, + box_id, + token_frames_count, + context_extension_data_size); uint8_t token_frame_index = 0; - uint8_t input_tokens_array[40] = { - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 - }; - BUFFER_FROM_ARRAY_FULL(input_tokens, input_tokens_array, sizeof(input_tokens_array)); + uint8_t input_tokens_array[] = {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + BUFFER_FROM_ARRAY(input_tokens, input_tokens_array, sizeof(input_tokens_array)); ergo_tx_serializer_full_add_input_tokens(&context, box_id, token_frame_index, &input_tokens); - uint8_t extension_chunk_array[2] = { - 0x01, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); + uint8_t extension_chunk_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); ergo_tx_serializer_full_add_input_context_extension(&context, &extension_chunk); - uint8_t inputs_array[32] = { - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05 - }; - BUFFER_FROM_ARRAY_FULL(inputs, inputs_array, sizeof(inputs_array)); - assert_int_equal( - ergo_tx_serializer_full_add_data_inputs(&context, &inputs), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + uint8_t inputs_array[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05}; + BUFFER_FROM_ARRAY(inputs, inputs_array, sizeof(inputs_array)); + assert_int_equal(ergo_tx_serializer_full_add_data_inputs(&context, &inputs), + ERGO_TX_SERIALIZER_FULL_RES_OK); } -#define ERGO_TX_SERIALIZER_FULL_ADD_BOX() \ - ergo_tx_serializer_full_context_t context; \ - uint16_t inputs_count = 1; \ - uint16_t data_inputs_count = 1; \ - uint16_t outputs_count = 1; \ - uint8_t tokens_count = 1; \ - cx_blake2b_t hash; \ - blake2b_256_init(&hash); \ - token_table_t tokens_table = { \ - 1, \ - { \ - { \ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, \ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, \ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, \ - 0x01, 0x01 \ - } \ - } \ - }; \ - ergo_tx_serializer_full_init( \ - &context, \ - inputs_count, \ - data_inputs_count, \ - outputs_count, \ - tokens_count, \ - &hash, \ - &tokens_table \ - ); \ - uint8_t tokens_array[32] = { \ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, \ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, \ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, \ - 0x02, 0x02 \ - }; \ - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); \ - ergo_tx_serializer_full_add_tokens(&context, &tokens); \ - uint8_t box_id[32] = { \ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \ - 0x03, 0x03 \ - }; \ - uint8_t token_frames_count = 1; \ - uint32_t context_extension_data_size = 2; \ - ergo_tx_serializer_full_add_input( \ - &context, \ - box_id, \ - token_frames_count, \ - context_extension_data_size \ - ); \ - uint8_t token_frame_index = 0; \ - uint8_t input_tokens_array[40] = { \ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ - 0x04, 0x04, \ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 \ - }; \ - BUFFER_FROM_ARRAY_FULL(input_tokens, input_tokens_array, sizeof(input_tokens_array)); \ +#define ERGO_TX_SERIALIZER_FULL_ADD_BOX() \ + ergo_tx_serializer_full_context_t context; \ + uint16_t inputs_count = 1; \ + uint16_t data_inputs_count = 1; \ + uint16_t outputs_count = 1; \ + uint8_t tokens_count = 1; \ + cx_blake2b_t hash; \ + blake2b_256_init(&hash); \ + token_table_t tokens_table = {0}; \ + ergo_tx_serializer_full_init(&context, \ + inputs_count, \ + data_inputs_count, \ + outputs_count, \ + tokens_count, \ + &hash, \ + &tokens_table); \ + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, \ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, \ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; \ + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); \ + ergo_tx_serializer_full_add_tokens(&context, &tokens); \ + uint8_t box_id[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \ + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \ + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}; \ + uint8_t token_frames_count = 1; \ + uint32_t context_extension_data_size = 2; \ + ergo_tx_serializer_full_add_input(&context, \ + box_id, \ + token_frames_count, \ + context_extension_data_size); \ + uint8_t token_frame_index = 0; \ + uint8_t input_tokens_array[] = {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, \ + 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; \ + BUFFER_FROM_ARRAY(input_tokens, input_tokens_array, sizeof(input_tokens_array)); \ ergo_tx_serializer_full_add_input_tokens(&context, box_id, token_frame_index, &input_tokens); \ - uint8_t extension_chunk_array[2] = { \ - 0x01, 0x02 \ - }; \ - BUFFER_FROM_ARRAY_FULL(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); \ - ergo_tx_serializer_full_add_input_context_extension(&context, &extension_chunk); \ - uint8_t inputs_array[32] = { \ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, \ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, \ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, \ - 0x05, 0x05 \ - }; \ - BUFFER_FROM_ARRAY_FULL(inputs, inputs_array, sizeof(inputs_array)); \ - ergo_tx_serializer_full_add_data_inputs(&context, &inputs); \ - uint64_t value = 12345; \ - uint32_t ergo_tree_size = 1; \ - uint32_t creation_height = 1; \ - uint32_t registers_size = 1; \ - assert_int_equal( \ - ergo_tx_serializer_full_add_box( \ - &context, \ - value, \ - ergo_tree_size, \ - creation_height, \ - tokens_count, \ - registers_size \ - ), \ - ERGO_TX_SERIALIZER_FULL_RES_OK \ - ); + uint8_t extension_chunk_array[] = {0x01, 0x02}; \ + BUFFER_FROM_ARRAY(extension_chunk, extension_chunk_array, sizeof(extension_chunk_array)); \ + ergo_tx_serializer_full_add_input_context_extension(&context, &extension_chunk); \ + uint8_t inputs_array[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, \ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, \ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05}; \ + BUFFER_FROM_ARRAY(inputs, inputs_array, sizeof(inputs_array)); \ + ergo_tx_serializer_full_add_data_inputs(&context, &inputs); \ + uint64_t value = 12345; \ + uint32_t ergo_tree_size = 1; \ + uint32_t creation_height = 1; \ + uint32_t registers_size = 1; \ + assert_int_equal(ergo_tx_serializer_full_add_box(&context, \ + value, \ + ergo_tree_size, \ + creation_height, \ + tokens_count, \ + registers_size), \ + ERGO_TX_SERIALIZER_FULL_RES_OK); static void test_ergo_tx_serializer_full_add_box(void** state) { (void) state; @@ -627,33 +447,24 @@ static void test_ergo_tx_serializer_full_add_box_ergo_tree(void** state) { (void) state; ERGO_TX_SERIALIZER_FULL_ADD_BOX(); - uint8_t tree_chunk_array[1] = { - 0x01 - }; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); - assert_int_equal( - ergo_tx_serializer_full_add_box_ergo_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + uint8_t tree_chunk_array[] = {0x01}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + assert_int_equal(ergo_tx_serializer_full_add_box_ergo_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_box_change_tree(void** state) { (void) state; ERGO_TX_SERIALIZER_FULL_ADD_BOX(); - const uint8_t raw_pub_key[65] = { - 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, - 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, - 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, - 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, 0x59, - 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, - 0x1a, 0x60, 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, - 0xe5, 0xcf, 0xf1, 0x0a, 0xe7 - }; - assert_int_equal( - ergo_tx_serializer_full_add_box_change_tree(&context, raw_pub_key), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + const uint8_t raw_pub_key[] = {0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, + 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, + 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, + 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, 0x59, 0x50, 0x0f, 0x5d, 0x31, + 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, 0x1a, 0x60, 0x53, 0xa1, 0x1d, + 0x53, 0x5d, 0x2d, 0x04, 0x3c, 0xe5, 0xcf, 0xf1, 0x0a, 0xe7}; + assert_int_equal(ergo_tx_serializer_full_add_box_change_tree(&context, raw_pub_key), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_box_miners_fee_tree(void** state) { @@ -661,72 +472,57 @@ static void test_ergo_tx_serializer_full_add_box_miners_fee_tree(void** state) { ERGO_TX_SERIALIZER_FULL_ADD_BOX(); bool is_mainnet = true; - assert_int_equal( - ergo_tx_serializer_full_add_box_miners_fee_tree(&context, is_mainnet), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + assert_int_equal(ergo_tx_serializer_full_add_box_miners_fee_tree(&context, is_mainnet), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_box_tokens(void** state) { (void) state; ERGO_TX_SERIALIZER_FULL_ADD_BOX(); - uint8_t tree_chunk_array[1] = { - 0x01 - }; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + uint8_t tree_chunk_array[] = {0x01}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_full_add_box_ergo_tree(&context, &tree_chunk); - uint8_t box_tokens_array[12] = { - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(box_tokens, box_tokens_array, sizeof(box_tokens_array)); - assert_int_equal( - ergo_tx_serializer_full_add_box_tokens(&context, &box_tokens), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + uint8_t box_tokens_array[] = + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(box_tokens, box_tokens_array, sizeof(box_tokens_array)); + assert_int_equal(ergo_tx_serializer_full_add_box_tokens(&context, &box_tokens), + ERGO_TX_SERIALIZER_FULL_RES_OK); } static void test_ergo_tx_serializer_full_add_box_registers(void** state) { (void) state; ERGO_TX_SERIALIZER_FULL_ADD_BOX(); - uint8_t tree_chunk_array[1] = { - 0x01 - }; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + uint8_t tree_chunk_array[1] = {0x01}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_full_add_box_ergo_tree(&context, &tree_chunk); - uint8_t box_tokens_array[12] = { - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(box_tokens, box_tokens_array, sizeof(box_tokens_array)); + uint8_t box_tokens_array[12] = + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(box_tokens, box_tokens_array, sizeof(box_tokens_array)); ergo_tx_serializer_full_add_box_tokens(&context, &box_tokens); - uint8_t registers_chunk_array[1] = { - 0x01 - }; - BUFFER_FROM_ARRAY_FULL(registers_chunk, registers_chunk_array, sizeof(registers_chunk_array)); - assert_int_equal( - ergo_tx_serializer_full_add_box_registers(&context, ®isters_chunk), - ERGO_TX_SERIALIZER_FULL_RES_OK - ); + uint8_t registers_chunk_array[1] = {0x01}; + BUFFER_FROM_ARRAY(registers_chunk, registers_chunk_array, sizeof(registers_chunk_array)); + assert_int_equal(ergo_tx_serializer_full_add_box_registers(&context, ®isters_chunk), + ERGO_TX_SERIALIZER_FULL_RES_OK); } int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_simple_send_tx), - cmocka_unit_test(test_ergo_tx_serializer_full_init), - cmocka_unit_test(test_ergo_tx_serializer_full_init_zero_tokens), - cmocka_unit_test(test_ergo_tx_serializer_full_add_tokens), - cmocka_unit_test(test_ergo_tx_serializer_full_add_input), - cmocka_unit_test(test_ergo_tx_serializer_full_add_input_tokens), - cmocka_unit_test(test_ergo_tx_serializer_full_add_input_context_extension), - cmocka_unit_test(test_ergo_tx_serializer_full_add_data_inputs), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box_ergo_tree), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box_change_tree), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box_miners_fee_tree), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box_tokens), - cmocka_unit_test(test_ergo_tx_serializer_full_add_box_registers)}; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_simple_send_tx), + cmocka_unit_test(test_ergo_tx_serializer_full_init), + cmocka_unit_test(test_ergo_tx_serializer_full_init_zero_tokens), + cmocka_unit_test(test_ergo_tx_serializer_full_add_tokens), + cmocka_unit_test(test_ergo_tx_serializer_full_add_input), + cmocka_unit_test(test_ergo_tx_serializer_full_add_input_tokens), + cmocka_unit_test(test_ergo_tx_serializer_full_add_input_context_extension), + cmocka_unit_test(test_ergo_tx_serializer_full_add_data_inputs), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box_ergo_tree), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box_change_tree), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box_miners_fee_tree), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box_tokens), + cmocka_unit_test(test_ergo_tx_serializer_full_add_box_registers)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_varint.c b/unit-tests/test_gve.c similarity index 87% rename from unit-tests/test_varint.c rename to unit-tests/test_gve.c index 74777a5e..3f0af597 100644 --- a/unit-tests/test_varint.c +++ b/unit-tests/test_gve.c @@ -6,13 +6,14 @@ #include -#include "common/varint.h" +#include "common/gve.h" +#include "macro_helpers.h" static void test_gve_get_u8(void **state) { (void) state; uint8_t tmp[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); uint8_t val; assert_int_equal(gve_get_u8(&buf, &val), GVE_OK); assert_int_equal(val, 0x01); @@ -25,7 +26,7 @@ static void test_gve_get_i8(void **state) { (void) state; uint8_t tmp[2] = {0x01, -0x02}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); int8_t val; assert_int_equal(gve_get_i8(&buf, &val), GVE_OK); assert_int_equal(val, 0x01); @@ -38,7 +39,7 @@ static void test_gve_get_u16(void **state) { (void) state; uint8_t tmp[3] = {0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); uint16_t val; assert_int_equal(gve_get_u16(&buf, &val), GVE_OK); assert_int_equal(val, 16643); @@ -48,7 +49,7 @@ static void test_gve_get_u16_too_big(void **state) { (void) state; uint8_t tmp[4] = {0x84, 0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); uint16_t val; assert_int_equal(gve_get_u16(&buf, &val), GVE_ERR_INT_TO_BIG); } @@ -57,7 +58,7 @@ static void test_gve_get_i16(void **state) { (void) state; uint8_t tmp[3] = {0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); int16_t val; assert_int_equal(gve_get_i16(&buf, &val), GVE_OK); assert_int_equal(val, -8322); @@ -67,7 +68,7 @@ static void test_gve_get_u32(void **state) { (void) state; uint8_t tmp[4] = {0x84, 0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); uint32_t val; assert_int_equal(gve_get_u32(&buf, &val), GVE_OK); assert_int_equal(val, 2130308); @@ -77,7 +78,7 @@ static void test_gve_get_i32(void **state) { (void) state; uint8_t tmp[4] = {0x85, 0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); int32_t val; assert_int_equal(gve_get_i32(&buf, &val), GVE_OK); assert_int_equal(val, -1065155); @@ -87,7 +88,7 @@ static void test_gve_get_u64(void **state) { (void) state; uint8_t tmp[6] = {0x86, 0x85, 0x84, 0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); uint64_t val; assert_int_equal(gve_get_u64(&buf, &val), GVE_OK); assert_int_equal(val, 34902966918); @@ -97,7 +98,7 @@ static void test_gve_get_i64(void **state) { (void) state; uint8_t tmp[6] = {0x87, 0x85, 0x84, 0x83, 0x82, 0x01}; - BUFFER_FROM_ARRAY_FULL(buf, tmp, sizeof(tmp)); + BUFFER_FROM_ARRAY(buf, tmp, sizeof(tmp)); int64_t val; assert_int_equal(gve_get_i64(&buf, &val), GVE_OK); assert_int_equal(val, -17451483460); @@ -107,7 +108,7 @@ static void test_gve_put_u8(void **state) { (void) state; uint8_t tmp[2] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); uint8_t val1 = 0x01; uint8_t expected1[1] = {0x01}; assert_int_equal(gve_put_u8(&buf, val1), GVE_OK); @@ -123,7 +124,7 @@ static void test_gve_put_i8(void **state) { (void) state; uint8_t tmp[2] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); int8_t val1 = -0x01; uint8_t expected1[1] = {-0x01}; assert_int_equal(gve_put_i8(&buf, val1), GVE_OK); @@ -139,7 +140,7 @@ static void test_gve_put_u16(void **state) { (void) state; uint8_t tmp[3] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); uint16_t val = 16643; uint8_t expected[3] = {0x83, 0x82, 0x01}; assert_int_equal(gve_put_u16(&buf, val), GVE_OK); @@ -150,7 +151,7 @@ static void test_gve_put_i16(void **state) { (void) state; uint8_t tmp[3] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); int16_t val = -8322; uint8_t expected[3] = {0x83, 0x82, 0x01}; assert_int_equal(gve_put_i16(&buf, val), GVE_OK); @@ -161,7 +162,7 @@ static void test_gve_put_u32(void **state) { (void) state; uint8_t tmp[4] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); uint32_t val = 2130308; uint8_t expected[4] = {0x84, 0x83, 0x82, 0x01}; assert_int_equal(gve_put_u32(&buf, val), GVE_OK); @@ -172,7 +173,7 @@ static void test_gve_put_i32(void **state) { (void) state; uint8_t tmp[4] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); int32_t val = -1065155; uint8_t expected[4] = {0x85, 0x83, 0x82, 0x01}; assert_int_equal(gve_put_i32(&buf, val), GVE_OK); @@ -183,7 +184,7 @@ static void test_gve_put_u64(void **state) { (void) state; uint8_t tmp[6] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); uint64_t val = 34902966918; uint8_t expected[6] = {0x86, 0x85, 0x84, 0x83, 0x82, 0x01}; assert_int_equal(gve_put_u64(&buf, val), GVE_OK); @@ -194,7 +195,7 @@ static void test_gve_put_i64(void **state) { (void) state; uint8_t tmp[6] = {0}; - BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); + RW_BUFFER_FROM_ARRAY_EMPTY(buf, tmp, sizeof(tmp)); int64_t val = -17451483460; uint8_t expected[6] = {0x87, 0x85, 0x84, 0x83, 0x82, 0x01}; assert_int_equal(gve_put_i64(&buf, val), GVE_OK); diff --git a/unit-tests/test_input_frame.c b/unit-tests/test_input_frame.c index f5b9604b..efa687d6 100644 --- a/unit-tests/test_input_frame.c +++ b/unit-tests/test_input_frame.c @@ -8,26 +8,21 @@ #include #include "helpers/input_frame.h" +#include "common/rwbuffer.h" +#include "macro_helpers.h" static void test_input_frame_data_length(void **state) { (void) state; - uint8_t input_array[99] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(input, input_array, sizeof(input_array)); + uint8_t input_array[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(input, input_array, sizeof(input_array)); uint8_t data_len = input_frame_data_length(&input); assert_int_equal(data_len, 83); } @@ -35,15 +30,12 @@ static void test_input_frame_data_length(void **state) { static void test_input_frame_data_length_bad_size(void **state) { (void) state; - uint8_t input_array[58] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - BUFFER_FROM_ARRAY_FULL(input, input_array, sizeof(input_array)); + uint8_t input_array[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + BUFFER_FROM_ARRAY(input, input_array, sizeof(input_array)); uint8_t data_len = input_frame_data_length(&input); assert_int_equal(data_len, 0); } @@ -51,22 +43,15 @@ static void test_input_frame_data_length_bad_size(void **state) { static void test_input_frame_data_length_bad_size_2(void **state) { (void) state; - uint8_t input_array[98] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(input, input_array, sizeof(input_array)); + uint8_t input_array[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(input, input_array, sizeof(input_array)); uint8_t data_len = input_frame_data_length(&input); assert_int_equal(data_len, 0); } @@ -74,44 +59,30 @@ static void test_input_frame_data_length_bad_size_2(void **state) { static void test_input_frame_signature_ptr(void **state) { (void) state; - uint8_t input_array[99] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(input, input_array, sizeof(input_array)); + uint8_t input_array[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(input, input_array, sizeof(input_array)); assert_ptr_equal(input_frame_signature_ptr(&input), buffer_read_ptr(&input) + 83); } static void test_input_frame_signature_ptr_null(void **state) { (void) state; - uint8_t input_array[98] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(input, input_array, sizeof(input_array)); + uint8_t input_array[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(input, input_array, sizeof(input_array)); assert_ptr_equal(input_frame_signature_ptr(&input), NULL); } diff --git a/unit-tests/test_read.c b/unit-tests/test_read.c deleted file mode 100644 index 108661c7..00000000 --- a/unit-tests/test_read.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "common/read.h" - -static void test_read_u16_be(void **state) { - (void) state; - - uint8_t tmp[2] = {0x01, 0x02}; - assert_int_equal(read_u16_be(tmp, 0), 0x0102); -} - -static void test_read_u16_le(void **state) { - (void) state; - - uint8_t tmp[2] = {0x01, 0x02}; - assert_int_equal(read_u16_le(tmp, 0), 0x0201); -} - -static void test_read_u32_be(void **state) { - (void) state; - - uint8_t tmp[4] = {0x01, 0x02, 0x03, 0x04}; - assert_int_equal(read_u32_be(tmp, 0), 0x01020304); -} - -static void test_read_u32_le(void **state) { - (void) state; - - uint8_t tmp[4] = {0x01, 0x02, 0x03, 0x04}; - assert_int_equal(read_u32_le(tmp, 0), 0x04030201); -} - -static void test_read_u64_be(void **state) { - (void) state; - - uint8_t tmp[8] = { - 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08 - }; - assert_int_equal(read_u64_be(tmp, 0), 0x0102030405060708); -} - -static void test_read_u64_le(void **state) { - (void) state; - - uint8_t tmp[8] = { - 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08 - }; - assert_int_equal(read_u64_le(tmp, 0), 0x0807060504030201); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_read_u16_be), - cmocka_unit_test(test_read_u16_le), - cmocka_unit_test(test_read_u32_be), - cmocka_unit_test(test_read_u32_le), - cmocka_unit_test(test_read_u64_be), - cmocka_unit_test(test_read_u64_le)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_int_ops.c b/unit-tests/test_safeint.c similarity index 98% rename from unit-tests/test_int_ops.c rename to unit-tests/test_safeint.c index e2855d8f..63362676 100644 --- a/unit-tests/test_int_ops.c +++ b/unit-tests/test_safeint.c @@ -6,7 +6,7 @@ #include -#include "common/int_ops.h" +#include "common/safeint.h" static void test_checked_add_u64_min(void **state) { (void) state; diff --git a/unit-tests/test_tx_ser_box.c b/unit-tests/test_tx_ser_box.c index 63faebb9..4ea8a48e 100644 --- a/unit-tests/test_tx_ser_box.c +++ b/unit-tests/test_tx_ser_box.c @@ -8,34 +8,32 @@ #include #include "ergo/tx_ser_box.h" - -#define ERGO_TX_SERIALIZER_BOX_INIT(name) \ - ergo_tx_serializer_box_context_t name; \ - uint64_t value = 12345; \ - uint32_t ergo_tree_size = 2; \ - uint32_t creation_height = 3; \ - uint8_t tokens_count = 2; \ - uint32_t registers_size = 2; \ - cx_blake2b_t hash; \ - assert_true(ergo_tx_serializer_box_id_hash_init(&hash)); \ - assert_int_equal( \ - ergo_tx_serializer_box_init( \ - &name, \ - value, \ - ergo_tree_size, \ - creation_height, \ - tokens_count, \ - registers_size, \ - &hash \ - ), \ - ERGO_TX_SERIALIZER_BOX_RES_OK \ - ); - -#define VERIFY_HASH(hash, expected) \ - uint8_t *data; \ - size_t data_len; \ - _cx_blake2b_get_data(hash, &data, &data_len); \ - assert_int_equal(data_len, sizeof(expected)); \ +#include "common/rwbuffer.h" +#include "macro_helpers.h" + +#define ERGO_TX_SERIALIZER_BOX_INIT(name) \ + ergo_tx_serializer_box_context_t name; \ + uint64_t value = 12345; \ + uint32_t ergo_tree_size = 2; \ + uint32_t creation_height = 3; \ + uint8_t tokens_count = 2; \ + uint32_t registers_size = 2; \ + cx_blake2b_t hash; \ + assert_true(ergo_tx_serializer_box_id_hash_init(&hash)); \ + assert_int_equal(ergo_tx_serializer_box_init(&name, \ + value, \ + ergo_tree_size, \ + creation_height, \ + tokens_count, \ + registers_size, \ + &hash), \ + ERGO_TX_SERIALIZER_BOX_RES_OK); + +#define VERIFY_HASH(hash, expected) \ + uint8_t *data; \ + size_t data_len; \ + _cx_blake2b_get_data(hash, &data, &data_len); \ + assert_int_equal(data_len, sizeof(expected)); \ assert_memory_equal(data, expected, sizeof(expected)); \ _cx_blake2b_free_data(hash); @@ -47,9 +45,7 @@ static void test_ergo_tx_serializer_box_init(void **state) { assert_int_equal(context.creation_height, creation_height); assert_int_equal(context.tokens_count, tokens_count); assert_int_equal(context.registers_size, registers_size); - uint8_t expected_hash[2] = { - 0xb9, 0x60 - }; + uint8_t expected_hash[2] = {0xb9, 0x60}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.value, value); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_TREE); @@ -67,18 +63,14 @@ static void test_ergo_tx_serializer_box_init_too_many_tokens(void **state) { uint32_t registers_size = 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - assert_int_equal( - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ), - ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MANY_TOKENS - ); + assert_int_equal(ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash), + ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MANY_TOKENS); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -93,18 +85,14 @@ static void test_ergo_tx_serializer_box_init_too_much_data_ergo_tree_size(void * uint32_t registers_size = 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - assert_int_equal( - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ), - ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA - ); + assert_int_equal(ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash), + ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -119,18 +107,14 @@ static void test_ergo_tx_serializer_box_init_too_much_data_registers_size(void * uint32_t registers_size = MAX_TX_DATA_PART_LEN + 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - assert_int_equal( - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ), - ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA - ); + assert_int_equal(ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash), + ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -144,18 +128,14 @@ static void test_ergo_tx_serializer_box_init_bad_hash(void **state) { uint8_t tokens_count = 1; uint32_t registers_size = 1; cx_blake2b_t hash; - assert_int_equal( - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ), - ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER - ); + assert_int_equal(ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash), + ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -164,14 +144,10 @@ static void test_ergo_tx_serializer_box_add_tree(void **state) { ERGO_TX_SERIALIZER_BOX_INIT(context); uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); - assert_int_equal( - ergo_tx_serializer_box_add_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[6] = { - 0xb9, 0x60, 0x01, 0x02, 0x03, 0x02 - }; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + assert_int_equal(ergo_tx_serializer_box_add_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_hash[6] = {0xb9, 0x60, 0x01, 0x02, 0x03, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_TREE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); @@ -184,11 +160,9 @@ static void test_ergo_tx_serializer_box_add_tree_bad_state(void **state) { memset(&context, 0, sizeof(ergo_tx_serializer_box_context_t)); context.state = ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED; uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); - assert_int_equal( - ergo_tx_serializer_box_add_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE - ); + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + assert_int_equal(ergo_tx_serializer_box_add_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -196,7 +170,7 @@ static void test_ergo_tx_serializer_box_add_tree_too_much_data(void **state) { (void) state; uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_box_context_t context; uint64_t value = 12345; uint32_t ergo_tree_size = sizeof(tree_chunk_array) - 1; @@ -205,19 +179,15 @@ static void test_ergo_tx_serializer_box_add_tree_too_much_data(void **state) { uint32_t registers_size = 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ); - assert_int_equal( - ergo_tx_serializer_box_add_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA - ); + ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash); + assert_int_equal(ergo_tx_serializer_box_add_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -225,7 +195,7 @@ static void test_ergo_tx_serializer_box_add_tree_bad_hash(void **state) { (void) state; uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_box_context_t context; uint64_t value = 12345; uint32_t ergo_tree_size = 2; @@ -234,20 +204,16 @@ static void test_ergo_tx_serializer_box_add_tree_bad_hash(void **state) { uint32_t registers_size = 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ); + ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash); memset(context.hash, 0, sizeof(*context.hash)); - assert_int_equal( - ergo_tx_serializer_box_add_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER - ); + assert_int_equal(ergo_tx_serializer_box_add_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -255,7 +221,7 @@ static void test_ergo_tx_serializer_box_add_tree_more_data(void **state) { (void) state; uint8_t tree_chunk_array[MAX_DATA_CHUNK_LEN] = {0}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_box_context_t context; uint64_t value = 12345; uint32_t ergo_tree_size = MAX_DATA_CHUNK_LEN + 1; @@ -264,19 +230,15 @@ static void test_ergo_tx_serializer_box_add_tree_more_data(void **state) { uint32_t registers_size = 1; cx_blake2b_t hash; ergo_tx_serializer_box_id_hash_init(&hash); - ergo_tx_serializer_box_init( - &context, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size, - &hash - ); - assert_int_equal( - ergo_tx_serializer_box_add_tree(&context, &tree_chunk), - ERGO_TX_SERIALIZER_BOX_RES_MORE_DATA - ); + ergo_tx_serializer_box_init(&context, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size, + &hash); + assert_int_equal(ergo_tx_serializer_box_add_tree(&context, &tree_chunk), + ERGO_TX_SERIALIZER_BOX_RES_MORE_DATA); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_TREE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_INITIALIZED); } @@ -286,23 +248,17 @@ static void test_ergo_tx_serializer_box_add_miners_fee_tree_mainnet(void **state ERGO_TX_SERIALIZER_BOX_INIT(context); bool is_mainnet = true; - assert_int_equal( - ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[109] = { - 0xb9, 0x60, 0x10, 0x05, 0x04, 0x00, 0x04, 0x00, 0x0e, 0x36, - 0x10, 0x02, 0x04, 0xa0, 0x0b, 0x08, 0xcd, 0x02, 0x79, 0xbe, - 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, - 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, - 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, - 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, 0x8c, 0xc7, 0xa7, 0x01, - 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, - 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, - 0x73, 0x00, 0x00, 0x01, 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, - 0x00, 0x74, 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, - 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04, 0x03, 0x02 - }; + assert_int_equal(ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_hash[] = { + 0xb9, 0x60, 0x10, 0x05, 0x04, 0x00, 0x04, 0x00, 0x0e, 0x36, 0x10, 0x02, 0x04, 0xa0, + 0x0b, 0x08, 0xcd, 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, + 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, + 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, + 0x8c, 0xc7, 0xa7, 0x01, 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, + 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, 0x73, 0x00, 0x00, 0x01, + 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, 0x00, 0x74, 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, + 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04, 0x03, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_FEE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); @@ -313,23 +269,17 @@ static void test_ergo_tx_serializer_box_add_miners_fee_tree_testnet(void **state ERGO_TX_SERIALIZER_BOX_INIT(context); bool is_mainnet = false; - assert_int_equal( - ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[109] = { - 0xb9, 0x60, 0x10, 0x05, 0x04, 0x00, 0x04, 0x00, 0x0e, 0x36, - 0x10, 0x02, 0x04, 0xa0, 0x0b, 0x08, 0xcd, 0x02, 0x79, 0xbe, - 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, - 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, - 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, - 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, 0x8c, 0xc7, 0xa7, 0x01, - 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, - 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, - 0x73, 0x00, 0x00, 0x01, 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, - 0x00, 0x74, 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, 0x08, 0xcd, - 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04, 0x03, 0x02 - }; + assert_int_equal(ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_hash[] = { + 0xb9, 0x60, 0x10, 0x05, 0x04, 0x00, 0x04, 0x00, 0x0e, 0x36, 0x10, 0x02, 0x04, 0xa0, + 0x0b, 0x08, 0xcd, 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, + 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, + 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 0xea, 0x02, 0xd1, 0x92, 0xa3, 0x9a, + 0x8c, 0xc7, 0xa7, 0x01, 0x73, 0x00, 0x73, 0x01, 0x10, 0x01, 0x02, 0x04, 0x02, 0xd1, + 0x96, 0x83, 0x03, 0x01, 0x93, 0xa3, 0x8c, 0xc7, 0xb2, 0xa5, 0x73, 0x00, 0x00, 0x01, + 0x93, 0xc2, 0xb2, 0xa5, 0x73, 0x01, 0x00, 0x74, 0x73, 0x02, 0x73, 0x03, 0x83, 0x01, + 0x08, 0xcd, 0xee, 0xac, 0x93, 0xb1, 0xa5, 0x73, 0x04, 0x03, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_FEE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); @@ -340,10 +290,8 @@ static void test_ergo_tx_serializer_box_add_miners_fee_tree_bad_state(void **sta ergo_tx_serializer_box_context_t context; bool is_mainnet = true; - assert_int_equal( - ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), - ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE - ); + assert_int_equal(ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), + ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -353,10 +301,8 @@ static void test_ergo_tx_serializer_box_add_miners_fee_tree_bad_hash(void **stat ERGO_TX_SERIALIZER_BOX_INIT(context); bool is_mainnet = true; memset(context.hash, 0, sizeof(*context.hash)); - assert_int_equal( - ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), - ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER - ); + assert_int_equal(ergo_tx_serializer_box_add_miners_fee_tree(&context, is_mainnet), + ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -364,25 +310,18 @@ static void test_ergo_tx_serializer_box_add_change_tree(void **state) { (void) state; ERGO_TX_SERIALIZER_BOX_INIT(context); - const uint8_t raw_public_key[PUBLIC_KEY_LEN] = { - 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, - 0xfc, 0x53, 0x9d, 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, - 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, 0x64, 0x18, 0xde, 0x5a, - 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, 0x59, - 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, - 0x1a, 0x60, 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, - 0xe5, 0xcf, 0xf1, 0x0a, 0xe7 - }; - assert_int_equal( - ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[40] = { - 0xb9, 0x60, 0x00, 0x08, 0xcd, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, - 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, - 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, - 0x99, 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, 0x03, 0x02 - }; + const uint8_t raw_public_key[] = { + 0x04, 0x8b, 0x9f, 0xf8, 0x5d, 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, + 0x39, 0xc7, 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, 0x99, + 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, 0xfa, 0x2d, 0x53, 0x17, 0x16, 0x0a, + 0x59, 0x50, 0x0f, 0x5d, 0x31, 0xfa, 0xe8, 0x6b, 0xce, 0xe9, 0xab, 0x1a, 0x60, + 0x53, 0xa1, 0x1d, 0x53, 0x5d, 0x2d, 0x04, 0x3c, 0xe5, 0xcf, 0xf1, 0x0a, 0xe7}; + assert_int_equal(ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_hash[] = {0xb9, 0x60, 0x00, 0x08, 0xcd, 0x03, 0x8b, 0x9f, 0xf8, 0x5d, + 0xdd, 0x9f, 0x1e, 0x22, 0x88, 0xfc, 0x53, 0x9d, 0x39, 0xc7, + 0xc4, 0xee, 0xb7, 0xa5, 0x56, 0xf4, 0xd8, 0x11, 0xcb, 0x73, + 0x99, 0x64, 0x18, 0xde, 0x5a, 0xbd, 0xcb, 0x2a, 0x03, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.type, ERGO_TX_SERIALIZER_BOX_TYPE_CHANGE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); @@ -395,10 +334,8 @@ static void test_ergo_tx_serializer_box_add_change_tree_bad_state(void **state) memset(&context, 0, sizeof(ergo_tx_serializer_box_context_t)); context.state = ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED; const uint8_t raw_public_key[PUBLIC_KEY_LEN] = {0}; - assert_int_equal( - ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), - ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE - ); + assert_int_equal(ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), + ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -408,10 +345,8 @@ static void test_ergo_tx_serializer_box_add_change_tree_bad_hash(void **state) { ERGO_TX_SERIALIZER_BOX_INIT(context); const uint8_t raw_public_key[PUBLIC_KEY_LEN] = {0}; memset(context.hash, 0, sizeof(*context.hash)); - assert_int_equal( - ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), - ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER - ); + assert_int_equal(ergo_tx_serializer_box_add_change_tree(&context, raw_public_key), + ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_ERROR); } @@ -419,42 +354,35 @@ static void test_ergo_tx_serializer_box_add_tokens(void **state) { (void) state; ERGO_TX_SERIALIZER_BOX_INIT(context); - uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); - ergo_tx_serializer_box_add_tree(&context, &tree_chunk); - uint8_t tokens_array[24] = { - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - token_table_t table = { - 2, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }, - { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - } - } - }; + + uint8_t table_tokens_array[] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(table_tokens, table_tokens_array, sizeof(table_tokens_array)); + token_table_t table = {0}; + ergo_tx_serializer_table_context_t table_ctx; assert_int_equal( - ergo_tx_serializer_box_add_tokens(&context, &tokens, &table), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[26] = { - 0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, 0x84, - 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, 0x84, 0x88, - 0x90, 0xa0, 0xc0, 0x80, 0x81, 0x02 - }; + ergo_tx_serializer_table_init(&table_ctx, sizeof(table_tokens_array) / ERGO_ID_LEN, &table), + ERGO_TX_SERIALIZER_TABLE_RES_OK); + assert_int_equal(ergo_tx_serializer_table_add(&table_ctx, &table_tokens), + ERGO_TX_SERIALIZER_TABLE_RES_OK); + + uint8_t tree_chunk_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + ergo_tx_serializer_box_add_tree(&context, &tree_chunk); + uint8_t tokens_array[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_box_add_tokens(&context, &tokens, &table_ctx), + ERGO_TX_SERIALIZER_BOX_RES_OK); + + uint8_t expected_hash[] = {0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, + 0x84, 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, + 0x84, 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x81, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_TOKENS_ADDED); } @@ -463,45 +391,35 @@ static void test_ergo_tx_serializer_box_add_registers(void **state) { (void) state; ERGO_TX_SERIALIZER_BOX_INIT(context); - uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + + token_table_t table = {0}; + ergo_tx_serializer_table_context_t table_ctx; + uint8_t distinct_tokens_array[] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(distinct_tokens, distinct_tokens_array, sizeof(distinct_tokens_array)); + ergo_tx_serializer_table_init(&table_ctx, sizeof(distinct_tokens_array) / ERGO_ID_LEN, &table); + ergo_tx_serializer_table_add(&table_ctx, &distinct_tokens); + + uint8_t tree_chunk_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_box_add_tree(&context, &tree_chunk); - uint8_t tokens_array[24] = { - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - token_table_t table = { - 2, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }, - { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - } - } - }; - ergo_tx_serializer_box_add_tokens(&context, &tokens, &table); - uint8_t rc_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(registers_chunk, rc_array, sizeof(rc_array)); - assert_int_equal( - ergo_tx_serializer_box_add_registers(&context, ®isters_chunk), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_hash[28] = { - 0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, 0x84, - 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, 0x84, 0x88, - 0x90, 0xa0, 0xc0, 0x80, 0x81, 0x02, 0x01, 0x02 - }; + uint8_t tokens_array[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + ergo_tx_serializer_box_add_tokens(&context, &tokens, &table_ctx); + + uint8_t rc_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(registers_chunk, rc_array, sizeof(rc_array)); + assert_int_equal(ergo_tx_serializer_box_add_registers(&context, ®isters_chunk), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_hash[] = {0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, 0x84, + 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, 0x84, 0x88, + 0x90, 0xa0, 0xc0, 0x80, 0x81, 0x02, 0x01, 0x02}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_FINISHED); } @@ -510,90 +428,74 @@ static void test_ergo_tx_serializer_box_id_hash(void **state) { (void) state; ERGO_TX_SERIALIZER_BOX_INIT(context); - uint8_t tree_chunk_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); + + token_table_t table = {0}; + ergo_tx_serializer_table_context_t table_ctx; + uint8_t distinct_tokens_array[] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(distinct_tokens, distinct_tokens_array, sizeof(distinct_tokens_array)); + ergo_tx_serializer_table_init(&table_ctx, sizeof(distinct_tokens_array) / ERGO_ID_LEN, &table); + ergo_tx_serializer_table_add(&table_ctx, &distinct_tokens); + + uint8_t tree_chunk_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(tree_chunk, tree_chunk_array, sizeof(tree_chunk_array)); ergo_tx_serializer_box_add_tree(&context, &tree_chunk); - uint8_t tokens_array[24] = { - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - token_table_t table = { - 2, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }, - { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - } - } - }; - ergo_tx_serializer_box_add_tokens(&context, &tokens, &table); - uint8_t rc_array[2] = {0x01, 0x02}; - BUFFER_FROM_ARRAY_FULL(registers_chunk, rc_array, sizeof(rc_array)); + uint8_t tokens_array[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + ergo_tx_serializer_box_add_tokens(&context, &tokens, &table_ctx); + + uint8_t rc_array[] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(registers_chunk, rc_array, sizeof(rc_array)); ergo_tx_serializer_box_add_registers(&context, ®isters_chunk); - const uint8_t tx_id[ERGO_ID_LEN] = { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }; + const uint8_t tx_id[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; uint16_t box_index = 1; uint8_t box_id[ERGO_ID_LEN]; - assert_int_equal( - ergo_tx_serializer_box_id_hash(&context, tx_id, box_index, box_id), - ERGO_TX_SERIALIZER_BOX_RES_OK - ); - uint8_t expected_box_id[ERGO_ID_LEN] = { - 0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, - 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, - 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, - 0x13, 0x73 - }; + assert_int_equal(ergo_tx_serializer_box_id_hash(&context, tx_id, box_index, box_id), + ERGO_TX_SERIALIZER_BOX_RES_OK); + uint8_t expected_box_id[] = {0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, 0x70, + 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, 0xbe, 0x5b, + 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, 0x13, 0x73}; assert_memory_equal(box_id, expected_box_id, ERGO_ID_LEN); - uint8_t expected_hash[61] = { - 0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, 0x84, - 0x88, 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, 0x84, 0x88, - 0x90, 0xa0, 0xc0, 0x80, 0x81, 0x02, 0x01, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01 - }; + uint8_t expected_hash[] = {0xb9, 0x60, 0x01, 0x02, 0x03, 0x02, 0x00, 0x81, 0x82, 0x84, 0x88, + 0x90, 0xa0, 0xc0, 0x80, 0x01, 0x01, 0x82, 0x84, 0x88, 0x90, 0xa0, + 0xc0, 0x80, 0x81, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_BOX_STATE_HASH_FINALIZED); } int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_ergo_tx_serializer_box_init), - cmocka_unit_test(test_ergo_tx_serializer_box_init_too_many_tokens), - cmocka_unit_test(test_ergo_tx_serializer_box_init_too_much_data_ergo_tree_size), - cmocka_unit_test(test_ergo_tx_serializer_box_init_too_much_data_registers_size), - cmocka_unit_test(test_ergo_tx_serializer_box_init_bad_hash), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tree), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_bad_state), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_too_much_data), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_bad_hash), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_more_data), - cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_mainnet), - cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_testnet), - cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_bad_state), - cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_bad_hash), - cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree), - cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree_bad_state), - cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree_bad_hash), - cmocka_unit_test(test_ergo_tx_serializer_box_add_tokens), - cmocka_unit_test(test_ergo_tx_serializer_box_add_registers), - cmocka_unit_test(test_ergo_tx_serializer_box_id_hash)}; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_ergo_tx_serializer_box_init), + cmocka_unit_test(test_ergo_tx_serializer_box_init_too_many_tokens), + cmocka_unit_test(test_ergo_tx_serializer_box_init_too_much_data_ergo_tree_size), + cmocka_unit_test(test_ergo_tx_serializer_box_init_too_much_data_registers_size), + cmocka_unit_test(test_ergo_tx_serializer_box_init_bad_hash), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tree), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_bad_state), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_too_much_data), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_bad_hash), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tree_more_data), + cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_mainnet), + cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_testnet), + cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_bad_state), + cmocka_unit_test(test_ergo_tx_serializer_box_add_miners_fee_tree_bad_hash), + cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree), + cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree_bad_state), + cmocka_unit_test(test_ergo_tx_serializer_box_add_change_tree_bad_hash), + cmocka_unit_test(test_ergo_tx_serializer_box_add_tokens), + cmocka_unit_test(test_ergo_tx_serializer_box_add_registers), + cmocka_unit_test(test_ergo_tx_serializer_box_id_hash)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_tx_ser_input.c b/unit-tests/test_tx_ser_input.c index dbedf3ca..da55966b 100644 --- a/unit-tests/test_tx_ser_input.c +++ b/unit-tests/test_tx_ser_input.c @@ -8,57 +8,42 @@ #include #include "ergo/tx_ser_input.h" - -const uint8_t test_box_id[32] = { \ - 0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, \ - 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, \ - 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, \ - 0x13, 0x73 \ -}; - -uint8_t test_tokens_array[40] = { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 -}; - -token_table_t test_tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } -}; - -#define ERGO_TX_SERIALIZER_INPUT_INIT(name) \ - ergo_tx_serializer_input_context_t name; \ - uint8_t token_frames_count = 1; \ - uint32_t proof_data_size = 3; \ - cx_blake2b_t hash; \ - blake2b_256_init(&hash); \ - assert_int_equal( \ - ergo_tx_serializer_input_init( \ - &context, \ - test_box_id, \ - token_frames_count, \ - proof_data_size, \ - &test_tokens_table, \ - &hash \ - ), \ - ERGO_TX_SERIALIZER_INPUT_RES_OK \ - ); - -#define VERIFY_HASH(hash, expected) \ - uint8_t *data; \ - size_t data_len; \ - _cx_blake2b_get_data(hash, &data, &data_len); \ - assert_int_equal(data_len, sizeof(expected)); \ +#include "common/rwbuffer.h" +#include "macro_helpers.h" + +const uint8_t test_box_id[] = {0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, 0x70, + 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, 0xbe, 0x5b, + 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, 0x13, 0x73}; + +uint8_t test_tokens_array[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + +token_table_t test_tokens_table = {1, {{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}}}; + +#define ERGO_TX_SERIALIZER_INPUT_INIT(name) \ + ergo_tx_serializer_input_context_t name; \ + uint8_t token_frames_count = 1; \ + uint32_t proof_data_size = 3; \ + cx_blake2b_t hash; \ + blake2b_256_init(&hash); \ + assert_int_equal(ergo_tx_serializer_input_init(&context, \ + test_box_id, \ + token_frames_count, \ + proof_data_size, \ + &test_tokens_table, \ + &hash), \ + ERGO_TX_SERIALIZER_INPUT_RES_OK); + +#define VERIFY_HASH(hash, expected) \ + uint8_t *data; \ + size_t data_len; \ + _cx_blake2b_get_data(hash, &data, &data_len); \ + assert_int_equal(data_len, sizeof(expected)); \ assert_memory_equal(data, expected, sizeof(expected)); \ _cx_blake2b_free_data(hash); @@ -83,17 +68,13 @@ static void test_ergo_tx_serializer_input_init_bad_extension_size(void **state) uint32_t proof_data_size = 1; cx_blake2b_t hash; blake2b_256_init(&hash); - assert_int_equal( - ergo_tx_serializer_input_init( - &context, - test_box_id, - token_frames_count, - proof_data_size, - &test_tokens_table, - &hash - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_CONTEXT_EXTENSION_SIZE - ); + assert_int_equal(ergo_tx_serializer_input_init(&context, + test_box_id, + token_frames_count, + proof_data_size, + &test_tokens_table, + &hash), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_CONTEXT_EXTENSION_SIZE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -102,22 +83,13 @@ static void test_ergo_tx_serializer_input_add_tokens(void **state) { ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_OK - ); - uint8_t expected_hash[33] = { - 0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, - 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, - 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, - 0x13, 0x73, 0x00 - }; + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_OK); + uint8_t expected_hash[33] = {0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, 0x70, + 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, 0xbe, 0x5b, + 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, 0x13, 0x73, 0x00}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_EXTENSION_STARTED); } @@ -130,31 +102,21 @@ static void test_ergo_tx_serializer_input_add_tokens_empty_extension(void **stat uint32_t proof_data_size = 0; cx_blake2b_t hash; blake2b_256_init(&hash); - ergo_tx_serializer_input_init( - &context, - test_box_id, - token_frames_count, - proof_data_size, - &test_tokens_table, - &hash - ); + ergo_tx_serializer_input_init(&context, + test_box_id, + token_frames_count, + proof_data_size, + &test_tokens_table, + &hash); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_OK - ); - uint8_t expected_hash[34] = { - 0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, - 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, - 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, - 0x13, 0x73, 0x00, 0x00 - }; + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_OK); + uint8_t expected_hash[34] = {0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, + 0x3d, 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, + 0x23, 0x89, 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, + 0x32, 0x6f, 0x86, 0x13, 0x73, 0x00, 0x00}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_FINISHED); } @@ -165,16 +127,10 @@ static void test_ergo_tx_serializer_input_add_tokens_bad_state(void **state) { ergo_tx_serializer_input_context_t context; context.state = ERGO_TX_SERIALIZER_INPUT_STATE_EXTENSION_STARTED; uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -183,22 +139,13 @@ static void test_ergo_tx_serializer_input_add_tokens_bad_input(void **state) { ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); - const uint8_t box_id[32] = { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }; + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); + const uint8_t box_id[32] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_INPUT_ID - ); + ergo_tx_serializer_input_add_tokens(&context, box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_INPUT_ID); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -207,16 +154,10 @@ static void test_ergo_tx_serializer_input_add_tokens_too_many_input_frames(void ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 1; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MANY_INPUT_FRAMES - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MANY_INPUT_FRAMES); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -228,25 +169,17 @@ static void test_ergo_tx_serializer_input_add_tokens_bad_frame_index(void **stat uint32_t proof_data_size = 3; cx_blake2b_t hash; blake2b_256_init(&hash); - ergo_tx_serializer_input_init( - &context, - test_box_id, - token_frames_count, - proof_data_size, - &test_tokens_table, - &hash - ); + ergo_tx_serializer_input_init(&context, + test_box_id, + token_frames_count, + proof_data_size, + &test_tokens_table, + &hash); uint8_t token_frame_index = 1; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_FRAME_INDEX - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_FRAME_INDEX); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -255,22 +188,13 @@ static void test_ergo_tx_serializer_input_add_tokens_bad_token_id(void **state) ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - uint8_t tokens_array[31] = { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + uint8_t tokens_array[31] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_ID - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_ID); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -279,23 +203,14 @@ static void test_ergo_tx_serializer_input_add_tokens_bad_token_value(void **stat ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - uint8_t tokens_array[39] = { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); + uint8_t tokens_array[39] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_VALUE - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_VALUE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -307,25 +222,17 @@ static void test_ergo_tx_serializer_input_add_tokens_more_data(void **state) { uint32_t proof_data_size = 3; cx_blake2b_t hash; blake2b_256_init(&hash); - ergo_tx_serializer_input_init( - &context, - test_box_id, - token_frames_count, - proof_data_size, - &test_tokens_table, - &hash - ); + ergo_tx_serializer_input_init(&context, + test_box_id, + token_frames_count, + proof_data_size, + &test_tokens_table, + &hash); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); assert_int_equal( - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ), - ERGO_TX_SERIALIZER_INPUT_RES_MORE_DATA - ); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens), + ERGO_TX_SERIALIZER_INPUT_RES_MORE_DATA); } static void test_ergo_tx_serializer_input_add_context_extension(void **state) { @@ -333,28 +240,17 @@ static void test_ergo_tx_serializer_input_add_context_extension(void **state) { ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ); - uint8_t chunk_array[3] = { - 0x01, 0x02, 0x03 - }; - BUFFER_FROM_ARRAY_FULL(chunk, chunk_array, sizeof(chunk_array)); - assert_int_equal( - ergo_tx_serializer_input_add_context_extension(&context, &chunk), - ERGO_TX_SERIALIZER_INPUT_RES_OK - ); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens); + uint8_t chunk_array[3] = {0x01, 0x02, 0x03}; + BUFFER_FROM_ARRAY(chunk, chunk_array, sizeof(chunk_array)); + assert_int_equal(ergo_tx_serializer_input_add_context_extension(&context, &chunk), + ERGO_TX_SERIALIZER_INPUT_RES_OK); assert_int_equal(context.context_extension_data_size, 0); - uint8_t expected_hash[36] = { - 0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, 0x3d, - 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, 0x23, 0x89, - 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, 0x32, 0x6f, 0x86, - 0x13, 0x73, 0x00, 0x01, 0x02, 0x03 - }; + uint8_t expected_hash[36] = {0xf1, 0xca, 0x1e, 0x06, 0x0a, 0xa1, 0x1f, 0x98, 0x9b, + 0x3d, 0x70, 0xec, 0x0e, 0x0c, 0x98, 0x7c, 0x95, 0x2e, + 0x23, 0x89, 0xbe, 0x5b, 0x82, 0x0b, 0xc7, 0xdb, 0xfc, + 0x32, 0x6f, 0x86, 0x13, 0x73, 0x00, 0x01, 0x02, 0x03}; VERIFY_HASH(context.hash, expected_hash); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_FINISHED); } @@ -363,14 +259,10 @@ static void test_ergo_tx_serializer_input_add_context_extension_bad_state(void * (void) state; ERGO_TX_SERIALIZER_INPUT_INIT(context); - uint8_t chunk_array[3] = { - 0x01, 0x02, 0x03 - }; - BUFFER_FROM_ARRAY_FULL(chunk, chunk_array, sizeof(chunk_array)); - assert_int_equal( - ergo_tx_serializer_input_add_context_extension(&context, &chunk), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE - ); + uint8_t chunk_array[3] = {0x01, 0x02, 0x03}; + BUFFER_FROM_ARRAY(chunk, chunk_array, sizeof(chunk_array)); + assert_int_equal(ergo_tx_serializer_input_add_context_extension(&context, &chunk), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -379,21 +271,12 @@ static void test_ergo_tx_serializer_input_add_context_extension_too_much_data(vo ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ); - uint8_t chunk_array[4] = { - 0x01, 0x02, 0x03, 0x04 - }; - BUFFER_FROM_ARRAY_FULL(chunk, chunk_array, sizeof(chunk_array)); - assert_int_equal( - ergo_tx_serializer_input_add_context_extension(&context, &chunk), - ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MUCH_PROOF_DATA - ); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens); + uint8_t chunk_array[4] = {0x01, 0x02, 0x03, 0x04}; + BUFFER_FROM_ARRAY(chunk, chunk_array, sizeof(chunk_array)); + assert_int_equal(ergo_tx_serializer_input_add_context_extension(&context, &chunk), + ERGO_TX_SERIALIZER_INPUT_RES_ERR_TOO_MUCH_PROOF_DATA); assert_int_equal(context.state, ERGO_TX_SERIALIZER_INPUT_STATE_ERROR); } @@ -402,39 +285,31 @@ static void test_ergo_tx_serializer_input_add_context_extension_more_data(void * ERGO_TX_SERIALIZER_INPUT_INIT(context); uint8_t token_frame_index = 0; - BUFFER_FROM_ARRAY_FULL(tokens, test_tokens_array, sizeof(test_tokens_array)); - ergo_tx_serializer_input_add_tokens( - &context, - test_box_id, - token_frame_index, - &tokens - ); - uint8_t chunk_array[2] = { - 0x01, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(chunk, chunk_array, sizeof(chunk_array)); - assert_int_equal( - ergo_tx_serializer_input_add_context_extension(&context, &chunk), - ERGO_TX_SERIALIZER_INPUT_RES_MORE_DATA - ); + BUFFER_FROM_ARRAY(tokens, test_tokens_array, sizeof(test_tokens_array)); + ergo_tx_serializer_input_add_tokens(&context, test_box_id, token_frame_index, &tokens); + uint8_t chunk_array[2] = {0x01, 0x02}; + BUFFER_FROM_ARRAY(chunk, chunk_array, sizeof(chunk_array)); + assert_int_equal(ergo_tx_serializer_input_add_context_extension(&context, &chunk), + ERGO_TX_SERIALIZER_INPUT_RES_MORE_DATA); } int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_ergo_tx_serializer_input_init), - cmocka_unit_test(test_ergo_tx_serializer_input_init_bad_extension_size), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_empty_extension), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_state), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_input), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_too_many_input_frames), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_frame_index), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_token_id), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_token_value), - cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_more_data), - cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension), - cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_bad_state), - cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_too_much_data), - cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_more_data)}; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_ergo_tx_serializer_input_init), + cmocka_unit_test(test_ergo_tx_serializer_input_init_bad_extension_size), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_empty_extension), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_state), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_input), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_too_many_input_frames), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_frame_index), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_token_id), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_bad_token_value), + cmocka_unit_test(test_ergo_tx_serializer_input_add_tokens_more_data), + cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension), + cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_bad_state), + cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_too_much_data), + cmocka_unit_test(test_ergo_tx_serializer_input_add_context_extension_more_data)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_tx_ser_table.c b/unit-tests/test_tx_ser_table.c index 91405f60..7b55e085 100644 --- a/unit-tests/test_tx_ser_table.c +++ b/unit-tests/test_tx_ser_table.c @@ -8,6 +8,8 @@ #include #include "ergo/tx_ser_table.h" +#include "common/rwbuffer.h" +#include "macro_helpers.h" static void test_ergo_tx_serializer_table_init(void **state) { (void) state; @@ -15,42 +17,28 @@ static void test_ergo_tx_serializer_table_init(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 1; token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - assert_int_equal( - ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table), - ERGO_TX_SERIALIZER_TABLE_RES_OK - ); + 0, + {{ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + }}}; + assert_int_equal(ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table), + ERGO_TX_SERIALIZER_TABLE_RES_OK); + assert_int_equal(context.distinct_tokens_count, tokens_count); + assert_ptr_equal(context.tokens_table, &tokens_table); + token_table_t empty = {0}; + assert_memory_equal(context.tokens_table, &empty, sizeof(empty)); } static void test_ergo_tx_serializer_table_init_too_many_tokens(void **state) { (void) state; ergo_tx_serializer_table_context_t context; - uint8_t tokens_count = TOKEN_MAX_COUNT; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; - assert_int_equal( - ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table), - ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS - ); + uint8_t tokens_count = TOKEN_MAX_COUNT + 1; + token_table_t tokens_table = {0}; + assert_int_equal(ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table), + ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS); } static void test_ergo_tx_serializer_table_add(void **state) { @@ -58,47 +46,28 @@ static void test_ergo_tx_serializer_table_add(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 2; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - assert_int_equal( - ergo_tx_serializer_table_add(&context, &tokens), - ERGO_TX_SERIALIZER_TABLE_RES_OK - ); + uint8_t tokens_array[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_OK); const token_table_t expected_tokens_table = { 2, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }, - { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - } - } - }; - assert_memory_equal(context.tokens_table, &expected_tokens_table, sizeof(expected_tokens_table)); + {{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}}}; + assert_memory_equal(context.tokens_table, + &expected_tokens_table, + sizeof(expected_tokens_table)); } static void test_ergo_tx_serializer_table_add_too_many_tokens(void **state) { @@ -106,29 +75,17 @@ static void test_ergo_tx_serializer_table_add_too_many_tokens(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 1; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - assert_int_equal( - ergo_tx_serializer_table_add(&context, &tokens), - ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS - ); + uint8_t tokens_array[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS); } static void test_ergo_tx_serializer_table_add_bad_token_id(void **state) { @@ -136,59 +93,32 @@ static void test_ergo_tx_serializer_table_add_bad_token_id(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 2; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); - uint8_t tokens_array[31] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - assert_int_equal( - ergo_tx_serializer_table_add(&context, &tokens), - ERGO_TX_SERIALIZER_TABLE_RES_ERR_BAD_TOKEN_ID - ); + uint8_t tokens_array[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_ERR_BAD_TOKEN_ID); } static void test_ergo_tx_serializer_table_add_more_data(void **state) { (void) state; ergo_tx_serializer_table_context_t context; - uint8_t tokens_count = 3; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + uint8_t tokens_count = 2; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); - uint8_t tokens_array[32] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02 - }; - BUFFER_FROM_ARRAY_FULL(tokens, tokens_array, sizeof(tokens_array)); - assert_int_equal( - ergo_tx_serializer_table_add(&context, &tokens), - ERGO_TX_SERIALIZER_TABLE_RES_MORE_DATA - ); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_MORE_DATA); } static void test_ergo_tx_serializer_table_hash(void **state) { @@ -196,34 +126,24 @@ static void test_ergo_tx_serializer_table_hash(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 1; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); + uint8_t tokens_array[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_OK); cx_blake2b_t hash; blake2b_256_init(&hash); - assert_int_equal( - ergo_tx_serializer_table_hash(&context, &hash), - ERGO_TX_SERIALIZER_TABLE_RES_OK - ); + assert_int_equal(ergo_tx_serializer_table_hash(&context, &hash), + ERGO_TX_SERIALIZER_TABLE_RES_OK); uint8_t *data; size_t data_len; _cx_blake2b_get_data(&hash, &data, &data_len); - uint8_t expected[] = { - 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - }; + uint8_t expected[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; assert_int_equal(data_len, sizeof(expected)); assert_memory_equal(data, expected, sizeof(expected)); _cx_blake2b_free_data(&hash); @@ -234,34 +154,29 @@ static void test_ergo_tx_serializer_table_hash_bad_hash(void **state) { ergo_tx_serializer_table_context_t context; uint8_t tokens_count = 1; - token_table_t tokens_table = { - 1, - { - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01 - } - } - }; + token_table_t tokens_table = {0}; ergo_tx_serializer_table_init(&context, tokens_count, &tokens_table); - cx_blake2b_t hash; - assert_int_equal( - ergo_tx_serializer_table_hash(&context, &hash), - ERGO_TX_SERIALIZER_TABLE_RES_ERR_HASHER - ); + uint8_t tokens_array[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + BUFFER_FROM_ARRAY(tokens, tokens_array, sizeof(tokens_array)); + assert_int_equal(ergo_tx_serializer_table_add(&context, &tokens), + ERGO_TX_SERIALIZER_TABLE_RES_OK); + cx_blake2b_t hash = {0}; + assert_int_equal(ergo_tx_serializer_table_hash(&context, &hash), + ERGO_TX_SERIALIZER_TABLE_RES_ERR_HASHER); } int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_ergo_tx_serializer_table_init), - cmocka_unit_test(test_ergo_tx_serializer_table_init_too_many_tokens), - cmocka_unit_test(test_ergo_tx_serializer_table_add), - cmocka_unit_test(test_ergo_tx_serializer_table_add_too_many_tokens), - cmocka_unit_test(test_ergo_tx_serializer_table_add_bad_token_id), - cmocka_unit_test(test_ergo_tx_serializer_table_add_more_data), - cmocka_unit_test(test_ergo_tx_serializer_table_hash), - cmocka_unit_test(test_ergo_tx_serializer_table_hash_bad_hash)}; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_ergo_tx_serializer_table_init), + cmocka_unit_test(test_ergo_tx_serializer_table_init_too_many_tokens), + cmocka_unit_test(test_ergo_tx_serializer_table_add), + cmocka_unit_test(test_ergo_tx_serializer_table_add_too_many_tokens), + cmocka_unit_test(test_ergo_tx_serializer_table_add_bad_token_id), + cmocka_unit_test(test_ergo_tx_serializer_table_add_more_data), + cmocka_unit_test(test_ergo_tx_serializer_table_hash), + cmocka_unit_test(test_ergo_tx_serializer_table_hash_bad_hash)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_write.c b/unit-tests/test_write.c deleted file mode 100644 index fde4807f..00000000 --- a/unit-tests/test_write.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/write.h" - -static void test_write_u16_be(void **state) { - (void) state; - - uint8_t tmp[2] = {0}; - uint8_t expected[2] = {0x01, 0x07}; - write_u16_be(tmp, 0, (uint16_t) 263U); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -static void test_write_u16_le(void **state) { - (void) state; - - uint8_t tmp[2] = {0}; - uint8_t expected[2] = {0x07, 0x01}; - write_u16_le(tmp, 0, (uint16_t) 263U); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -static void test_write_u32_be(void **state) { - (void) state; - - uint8_t tmp[4] = {0}; - uint8_t expected[4] = {0x01, 0x3B, 0xAC, 0xC7}; - write_u32_be(tmp, 0, (uint32_t) 20688071UL); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -static void test_write_u32_le(void **state) { - (void) state; - - uint8_t tmp[4] = {0}; - uint8_t expected[4] = {0xC7, 0xAC, 0x3B, 0x01}; - write_u32_le(tmp, 0, (uint32_t) 20688071UL); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -static void test_write_u64_be(void **state) { - (void) state; - - uint8_t tmp[8] = {0}; - uint8_t expected[8] = {0xEB, 0x68, 0x44, 0xC0, 0x2C, 0x61, 0xB0, 0x99}; - write_u64_be(tmp, 0, (uint64_t) 16962883588659982489ULL); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -static void test_write_u64_le(void **state) { - (void) state; - - uint8_t tmp[8] = {0}; - uint8_t expected[8] = {0x99, 0xB0, 0x61, 0x2C, 0xC0, 0x44, 0x68, 0xEB}; - write_u64_le(tmp, 0, (uint64_t) 16962883588659982489ULL); - assert_memory_equal(tmp, expected, sizeof(expected)); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_write_u16_be), - cmocka_unit_test(test_write_u16_le), - cmocka_unit_test(test_write_u32_be), - cmocka_unit_test(test_write_u32_le), - cmocka_unit_test(test_write_u64_be), - cmocka_unit_test(test_write_u64_le)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/src/common/base58.c b/unit-tests/utils/base58.c similarity index 91% rename from src/common/base58.c rename to unit-tests/utils/base58.c index 0965abfd..b5262692 100644 --- a/src/common/base58.c +++ b/unit-tests/utils/base58.c @@ -1,3 +1,4 @@ + /***************************************************************************** * (c) 2020 Ledger SAS. * @@ -42,8 +43,9 @@ char const BASE58_ALPHABET[] = { 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' // }; -int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) { - uint8_t tmp[MAX_DEC_INPUT_SIZE] = {0}; +int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) +{ + uint8_t tmp[MAX_DEC_INPUT_SIZE] = {0}; uint8_t buffer[MAX_DEC_INPUT_SIZE] = {0}; uint8_t j; uint8_t start_at; @@ -71,15 +73,15 @@ int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) { ++zero_count; } - j = in_len; + j = in_len; start_at = zero_count; while (start_at < in_len) { uint16_t remainder = 0; for (uint8_t div_loop = start_at; div_loop < in_len; div_loop++) { uint16_t digit256 = (uint16_t) (tmp[div_loop] & 0xFF); - uint16_t tmp_div = remainder * 58 + digit256; - tmp[div_loop] = (uint8_t) (tmp_div / 256); - remainder = tmp_div % 256; + uint16_t tmp_div = remainder * 58 + digit256; + tmp[div_loop] = (uint8_t) (tmp_div / 256); + remainder = tmp_div % 256; } if (tmp[start_at] == 0) { @@ -104,12 +106,13 @@ int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) { return length; } -int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) { +int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) +{ uint8_t buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; - size_t i, j; - size_t stop_at; - size_t zero_count = 0; - size_t output_size; + size_t i, j; + size_t stop_at; + size_t zero_count = 0; + size_t output_size; if (in_len > MAX_ENC_INPUT_SIZE) { return -1; @@ -120,7 +123,7 @@ int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) { } output_size = (in_len - zero_count) * 138 / 100 + 1; - stop_at = output_size - 1; + stop_at = output_size - 1; for (size_t start_at = zero_count; start_at < in_len; start_at++) { int carry = in[start_at]; for (j = output_size - 1; (int) j >= 0; j--) { @@ -152,4 +155,4 @@ int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) { } return i; -} +} \ No newline at end of file diff --git a/src/common/base58.h b/unit-tests/utils/base58.h similarity index 98% rename from src/common/base58.h rename to unit-tests/utils/base58.h index f214afd8..9c467d57 100644 --- a/src/common/base58.h +++ b/unit-tests/utils/base58.h @@ -49,4 +49,4 @@ int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len); * @return number of bytes encoded, -1 otherwise. * */ -int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len); +int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len); \ No newline at end of file diff --git a/unit-tests/utils/bip32.c b/unit-tests/utils/bip32.c new file mode 100644 index 00000000..2f7ec968 --- /dev/null +++ b/unit-tests/utils/bip32.c @@ -0,0 +1,86 @@ +/***************************************************************************** + * (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 // snprintf +#include // memset, strlen +#include // size_t +#include // uint*_t +#include // bool + +#include "bip32.h" +#include "read.h" + +bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, size_t out_len) +{ + if (out_len == 0 || out_len > MAX_BIP32_PATH) { + return false; + } + + size_t offset = 0; + + for (size_t i = 0; i < out_len; i++) { + if (offset + 4 > in_len) { + return false; + } + out[i] = read_u32_be(in, offset); + offset += 4; + } + + return true; +} + +bool bip32_path_format(const uint32_t *bip32_path, size_t bip32_path_len, char *out, size_t out_len) +{ + if (bip32_path_len == 0 || bip32_path_len > MAX_BIP32_PATH) { + return false; + } + + size_t offset = 0; + + for (uint16_t i = 0; i < bip32_path_len; i++) { + size_t written; + + snprintf(out + offset, out_len - offset, "%u", bip32_path[i] & 0x7FFFFFFFu); + written = strlen(out + offset); + if (written == 0 || written >= out_len - offset) { + memset(out, 0, out_len); + return false; + } + offset += written; + + if ((bip32_path[i] & 0x80000000u) != 0) { + snprintf(out + offset, out_len - offset, "'"); + written = strlen(out + offset); + if (written == 0 || written >= out_len - offset) { + memset(out, 0, out_len); + return false; + } + offset += written; + } + + if (i != bip32_path_len - 1) { + snprintf(out + offset, out_len - offset, "/"); + written = strlen(out + offset); + if (written == 0 || written >= out_len - offset) { + memset(out, 0, out_len); + return false; + } + offset += written; + } + } + + return true; +} \ No newline at end of file diff --git a/src/common/bip32.h b/unit-tests/utils/bip32.h similarity index 57% rename from src/common/bip32.h rename to unit-tests/utils/bip32.h index 6b501ad7..734c7667 100644 --- a/src/common/bip32.h +++ b/unit-tests/utils/bip32.h @@ -9,19 +9,6 @@ */ #define MAX_BIP32_PATH 10 -#define BIP32_HARDENED_CONSTANT 0x80000000u - -#define BIP32_HARDENED(x) (BIP32_HARDENED_CONSTANT + x) - -typedef enum { - BIP32_PATH_VALIDATE_COIN, - BIP32_PATH_VALIDATE_COIN_GE2_HARD, - BIP32_PATH_VALIDATE_ACCOUNT_E3, - BIP32_PATH_VALIDATE_ACCOUNT_GE3, - BIP32_PATH_VALIDATE_ADDRESS_E5, - BIP32_PATH_VALIDATE_ADDRESS_GE5 -} bip32_path_validation_type_e; - /** * Read BIP32 path from byte buffer. * @@ -37,7 +24,7 @@ typedef enum { * @return true if success, false otherwise. * */ -bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, uint8_t out_len); +bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, size_t out_len); /** * Format BIP32 path as string. @@ -55,12 +42,6 @@ bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, uint8_t ou * */ bool bip32_path_format(const uint32_t *bip32_path, - size_t bip32_path_len, - char *out, - size_t out_len); - -bool bip32_path_validate(const uint32_t *bip32_path, - uint8_t bip32_path_len, - uint32_t type, - uint32_t coin, - bip32_path_validation_type_e vtype); + size_t bip32_path_len, + char *out, + size_t out_len); \ No newline at end of file diff --git a/unit-tests/utils/buffer.c b/unit-tests/utils/buffer.c new file mode 100644 index 00000000..96071a20 --- /dev/null +++ b/unit-tests/utils/buffer.c @@ -0,0 +1,173 @@ +/***************************************************************************** + * (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 // uint*_t +#include // size_t +#include // bool +#include // memmove + +#include "buffer.h" +#include "read.h" +#include "varint.h" +#include "bip32.h" + +bool buffer_can_read(const buffer_t *buffer, size_t n) +{ + return buffer->size - buffer->offset >= n; +} + +bool buffer_seek_set(buffer_t *buffer, size_t offset) +{ + if (offset > buffer->size) { + return false; + } + + buffer->offset = offset; + + return true; +} + +bool buffer_seek_cur(buffer_t *buffer, size_t offset) +{ + if (buffer->offset + offset < buffer->offset || // overflow + buffer->offset + offset > buffer->size) { // exceed buffer size + return false; + } + + buffer->offset += offset; + + return true; +} + +bool buffer_seek_end(buffer_t *buffer, size_t offset) +{ + if (offset > buffer->size) { + return false; + } + + buffer->offset = buffer->size - offset; + + return true; +} + +bool buffer_read_u8(buffer_t *buffer, uint8_t *value) +{ + if (!buffer_can_read(buffer, 1)) { + *value = 0; + + return false; + } + + *value = buffer->ptr[buffer->offset]; + buffer_seek_cur(buffer, 1); + + return true; +} + +bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness) +{ + if (!buffer_can_read(buffer, 2)) { + *value = 0; + + return false; + } + + *value = ((endianness == BE) ? read_u16_be(buffer->ptr, buffer->offset) + : read_u16_le(buffer->ptr, buffer->offset)); + + buffer_seek_cur(buffer, 2); + + return true; +} + +bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness) +{ + if (!buffer_can_read(buffer, 4)) { + *value = 0; + + return false; + } + + *value = ((endianness == BE) ? read_u32_be(buffer->ptr, buffer->offset) + : read_u32_le(buffer->ptr, buffer->offset)); + + buffer_seek_cur(buffer, 4); + + return true; +} + +bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness) +{ + if (!buffer_can_read(buffer, 8)) { + *value = 0; + + return false; + } + + *value = ((endianness == BE) ? read_u64_be(buffer->ptr, buffer->offset) + : read_u64_le(buffer->ptr, buffer->offset)); + + buffer_seek_cur(buffer, 8); + + return true; +} + +bool buffer_read_varint(buffer_t *buffer, uint64_t *value) +{ + int length = varint_read(buffer->ptr + buffer->offset, buffer->size - buffer->offset, value); + + if (length < 0) { + *value = 0; + + return false; + } + + return buffer_seek_cur(buffer, (size_t) length); +} + +bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, size_t out_len) +{ + if (!bip32_path_read( + buffer->ptr + buffer->offset, buffer->size - buffer->offset, out, out_len)) { + return false; + } + + buffer_seek_cur(buffer, sizeof(*out) * out_len); + + return true; +} + +bool buffer_copy(const buffer_t *buffer, uint8_t *out, size_t out_len) +{ + if (buffer->size - buffer->offset > out_len) { + return false; + } + + memmove(out, buffer->ptr + buffer->offset, buffer->size - buffer->offset); + + return true; +} + +bool buffer_move(buffer_t *buffer, uint8_t *out, size_t out_len) +{ + if (!buffer_copy(buffer, out, out_len)) { + return false; + } + + buffer_seek_cur(buffer, out_len); + + return true; +} diff --git a/unit-tests/utils/buffer.h b/unit-tests/utils/buffer.h new file mode 100644 index 00000000..6b31ab0b --- /dev/null +++ b/unit-tests/utils/buffer.h @@ -0,0 +1,192 @@ +#pragma once + +#include // uint*_t +#include // size_t +#include // bool + +/** + * Enumeration for endianness. + */ +typedef enum { + BE, /// Big Endian + LE /// Little Endian +} endianness_t; + +/** + * Struct for buffer with size and offset. + */ +typedef struct { + const uint8_t *ptr; /// Pointer to byte buffer + size_t size; /// Size of byte buffer + size_t offset; /// Offset in byte buffer +} buffer_t; + +/** + * Tell whether buffer can read bytes or not. + * + * @param[in] buffer + * Pointer to input buffer struct. + * @param[in] n + * Number of bytes to read in buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_can_read(const buffer_t *buffer, size_t n); + +/** + * Seek the buffer to specific offset. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[in] offset + * Specific offset to seek. + * + * @return true if success, false otherwise. + * + */ +bool buffer_seek_set(buffer_t *buffer, size_t offset); + +/** + * Seek buffer relatively to current offset. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[in] offset + * Offset to seek relatively to `buffer->offset`. + * + * @return true if success, false otherwise. + * + */ +bool buffer_seek_cur(buffer_t *buffer, size_t offset); + +/** + * Seek the buffer relatively to the end. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[in] offset + * Offset to seek relatively to `buffer->size`. + * + * @return true if success, false otherwise. + * + */ +bool buffer_seek_end(buffer_t *buffer, size_t offset); + +/** + * Read 1 byte from buffer into uint8_t. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] value + * Pointer to 8-bit unsigned integer read from buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_u8(buffer_t *buffer, uint8_t *value); + +/** + * Read 2 bytes from buffer into uint16_t. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] value + * Pointer to 16-bit unsigned integer read from buffer. + * @param[in] endianness + * Either BE (Big Endian) or LE (Little Endian). + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness); + +/** + * Read 4 bytes from buffer into uint32_t. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] value + * Pointer to 32-bit unsigned integer read from buffer. + * @param[in] endianness + * Either BE (Big Endian) or LE (Little Endian). + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness); + +/** + * Read 8 bytes from buffer into uint64_t. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] value + * Pointer to 64-bit unsigned integer read from buffer. + * @param[in] endianness + * Either BE (Big Endian) or LE (Little Endian). + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness); + +/** + * Read Bitcoin-like varint from buffer into uint64_t. + * + * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] value + * Pointer to 64-bit unsigned integer read from buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_varint(buffer_t *buffer, uint64_t *value); + +/** + * Read BIP32 path from buffer. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] out + * Pointer to output 32-bit integer buffer. + * @param[in] out_len + * Number of BIP32 paths read in the output buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, size_t out_len); + +/** + * Copy bytes from buffer without moving offset. + * + * @param[in] buffer + * Pointer to input buffer struct. + * @param[out] out + * Pointer to output byte buffer. + * @param[in] out_len + * Length of output byte buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_copy(const buffer_t *buffer, uint8_t *out, size_t out_len); + +/** + * Move bytes from buffer. + * + * @param[in,out] buffer + * Pointer to input buffer struct. + * @param[out] out + * Pointer to output byte buffer. + * @param[in] out_len + * Length of output byte buffer. + * + * @return true if success, false otherwise. + * + */ +bool buffer_move(buffer_t *buffer, uint8_t *out, size_t out_len); diff --git a/unit-tests/utils/cx.c b/unit-tests/utils/cx.c index a518f4a0..929fbb9c 100644 --- a/unit-tests/utils/cx.c +++ b/unit-tests/utils/cx.c @@ -1,5 +1,4 @@ #include "cx.h" -#include "common/buffer.h" #include "blake2b-ref.h" #include #include @@ -8,7 +7,7 @@ typedef struct { uint8_t hashed_data[BUFFER_SIZE]; - buffer_t hashed_data_buf; + size_t hashed_data_offset; blake2b_state ctx; } b2b_context; @@ -19,13 +18,15 @@ static cx_err_t blake2_hash(cx_blake2b_t *hash, uint8_t *out, size_t out_len) { b2b_context *_ctx = (b2b_context *) hash->ctx; - if (!buffer_write_bytes(&_ctx->hashed_data_buf, in, len)) return -1; + if ((BUFFER_SIZE - _ctx->hashed_data_offset) < len) return -1; + memmove(_ctx->hashed_data + _ctx->hashed_data_offset, in, len); + _ctx->hashed_data_offset += len; if (blake2b_ref_update(&_ctx->ctx, in, len) != 0) return -1; if (mode & CX_LAST) { if (blake2b_ref_final(&_ctx->ctx, out, out_len) != 0) return -1; if (mode & CX_NO_REINIT) return 0; memset(_ctx->hashed_data, 0, BUFFER_SIZE); - buffer_init(&_ctx->hashed_data_buf, _ctx->hashed_data, BUFFER_SIZE, 0); + _ctx->hashed_data_offset = 0; return blake2b_ref_init(&_ctx->ctx, hash->info.output_size / 8); } return 0; @@ -37,7 +38,8 @@ cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t out_len) { hash->ctx = (void *) ctx; hash->info.md_type = CX_BLAKE2B; hash->info.output_size = out_len; - buffer_init(&ctx->hashed_data_buf, ctx->hashed_data, BUFFER_SIZE, 0); + memset(ctx->hashed_data, 0, BUFFER_SIZE); + ctx->hashed_data_offset = 0; return 0; } else { free(ctx); @@ -59,10 +61,17 @@ cx_err_t cx_hash_no_throw(cx_hash_t *hash, } } +cx_err_t cx_blake2b_256_hash(const uint8_t* data, + size_t len, + uint8_t out[static CX_BLAKE2B_256_SIZE]) +{ + return blake2b_ref(out, CX_BLAKE2B_256_SIZE, data, len, NULL, 0); +} + void _cx_blake2b_get_data(cx_blake2b_t *ctx, uint8_t **data, size_t *len) { b2b_context *_ctx = (b2b_context *) ctx->ctx; *data = _ctx->hashed_data; - *len = buffer_data_len(&_ctx->hashed_data_buf); + *len = _ctx->hashed_data_offset; } void _cx_blake2b_free_data(cx_blake2b_t *ctx) { diff --git a/unit-tests/utils/cx.h b/unit-tests/utils/cx.h index 20697835..cf465b5c 100644 --- a/unit-tests/utils/cx.h +++ b/unit-tests/utils/cx.h @@ -23,6 +23,10 @@ struct cx_blake2b_s { /** Convenience type. See #cx_blake2b_s. */ typedef struct cx_blake2b_s cx_blake2b_t; +#define CX_OK 0 + +#define CX_BLAKE2B_256_SIZE 32 + #define CX_FLAG /* * Bit 0 @@ -41,5 +45,9 @@ cx_err_t cx_hash_no_throw(cx_hash_t *hash, uint8_t *out, size_t out_len); +cx_err_t cx_blake2b_256_hash(const uint8_t* data, + size_t len, + uint8_t out[static CX_BLAKE2B_256_SIZE]); + void _cx_blake2b_get_data(cx_blake2b_t *ctx, uint8_t **data, size_t *len); void _cx_blake2b_free_data(cx_blake2b_t *ctx); \ No newline at end of file diff --git a/unit-tests/utils/ledger_assert.h b/unit-tests/utils/ledger_assert.h new file mode 100644 index 00000000..7acf9639 --- /dev/null +++ b/unit-tests/utils/ledger_assert.h @@ -0,0 +1,3 @@ +#include + +#define LEDGER_ASSERT(_test, ...) assert(_test) \ No newline at end of file diff --git a/unit-tests/utils/macro_helpers.h b/unit-tests/utils/macro_helpers.h index 765b28c2..a9bb897e 100644 --- a/unit-tests/utils/macro_helpers.h +++ b/unit-tests/utils/macro_helpers.h @@ -2,4 +2,14 @@ #pragma once // UNUSED macro. Defined in the Makefile -#define UNUSED(x) (void)(x) \ No newline at end of file +#define UNUSED(x) (void)(x) + + +#define BUFFER_FROM_ARRAY(_name, _array, _size) \ + RW_BUFFER_FROM_ARRAY_FULL(__rw_##_name, _array, _size); \ + buffer_t _name = __rw_##_name.read + + +#define BUFFER_NEW_LOCAL_EMPTY(_name, _size) \ + RW_BUFFER_NEW_LOCAL_EMPTY(__rw_##_name, _size); \ + buffer_t _name = __rw_##_name.read \ No newline at end of file diff --git a/unit-tests/utils/macros.h b/unit-tests/utils/macros.h new file mode 100644 index 00000000..cc4a0706 --- /dev/null +++ b/unit-tests/utils/macros.h @@ -0,0 +1,10 @@ +#pragma once + +/** + * Macro for the size of a specific structure field. + */ +#define MEMBER_SIZE(type, member) (sizeof(((type *) 0)->member)) + +#define WEAK __attribute((weak)) + +#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof((array)[0])) \ No newline at end of file diff --git a/src/common/read.c b/unit-tests/utils/read.c similarity index 85% rename from src/common/read.c rename to unit-tests/utils/read.c index c8ee851f..09a7d71f 100644 --- a/src/common/read.c +++ b/unit-tests/utils/read.c @@ -17,19 +17,24 @@ #include // uint*_t #include // size_t -uint16_t read_u16_be(const uint8_t *ptr, size_t offset) { +#include "read.h" + +uint16_t read_u16_be(const uint8_t *ptr, size_t offset) +{ return (uint16_t) ptr[offset + 0] << 8 | // (uint16_t) ptr[offset + 1] << 0; } -uint32_t read_u32_be(const uint8_t *ptr, size_t offset) { +uint32_t read_u32_be(const uint8_t *ptr, size_t offset) +{ return (uint32_t) ptr[offset + 0] << 24 | // (uint32_t) ptr[offset + 1] << 16 | // (uint32_t) ptr[offset + 2] << 8 | // (uint32_t) ptr[offset + 3] << 0; } -uint64_t read_u64_be(const uint8_t *ptr, size_t offset) { +uint64_t read_u64_be(const uint8_t *ptr, size_t offset) +{ return (uint64_t) ptr[offset + 0] << 56 | // (uint64_t) ptr[offset + 1] << 48 | // (uint64_t) ptr[offset + 2] << 40 | // @@ -40,19 +45,22 @@ uint64_t read_u64_be(const uint8_t *ptr, size_t offset) { (uint64_t) ptr[offset + 7] << 0; } -uint16_t read_u16_le(const uint8_t *ptr, size_t offset) { +uint16_t read_u16_le(const uint8_t *ptr, size_t offset) +{ return (uint16_t) ptr[offset + 0] << 0 | // (uint16_t) ptr[offset + 1] << 8; } -uint32_t read_u32_le(const uint8_t *ptr, size_t offset) { +uint32_t read_u32_le(const uint8_t *ptr, size_t offset) +{ return (uint32_t) ptr[offset + 0] << 0 | // (uint32_t) ptr[offset + 1] << 8 | // (uint32_t) ptr[offset + 2] << 16 | // (uint32_t) ptr[offset + 3] << 24; } -uint64_t read_u64_le(const uint8_t *ptr, size_t offset) { +uint64_t read_u64_le(const uint8_t *ptr, size_t offset) +{ return (uint64_t) ptr[offset + 0] << 0 | // (uint64_t) ptr[offset + 1] << 8 | // (uint64_t) ptr[offset + 2] << 16 | // diff --git a/src/common/read.h b/unit-tests/utils/read.h similarity index 100% rename from src/common/read.h rename to unit-tests/utils/read.h diff --git a/unit-tests/utils/varint.c b/unit-tests/utils/varint.c new file mode 100644 index 00000000..fb199f91 --- /dev/null +++ b/unit-tests/utils/varint.c @@ -0,0 +1,104 @@ +/***************************************************************************** + * (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 // uint*_t +#include // size_t +#include // bool + +#include "varint.h" +#include "write.h" +#include "read.h" + +uint8_t varint_size(uint64_t value) +{ + if (value <= 0xFC) { + return 1; + } + + if (value <= UINT16_MAX) { + return 3; + } + + if (value <= UINT32_MAX) { + return 5; + } + + return 9; // <= UINT64_MAX +} + +int varint_read(const uint8_t *in, size_t in_len, uint64_t *value) +{ + if (in_len < 1) { + return -1; + } + + uint8_t prefix = in[0]; + + if (prefix == 0xFD) { + if (in_len < 3) { + return -1; + } + *value = (uint64_t) read_u16_le(in, 1); + return 3; + } + + if (prefix == 0xFE) { + if (in_len < 5) { + return -1; + } + *value = (uint64_t) read_u32_le(in, 1); + return 5; + } + + if (prefix == 0xFF) { + if (in_len < 9) { + return -1; + } + *value = (uint64_t) read_u64_le(in, 1); + return 9; + } + + *value = (uint64_t) prefix; // prefix <= 0xFC + + return 1; +} + +int varint_write(uint8_t *out, size_t offset, uint64_t value) +{ + uint8_t varint_len = varint_size(value); + + switch (varint_len) { + case 1: + out[offset] = (uint8_t) value; + break; + case 3: + out[offset++] = 0xFD; + write_u16_le(out, offset, (uint16_t) value); + break; + case 5: + out[offset++] = 0xFE; + write_u32_le(out, offset, (uint32_t) value); + break; + case 9: + out[offset++] = 0xFF; + write_u64_le(out, offset, (uint64_t) value); + break; + default: + return -1; + } + + return varint_len; +} diff --git a/unit-tests/utils/varint.h b/unit-tests/utils/varint.h new file mode 100644 index 00000000..80aeb430 --- /dev/null +++ b/unit-tests/utils/varint.h @@ -0,0 +1,52 @@ +#pragma once + +#include // uint*_t +#include // size_t +#include // bool + +/** + * Size of value represented as Bitcoin-like varint. + * + * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer + * + * @param[in] value + * 64-bit unsigned integer to compute varint size. + * + * @return number of bytes to write value as varint (1, 3, 5 or 9 bytes). + * + */ +uint8_t varint_size(uint64_t value); + +/** + * Read Bitcoin-like varint from byte buffer. + * + * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer + * + * @param[in] in + * Pointer to input byte buffer. + * @param[in] in_len + * Length of the input byte buffer. + * @param[out] value + * Pointer to 64-bit unsigned integer to output varint. + * + * @return number of bytes read (1, 3, 5 or 9 bytes), -1 otherwise. + * + */ +int varint_read(const uint8_t *in, size_t in_len, uint64_t *value); + +/** + * Write Bitcoin-like varint to byte buffer. + * + * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer + * + * @param[out] out + * Pointer to output byte buffer. + * @param[in] offset + * Offset in the output byte buffer. + * @param[in] value + * 64-bit unsigned integer to write as varint. + * + * @return number of bytes written (1, 3, 5 or 9 bytes), -1 otherwise. + * + */ +int varint_write(uint8_t *out, size_t offset, uint64_t value); diff --git a/src/common/write.c b/unit-tests/utils/write.c similarity index 83% rename from src/common/write.c rename to unit-tests/utils/write.c index 58bc8f4e..b6ae4b7f 100644 --- a/src/common/write.c +++ b/unit-tests/utils/write.c @@ -17,19 +17,24 @@ #include // uint*_t #include // size_t -void write_u16_be(uint8_t *ptr, size_t offset, uint16_t value) { +#include "write.h" + +void write_u16_be(uint8_t *ptr, size_t offset, uint16_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 8); ptr[offset + 1] = (uint8_t) (value >> 0); } -void write_u32_be(uint8_t *ptr, size_t offset, uint32_t value) { +void write_u32_be(uint8_t *ptr, size_t offset, uint32_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 24); ptr[offset + 1] = (uint8_t) (value >> 16); ptr[offset + 2] = (uint8_t) (value >> 8); ptr[offset + 3] = (uint8_t) (value >> 0); } -void write_u64_be(uint8_t *ptr, size_t offset, uint64_t value) { +void write_u64_be(uint8_t *ptr, size_t offset, uint64_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 56); ptr[offset + 1] = (uint8_t) (value >> 48); ptr[offset + 2] = (uint8_t) (value >> 40); @@ -40,19 +45,22 @@ void write_u64_be(uint8_t *ptr, size_t offset, uint64_t value) { ptr[offset + 7] = (uint8_t) (value >> 0); } -void write_u16_le(uint8_t *ptr, size_t offset, uint16_t value) { +void write_u16_le(uint8_t *ptr, size_t offset, uint16_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 0); ptr[offset + 1] = (uint8_t) (value >> 8); } -void write_u32_le(uint8_t *ptr, size_t offset, uint32_t value) { +void write_u32_le(uint8_t *ptr, size_t offset, uint32_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 0); ptr[offset + 1] = (uint8_t) (value >> 8); ptr[offset + 2] = (uint8_t) (value >> 16); ptr[offset + 3] = (uint8_t) (value >> 24); } -void write_u64_le(uint8_t *ptr, size_t offset, uint64_t value) { +void write_u64_le(uint8_t *ptr, size_t offset, uint64_t value) +{ ptr[offset + 0] = (uint8_t) (value >> 0); ptr[offset + 1] = (uint8_t) (value >> 8); ptr[offset + 2] = (uint8_t) (value >> 16); @@ -61,4 +69,4 @@ void write_u64_le(uint8_t *ptr, size_t offset, uint64_t value) { ptr[offset + 5] = (uint8_t) (value >> 40); ptr[offset + 6] = (uint8_t) (value >> 48); ptr[offset + 7] = (uint8_t) (value >> 56); -} +} \ No newline at end of file diff --git a/src/common/write.h b/unit-tests/utils/write.h similarity index 96% rename from src/common/write.h rename to unit-tests/utils/write.h index 0418f5c6..41b99c45 100644 --- a/src/common/write.h +++ b/unit-tests/utils/write.h @@ -14,7 +14,7 @@ * 16-bit unsigned integer to write in output byte buffer as Big Endian. * */ -void write_u16_be(const uint8_t *ptr, size_t offset, uint16_t value); +void write_u16_be(uint8_t *ptr, size_t offset, uint16_t value); /** * Write 32-bit unsigned integer value as Big Endian.