diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 0000000..0cbcb22 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,7 @@ +FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER + +FROM gcr.io/oss-fuzz-base/base-builder:v1 +COPY . $SRC/app-kaspa +COPY ./.clusterfuzzlite/build.sh $SRC/ +COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-kaspa/BOLOS_SDK +WORKDIR $SRC/app-kaspa \ No newline at end of file diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100644 index 0000000..80bc5f5 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash -eu + +# build fuzzers + +pushd fuzzing +cmake -DBOLOS_SDK=../BOLOS_SDK -Bbuild -H. +make -C build +mv ./build/fuzz_tx_parser $OUT +mv ./build/fuzz_txin_parser $OUT +mv ./build/fuzz_txout_parser $OUT +popd \ No newline at end of file diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 0000000..e196c5c --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..98b720f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +# Checklist + +- [ ] App update process has been followed +- [ ] Target branch is `develop` +- [ ] Application version has been bumped + + diff --git a/.github/workflows/cflite_cron.yaml b/.github/workflows/cflite_cron.yaml new file mode 100644 index 0000000..9261ce7 --- /dev/null +++ b/.github/workflows/cflite_cron.yaml @@ -0,0 +1,40 @@ +name: ClusterFuzzLite cron tasks +on: + workflow_dispatch: + push: + branches: + - main # Use your actual default branch here. + schedule: + - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday +permissions: read-all +jobs: + Fuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - mode: batch + sanitizer: address + - mode: batch + sanitizer: memory + - mode: prune + sanitizer: address + - mode: coverage + sanitizer: coverage + steps: + - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + language: c # Change this to the language you are fuzzing. + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: ${{ matrix.mode }} + sanitizer: ${{ matrix.sanitizer }} diff --git a/.github/workflows/cflite_pr.yaml b/.github/workflows/cflite_pr.yaml new file mode 100644 index 0000000..f70175e --- /dev/null +++ b/.github/workflows/cflite_pr.yaml @@ -0,0 +1,43 @@ +name: ClusterFuzzLite PR fuzzing +on: + pull_request: + paths: + - '**' +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] # Override this with the sanitizers you want. + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c # Change this to the language you are fuzzing. + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". \ No newline at end of file diff --git a/Makefile b/Makefile index e9d02a2..525f87b 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ APPNAME = "Kaspa" # Application version APPVERSION_M = 1 APPVERSION_N = 0 -APPVERSION_P = 0 +APPVERSION_P = 2 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(TARGET_NAME),TARGET_NANOS) diff --git a/doc/COMMANDS.md b/doc/COMMANDS.md index ef049a2..80e0927 100644 --- a/doc/COMMANDS.md +++ b/doc/COMMANDS.md @@ -8,6 +8,7 @@ | `GET_APP_NAME` | 0x04 | Get ASCII encoded application name | | `GET_PUBLIC_KEY` | 0x05 | Get public key given BIP32 path | | `SIGN_TX` | 0x06 | Sign transaction given transaction info, utxos and outputs | +| `SIGN_MESSAGE` | 0x07 | Sign the personal message | ## GET_VERSION @@ -55,11 +56,11 @@ Keys for kaspa normally use the derivation path `m/44'/111111'/'/ | CData Part | Description | | --- | --- | -| `purpose` | Must be `44'` or `80000002c` | -| `coin_type` | Must be `111111'` or `8001b207` | -| `account` | Current wallets all use `80000000` (aka. `0'`) for default account but any value from `00000000` to `11111111` is accepted if passed | -| `type` | Current wallets use either `00000000` for Receive Address or `00000001` for Change Address, but any value from `00000000` to `11111111` is accepted if passed | -| `index` | Any value from `00000000` to `11111111` if passed | +| `purpose` | Must be `44'` or `0x80000002c` | +| `coin_type` | Must be `111111'` or `0x8001b207` | +| `account` | Current wallets all use `0x80000000` (aka. `0'`) for default account but any value from `0x80000000` to `0xFFFFFFFF` is accepted if passed | +| `type` | Current wallets use either `0x00000000` for Receive Address or `0x00000001` for Change Address, but any value from `0x00000000` to `0xFFFFFFFF` is accepted if passed | +| `index` | Any value from `0x00000000` to `0xFFFFFFFF` if passed | If you want to generate addresses using a root public key, @@ -88,7 +89,7 @@ Transactions signed with ECDSA are currently not supported. | P1 Value | Usage | CData | | --- | --- | --- | -| 0x00 | Sending transaction metadata | `version (2)` \|\| `output_len (1)` \|\| `input_len (1)` | +| 0x00 | Sending transaction metadata | `version (2)` \|\| `output_len (1)` \|\| `input_len (1)` \|\| `change_address_type (1)` \|\| `change_address_index (4)` \|\| `account (4)` | | 0x01 | Sending a tx output | `value (8)` \|\| `script_public_key (34/35)` | | 0x02 | Sending a tx input | `value (8)` \|\| `tx_id (32)` \|\| `address_type (1)` \|\| `address_index (4)` \|\| `outpoint_index (1)` | | 0x03 | Requesting for next signature | - | @@ -102,7 +103,7 @@ Transactions signed with ECDSA are currently not supported. `P2` value is used only if `P1 in {0x00, 0x01, 0x02}`. If `P1 = 0x03`, `P2` is ignored. #### Flow -1. Send the first APDU `P1 = 0x00` with the version, output length and input length +1. Send the first APDU `P1 = 0x00` with the version, output length and input length, change address type and index, and account (for UTXOs and change) 2. For each output (up to 2), send `P1 = 0x01` with the output CData 3. For each UTXO input send `P1 = 0x02` with the input CData. When sending the last UTXO input set `P2 = 0x00` to indicate that it is the last APDU. The signatures will later be sent back to you in the same order these inputs come in. 4. [Display] User will be able to view the transaction info and choose to `Approve` or `Reject`. @@ -133,12 +134,13 @@ Transactions signed with ECDSA are currently not supported. | CLA | INS | P1 | P2 | Lc | CData | | --- | --- | --- | --- | --- | --- | -| 0xE0 | 0x07 | 0x00 | 0x00 | var | `address_type (1)` \|\| `address_index (4)` \|\|
`message_len (1 bytes)` \|\| `message (var bytes)` | +| 0xE0 | 0x07 | 0x00 | 0x00 | var | `address_type (1)` \|\| `address_index (4)` \|\|
`account (4)` \|\|
`message_len (1 bytes)` \|\| `message (var bytes)` | | CData Part | Description | | --- | --- | | `address_type` | Either `00` for Receive Address or `01` for Change Address | -| `address_index` | Any value from `00000000` to `11111111` | +| `address_index` | Any value from `00000000` to `FFFFFFFF` | +| `account` | Any value from `80000000` to `FFFFFFFF` | | `message_len` | How long the message is. Must be a value from `1` to `128`, inclusive | | `message` | The message to sign | diff --git a/doc/TRANSACTION.md b/doc/TRANSACTION.md index 9bc76bc..a0c003b 100644 --- a/doc/TRANSACTION.md +++ b/doc/TRANSACTION.md @@ -25,12 +25,16 @@ For ECDSA-signed addresses (supported by this app only as a send address), it be | `n_outputs` | 1 | The number of outputs. Exactly 1 or 2. | `change_address_type` | 1 | `0` if `RECEIVE` or `1` if `CHANGE`* | | `change_address_index` | 4 | `0x00000000` to `0xFFFFFFFF`**| +| `account` | 4 | `0x80000000` to `0xFFFFFFFF`, normally should use `0x80000000` (the default account)***| \* While this will be used for the change, the path may be either `RECEIVE` or `CHANGE`. This is necessary in case the user wants to send the change back to the same address. In this case, the `change_address_type` has to be set to `RECEIVE`. \*\* `change_address_type` and `change_address_index` are ignored if `n_outputs == 1`. If `n_outputs == 2` then the path defined here must resolve to the same `script_public_key` in `outputs[1]`. + +\*\*\* `account` is the BIP44 account. A transaction can only come from a single account. Current Kaspa ecosystem only uses `0'` (or `0x80000000`) but support this is in anticipation of wider account-based support. + ### Transaction Input Total bytes: 46 @@ -54,7 +58,7 @@ Total bytes: 43 (max) | Field | Size (bytes) | Description | | --- | --- | --- | | `value` | 8 | The amount of KAS in sompi that will go send to the address | -| `script_public_key` | 35 | Schnorr: `20` + public_key (32 bytes) + `ac`
ECDSA: `20` + public_key (33 bytes) + `ab`
P2SH: `aa20` + public_key (32 bytes) + `87` | +| `script_public_key` | 35 | Schnorr: `0x20` + public_key (32 bytes) + `0xac`
ECDSA: `0x20` + public_key (33 bytes) + `0xab`
P2SH: `0xaa, 0x20` + script_hash (32 bytes) + `0x87` | ### Transaction Requirements - Fee = (total inputs amount) - (total outputs amount) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 53891ae..f974f7a 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -8,47 +8,53 @@ endif() project(FuzzTxParser VERSION 1.0 DESCRIPTION "Fuzzing of transaction parser" - LANGUAGES CXX) + LANGUAGES C) # guard against bad build-type strings if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug") endif() +if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "Fuzzer needs to be built with Clang") +endif() + +if (NOT DEFINED BOLOS_SDK) + message(FATAL_ERROR "BOLOS_SDK environment variable not found.") +endif() + # guard against in-source builds if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") endif() +# compatible with ClusterFuzzLite +if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + set(COMPILATION_FLAGS_ "-g -Wall -fsanitize=fuzzer,address,undefined") +else() + set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}") +endif() + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_compile_definitions(MAX_INPUT_COUNT=15 MAX_MESSAGE_LEN=200 USB_SEGMENT_SIZE=64) +string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_}) + include(extra/TxParser.cmake) -add_executable(fuzz_tx_parser fuzz_tx_parser.cc) -add_executable(fuzz_txout_parser fuzz_txout_parser.cc) -add_executable(fuzz_txin_parser fuzz_txin_parser.cc) - -target_compile_options(fuzz_tx_parser - PRIVATE $<$:-g -O2 -fsanitize=fuzzer,address,undefined> -) -target_compile_options(fuzz_txout_parser - PRIVATE $<$:-g -O2 -fsanitize=fuzzer,address,undefined> -) -target_compile_options(fuzz_txin_parser - PRIVATE $<$:-g -O2 -fsanitize=fuzzer,address,undefined> -) - -target_link_libraries(fuzz_tx_parser - PRIVATE $<$:-fsanitize=fuzzer,address,undefined> - PUBLIC txparser -) -target_link_libraries(fuzz_txout_parser - PRIVATE $<$:-fsanitize=fuzzer,address,undefined> - PUBLIC txparser -) -target_link_libraries(fuzz_txin_parser - PRIVATE $<$:-fsanitize=fuzzer,address,undefined> - PUBLIC txparser -) +add_executable(fuzz_tx_parser fuzz_tx_parser.c) +add_executable(fuzz_txout_parser fuzz_txout_parser.c) +add_executable(fuzz_txin_parser fuzz_txin_parser.c) + +target_compile_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_libraries(fuzz_tx_parser PUBLIC txparser) + +target_compile_options(fuzz_txout_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_options(fuzz_txout_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_libraries(fuzz_txout_parser PUBLIC txparser) + +target_compile_options(fuzz_txin_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_options(fuzz_txin_parser PUBLIC ${COMPILATION_FLAGS}) +target_link_libraries(fuzz_txin_parser PUBLIC txparser) \ No newline at end of file diff --git a/fuzzing/README.md b/fuzzing/README.md index be3d7a8..8c0da96 100644 --- a/fuzzing/README.md +++ b/fuzzing/README.md @@ -1,18 +1,22 @@ # Fuzzing on transaction parser +## Setup + +Change `~/ledger/app-kaspa` to wherever you actual `app-kaspa` folder is. + +``` +docker run --rm -it -v ~/kaspa/ledger/app-kaspa:/app ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest bash +``` + ## Compilation + In `fuzzing` folder ``` -cmake -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -Bbuild -H. +cmake -DBOLOS_SDK=$NANOSP_SDK -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H. ``` -cmake -DCMAKE_C_COMPILER=/tmp/llvm-project/build/bin/clang \ --DCMAKE_CXX_COMPILER=/tmp/llvm-project/build/bin/clang++ \ --DGCC_INSTALL_PREFIX=/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/ \ --Bbuild -H. - then ``` @@ -23,22 +27,37 @@ make -C build ``` ./build/fuzz_tx_parser +./build/fuzz_txin_parser +./build/fuzz_txout_parser ``` -## Extra installs +## LLVM Compile +Use this if you want to build the LLVM from scratch and use it + +A pre-compiled version of the ones this fuzzing needs is in `llvm-headers`. + +Update your docker run to: ``` -apk add build-base libc-dev linux-headers libexecinfo-dev llvm12 compiler-rt +docker run -it -v ~/ledger/app-kaspa:/app -v ~/llvm-project:/tmp/llvm-project ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest bash +apk add build-base libc-dev linux-headers libexecinfo-dev compiler-rt +apk del llvm15 ``` -## LLVM Compile +Clone the LLVM project from: https://github.com/llvm/llvm-project +``` +git clone https://github.com/llvm/llvm-project ~/llvm-project +``` ``` cd /tmp/llvm-project mkdir build cd build -cmake ../llvm/ -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/tmp/llvm-project/build/ -DBUILD_SHARED_LIBS=on -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" -DLLVM_ENABLE_BACKTRACES=OFF -DCOMPILER_RT_BUILD_GWP_ASAN=OFF +cmake ../llvm/ -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/tmp/llvm-project/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=on -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" -DLLVM_ENABLE_BACKTRACES=OFF -DCOMPILER_RT_BUILD_GWP_ASAN=OFF + +make -j8 -cp /tmp/llvm-project/build/lib/clang/15.0.0/lib/linux/libclang* /usr/lib/clang/12.0.1/lib/linux/ -``` \ No newline at end of file +cp /tmp/llvm-project/build/lib/clang/16/lib/x86_64-unknown-linux-gnu/libclang_rt.asan.a /usr/lib/clang/12.0.1/lib/linux/libclang_rt.asan-x86_64.a +cp /tmp/llvm-project/build/lib/clang/16/lib/x86_64-unknown-linux-gnu/libclang_rt.fuzzer.a /usr/lib/clang/12.0.1/lib/linux/libclang_rt.fuzzer-x86_64.a +``` diff --git a/fuzzing/extra/TxParser.cmake b/fuzzing/extra/TxParser.cmake index 48d9a27..3585667 100644 --- a/fuzzing/extra/TxParser.cmake +++ b/fuzzing/extra/TxParser.cmake @@ -8,18 +8,22 @@ project(TxParser set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED True) set(CMAKE_C_FLAGS_DEBUG - "${CMAKE_C_FLAGS_DEBUG} -Werror -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0" + "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0" ) -add_library(txparser SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/../src/common/bip32.c - ${CMAKE_CURRENT_SOURCE_DIR}/../src/common/read.c - ${CMAKE_CURRENT_SOURCE_DIR}/../src/common/write.c - ${CMAKE_CURRENT_SOURCE_DIR}/../src/common/buffer.c - ${CMAKE_CURRENT_SOURCE_DIR}/../src/common/format.c +add_library(txparser + ${BOLOS_SDK}/lib_standard_app/format.c + ${BOLOS_SDK}/lib_standard_app/buffer.c + ${BOLOS_SDK}/lib_standard_app/read.c + ${BOLOS_SDK}/lib_standard_app/varint.c + ${BOLOS_SDK}/lib_standard_app/bip32.c + ${BOLOS_SDK}/lib_standard_app/write.c ${CMAKE_CURRENT_SOURCE_DIR}/../src/transaction/deserialize.c ) set_target_properties(txparser PROPERTIES SOVERSION 1) -target_include_directories(txparser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../src) +target_include_directories(txparser PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ${BOLOS_SDK}/lib_standard_app +) \ No newline at end of file diff --git a/fuzzing/fuzz_tx_parser.cc b/fuzzing/fuzz_tx_parser.c similarity index 93% rename from fuzzing/fuzz_tx_parser.cc rename to fuzzing/fuzz_tx_parser.c index 4179b83..2ce1a18 100644 --- a/fuzzing/fuzz_tx_parser.cc +++ b/fuzzing/fuzz_tx_parser.c @@ -26,18 +26,17 @@ #include #include -extern "C" { #include "buffer.h" -#include "common/format_local.h" +#include "format.h" #include "transaction/deserialize.h" #include "transaction/types.h" -} +#include "constants.h" -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { buffer_t buf = {.ptr = data, .size = size, .offset = 0}; transaction_t tx; parser_status_e status; - uint32_t bip32_path[5]; + uint32_t bip32_path[KASPA_MAX_BIP32_PATH_LEN]; char version[3] = {0}; char tx_input_len[3] = {0}; char tx_output_len[3] = {0}; @@ -56,4 +55,4 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { } return 0; -} \ No newline at end of file +} diff --git a/fuzzing/fuzz_txin_parser.cc b/fuzzing/fuzz_txin_parser.c similarity index 94% rename from fuzzing/fuzz_txin_parser.cc rename to fuzzing/fuzz_txin_parser.c index 5bc030f..2f0a468 100644 --- a/fuzzing/fuzz_txin_parser.cc +++ b/fuzzing/fuzz_txin_parser.c @@ -26,14 +26,12 @@ #include #include -extern "C" { #include "buffer.h" -#include "common/format_local.h" +#include "format.h" #include "transaction/deserialize.h" #include "transaction/types.h" -} -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { buffer_t buf = {.ptr = data, .size = size, .offset = 0}; transaction_input_t txin; parser_status_e status; diff --git a/fuzzing/fuzz_txout_parser.cc b/fuzzing/fuzz_txout_parser.c similarity index 94% rename from fuzzing/fuzz_txout_parser.cc rename to fuzzing/fuzz_txout_parser.c index cee3e4a..e205d8e 100644 --- a/fuzzing/fuzz_txout_parser.cc +++ b/fuzzing/fuzz_txout_parser.c @@ -26,14 +26,12 @@ #include #include -extern "C" { #include "buffer.h" -#include "common/format_local.h" +#include "format.h" #include "transaction/deserialize.h" #include "transaction/types.h" -} -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { buffer_t buf = {.ptr = data, .size = size, .offset = 0}; transaction_output_t txout; parser_status_e status; diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 0000000..b5d4c3a --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,8 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"] + +[tests] +unit_directory = "./unit-tests/" +pytest_directory = "./tests/" \ No newline at end of file diff --git a/src/address.c b/src/address.c index 55c41ab..f61a5cb 100644 --- a/src/address.c +++ b/src/address.c @@ -33,12 +33,19 @@ size_t compress_public_key(const uint8_t public_key[static 64], address_type_e address_type, - uint8_t *out) { + uint8_t *out, + size_t out_len) { size_t compressed_pub_size = 0; if (address_type == SCHNORR || address_type == P2SH) { compressed_pub_size = 32; + if (out_len < 32) { + return 0; + } memmove(out, public_key, 32); } else if (address_type == ECDSA) { + if (out_len < 33) { + return 0; + } compressed_pub_size = 33; // If Y coord is even, first byte is 0x02. if odd then 0x03 out[0] = public_key[63] % 2 == 0 ? 0x02 : 0x03; @@ -81,8 +88,10 @@ bool address_from_pubkey(const uint8_t public_key[static 64], // For schnorr, compressed public key we care about is the X coordinate // For ecdsa, compress public key is 1 byte (y-coord: 0x02 if even, 0x03 if odd) then X // coordinate - size_t compressed_pub_size = - compress_public_key(public_key, address_type, compressed_public_key); + size_t compressed_pub_size = compress_public_key(public_key, + address_type, + compressed_public_key, + sizeof(compressed_public_key)); if (compressed_pub_size == 0) { return false; diff --git a/src/address.h b/src/address.h index 18af109..afd0508 100644 --- a/src/address.h +++ b/src/address.h @@ -39,7 +39,8 @@ */ size_t compress_public_key(const uint8_t public_key[static 64], address_type_e address_type, - uint8_t *out); + uint8_t *out, + size_t out_len); /** * Convert public key to address. diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h index 00873cc..de090c1 100644 --- a/src/apdu/dispatcher.h +++ b/src/apdu/dispatcher.h @@ -24,6 +24,7 @@ #pragma once #include "../types.h" +#include "parser.h" /** * Parameter 2 for last APDU to receive. diff --git a/src/apdu/parser.c b/src/apdu/parser.c deleted file mode 100644 index 6ac0a2e..0000000 --- a/src/apdu/parser.c +++ /dev/null @@ -1,46 +0,0 @@ -/***************************************************************************** - * MIT License - * - * Copyright (c) 2023 coderofstuff - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#include // size_t -#include // uint*_t -#include // bool - -#include "parser.h" -#include "../types.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 7bc39a3..0000000 --- a/src/apdu/parser.h +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * MIT License - * - * Copyright (c) 2023 coderofstuff - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ -#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/app_main.c b/src/app_main.c index 07fb70f..5a2f5b1 100644 --- a/src/app_main.c +++ b/src/app_main.c @@ -32,7 +32,7 @@ #include "io.h" #include "sw.h" #include "ui/menu.h" -#include "apdu/parser.h" +#include "parser.h" #include "apdu/dispatcher.h" global_ctx_t G_context; diff --git a/src/constants.h b/src/constants.h index 151d691..33077f4 100644 --- a/src/constants.h +++ b/src/constants.h @@ -67,4 +67,6 @@ #define MESSAGE_SIGNING_KEY "PersonalMessageSigningHash" -#define MAX_OUTPUT_COUNT 2 +#define MAX_OUTPUT_COUNT 2 +#define SCRIPT_PUBLIC_KEY_BUFFER_LEN 40 +#define KASPA_MAX_BIP32_PATH_LEN 5 diff --git a/src/crypto.c b/src/crypto.c index 53a2c72..a429f32 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -63,10 +63,10 @@ int crypto_sign_transaction(void) { transaction_input_t *txin = &G_context.tx_info.transaction.tx_inputs[G_context.tx_info.signing_input_index]; - // 44'/111111'/0'/ address_type / address_index + // 44'/111111'/account'/ address_type / address_index G_context.bip32_path[0] = 0x8000002C; G_context.bip32_path[1] = 0x8001b207; - G_context.bip32_path[2] = 0x80000000; + G_context.bip32_path[2] = G_context.tx_info.transaction.account; G_context.bip32_path[3] = (uint32_t)(txin->address_type); G_context.bip32_path[4] = txin->address_index; @@ -92,10 +92,13 @@ int crypto_sign_transaction(void) { return error; } - calc_sighash(&G_context.tx_info.transaction, - txin, - public_key.W + 1, - G_context.tx_info.sighash); + if (!calc_sighash(&G_context.tx_info.transaction, + txin, + public_key.W + 1, + G_context.tx_info.sighash, + sizeof(G_context.tx_info.sighash))) { + return -1; + } size_t sig_len = sizeof(G_context.tx_info.signature); error = cx_ecschnorr_sign_no_throw(&private_key, @@ -120,9 +123,12 @@ int crypto_sign_transaction(void) { } int crypto_sign_personal_message(void) { - hash_personal_message(G_context.msg_info.message, - G_context.msg_info.message_len, - G_context.msg_info.message_hash); + if (!hash_personal_message(G_context.msg_info.message, + G_context.msg_info.message_len, + G_context.msg_info.message_hash, + sizeof(G_context.msg_info.message_hash))) { + return -1; + } cx_ecfp_private_key_t private_key = {0}; uint8_t chain_code[32] = {0}; diff --git a/src/handler/sign_msg.c b/src/handler/sign_msg.c index 5005842..9ada060 100644 --- a/src/handler/sign_msg.c +++ b/src/handler/sign_msg.c @@ -61,6 +61,14 @@ int handler_sign_msg(buffer_t *cdata) { return io_send_sw(SW_MESSAGE_ADDRESS_TYPE_FAIL); } + if (!buffer_read_u32(cdata, &G_context.msg_info.account, BE)) { + return io_send_sw(SW_MESSAGE_ADDRESS_TYPE_FAIL); + } + + if (G_context.msg_info.account < 0x80000000) { + return io_send_sw(SW_MESSAGE_ADDRESS_TYPE_FAIL); + } + uint8_t message_len = 0; if (!buffer_read_u8(cdata, &message_len)) { return io_send_sw(SW_MESSAGE_LEN_PARSING_FAIL); @@ -88,7 +96,7 @@ int handler_sign_msg(buffer_t *cdata) { G_context.bip32_path[0] = 0x8000002C; G_context.bip32_path[1] = 0x8001b207; - G_context.bip32_path[2] = 0x80000000; + G_context.bip32_path[2] = G_context.msg_info.account; G_context.bip32_path[3] = (uint32_t)(G_context.msg_info.address_type); G_context.bip32_path[4] = G_context.msg_info.address_index; diff --git a/src/personal_message.c b/src/personal_message.c index f9196e1..81397d4 100644 --- a/src/personal_message.c +++ b/src/personal_message.c @@ -29,7 +29,7 @@ #include "./import/blake2b.h" #include "./personal_message.h" -static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { +static bool hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { if (key == NULL && key_len != 0) { goto err; } @@ -44,29 +44,39 @@ static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_ if (blake2b_init_key(hash, size, key, key_len) < 0) { goto err; } - return 0; + return true; err: - return -1; + return false; } -static void hash_update(blake2b_state* hash, uint8_t* data, size_t len) { - blake2b_update(hash, data, len); +static bool hash_update(blake2b_state* hash, uint8_t* data, size_t len) { + return blake2b_update(hash, data, len) == 0; } -static void hash_finalize(blake2b_state* hash, uint8_t* out) { - blake2b_final(hash, out, 32); +static bool hash_finalize(blake2b_state* hash, uint8_t* out, size_t out_len) { + if (out_len < 32) { + return false; + } + return blake2b_final(hash, out, 32) == 0; } -bool hash_personal_message(uint8_t* message_bytes, size_t message_byte_len, uint8_t* out_hash) { +bool hash_personal_message(uint8_t* message_bytes, + size_t message_byte_len, + uint8_t* out_hash, + size_t out_len) { + if (out_len < 32) { + return false; + } + blake2b_state inner_hash_writer; - int err = hash_init(&inner_hash_writer, 256, (uint8_t*) MESSAGE_SIGNING_KEY, 26); - if (err < 0) { + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) MESSAGE_SIGNING_KEY, 26)) { return false; } - hash_update(&inner_hash_writer, message_bytes, message_byte_len); - hash_finalize(&inner_hash_writer, out_hash); + if (!hash_update(&inner_hash_writer, message_bytes, message_byte_len)) { + return false; + } - return true; + return hash_finalize(&inner_hash_writer, out_hash, out_len); } diff --git a/src/personal_message.h b/src/personal_message.h index 9d31527..901c1e9 100644 --- a/src/personal_message.h +++ b/src/personal_message.h @@ -26,4 +26,7 @@ #include #include -bool hash_personal_message(uint8_t* message_bytes, size_t message_byte_len, uint8_t* out_hash); \ No newline at end of file +bool hash_personal_message(uint8_t* message_bytes, + size_t message_byte_len, + uint8_t* out_hash, + size_t out_len); diff --git a/src/sighash.c b/src/sighash.c index 47124ac..0b0475e 100644 --- a/src/sighash.c +++ b/src/sighash.c @@ -34,10 +34,7 @@ #include "globals.h" #include "./constants.h" -uint8_t outer_buffer[32] = {0}; -uint8_t inner_buffer[32] = {0}; - -static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { +static bool hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { if (key == NULL && key_len != 0) { goto err; } @@ -52,75 +49,104 @@ static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_ if (blake2b_init_key(hash, size, key, key_len) < 0) { goto err; } - return 0; + return true; err: - return -1; + return false; } -static void hash_update(blake2b_state* hash, uint8_t* data, size_t len) { - blake2b_update(hash, data, len); +static bool hash_update(blake2b_state* hash, uint8_t* data, size_t len) { + // blake2b_update currently always returns 0 + return blake2b_update(hash, data, len) == 0; } -static void hash_finalize(blake2b_state* hash, uint8_t* out) { - blake2b_final(hash, out, 32); +static bool hash_finalize(blake2b_state* hash, uint8_t* out, size_t out_len) { + if (out_len < 32) { + return false; + } + // blake2b_final returns 0 for success and -1 for any error + return blake2b_final(hash, out, 32) == 0; } -static void calc_prev_outputs_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_prev_outputs_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u32_le(inner_buffer, 0, tx->tx_inputs[i].index); - hash_update(&inner_hash_writer, tx->tx_inputs[i].tx_id, 32); - hash_update(&inner_hash_writer, inner_buffer, 4); + if (!hash_update(&inner_hash_writer, tx->tx_inputs[i].tx_id, 32)) { + return false; + } + if (!hash_update(&inner_hash_writer, inner_buffer, 4)) { + return false; + } } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_sequences_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_sequences_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u64_le(inner_buffer, 0, tx->tx_inputs[i].sequence); - hash_update(&inner_hash_writer, inner_buffer, 8); + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_sig_op_count_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_sig_op_count_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 1, 1); - hash_update(&inner_hash_writer, inner_buffer, 1); + if (!hash_update(&inner_hash_writer, inner_buffer, 1)) { + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_outputs_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_outputs_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_output_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u64_le(inner_buffer, 0, tx->tx_outputs[i].value); - hash_update(&inner_hash_writer, inner_buffer, 8); // Write the output value + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + // Write the output value + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); - hash_update(&inner_hash_writer, - inner_buffer, - 2); // Write the output script version, assume 0 + if (!hash_update(&inner_hash_writer, inner_buffer, 2)) { + // Write the output script version, assume 0 + return false; + } uint8_t script_len = 0; if (tx->tx_outputs[i].script_public_key[0] == 0xaa) { @@ -137,14 +163,21 @@ static void calc_outputs_hash(transaction_t* tx, uint8_t* out_hash) { script_len); // Write the number of bytes of the script public key } - hash_update(&inner_hash_writer, inner_buffer, 8); - hash_update(&inner_hash_writer, tx->tx_outputs[i].script_public_key, script_len); + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + return false; + } + if (!hash_update(&inner_hash_writer, tx->tx_outputs[i].script_public_key, script_len)) { + return false; + } } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash) { +static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash, size_t out_len) { + if (out_len < 34) { + return false; + } // Assume schnorr out_hash[0] = 0x20; memmove(out_hash + 1, public_key, 32); @@ -153,84 +186,141 @@ static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash) return true; } -void calc_sighash(transaction_t* tx, +bool calc_sighash(transaction_t* tx, transaction_input_t* txin, uint8_t* public_key, - uint8_t* out_hash) { + uint8_t* out_hash, + size_t out_len) { + if (out_len < 32) { + return false; + } + uint8_t outer_buffer[36] = {0}; blake2b_state sighash; memset(outer_buffer, 0, sizeof(outer_buffer)); - memset(inner_buffer, 0, sizeof(inner_buffer)); - hash_init(&sighash, 256, (uint8_t*) SIGNING_KEY, 22); + if (!hash_init(&sighash, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } // Write version, little endian, 2 bytes write_u16_le(outer_buffer, 0, tx->version); - hash_update(&sighash, outer_buffer, 2); + if (!hash_update(&sighash, outer_buffer, 2)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write previous outputs hash - calc_prev_outputs_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_prev_outputs_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sequence hash - calc_sequences_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_sequences_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sig op count hash - calc_sig_op_count_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_sig_op_count_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write Hash of the outpoint - hash_update(&sighash, txin->tx_id, 32); + if (!hash_update(&sighash, txin->tx_id, 32)) { + return false; + } write_u32_le(outer_buffer, 0, txin->index); - hash_update(&sighash, outer_buffer, 4); + if (!hash_update(&sighash, outer_buffer, 4)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); - hash_update(&sighash, outer_buffer, 2); // Write input script version, assume 0 + if (!hash_update(&sighash, outer_buffer, 2)) { + // Write input script version, assume 0 + return false; + } // Write input's script_public_key. Length as uint64_t followed by script // count (1 byte) + public key (32/33 byte) + op (1 byte) uint64_t script_len = 34; write_u64_le(outer_buffer, 0, script_len); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } - calc_txin_script_public_key(public_key, outer_buffer); - hash_update(&sighash, outer_buffer, script_len); + if (!calc_txin_script_public_key(public_key, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, script_len)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write input's value write_u64_le(outer_buffer, 0, txin->value); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write input's sequence number write_u64_le(outer_buffer, 0, txin->sequence); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sigopcount, assume 1 outer_buffer[0] = 0x01; - hash_update(&sighash, outer_buffer, 1); + if (!hash_update(&sighash, outer_buffer, 1)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write outputs hash - calc_outputs_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_outputs_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write last bits of data, assuming 0 - hash_update(&sighash, outer_buffer, 8); // Write locktime of 0 - hash_update(&sighash, outer_buffer, 20); // Write subnetwork Id, assume zero hash - hash_update(&sighash, outer_buffer, 8); // Write gas, assume 0 - hash_update(&sighash, outer_buffer, 32); // Write payload hash, assume 0 + if (!hash_update(&sighash, outer_buffer, 8)) { + // Write locktime of 0 + return false; + } + if (!hash_update(&sighash, outer_buffer, 20)) { + // Write subnetwork Id, assume zero hash + return false; + } + if (!hash_update(&sighash, outer_buffer, 8)) { + // Write gas, assume 0 + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + // Write payload hash, assume 0 + return false; + } // Write sighash type, assume SigHashAll => 0x01 outer_buffer[0] = 0x01; - hash_update(&sighash, outer_buffer, 1); + if (!hash_update(&sighash, outer_buffer, 1)) { + return false; + } - hash_finalize(&sighash, out_hash); + return hash_finalize(&sighash, out_hash, out_len); } diff --git a/src/sighash.h b/src/sighash.h index 5743399..ad790d6 100644 --- a/src/sighash.h +++ b/src/sighash.h @@ -29,7 +29,8 @@ /** * Calculate the signature hash for the given transaction and input */ -void calc_sighash(transaction_t* tx, +bool calc_sighash(transaction_t* tx, transaction_input_t* txin, uint8_t* public_key, - uint8_t* out_hash); + uint8_t* out_hash, + size_t out_len); diff --git a/src/transaction/deserialize.c b/src/transaction/deserialize.c index 8451f33..32747ff 100644 --- a/src/transaction/deserialize.c +++ b/src/transaction/deserialize.c @@ -33,12 +33,26 @@ parser_status_e transaction_output_deserialize(buffer_t *buf, transaction_output return OUTPUT_VALUE_PARSING_ERROR; } - size_t script_len = (size_t) * (buf->ptr + buf->offset); + if (!buffer_can_read(buf, 1)) { + return OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR; + } + + uint8_t script_len = (uint8_t) * (buf->ptr + buf->offset); if (script_len == OP_BLAKE2B) { - // P2SH = 0xaa + 0x20 + (pubkey) + 0x87 + // P2SH = 0xaa + 0x20 + (script hash) + 0x87 + // Total length = 35 // script len is actually the second byte if the first one is 0xaa - script_len = (size_t) * (buf->ptr + buf->offset + 1); + if (!buffer_can_read(buf, 2)) { + return OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR; + } + + script_len = (uint8_t) * (buf->ptr + buf->offset + 1); + + // For P2SH, we expect len to always be 0x20 + if (script_len != 0x20) { + return OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR; + } if (!buffer_can_read(buf, script_len + 3)) { return OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR; @@ -46,7 +60,8 @@ parser_status_e transaction_output_deserialize(buffer_t *buf, transaction_output uint8_t sig_op_code = *(buf->ptr + buf->offset + script_len + 2); - if (script_len == 0x20 && sig_op_code != OP_EQUAL) { + // We expect the end to always be 0x87 for P2SH + if (sig_op_code != OP_EQUAL) { return OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR; } @@ -120,6 +135,10 @@ parser_status_e transaction_input_deserialize(buffer_t *buf, transaction_input_t } parser_status_e transaction_deserialize(buffer_t *buf, transaction_t *tx, uint32_t *bip32_path) { + if (KASPA_MAX_BIP32_PATH_LEN < 5) { + return HEADER_PARSING_ERROR; + } + uint8_t n_output = 0; uint8_t n_input = 0; uint8_t change_address_type = 0; @@ -164,9 +183,18 @@ parser_status_e transaction_deserialize(buffer_t *buf, transaction_t *tx, uint32 return HEADER_PARSING_ERROR; } + if (!buffer_read_u32(buf, &tx->account, BE)) { + return HEADER_PARSING_ERROR; + } + + // Account must be hardened + if (tx->account < 0x80000000) { + return HEADER_PARSING_ERROR; + } + bip32_path[0] = 0x8000002C; bip32_path[1] = 0x8001b207; - bip32_path[2] = 0x80000000; + bip32_path[2] = tx->account; bip32_path[3] = (uint32_t)(change_address_type); bip32_path[4] = change_address_index; diff --git a/src/transaction/serialize.c b/src/transaction/serialize.c index 7cdc35e..c27509a 100644 --- a/src/transaction/serialize.c +++ b/src/transaction/serialize.c @@ -32,7 +32,7 @@ int transaction_serialize(const transaction_t *tx, uint32_t *path, uint8_t *out, size_t out_len) { size_t offset = 0; - if (out_len < 4) { + if (out_len < 9) { return -1; } @@ -46,6 +46,9 @@ int transaction_serialize(const transaction_t *tx, uint32_t *path, uint8_t *out, write_u32_be(out, offset, path[4]); offset += 4; + write_u32_be(out, offset, path[2]); + offset += 4; + return (int) offset; } diff --git a/src/transaction/tx_validate.c b/src/transaction/tx_validate.c index 1eaa785..55f8fb2 100644 --- a/src/transaction/tx_validate.c +++ b/src/transaction/tx_validate.c @@ -55,9 +55,9 @@ bool tx_validate_parsed_transaction(transaction_t* tx) { // Forcing these values. path[3] and path[4] // would've been set by transaction_deserialize - G_context.bip32_path[0] = 0x8000002C; - G_context.bip32_path[1] = 0x8001b207; - G_context.bip32_path[2] = 0x80000000; + G_context.bip32_path[0] = 0x8000002C; // 44' + G_context.bip32_path[1] = 0x8001b207; // 111111' + G_context.bip32_path[2] = tx->account; // the account G_context.bip32_path_len = 5; diff --git a/src/transaction/types.h b/src/transaction/types.h index 49eaed2..9c1ad9e 100644 --- a/src/transaction/types.h +++ b/src/transaction/types.h @@ -77,13 +77,15 @@ typedef struct { typedef struct { uint64_t value; - uint8_t script_public_key[40]; // In hex: 20 + public_key_hex + ac (34/35 bytes total) + uint8_t script_public_key[SCRIPT_PUBLIC_KEY_BUFFER_LEN]; // In hex: 20 + public_key_hex + ac + // (34/35 bytes total) } transaction_output_t; typedef struct { // For signature purposes: // Based on: https://kaspa-mdbook.aspectron.com/transactions/constraints/size.html uint16_t version; + uint32_t account; // The BIP44 account used for inputs in this transaction size_t tx_input_len; // check size_t tx_output_len; diff --git a/src/transaction/utils.c b/src/transaction/utils.c index 4a56eff..9215b8a 100644 --- a/src/transaction/utils.c +++ b/src/transaction/utils.c @@ -38,18 +38,36 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len) { return true; } -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key) { +bool script_public_key_to_address(uint8_t* out_address, + size_t out_len, + uint8_t* in_script_public_key, + size_t script_len) { uint8_t public_key[64] = {0}; + + // script public keys are always at least 32 bytes. We'll check this again + // once we know more about the script + if (script_len < 32) { + return false; + } + // public script keys begin with the length, followed by the amount of data size_t first_byte = (size_t) in_script_public_key[0]; address_type_e type = SCHNORR; size_t address_len = SCHNORR_ADDRESS_LEN; if (first_byte == 0xaa) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } type = P2SH; address_len = SCHNORR_ADDRESS_LEN; memmove(public_key, in_script_public_key + 2, 32); } else if (first_byte == 0x21) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } // We're dealing with ECDSA instead: type = ECDSA; address_len = ECDSA_ADDRESS_LEN; @@ -62,10 +80,19 @@ void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_publi // Set the correct parity for the y-coord memset(public_key + 32, parity, 32); } else { + // In this case, script len must be at least 35 chars + if (script_len < 34) { + return false; + } memmove(public_key, in_script_public_key + 1, 32); } - address_from_pubkey(public_key, type, out_address, address_len); + // We need space to write address_len + if (out_len < address_len) { + return false; + } + + return address_from_pubkey(public_key, type, out_address, address_len); } uint64_t calc_fees(transaction_input_t* inputs, diff --git a/src/transaction/utils.h b/src/transaction/utils.h index ccc81aa..436129b 100644 --- a/src/transaction/utils.h +++ b/src/transaction/utils.h @@ -46,10 +46,15 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len); * * @param[out] out_address * Pointer to the buffer to write the address to + * @param[in] out_len length of output buffer * @param[in] in_script_public_key * Pointer to the buffer to read script_public_key from + * @param[in] script_len length of script output buffer */ -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key); +void script_public_key_to_address(uint8_t* out_address, + size_t out_len, + uint8_t* in_script_public_key, + size_t script_len); /** * Calculate the fees by checking the difference between inputs and outputs diff --git a/src/types.h b/src/types.h index 454b86e..3a6a587 100644 --- a/src/types.h +++ b/src/types.h @@ -44,18 +44,6 @@ typedef enum { SIGN_MESSAGE = 0x07 /// sign a personal message with BIP32 path } command_e; -/** - * Structure with fields of APDU command. - */ -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; - /** * Enumeration with parsing state. */ @@ -108,6 +96,7 @@ typedef struct { uint8_t message[128]; /// message bytes uint8_t message_hash[32]; /// message hash uint8_t signature[MAX_DER_SIG_LEN]; /// signature of the message + uint32_t account; /// The account this message will be signed with uint8_t address_type; /// address type to use for bip32 path uint32_t address_index; /// address index to use for bip32 path } message_sign_ctx_t; @@ -122,7 +111,7 @@ typedef struct { transaction_ctx_t tx_info; /// transaction context message_sign_ctx_t msg_info; /// message sign context }; - request_type_e req_type; /// user request - uint32_t bip32_path[MAX_BIP32_PATH]; /// BIP32 path - uint8_t bip32_path_len; /// length of BIP32 path + request_type_e req_type; /// user request + uint32_t bip32_path[KASPA_MAX_BIP32_PATH_LEN]; /// BIP32 path + uint8_t bip32_path_len; /// length of BIP32 path } global_ctx_t; diff --git a/src/ui/bagl_display.c b/src/ui/bagl_display.c index 30b58e7..5512600 100644 --- a/src/ui/bagl_display.c +++ b/src/ui/bagl_display.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_BAGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset @@ -218,8 +215,11 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; - script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + script_public_key_to_address( + address, + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + sizeof(G_context.tx_info.transaction.tx_outputs[0].script_public_key)); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); g_validate_callback = &ui_action_validate_transaction; diff --git a/src/ui/nbgl_display_address.c b/src/ui/nbgl_display_address.c index decebab..cd8789f 100644 --- a/src/ui/nbgl_display_address.c +++ b/src/ui/nbgl_display_address.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset diff --git a/src/ui/nbgl_display_message.c b/src/ui/nbgl_display_message.c index f6a6a17..8eb0fcf 100644 --- a/src/ui/nbgl_display_message.c +++ b/src/ui/nbgl_display_message.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset diff --git a/src/ui/nbgl_display_transaction.c b/src/ui/nbgl_display_transaction.c index 06feb71..450dd4b 100755 --- a/src/ui/nbgl_display_transaction.c +++ b/src/ui/nbgl_display_transaction.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset @@ -143,8 +140,11 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; - script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + script_public_key_to_address( + address, + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + sizeof(G_context.tx_info.transaction.tx_outputs[0].script_public_key)); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); // Start review diff --git a/tests/application_client/kaspa_message.py b/tests/application_client/kaspa_message.py index 4fdf59f..602c5af 100644 --- a/tests/application_client/kaspa_message.py +++ b/tests/application_client/kaspa_message.py @@ -5,17 +5,21 @@ def hash_init() -> blake2b: class PersonalMessage: def __init__(self, - address_type: int, - address_index: int, - message: str): - self.address_type: int = address_type # 1 byte - self.address_index:int = address_index # 4 bytes + message: str, + address_type: int = 0, + address_index: int = 0, + account: int = 0x80000000, + ): self.message: bytes = bytes(message, 'utf8') # var + self.address_type: int = address_type # 1 byte + self.address_index: int = address_index # 4 bytes + self.account: int = account # 4 bytes def serialize(self) -> bytes: return b"".join([ self.address_type.to_bytes(1, byteorder="big"), self.address_index.to_bytes(4, byteorder="big"), + self.account.to_bytes(4, byteorder="big"), len(self.message).to_bytes(1, byteorder="big"), self.message ]) diff --git a/tests/application_client/kaspa_transaction.py b/tests/application_client/kaspa_transaction.py index 3a031a4..78bc002 100644 --- a/tests/application_client/kaspa_transaction.py +++ b/tests/application_client/kaspa_transaction.py @@ -83,12 +83,14 @@ def __init__(self, outputs: list[TransactionOutput], change_address_type: int = 0, change_address_index: int = 0, + account: int = 0x80000000, do_check: bool = True) -> None: self.version: int = version self.inputs: list[TransactionInput] = inputs self.outputs: list[TransactionOutput] = outputs self.change_address_type: int = change_address_type self.change_address_index: int = change_address_index + self.account: int = account if do_check: if not 0 <= self.version <= 1: @@ -101,6 +103,7 @@ def serialize_first_chunk(self) -> bytes: len(self.inputs).to_bytes(1, byteorder="big"), self.change_address_type.to_bytes(1, byteorder="big"), self.change_address_index.to_bytes(4, byteorder="big"), + self.account.to_bytes(4, byteorder="big"), ]) def serialize(self) -> bytes: diff --git a/tests/snapshots/nanos/test_app_mainmenu/00001.png b/tests/snapshots/nanos/test_app_mainmenu/00001.png index dc3cd97..5330756 100644 Binary files a/tests/snapshots/nanos/test_app_mainmenu/00001.png and b/tests/snapshots/nanos/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/nanos/test_sign_message_simple_different_account/00000.png b/tests/snapshots/nanos/test_sign_message_simple_different_account/00000.png new file mode 100644 index 0000000..b102b44 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_message_simple_different_account/00000.png differ diff --git a/tests/snapshots/nanos/test_sign_message_simple_different_account/00001.png b/tests/snapshots/nanos/test_sign_message_simple_different_account/00001.png new file mode 100644 index 0000000..1f333a2 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_message_simple_different_account/00001.png differ diff --git a/tests/snapshots/nanos/test_sign_message_simple_different_account/00002.png b/tests/snapshots/nanos/test_sign_message_simple_different_account/00002.png new file mode 100644 index 0000000..0964ed8 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_message_simple_different_account/00002.png differ diff --git a/tests/snapshots/nanos/test_sign_message_simple_different_account/00003.png b/tests/snapshots/nanos/test_sign_message_simple_different_account/00003.png new file mode 100644 index 0000000..66c411c Binary files /dev/null and b/tests/snapshots/nanos/test_sign_message_simple_different_account/00003.png differ diff --git a/tests/snapshots/nanos/test_sign_message_simple_different_account/00004.png b/tests/snapshots/nanos/test_sign_message_simple_different_account/00004.png new file mode 100644 index 0000000..9ab6248 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_message_simple_different_account/00004.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00000.png b/tests/snapshots/nanos/test_sign_tx_different_account/00000.png new file mode 100644 index 0000000..8842989 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00000.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00001.png b/tests/snapshots/nanos/test_sign_tx_different_account/00001.png new file mode 100644 index 0000000..fea2d47 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00001.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00002.png b/tests/snapshots/nanos/test_sign_tx_different_account/00002.png new file mode 100644 index 0000000..75c39aa Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00002.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00003.png b/tests/snapshots/nanos/test_sign_tx_different_account/00003.png new file mode 100644 index 0000000..990dd21 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00003.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00004.png b/tests/snapshots/nanos/test_sign_tx_different_account/00004.png new file mode 100644 index 0000000..044c844 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00004.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00005.png b/tests/snapshots/nanos/test_sign_tx_different_account/00005.png new file mode 100644 index 0000000..2f595a3 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00005.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00006.png b/tests/snapshots/nanos/test_sign_tx_different_account/00006.png new file mode 100644 index 0000000..1267831 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00006.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00007.png b/tests/snapshots/nanos/test_sign_tx_different_account/00007.png new file mode 100644 index 0000000..66c411c Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00007.png differ diff --git a/tests/snapshots/nanos/test_sign_tx_different_account/00008.png b/tests/snapshots/nanos/test_sign_tx_different_account/00008.png new file mode 100644 index 0000000..9ab6248 Binary files /dev/null and b/tests/snapshots/nanos/test_sign_tx_different_account/00008.png differ diff --git a/tests/snapshots/nanosp/test_app_mainmenu/00000.png b/tests/snapshots/nanosp/test_app_mainmenu/00000.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_app_mainmenu/00000.png and b/tests/snapshots/nanosp/test_app_mainmenu/00000.png differ diff --git a/tests/snapshots/nanosp/test_app_mainmenu/00001.png b/tests/snapshots/nanosp/test_app_mainmenu/00001.png index 2b89efe..104e14f 100644 Binary files a/tests/snapshots/nanosp/test_app_mainmenu/00001.png and b/tests/snapshots/nanosp/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png index f6fbd41..9145051 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png index 1da459c..88d6041 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png index f6fbd41..9145051 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png index 1da459c..88d6041 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png index c922246..e90cd9d 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png differ diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00006.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00006.png and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_kanji/00005.png b/tests/snapshots/nanosp/test_sign_message_kanji/00005.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_message_kanji/00005.png and b/tests/snapshots/nanosp/test_sign_message_kanji/00005.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_refused/00004.png b/tests/snapshots/nanosp/test_sign_message_refused/00004.png index c922246..e90cd9d 100644 Binary files a/tests/snapshots/nanosp/test_sign_message_refused/00004.png and b/tests/snapshots/nanosp/test_sign_message_refused/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_refused/00005.png b/tests/snapshots/nanosp/test_sign_message_refused/00005.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_message_refused/00005.png and b/tests/snapshots/nanosp/test_sign_message_refused/00005.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple/00004.png b/tests/snapshots/nanosp/test_sign_message_simple/00004.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_message_simple/00004.png and b/tests/snapshots/nanosp/test_sign_message_simple/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple_different_account/00000.png b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00000.png new file mode 100644 index 0000000..0307217 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00000.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple_different_account/00001.png b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00001.png new file mode 100644 index 0000000..ffbb998 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple_different_account/00002.png b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00002.png new file mode 100644 index 0000000..6df9c9d Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple_different_account/00003.png b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00003.png differ diff --git a/tests/snapshots/nanosp/test_sign_message_simple_different_account/00004.png b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00004.png new file mode 100644 index 0000000..8ce05d9 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message_simple_different_account/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00000.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00000.png new file mode 100644 index 0000000..df51419 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00000.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00001.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00001.png new file mode 100644 index 0000000..ff1d02e Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00002.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00002.png new file mode 100644 index 0000000..f32599b Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00003.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00003.png new file mode 100644 index 0000000..596ee5f Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00003.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00004.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00004.png new file mode 100644 index 0000000..848a5ce Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00004.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00005.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00005.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00005.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_different_account/00006.png b/tests/snapshots/nanosp/test_sign_tx_different_account/00006.png new file mode 100644 index 0000000..8ce05d9 Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_different_account/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_max/00001.png b/tests/snapshots/nanosp/test_sign_tx_max/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_max/00001.png and b/tests/snapshots/nanosp/test_sign_tx_max/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_max/00002.png b/tests/snapshots/nanosp/test_sign_tx_max/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_max/00002.png and b/tests/snapshots/nanosp/test_sign_tx_max/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_max/00006.png b/tests/snapshots/nanosp/test_sign_tx_max/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_max/00006.png and b/tests/snapshots/nanosp/test_sign_tx_max/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_p2sh/00001.png b/tests/snapshots/nanosp/test_sign_tx_p2sh/00001.png index 52c8036..c08ef70 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_p2sh/00001.png and b/tests/snapshots/nanosp/test_sign_tx_p2sh/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_p2sh/00002.png b/tests/snapshots/nanosp/test_sign_tx_p2sh/00002.png index 17aa5fd..294633e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_p2sh/00002.png and b/tests/snapshots/nanosp/test_sign_tx_p2sh/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_p2sh/00006.png b/tests/snapshots/nanosp/test_sign_tx_p2sh/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_p2sh/00006.png and b/tests/snapshots/nanosp/test_sign_tx_p2sh/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_refused/00001.png b/tests/snapshots/nanosp/test_sign_tx_refused/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_refused/00001.png and b/tests/snapshots/nanosp/test_sign_tx_refused/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_refused/00002.png b/tests/snapshots/nanosp/test_sign_tx_refused/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_refused/00002.png and b/tests/snapshots/nanosp/test_sign_tx_refused/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_refused/00006.png b/tests/snapshots/nanosp/test_sign_tx_refused/00006.png index c922246..e90cd9d 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_refused/00006.png and b/tests/snapshots/nanosp/test_sign_tx_refused/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_refused/00007.png b/tests/snapshots/nanosp/test_sign_tx_refused/00007.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_refused/00007.png and b/tests/snapshots/nanosp/test_sign_tx_refused/00007.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple/00001.png b/tests/snapshots/nanosp/test_sign_tx_simple/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple/00001.png and b/tests/snapshots/nanosp/test_sign_tx_simple/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple/00002.png b/tests/snapshots/nanosp/test_sign_tx_simple/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple/00002.png and b/tests/snapshots/nanosp/test_sign_tx_simple/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple/00006.png b/tests/snapshots/nanosp/test_sign_tx_simple/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple/00006.png and b/tests/snapshots/nanosp/test_sign_tx_simple/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00001.png b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00001.png index 81ff98e..bf75c98 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00001.png and b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00002.png b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00002.png index ef35add..6b4439e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00002.png and b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00006.png b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00006.png and b/tests/snapshots/nanosp/test_sign_tx_simple_change_idx1/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00001.png b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00001.png index f7a5d5a..fe57e7f 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00001.png and b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00002.png b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00002.png index 8c13c47..909f2d7 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00002.png and b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00006.png b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00006.png and b/tests/snapshots/nanosp/test_sign_tx_simple_ecdsa/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00001.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00001.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00002.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00002.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00006.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00006.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendint/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00001.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00001.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00002.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00002.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00006.png b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00006.png and b/tests/snapshots/nanosp/test_sign_tx_simple_sendmaxu64/00006.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_with_change/00001.png b/tests/snapshots/nanosp/test_sign_tx_with_change/00001.png index 94b99d5..ff1d02e 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_with_change/00001.png and b/tests/snapshots/nanosp/test_sign_tx_with_change/00001.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_with_change/00002.png b/tests/snapshots/nanosp/test_sign_tx_with_change/00002.png index c49815e..f32599b 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_with_change/00002.png and b/tests/snapshots/nanosp/test_sign_tx_with_change/00002.png differ diff --git a/tests/snapshots/nanosp/test_sign_tx_with_change/00006.png b/tests/snapshots/nanosp/test_sign_tx_with_change/00006.png index 63b43ce..8ce05d9 100644 Binary files a/tests/snapshots/nanosp/test_sign_tx_with_change/00006.png and b/tests/snapshots/nanosp/test_sign_tx_with_change/00006.png differ diff --git a/tests/snapshots/nanox/test_app_mainmenu/00001.png b/tests/snapshots/nanox/test_app_mainmenu/00001.png index 2b89efe..104e14f 100644 Binary files a/tests/snapshots/nanox/test_app_mainmenu/00001.png and b/tests/snapshots/nanox/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/nanox/test_sign_message_simple_different_account/00000.png b/tests/snapshots/nanox/test_sign_message_simple_different_account/00000.png new file mode 100644 index 0000000..0307217 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message_simple_different_account/00000.png differ diff --git a/tests/snapshots/nanox/test_sign_message_simple_different_account/00001.png b/tests/snapshots/nanox/test_sign_message_simple_different_account/00001.png new file mode 100644 index 0000000..ffbb998 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message_simple_different_account/00001.png differ diff --git a/tests/snapshots/nanox/test_sign_message_simple_different_account/00002.png b/tests/snapshots/nanox/test_sign_message_simple_different_account/00002.png new file mode 100644 index 0000000..6df9c9d Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message_simple_different_account/00002.png differ diff --git a/tests/snapshots/nanox/test_sign_message_simple_different_account/00003.png b/tests/snapshots/nanox/test_sign_message_simple_different_account/00003.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message_simple_different_account/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_message_simple_different_account/00004.png b/tests/snapshots/nanox/test_sign_message_simple_different_account/00004.png new file mode 100644 index 0000000..8ce05d9 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message_simple_different_account/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00000.png b/tests/snapshots/nanox/test_sign_tx_different_account/00000.png new file mode 100644 index 0000000..df51419 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00000.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00001.png b/tests/snapshots/nanox/test_sign_tx_different_account/00001.png new file mode 100644 index 0000000..ff1d02e Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00001.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00002.png b/tests/snapshots/nanox/test_sign_tx_different_account/00002.png new file mode 100644 index 0000000..f32599b Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00002.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00003.png b/tests/snapshots/nanox/test_sign_tx_different_account/00003.png new file mode 100644 index 0000000..596ee5f Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00003.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00004.png b/tests/snapshots/nanox/test_sign_tx_different_account/00004.png new file mode 100644 index 0000000..848a5ce Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00004.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00005.png b/tests/snapshots/nanox/test_sign_tx_different_account/00005.png new file mode 100644 index 0000000..53ae651 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00005.png differ diff --git a/tests/snapshots/nanox/test_sign_tx_different_account/00006.png b/tests/snapshots/nanox/test_sign_tx_different_account/00006.png new file mode 100644 index 0000000..8ce05d9 Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_different_account/00006.png differ diff --git a/tests/snapshots/stax/test_app_mainmenu/00001.png b/tests/snapshots/stax/test_app_mainmenu/00001.png index 2d6324e..ac2314e 100644 Binary files a/tests/snapshots/stax/test_app_mainmenu/00001.png and b/tests/snapshots/stax/test_app_mainmenu/00001.png differ diff --git a/tests/snapshots/stax/test_sign_message_simple_different_account/00000.png b/tests/snapshots/stax/test_sign_message_simple_different_account/00000.png new file mode 100644 index 0000000..ce64ced Binary files /dev/null and b/tests/snapshots/stax/test_sign_message_simple_different_account/00000.png differ diff --git a/tests/snapshots/stax/test_sign_message_simple_different_account/00001.png b/tests/snapshots/stax/test_sign_message_simple_different_account/00001.png new file mode 100644 index 0000000..87cd6ac Binary files /dev/null and b/tests/snapshots/stax/test_sign_message_simple_different_account/00001.png differ diff --git a/tests/snapshots/stax/test_sign_message_simple_different_account/00002.png b/tests/snapshots/stax/test_sign_message_simple_different_account/00002.png new file mode 100644 index 0000000..0ec6c37 Binary files /dev/null and b/tests/snapshots/stax/test_sign_message_simple_different_account/00002.png differ diff --git a/tests/snapshots/stax/test_sign_message_simple_different_account/00003.png b/tests/snapshots/stax/test_sign_message_simple_different_account/00003.png new file mode 100644 index 0000000..c1a8fd4 Binary files /dev/null and b/tests/snapshots/stax/test_sign_message_simple_different_account/00003.png differ diff --git a/tests/snapshots/stax/test_sign_message_simple_different_account/00004.png b/tests/snapshots/stax/test_sign_message_simple_different_account/00004.png new file mode 100644 index 0000000..ad6b72e Binary files /dev/null and b/tests/snapshots/stax/test_sign_message_simple_different_account/00004.png differ diff --git a/tests/snapshots/stax/test_sign_tx_different_account/00000.png b/tests/snapshots/stax/test_sign_tx_different_account/00000.png new file mode 100644 index 0000000..1b50145 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_different_account/00000.png differ diff --git a/tests/snapshots/stax/test_sign_tx_different_account/00001.png b/tests/snapshots/stax/test_sign_tx_different_account/00001.png new file mode 100644 index 0000000..b8163e4 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_different_account/00001.png differ diff --git a/tests/snapshots/stax/test_sign_tx_different_account/00002.png b/tests/snapshots/stax/test_sign_tx_different_account/00002.png new file mode 100644 index 0000000..3c651ba Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_different_account/00002.png differ diff --git a/tests/snapshots/stax/test_sign_tx_different_account/00003.png b/tests/snapshots/stax/test_sign_tx_different_account/00003.png new file mode 100644 index 0000000..cd2f527 Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_different_account/00003.png differ diff --git a/tests/snapshots/stax/test_sign_tx_different_account/00004.png b/tests/snapshots/stax/test_sign_tx_different_account/00004.png new file mode 100644 index 0000000..ad6b72e Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_different_account/00004.png differ diff --git a/tests/test_name_version.py b/tests/test_name_version.py index d0ed305..61ebf38 100644 --- a/tests/test_name_version.py +++ b/tests/test_name_version.py @@ -12,4 +12,4 @@ def test_get_app_and_version(backend, backend_name): app_name, version = unpack_get_app_and_version_response(response.data) assert app_name == "Kaspa" - assert version == "1.0.0" + assert version == "1.0.2" diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py index 492e3bf..653eb6f 100644 --- a/tests/test_sign_cmd.py +++ b/tests/test_sign_cmd.py @@ -66,6 +66,63 @@ def test_sign_tx_simple(firmware, backend, navigator, test_name): assert transaction.get_sighash(0) == sighash assert check_signature_validity(public_key, der_sig, sighash) +def test_sign_tx_different_account(firmware, backend, navigator, test_name): + # Use the app interface instead of raw interface + client = KaspaCommandSender(backend) + # The path used for this entire test + path: str = "m/44'/111111'/1'/0/0" + + # First we need to get the public key of the device in order to build the transaction + rapdu = client.get_public_key(path=path) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + # Create the transaction that will be sent to the device for signing + transaction = Transaction( + version=0, + account=0x80000001, + inputs=[ + TransactionInput( + value=1100000, + tx_id="40b022362f1a303518e2b49f86f87a317c87b514ca0f3d08ad2e7cf49d08cc70", + address_type=0, + address_index=0, + index=0, + public_key=public_key[1:33] + ) + ], + outputs=[ + TransactionOutput( + value=1090000, + script_public_key="2011a7215f668e921013eb7aac9b7e64b9ec6e757c1b648e89388c919f676aa88cac" + ) + ] + ) + + # Send the sign device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + with client.sign_tx(transaction=transaction): + # Validate the on-screen request by performing the navigation appropriate for this device + if firmware.device.startswith("nano"): + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Approve", + ROOT_SCREENSHOT_PATH, + test_name) + else: + navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP, + [NavInsID.USE_CASE_REVIEW_CONFIRM, + NavInsID.USE_CASE_STATUS_DISMISS], + "Hold to sign", + ROOT_SCREENSHOT_PATH, + test_name) + + # The device as yielded the result, parse it and ensure that the signature is correct + response = client.get_async_response().data + _, _, _, der_sig, _, sighash = unpack_sign_tx_response(response) + assert transaction.get_sighash(0) == sighash + assert check_signature_validity(public_key, der_sig, sighash) + def test_sign_tx_simple_ecdsa(firmware, backend, navigator, test_name): # Use the app interface instead of raw interface client = KaspaCommandSender(backend) diff --git a/tests/test_sign_personal_message_cmd.py b/tests/test_sign_personal_message_cmd.py index 7812b57..c321f95 100644 --- a/tests/test_sign_personal_message_cmd.py +++ b/tests/test_sign_personal_message_cmd.py @@ -24,7 +24,50 @@ def test_sign_message_simple(firmware, backend, navigator, test_name): address_index = 5 message = "Hello Kaspa!" - message_data = PersonalMessage(address_type, address_index, message) + message_data = PersonalMessage(message, address_type, address_index) + + # Send the sign device instruction. + # As it requires on-screen validation, the function is asynchronous. + # It will yield the result when the navigation is done + with client.sign_message(message_data=message_data): + # Validate the on-screen request by performing the navigation appropriate for this device + if firmware.device.startswith("nano"): + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Approve", + ROOT_SCREENSHOT_PATH, + test_name) + else: + navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP, + [NavInsID.USE_CASE_REVIEW_CONFIRM, + NavInsID.USE_CASE_STATUS_DISMISS], + "Hold to sign", + ROOT_SCREENSHOT_PATH, + test_name) + + # The device as yielded the result, parse it and ensure that the signature is correct + response = client.get_async_response().data + _, der_sig, _, message_hash = unpack_sign_message_response(response) + + assert message_hash == message_data.to_hash() + assert check_signature_validity(public_key, der_sig, message_hash) + +def test_sign_message_simple_different_account(firmware, backend, navigator, test_name): + # Use the app interface instead of raw interface + client = KaspaCommandSender(backend) + # The path used for this entire test + path: str = "m/44'/111111'/1'/1/5" + + # First we need to get the public key of the device in order to build the transaction + rapdu = client.get_public_key(path=path) + _, public_key, _, _ = unpack_get_public_key_response(rapdu.data) + + address_type = 1 + address_index = 5 + account = 0x80000001 # This is account 1' + message = "Hello Kaspa!" + + message_data = PersonalMessage(message, address_type, address_index, account) # Send the sign device instruction. # As it requires on-screen validation, the function is asynchronous. @@ -66,7 +109,7 @@ def test_sign_message_kanji(firmware, backend, navigator, test_name): address_index = 3 message = "こんにちは世界" - message_data = PersonalMessage(address_type, address_index, message) + message_data = PersonalMessage(message, address_type, address_index) # Send the sign device instruction. # As it requires on-screen validation, the function is asynchronous. @@ -101,9 +144,9 @@ def test_sign_message_too_long(firmware, backend, navigator, test_name): address_type = 1 address_index = 4 - message = '''Lorem ipsum dolor sit amet. Aut omnis amet id voluptatem eligendi sit accusantium dolorem 33 corrupti necessitatibus hic consequatur quod et maiores alias non molestias suscipit? Est voluptatem magni qui odit eius est eveniet cupiditate id eius quae''' + message = '''Lorem ipsum dolor sit amet. Aut omnis amet id voluptatem eligendi sit accusantium dolorem 33 corrupti necessitatibus hic consequatur quod et maiores alias non molestias suscipit? Est voluptatem magni qui odit eius est eveniet cupiditate id eius''' - message_data = PersonalMessage(address_type, address_index, message) + message_data = PersonalMessage(message, address_type, address_index) last_response = client.send_raw_apdu(InsType.SIGN_MESSAGE, p1=P1.P1_INPUTS, p2=P2.P2_LAST, data=message_data.serialize()) @@ -117,7 +160,7 @@ def test_sign_message_refused(firmware, backend, navigator, test_name): address_index = 6 message = "Hello Kaspa!" - message_data = PersonalMessage(address_type, address_index, message) + message_data = PersonalMessage(message, address_type, address_index) if firmware.device.startswith("nano"): with client.sign_message(message_data=message_data): diff --git a/tests/test_version_cmd.py b/tests/test_version_cmd.py index f13232e..3b7d7e8 100644 --- a/tests/test_version_cmd.py +++ b/tests/test_version_cmd.py @@ -4,7 +4,7 @@ # Taken from the Makefile, to update every time the Makefile version is bumped MAJOR = 1 MINOR = 0 -PATCH = 0 +PATCH = 2 # In this test we check the behavior of the device when asked to provide the app version def test_version(backend): diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 10fade0..143df34 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -62,7 +62,7 @@ add_library(sighash SHARED ../src/sighash.c) add_library(personal_message SHARED ../src/personal_message.c) add_library(write SHARED /opt/ledger-secure-sdk/lib_standard_app/write.c) add_library(format_local SHARED ../src/common/format_local.c) -add_library(apdu_parser SHARED ../src/apdu/parser.c) +add_library(apdu_parser SHARED /opt/ledger-secure-sdk/lib_standard_app/parser.c) add_library(transaction_deserialize ../src/transaction/deserialize.c) add_library(transaction_serialize ../src/transaction/serialize.c) add_library(transaction_utils ../src/transaction/utils.c) diff --git a/unit-tests/test_address.c b/unit-tests/test_address.c index 4b4c2c4..bd32bf1 100644 --- a/unit-tests/test_address.c +++ b/unit-tests/test_address.c @@ -118,11 +118,81 @@ static void test_invalid_type(void **state) { assert_int_equal(res, 0); } +static void test_compress_address_schnorr(void **state) { + uint8_t public_key[] = { + 0xF3, 0x80, 0x31, 0xF6, 0x1C, 0xA2, 0x3D, 0x70, 0x84, 0x4F, 0x63, 0xA4, 0x77, 0xD0, 0x7F, 0x0B, + 0x2C, 0x2D, 0xEC, 0xAB, 0x90, 0x7C, 0x2E, 0x09, 0x6E, 0x54, 0x8B, 0x0E, 0x08, 0x72, 0x1C, 0x79, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + uint8_t compressed[32] = {0}; + + size_t result = compress_public_key(public_key, SCHNORR, compressed, sizeof(compressed)); + + assert_true(result > 0); + assert_memory_equal(compressed, public_key, 32); +} + +static void test_compress_address_ecdsa(void **state) { + uint8_t public_key_even[] = { + 0xd5, 0xfd, 0xc7, 0xad, 0x11, 0xa6, 0x5d, 0x0b, 0xbe, 0x78, 0x82, 0xfc, 0x3d, 0xbc, 0x91, 0xb5, + 0x86, 0x1d, 0x18, 0x2d, 0xcc, 0xe7, 0x9f, 0x7c, 0x1b, 0xe5, 0xbf, 0xd3, 0x0a, 0x67, 0x7c, 0xd6, + 0xc5, 0x62, 0xad, 0x66, 0xab, 0xcd, 0xb1, 0xec, 0x02, 0xf3, 0xe4, 0xb0, 0x7c, 0x11, 0xbc, 0x5a, + 0x94, 0xa6, 0x85, 0xfe, 0xdb, 0x5d, 0x55, 0x87, 0x07, 0x6e, 0x48, 0xb1, 0x2d, 0xa6, 0xc2, 0x82 + }; + + uint8_t compressed_even[33] = {0}; + + size_t result_even = compress_public_key(public_key_even, ECDSA, compressed_even, sizeof(compressed_even)); + + assert_true(result_even > 0); + assert_true(compressed_even[0] == 0x02); + assert_memory_equal(compressed_even +1, public_key_even, 32); + + uint8_t public_key_odd[] = { + 0xe3, 0x10, 0x0d, 0x85, 0xef, 0xae, 0x93, 0xe0, 0xc2, 0xfc, 0x65, 0x4b, 0x2f, 0x0c, 0x33, 0x58, + 0x4f, 0x21, 0x3a, 0x3f, 0xdf, 0xfd, 0x02, 0x3c, 0x82, 0x12, 0x77, 0xb2, 0x17, 0x89, 0xe0, 0x64, + 0xe0, 0x6b, 0x45, 0x4f, 0x5c, 0xba, 0x0e, 0xff, 0x1c, 0xe8, 0x01, 0xd3, 0x83, 0x5c, 0x39, 0xec, + 0x01, 0xca, 0x94, 0x9c, 0xa8, 0x77, 0xc0, 0xb5, 0x5b, 0xbd, 0xec, 0xa8, 0xff, 0x84, 0x91, 0xd9 + }; + + uint8_t compressed_odd[33] = {0}; + + size_t result_odd = compress_public_key(public_key_odd, ECDSA, compressed_odd, sizeof(compressed_odd)); + + assert_true(result_odd > 0); + assert_true(compressed_odd[0] == 0x03); + assert_memory_equal(compressed_odd + 1, public_key_odd, 32); +} + +static void test_invalid_compress_address(void **state) { + uint8_t public_key[] = { + 0xe3, 0x10, 0x0d, 0x85, 0xef, 0xae, 0x93, 0xe0, 0xc2, 0xfc, 0x65, 0x4b, 0x2f, 0x0c, 0x33, 0x58, + 0x4f, 0x21, 0x3a, 0x3f, 0xdf, 0xfd, 0x02, 0x3c, 0x82, 0x12, 0x77, 0xb2, 0x17, 0x89, 0xe0, 0x64, + 0xe0, 0x6b, 0x45, 0x4f, 0x5c, 0xba, 0x0e, 0xff, 0x1c, 0xe8, 0x01, 0xd3, 0x83, 0x5c, 0x39, 0xec, + 0x01, 0xca, 0x94, 0x9c, 0xa8, 0x77, 0xc0, 0xb5, 0x5b, 0xbd, 0xec, 0xa8, 0xff, 0x84, 0x91, 0xd9 + }; + + uint8_t compressed_too_small_schnorr[31] = {0}; // We need 32 for valid + + size_t result_schnorr = compress_public_key(public_key, SCHNORR, compressed_too_small_schnorr, sizeof(compressed_too_small_schnorr)); + assert_true(result_schnorr == 0); + + uint8_t compressed_too_small_ecdsa[32] = {0}; // We need 33 for valid + + size_t result_ecdsa = compress_public_key(public_key, ECDSA, compressed_too_small_ecdsa, sizeof(compressed_too_small_ecdsa)); + assert_true(result_ecdsa == 0); +} + int main() { const struct CMUnitTest tests[] = {cmocka_unit_test(test_schnorr_address_from_public_key), cmocka_unit_test(test_ecdsa_address_from_public_key), cmocka_unit_test(test_p2sh_address_from_public_key), - cmocka_unit_test(test_invalid_type)}; + cmocka_unit_test(test_invalid_type), + cmocka_unit_test(test_compress_address_schnorr), + cmocka_unit_test(test_compress_address_ecdsa), + cmocka_unit_test(test_invalid_compress_address)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_apdu_parser.c b/unit-tests/test_apdu_parser.c index c0d3f4d..a5f70e6 100644 --- a/unit-tests/test_apdu_parser.c +++ b/unit-tests/test_apdu_parser.c @@ -31,7 +31,7 @@ #include #include "types.h" -#include "apdu/parser.h" +#include "parser.h" static void test_apdu_parser(void **state) { (void) state; @@ -42,10 +42,11 @@ static void test_apdu_parser(void **state) { command_t cmd; memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_min_len, sizeof(apdu_bad_min_len))); + assert_true(apdu_parser(&cmd, apdu_bad_min_len, sizeof(apdu_bad_min_len))); + assert_int_equal(cmd.lc, 0); memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_lc, sizeof(apdu_bad_min_len))); + assert_false(apdu_parser(&cmd, apdu_bad_lc, sizeof(apdu_bad_lc))); memset(&cmd, 0, sizeof(cmd)); assert_true(apdu_parser(&cmd, apdu, sizeof(apdu))); diff --git a/unit-tests/test_personal_message.c b/unit-tests/test_personal_message.c index 7616863..bc8a9c1 100644 --- a/unit-tests/test_personal_message.c +++ b/unit-tests/test_personal_message.c @@ -59,7 +59,7 @@ static void test_hash_personal_message_vector0(void **state) { uint8_t out_hash[32] = {0}; - bool result = hash_personal_message((uint8_t*) message, 12, out_hash); + bool result = hash_personal_message((uint8_t*) message, 12, out_hash, sizeof(out_hash)); assert_true(result); diff --git a/unit-tests/test_sighash.c b/unit-tests/test_sighash.c index 0c67887..5ff7ef5 100644 --- a/unit-tests/test_sighash.c +++ b/unit-tests/test_sighash.c @@ -99,7 +99,7 @@ static void test_sighash(void **state) { tx.tx_output_len = 1; uint8_t out_hash[32] = {0}; - calc_sighash(&tx, &txin, input_public_key_data, out_hash); + bool success = calc_sighash(&tx, &txin, input_public_key_data, out_hash, sizeof(out_hash)); uint8_t res[32] = {0x7c, 0xcd, 0xa6, 0xc6, 0x4a, 0x18, 0x1e, 0x62, 0x63, 0xf0, 0xee, 0xe2, 0xed, 0xc8, 0x59, 0xdb, @@ -107,6 +107,7 @@ static void test_sighash(void **state) { 0x7d, 0xce, 0x10, 0x81, 0xbe, 0xc5, 0xba, 0xa5}; assert_memory_equal(out_hash, res, 32); + assert_true(success); } //612d56e633ee5da1caa4563c6ace0c98d3549ad4e3d2b1f1ea6810e6c34047bd @@ -151,7 +152,7 @@ static void test_sighash_zeros(void **state) { tx.tx_output_len = 1; uint8_t out_hash[32] = {0}; - calc_sighash(&tx, &txin, input_public_key_data, out_hash); + bool success = calc_sighash(&tx, &txin, input_public_key_data, out_hash, sizeof(out_hash)); uint8_t res[32] = {0x61, 0x2d, 0x56, 0xe6, 0x33, 0xee, 0x5d, 0xa1, 0xca, 0xa4, 0x56, 0x3c, 0x6a, 0xce, 0x0c, 0x98, @@ -159,6 +160,7 @@ static void test_sighash_zeros(void **state) { 0xea, 0x68, 0x10, 0xe6, 0xc3, 0x40, 0x47, 0xbd}; assert_memory_equal(out_hash, res, 32); + assert_true(success); } int main() { diff --git a/unit-tests/test_tx_parser.c b/unit-tests/test_tx_parser.c index 1c23655..7e4a966 100644 --- a/unit-tests/test_tx_parser.c +++ b/unit-tests/test_tx_parser.c @@ -41,14 +41,15 @@ static void test_tx_serialization(void **state) { tx.tx_output_len = 2; tx.tx_input_len = 3; - uint32_t path[5] = {0}; + uint32_t path[KASPA_MAX_BIP32_PATH_LEN] = {0}; // clang-format off uint8_t raw_tx[] = { // header 0x00, 0x01, 0x02, 0x03, 0x01, - 0x04, 0x05, 0x06, 0xFF + 0x04, 0x05, 0x06, 0xFF, + 0x80, 0x00, 0x00, 0x00 }; buffer_t buf = {.ptr = raw_tx, .size = sizeof(raw_tx), .offset = 0}; @@ -69,15 +70,13 @@ static int run_test_tx_serialize(uint8_t* raw_tx, size_t raw_tx_len) { buffer_t buf = {.ptr = raw_tx, .size = raw_tx_len, .offset = 0}; - uint32_t path[5] = {0}; + uint32_t path[KASPA_MAX_BIP32_PATH_LEN] = {0}; return transaction_deserialize(&buf, &tx, path); } static void test_tx_deserialization_fail(void **state) { (void) state; - - transaction_t tx; // clang-format off uint8_t invalid_version[] = { @@ -105,12 +104,27 @@ static void test_tx_deserialization_fail(void **state) { 0x00, 0x01, 0x02, 0x03, 0x02 }; + uint8_t invalid_change_index[] = { + 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00 + }; + + uint8_t invalid_account[] = { + 0x00, 0x01, 0x02, 0x03, 0x01, 0x7F, 0xFF, 0xFF + }; + + uint8_t invalid_account_too_low[] = { + 0x00, 0x01, 0x02, 0x03, 0x01, 0x7F, 0xFF, 0xFF, 0xFF + }; + assert_int_equal(run_test_tx_serialize(invalid_version, sizeof(invalid_version)), VERSION_PARSING_ERROR); assert_int_equal(run_test_tx_serialize(missing_outlen, sizeof(missing_outlen)), OUTPUTS_LENGTH_PARSING_ERROR); assert_int_equal(run_test_tx_serialize(invalid_outlen, sizeof(invalid_outlen)), OUTPUTS_LENGTH_PARSING_ERROR); assert_int_equal(run_test_tx_serialize(missing_inlen, sizeof(missing_inlen)), INPUTS_LENGTH_PARSING_ERROR); assert_int_equal(run_test_tx_serialize(invalid_inlen, sizeof(invalid_inlen)), INPUTS_LENGTH_PARSING_ERROR); assert_int_equal(run_test_tx_serialize(invalid_change_type, sizeof(invalid_change_type)), HEADER_PARSING_ERROR); + assert_int_equal(run_test_tx_serialize(invalid_change_index, sizeof(invalid_change_type)), HEADER_PARSING_ERROR); + assert_int_equal(run_test_tx_serialize(invalid_account, sizeof(invalid_change_type)), HEADER_PARSING_ERROR); + assert_int_equal(run_test_tx_serialize(invalid_account_too_low, sizeof(invalid_change_type)), HEADER_PARSING_ERROR); } static void test_tx_input_serialization(void **state) { @@ -299,14 +313,17 @@ static int run_test_tx_output_serialize(uint8_t* raw_tx, size_t raw_tx_len) { static void test_tx_output_deserialization_fail(void **state) { (void) state; - transaction_output_t txout; - // clang-format off uint8_t invalid_value[] = { // Value is only 7 bytes 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86 }; + uint8_t invalid_script_missing[] = { + // Value only, no script + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0x00 + }; + uint8_t invalid_script_start[] = { // Start is not 0x20 or 0x21 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xa0, @@ -360,22 +377,25 @@ static void test_tx_output_deserialization_fail(void **state) { 0x00, OP_CHECKSIG }; - uint8_t raw_tx[] = { + uint8_t invalid_p2sh_script_hash_len[] = { // Output 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xa0, - 0x21, + OP_BLAKE2B, 0x21, 0xe1, 0x19, 0xd5, 0x35, 0x14, 0xc1, 0xb0, 0xe2, 0xef, 0xce, 0x7a, 0x89, 0xe3, 0xd1, 0xd5, 0xd6, 0xcd, 0x73, 0x58, 0x2e, 0xa2, 0x06, 0x87, 0x64, 0x1c, 0x8f, 0xdc, 0xcb, 0x60, 0x60, 0xa9, 0xad, - 0x00, OP_CHECKSIGECDSA + 0x00, OP_EQUAL }; assert_int_equal(run_test_tx_output_serialize(invalid_value, sizeof(invalid_value)), OUTPUT_VALUE_PARSING_ERROR); + assert_int_equal(run_test_tx_output_serialize(invalid_script_missing, sizeof(invalid_script_missing)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); assert_int_equal(run_test_tx_output_serialize(invalid_script_start, sizeof(invalid_script_start)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); + assert_int_equal(run_test_tx_output_serialize(invalid_script_end_schnorr, sizeof(invalid_script_end_ecdsa)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); assert_int_equal(run_test_tx_output_serialize(invalid_script_end_ecdsa, sizeof(invalid_script_end_ecdsa)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); assert_int_equal(run_test_tx_output_serialize(invalid_script_len, sizeof(invalid_script_len)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); assert_int_equal(run_test_tx_output_serialize(invalid_p2sh_opcode, sizeof(invalid_p2sh_opcode)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); + assert_int_equal(run_test_tx_output_serialize(invalid_p2sh_script_hash_len, sizeof(invalid_p2sh_script_hash_len)), OUTPUT_SCRIPT_PUBKEY_PARSING_ERROR); } static void test_serialization_fail(void **state) { @@ -384,7 +404,7 @@ static void test_serialization_fail(void **state) { transaction_input_t txin; uint8_t buffer[1] = {0}; - uint32_t path[5] = {0}; + uint32_t path[KASPA_MAX_BIP32_PATH_LEN] = {0}; assert_int_equal(transaction_serialize(&tx, path, buffer, sizeof(buffer)), -1); assert_int_equal(transaction_output_serialize(&txout, buffer, sizeof(buffer)), -1); diff --git a/unit-tests/test_tx_utils.c b/unit-tests/test_tx_utils.c index 0ef0b46..09b22b2 100644 --- a/unit-tests/test_tx_utils.c +++ b/unit-tests/test_tx_utils.c @@ -57,7 +57,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t schnorr_address[68] = {0}; - script_public_key_to_address(schnorr_address, schnorr_spk); + script_public_key_to_address(schnorr_address, sizeof(schnorr_address), schnorr_spk, sizeof(schnorr_spk)); assert_string_equal((char *) schnorr_address, "kaspa:qrazhptjkcvrv23xz2xm8z8sfmg6jhxvmrscn7wph4k9we5tzxedwfxf0v6f8"); @@ -70,7 +70,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t p2sh_address[68] = {0}; - script_public_key_to_address(p2sh_address, p2sh_spk); + script_public_key_to_address(p2sh_address, sizeof(p2sh_address), p2sh_spk, sizeof(p2sh_spk)); assert_string_equal((char *) p2sh_address, "kaspa:precqv0krj3r6uyyfa36ga7s0u9jct0v4wg8ctsfde2gkrsgwgw8jgxfzfc98"); @@ -85,7 +85,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_even_address[70] = {0}; - script_public_key_to_address(ecdsa_even_address, ecdsa_even_spk); + script_public_key_to_address(ecdsa_even_address, sizeof(ecdsa_even_address), ecdsa_even_spk, sizeof(ecdsa_even_spk)); assert_string_equal((char *) ecdsa_even_address, "kaspa:qypdtlw845g6vhgtheug9lpahjgmtpsarqkueeul0sd7t07npfnhe4s7fd82n0v"); @@ -100,7 +100,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_odd_address[70] = {0}; - script_public_key_to_address(ecdsa_odd_address, ecdsa_odd_spk); + script_public_key_to_address(ecdsa_odd_address, sizeof(ecdsa_odd_address), ecdsa_odd_spk, sizeof(ecdsa_odd_spk)); assert_string_equal((char *) ecdsa_odd_address, "kaspa:qyp7xyqdshh6aylqct7x2je0pse4snep8glallgz8jppyaajz7y7qeq4x79fq4z"); }