From 07f9598b49561da377bca12efcaa9e92439aa441 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Sun, 5 Jul 2020 00:25:46 +0200 Subject: [PATCH] upgrading zxlib (#45) * upgrading zxlib * adding missing files * remove webusb popups * upgrade zxlib * upgrade zxlib + UI * bump version number * bump version numbers * add missing file * update zemu tests --- app/Makefile | 88 +-- app/script.ld | 2 +- app/src/addr.c | 57 ++ app/src/addr.h | 34 ++ app/src/coin.h | 6 +- app/src/common/actions.c | 38 +- app/src/common/actions.h | 40 +- app/src/common/app_main.h | 8 +- app/src/common/main.c | 16 +- app/src/common/tx.c | 44 +- app/src/common/tx.h | 18 +- app/src/crypto.h | 8 +- deps/ledger-zxlib/.circleci/config.yml | 2 +- deps/ledger-zxlib/app/common/app_mode.c | 69 +++ .../ledger-zxlib/app/common/app_mode.h | 30 +- deps/ledger-zxlib/app/common/view.c | 135 +++-- deps/ledger-zxlib/app/common/view.h | 4 +- deps/ledger-zxlib/app/common/view_internal.h | 28 +- deps/ledger-zxlib/app/common/view_s.c | 230 +++----- deps/ledger-zxlib/app/common/view_x.c | 117 ++-- deps/ledger-zxlib/app/common/zbuffer.c | 88 +++ deps/ledger-zxlib/dockerized_build.mk | 24 +- deps/ledger-zxlib/include/base58.h | 38 ++ deps/ledger-zxlib/include/bech32.h | 3 +- deps/ledger-zxlib/include/timeutils.h | 74 +++ deps/ledger-zxlib/include/zbuffer.h | 38 ++ deps/ledger-zxlib/include/zxerror.h | 6 + deps/ledger-zxlib/include/zxformat.h | 27 +- deps/ledger-zxlib/include/zxmacros.h | 56 +- deps/ledger-zxlib/include/zxversion.h | 4 +- deps/ledger-zxlib/scripts/template.sh | 2 +- deps/ledger-zxlib/src/base58.c | 153 ++++++ deps/ledger-zxlib/src/bech32.c | 8 +- deps/ledger-zxlib/src/bignum.c | 4 +- deps/ledger-zxlib/src/timeutils.c | 508 ++++++++++++++++++ deps/ledger-zxlib/src/zxmacros.c | 28 +- deps/ledger-zxlib/tests/bech32.cpp | 20 +- deps/ledger-zxlib/tests/macros.cpp | 37 +- deps/ledger-zxlib/tests/timeutils.cpp | 95 ++++ docs/img/clion_debugging.png | Bin 0 -> 130508 bytes tests/crypto.cpp | 10 +- tests/testvectors.cpp | 2 + tests_zemu/snapshots/show-address/0.png | Bin 812 -> 1089 bytes tests_zemu/snapshots/show-address/1.png | Bin 844 -> 618 bytes tests_zemu/snapshots/show-address/2.png | Bin 699 -> 334 bytes tests_zemu/snapshots/show-address/3.png | Bin 583 -> 529 bytes tests_zemu/snapshots/show-address/4.png | Bin 303 -> 0 bytes tests_zemu/snapshots/show-address/5.png | Bin 554 -> 0 bytes tests_zemu/snapshots/sign-basic/0.png | Bin 873 -> 902 bytes tests_zemu/snapshots/sign-basic/1.png | Bin 360 -> 429 bytes tests_zemu/snapshots/sign-basic/2.png | Bin 971 -> 1041 bytes tests_zemu/snapshots/sign-basic/3.png | Bin 394 -> 483 bytes tests_zemu/snapshots/sign-basic/8.png | Bin 644 -> 443 bytes tests_zemu/tests/test.js | 20 +- tests_zemu/tools/debug.mjs | 11 +- 55 files changed, 1745 insertions(+), 485 deletions(-) create mode 100644 app/src/addr.c create mode 100644 app/src/addr.h create mode 100644 deps/ledger-zxlib/app/common/app_mode.c rename app/src/view_custom.c => deps/ledger-zxlib/app/common/app_mode.h (58%) create mode 100644 deps/ledger-zxlib/app/common/zbuffer.c create mode 100644 deps/ledger-zxlib/include/base58.h create mode 100644 deps/ledger-zxlib/include/timeutils.h create mode 100644 deps/ledger-zxlib/include/zbuffer.h create mode 100644 deps/ledger-zxlib/src/base58.c create mode 100644 deps/ledger-zxlib/src/timeutils.c create mode 100644 deps/ledger-zxlib/tests/timeutils.cpp create mode 100644 docs/img/clion_debugging.png delete mode 100644 tests_zemu/snapshots/show-address/4.png delete mode 100644 tests_zemu/snapshots/show-address/5.png diff --git a/app/Makefile b/app/Makefile index 64290fde..b3aa69e4 100755 --- a/app/Makefile +++ b/app/Makefile @@ -22,6 +22,24 @@ endif MY_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +ifeq ($(APP_TESTING),1) +DEFINES += APP_TESTING +DEFINES += ZEMU_LOGGING +endif + +all: bin/app.elf + @echo "#!/usr/bin/env bash" > $(CURDIR)/pkg/zxtool.sh + @echo "APPNAME=\"${APPNAME}\"" >> $(CURDIR)/pkg/zxtool.sh + @echo "APPVERSION=\"${APPVERSION}\"" >> $(CURDIR)/pkg/zxtool.sh + @echo "APPPATH=\""${APPPATH}"\"" >> $(CURDIR)/pkg/zxtool.sh + @echo "LOAD_PARAMS=\"${COMMON_LOAD_PARAMS}\"" >> $(CURDIR)/pkg/zxtool.sh + @echo "DELETE_PARAMS=\"${COMMON_DELETE_PARAMS}\"" >> $(CURDIR)/pkg/zxtool.sh + @echo "APPHEX=\"" >> $(CURDIR)/pkg/zxtool.sh + @cat $(CURDIR)/bin/app.hex >> $(CURDIR)/pkg/zxtool.sh + @echo "\"" >> $(CURDIR)/pkg/zxtool.sh + @cat $(CURDIR)/../deps/ledger-zxlib/scripts/template.sh >> $(CURDIR)/pkg/zxtool.sh + @chmod +x $(CURDIR)/pkg/zxtool.sh + include $(BOLOS_SDK)/Makefile.defines ifndef COIN @@ -29,8 +47,8 @@ COIN=FIL endif APPVERSION_M=0 -APPVERSION_N=15 -APPVERSION_P=2 +APPVERSION_N=16 +APPVERSION_P=0 $(info COIN = [$(COIN)]) ifeq ($(COIN),FIL) @@ -51,7 +69,7 @@ endef $(error "$(error_message)") endif -APP_LOAD_PARAMS = --appFlags 0x200 --delete $(COMMON_LOAD_PARAMS) --path $(APPPATH) --path "44'/1'" +APP_LOAD_PARAMS = --appFlags 0x200 --delete $(COMMON_LOAD_PARAMS) --path ${APPPATH} --path "44'/1'" ifeq ($(TARGET_NAME),TARGET_NANOS) SCRIPT_LD:=$(CURDIR)/script.ld @@ -66,42 +84,25 @@ ifndef ICONNAME $(error ICONNAME is not set) endif -all: default - @echo "#!/usr/bin/env bash" > $(CURDIR)/pkg/zxtool.sh - @echo "APPNAME=\"${APPNAME}\"" >> $(CURDIR)/pkg/zxtool.sh - @echo "APPVERSION=\"${APPVERSION}\"" >> $(CURDIR)/pkg/zxtool.sh - @echo "APPPATH=\""${APPPATH}"\"" >> $(CURDIR)/pkg/zxtool.sh - @echo "LOAD_PARAMS=\"${COMMON_LOAD_PARAMS}\"" >> $(CURDIR)/pkg/zxtool.sh - @echo "DELETE_PARAMS=\"${COMMON_DELETE_PARAMS}\"" >> $(CURDIR)/pkg/zxtool.sh - @echo "APPHEX=\"" >> $(CURDIR)/pkg/zxtool.sh - @cat $(CURDIR)/bin/app.hex >> $(CURDIR)/pkg/zxtool.sh - @echo "\"" >> $(CURDIR)/pkg/zxtool.sh - @cat $(CURDIR)/../deps/ledger-zxlib/scripts/template.sh >> $(CURDIR)/pkg/zxtool.sh - @chmod +x $(CURDIR)/pkg/zxtool.sh - ############ # Platform -DEFINES += UNUSED\(x\)=\(void\)x -DEFINES += PRINTF\(...\)= +DEFINES += UNUSED\(x\)=\(void\)x +DEFINES += PRINTF\(...\)= APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -DEFINES += APPVERSION=\"$(APPVERSION)\" +DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += OS_IO_SEPROXYHAL -DEFINES += HAVE_BAGL HAVE_SPRINTF -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU +DEFINES += OS_IO_SEPROXYHAL +DEFINES += HAVE_BAGL HAVE_SPRINTF +DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) +DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) -DEFINES += HAVE_U2F HAVE_IO_U2F -DEFINES += U2F_PROXY_MAGIC=\"FIL\" -DEFINES += USB_SEGMENT_SIZE=64 -DEFINES += U2F_MAX_MESSAGE_SIZE=264 #257+5+2 -DEFINES += HAVE_BOLOS_APP_STACK_CANARY +DEFINES += USB_SEGMENT_SIZE=64 +DEFINES += HAVE_BOLOS_APP_STACK_CANARY -WEBUSB_URL = www.ledgerwallet.com -DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g") +DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" ifeq ($(TARGET_NAME),TARGET_NANOX) DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 @@ -115,12 +116,14 @@ DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX DEFINES += HAVE_UX_FLOW -#SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -SDK_SOURCE_PATH += lib_ux +DEFINES += HAVE_BLE +DEFINES += HAVE_BLE_APDU BLE_COMMAND_TIMEOUT_MS=2000 + +SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl else # Assume Nano S DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 -DEFINES += HAVE_BOLOS_UX COMPLIANCE_UX_160 HAVE_UX_LEGACY HAVE_UX_FLOW +DEFINES += HAVE_BOLOS_UX COMPLIANCE_UX_160 HAVE_UX_LEGACY endif # X specific @@ -167,39 +170,44 @@ APP_SOURCE_PATH += $(MY_DIR)/../deps/ledger-zxlib/include APP_SOURCE_PATH += $(MY_DIR)/../deps/ledger-zxlib/src APP_SOURCE_PATH += $(MY_DIR)/../deps/ledger-zxlib/app/common -SDK_SOURCE_PATH += lib_stusb lib_u2f lib_stusb_impl +SDK_SOURCE_PATH += lib_stusb lib_stusb_impl +SDK_SOURCE_PATH += lib_ux # NanoX SDK does not allow += in APP_SOURCE_PATH or INCLUDES_PATH CFLAGS += -I$(MY_DIR)/../deps/tinycbor/src APP_SOURCE_PATH += $(MY_DIR)/../deps/tinycbor-ledger -#SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -SDK_SOURCE_PATH += lib_ux +.PHONY: rust rust: @echo "No rust code" # cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo build --target thumbv6m-none-eabi --release +# Before linking, we need to be sure rust lib is there +bin/app.elf: rust + +.PHONY: rust_clean rust_clean: @echo "No rust code" # cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo clean +clean: rust_clean + # load, delete and listvariants are provided to comply with Ledger requirements +.PHONY: load load: python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) +.PHONY: delete delete: python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) -.PHONY: rust - -all: default rust - # Import generic rules from the SDK include $(BOLOS_SDK)/Makefile.rules #add dependency on custom makefile filename dep/%.d: %.c Makefile +.PHONY: listvariants listvariants: @echo VARIANTS COIN FIL diff --git a/app/script.ld b/app/script.ld index 15801621..73e2a6e2 100644 --- a/app/script.ld +++ b/app/script.ld @@ -30,7 +30,7 @@ MEMORY } PAGE_SIZE = 64; -STACK_SIZE = 848; +STACK_SIZE = 2008; END_STACK = ORIGIN(SRAM) + LENGTH(SRAM); SECTIONS diff --git a/app/src/addr.c b/app/src/addr.c new file mode 100644 index 00000000..fcab250c --- /dev/null +++ b/app/src/addr.c @@ -0,0 +1,57 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include +#include "coin.h" +#include "zxerror.h" +#include "zxmacros.h" +#include "app_mode.h" +#include "crypto.h" + +zxerr_t addr_getNumItems(uint8_t *num_items) { + zemu_log_stack("addr_getNumItems"); + *num_items = 1; + if (app_mode_expert()) { + *num_items = 2; + } + return zxerr_ok; +} + +zxerr_t addr_getItem(int8_t displayIdx, + char *outKey, uint16_t outKeyLen, + char *outVal, uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { + zemu_log_stack("addr_getItem"); + switch (displayIdx) { + case 0: + snprintf(outKey, outKeyLen, "Your Address"); + pageString(outVal, outValLen, (char *) (G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1), pageIdx, pageCount); + return zxerr_ok; + case 1: { + if (!app_mode_expert()) { + return zxerr_no_data; + } + + snprintf(outKey, outKeyLen, "Your Path"); + char buffer[300]; + bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); + pageString(outVal, outValLen, buffer, pageIdx, pageCount); + return zxerr_ok; + } + default: + return zxerr_no_data; + } +} diff --git a/app/src/addr.h b/app/src/addr.h new file mode 100644 index 00000000..01406719 --- /dev/null +++ b/app/src/addr.h @@ -0,0 +1,34 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/// Return the number of items in the address view +zxerr_t addr_getNumItems(uint8_t *num_items); + +/// Gets an specific item from the address view (including paging) +zxerr_t addr_getItem(int8_t displayIdx, + char *outKey, uint16_t outKeyLen, + char *outValue, uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); + +#ifdef __cplusplus +} +#endif diff --git a/app/src/coin.h b/app/src/coin.h index 494ad32a..d454e9dc 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define CLA 0x06 + #include #include @@ -40,8 +42,6 @@ typedef enum { } address_kind_e; #define VIEW_ADDRESS_OFFSET_SECP256K1 (SECP256K1_PK_LEN + ADDRESS_PROTOCOL_SECP256K1_PAYLOAD_LEN + ADDRESS_PROTOCOL_LEN + 2) -#define VIEW_ADDRESS_ITEM_COUNT 2 -#define VIEW_ADDRESS_LAST_PAGE_DEFAULT 0 #define CRYPTO_BLOB_SKIP_BYTES 1 @@ -50,7 +50,7 @@ typedef enum { #define COIN_SUPPORTED_TX_VERSION 0 #define MENU_MAIN_APP_LINE1 "Filecoin" -#define MENU_MAIN_APP_LINE2 "Network" +#define MENU_MAIN_APP_LINE2 "Ready" #define APPVERSION_LINE1 "Version" #define APPVERSION_LINE2 "v"APPVERSION diff --git a/app/src/common/actions.c b/app/src/common/actions.c index e7c64953..8f065911 100644 --- a/app/src/common/actions.c +++ b/app/src/common/actions.c @@ -16,41 +16,5 @@ ********************************************************************************/ #include "actions.h" -#include "crypto.h" -#include "tx.h" -#include "apdu_codes.h" -#include -#include "coin.h" -void app_sign() { - uint8_t *signature = G_io_apdu_buffer; - - const uint8_t *message = tx_get_buffer() + CRYPTO_BLOB_SKIP_BYTES; - const uint16_t messageLength = tx_get_buffer_length() - CRYPTO_BLOB_SKIP_BYTES; - - const uint8_t replyLen = crypto_sign(signature, IO_APDU_BUFFER_SIZE - 2, message, messageLength); - if (replyLen > 0) { - set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2); - } else { - set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); - } -} - -uint8_t app_fill_address() { - // Put data directly in the apdu buffer - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - return crypto_fillAddress(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); -} - -void app_reply_address() { - const uint8_t replyLen = app_fill_address(); - set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2); -} - -void app_reply_error() { - set_code(G_io_apdu_buffer, 0, APDU_CODE_DATA_INVALID); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); -} +uint8_t action_addr_len; diff --git a/app/src/common/actions.h b/app/src/common/actions.h index 6ca44c7a..60b19e5b 100644 --- a/app/src/common/actions.h +++ b/app/src/common/actions.h @@ -16,11 +16,43 @@ #pragma once #include +#include "crypto.h" +#include "tx.h" +#include "apdu_codes.h" +#include +#include "coin.h" -void app_sign(); +extern uint8_t action_addr_len; -uint8_t app_fill_address(); +__Z_INLINE void app_sign() { + uint8_t *signature = G_io_apdu_buffer; -void app_reply_address(); + const uint8_t *message = tx_get_buffer() + CRYPTO_BLOB_SKIP_BYTES; + const uint16_t messageLength = tx_get_buffer_length() - CRYPTO_BLOB_SKIP_BYTES; -void app_reply_error(); + const uint8_t replyLen = crypto_sign(signature, IO_APDU_BUFFER_SIZE - 3, message, messageLength); + if (replyLen > 0) { + set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2); + } else { + set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + } +} + +__Z_INLINE uint8_t app_fill_address() { + // Put data directly in the apdu buffer + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + action_addr_len = crypto_fillAddress(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + return action_addr_len; +} + +__Z_INLINE void app_reply_address() { + set_code(G_io_apdu_buffer, action_addr_len, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, action_addr_len + 2); +} + +__Z_INLINE void app_reply_error() { + set_code(G_io_apdu_buffer, 0, APDU_CODE_DATA_INVALID); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); +} diff --git a/app/src/common/app_main.h b/app/src/common/app_main.h index 3b2f86bf..d4cc7ad4 100644 --- a/app/src/common/app_main.h +++ b/app/src/common/app_main.h @@ -19,8 +19,6 @@ #include #include "apdu_codes.h" -#define CLA 0x06 - #define OFFSET_CLA 0 #define OFFSET_INS 1 //< Instruction offset #define OFFSET_P1 2 //< P1 @@ -32,9 +30,9 @@ #define OFFSET_PAYLOAD_TYPE OFFSET_P1 -#define INS_GET_VERSION 0 -#define INS_GET_ADDR_SECP256K1 1 -#define INS_SIGN_SECP256K1 2 +#define INS_GET_VERSION 0x00 +#define INS_GET_ADDR_SECP256K1 0x01 +#define INS_SIGN_SECP256K1 0x02 void app_init(); diff --git a/app/src/common/main.c b/app/src/common/main.c index 87150f07..7ecf4a67 100644 --- a/app/src/common/main.c +++ b/app/src/common/main.c @@ -26,18 +26,6 @@ main(void) { view_init(); os_boot(); - - BEGIN_TRY - { - TRY - { - app_init(); - app_main(); - } - CATCH_OTHER(e) - {} - FINALLY - {} - } - END_TRY; + app_init(); + app_main(); } diff --git a/app/src/common/tx.c b/app/src/common/tx.c index 2a940d43..eee1c72d 100644 --- a/app/src/common/tx.c +++ b/app/src/common/tx.c @@ -50,10 +50,10 @@ parser_context_t ctx_parsed_tx; void tx_initialize() { buffering_init( - ram_buffer, - sizeof(ram_buffer), - N_appdata.buffer, - sizeof(N_appdata.buffer) + ram_buffer, + sizeof(ram_buffer), + N_appdata.buffer, + sizeof(N_appdata.buffer) ); } @@ -93,46 +93,42 @@ const char *tx_parse() { return NULL; } -tx_error_t tx_getNumItems(uint8_t *num_items) { +zxerr_t tx_getNumItems(uint8_t *num_items) { parser_error_t err = parser_getNumItems(&ctx_parsed_tx, num_items); if (err != parser_ok) { - return tx_no_data; + return zxerr_no_data; } - return tx_no_error; + return zxerr_ok; } -tx_error_t tx_getItem(int8_t displayIdx, +zxerr_t tx_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { - tx_error_t err = tx_no_error; - uint8_t numItems = 0; - err = tx_getNumItems(&numItems); - if (err != tx_no_error) { - return err; - } + + CHECK_ZXERR(tx_getNumItems(&numItems)) if (displayIdx < 0 || displayIdx > numItems) { - return tx_no_data; + return zxerr_no_data; } - err = (tx_error_t) parser_getItem(&ctx_parsed_tx, - displayIdx, - outKey, outKeyLen, - outVal, outValLen, - pageIdx, pageCount); + parser_error_t err = parser_getItem(&ctx_parsed_tx, + displayIdx, + outKey, outKeyLen, + outVal, outValLen, + pageIdx, pageCount); // Convert error codes if (err == parser_no_data || err == parser_display_idx_out_of_range || err == parser_display_page_out_of_range) - return tx_no_data; + return zxerr_no_data; - if (err == parser_ok) - return tx_no_error; + if (err != parser_ok) + return zxerr_unknown; - return err; + return zxerr_ok; } diff --git a/app/src/common/tx.h b/app/src/common/tx.h index 007a8bdd..b84b9151 100644 --- a/app/src/common/tx.h +++ b/app/src/common/tx.h @@ -17,11 +17,7 @@ #include "os.h" #include "coin.h" - -typedef enum { - tx_no_error = 0, - tx_no_data = 1, -} tx_error_t; +#include "zxerror.h" void tx_initialize(); @@ -45,14 +41,14 @@ uint8_t *tx_get_buffer(); /// Parse message stored in transaction buffer /// This function should be called as soon as full buffer data is loaded. -/// \return It returns NULL if json is valid or error message otherwise. +/// \return It returns NULL if data is valid or error message otherwise. const char *tx_parse(); /// Return the number of items in the transaction -tx_error_t tx_getNumItems(uint8_t *num_items); +zxerr_t tx_getNumItems(uint8_t *num_items); /// Gets an specific item from the transaction (including paging) -tx_error_t tx_getItem(int8_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, - uint8_t pageIdx, uint8_t *pageCount); +zxerr_t tx_getItem(int8_t displayIdx, + char *outKey, uint16_t outKeyLen, + char *outValue, uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); diff --git a/app/src/crypto.h b/app/src/crypto.h index 5cd35c83..0537b3bc 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -16,15 +16,15 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + #include #include "coin.h" #include #include -#ifdef __cplusplus -extern "C" { -#endif - #define CHECKSUM_LENGTH 4 extern uint32_t hdPath[HDPATH_LEN_DEFAULT]; diff --git a/deps/ledger-zxlib/.circleci/config.yml b/deps/ledger-zxlib/.circleci/config.yml index 64441bcb..0c981f72 100644 --- a/deps/ledger-zxlib/.circleci/config.yml +++ b/deps/ledger-zxlib/.circleci/config.yml @@ -9,7 +9,7 @@ jobs: command: apt update && apt-get -y install build-essential git sudo wget cmake libssl-dev libgmp-dev autoconf libtool - checkout - run: git submodule update --init --recursive - - run: cmake -DDISABLE_DOCKER_BUILDS=ON . && make + - run: cmake . && make - run: export GTEST_COLOR=1 && ctest -VV workflows: diff --git a/deps/ledger-zxlib/app/common/app_mode.c b/deps/ledger-zxlib/app/common/app_mode.c new file mode 100644 index 00000000..761ff506 --- /dev/null +++ b/deps/ledger-zxlib/app/common/app_mode.c @@ -0,0 +1,69 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "app_mode.h" + +typedef struct { + uint8_t expert; +} app_mode_t; + +#if defined(TARGET_NANOS) || defined(TARGET_NANOX) +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +app_mode_t NV_CONST N_appmode_impl __attribute__ ((aligned(64))); +#define N_appmode (*(NV_VOLATILE app_mode_t *)PIC(&N_appmode_impl)) + +void app_mode_reset(){ +} + +bool app_mode_expert() { + return N_appmode.expert; +} + +void app_mode_set_expert(uint8_t val) { + app_mode_t mode; + mode.expert = val; + MEMCPY_NV( (void*) PIC(&N_appmode_impl), (void*) &mode, sizeof(app_mode_t)); +} + +#else +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// + +app_mode_t app_mode; + +void app_mode_reset() { + app_mode.expert = 0; +} + +bool app_mode_expert() { + return app_mode.expert; +} + +void app_mode_set_expert(uint8_t val) { + app_mode.expert = val; +} + +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////// + +#endif diff --git a/app/src/view_custom.c b/deps/ledger-zxlib/app/common/app_mode.h similarity index 58% rename from app/src/view_custom.c rename to deps/ledger-zxlib/app/common/app_mode.h index cf6fea2c..1142dd54 100644 --- a/app/src/view_custom.c +++ b/deps/ledger-zxlib/app/common/app_mode.h @@ -1,6 +1,6 @@ /******************************************************************************* -* (c) 2018, 2019 Zondax GmbH * (c) 2016 Ledger +* (c) 2018 Zondax GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ +#pragma once +#include "zxmacros.h" +#include "stdbool.h" -#include "view.h" -#include "coin.h" -#include "crypto.h" -#include "view_internal.h" -#include +#ifdef __cplusplus +extern "C" { +#endif -#include -#include +void app_mode_reset(); -view_error_t view_printAddr() { - snprintf(viewdata.addr, MAX_CHARS_ADDR, "%s", (char *) (G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1)); - splitValueField(); - return view_no_error; -} +bool app_mode_expert(); + +void app_mode_set_expert(uint8_t val); -view_error_t view_printPath() { - bip32_to_str(viewdata.addr, MAX_CHARS_ADDR, hdPath, HDPATH_LEN_DEFAULT); - splitValueField(); - return view_no_error; +#ifdef __cplusplus } +#endif diff --git a/deps/ledger-zxlib/app/common/view.c b/deps/ledger-zxlib/app/common/view.c index e39e4612..1fd10ece 100644 --- a/deps/ledger-zxlib/app/common/view.c +++ b/deps/ledger-zxlib/app/common/view.c @@ -27,6 +27,9 @@ #include "zxmacros.h" #include "view_templates.h" #include "tx.h" +#include "addr.h" +#include "app_mode.h" +#include "zxerror.h" #include #include @@ -37,7 +40,7 @@ void h_address_accept(unsigned int _) { UNUSED(_); view_idle_show(0); UX_WAIT(); - app_reply_address(viewdata.addrKind); + app_reply_address(); } void h_error_accept(unsigned int _) { @@ -63,12 +66,27 @@ void h_sign_reject(unsigned int _) { io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } +/////////////////////////////////// +// Paging related + void h_paging_init() { viewdata.itemIdx = 0; viewdata.pageIdx = 0; viewdata.pageCount = 1; } +uint8_t h_paging_can_increase() { + if (viewdata.pageIdx + 1 < viewdata.pageCount) { + return 1; + } else { + // passed page count, go to next index + if (viewdata.itemIdx + 1 < viewdata.itemCount) { + return 1; + } + } + return 0; +} + void h_paging_increase() { if (viewdata.pageIdx + 1 < viewdata.pageCount) { // increase page @@ -82,6 +100,17 @@ void h_paging_increase() { } } +uint8_t h_paging_can_decrease() { + if (viewdata.pageIdx != 0) { + return 1; + } else { + if (viewdata.itemIdx > 0) { + return 1; + } + } + return 0; +} + void h_paging_decrease() { if (viewdata.pageIdx != 0) { viewdata.pageIdx--; @@ -89,7 +118,7 @@ void h_paging_decrease() { if (viewdata.itemIdx > 0) { viewdata.itemIdx--; // jump to last page. update will cap this value - viewdata.pageIdx = VIEW_ADDRESS_LAST_PAGE_DEFAULT; + viewdata.pageIdx = 255; } } } @@ -101,32 +130,58 @@ void h_paging_set_page_count(uint8_t pageCount) { } } -view_error_t h_review_update_data() { - tx_error_t err = tx_no_error; +/////////////////////////////////// +// Paging related +zxerr_t h_review_update_data() { do { - err = tx_getNumItems(&viewdata.itemCount); - viewdata.itemCount++; - - if (err == tx_no_data) { - return view_no_data; - } - - if (err != tx_no_error) { - return view_error_detected; - } - - err = tx_getItem(viewdata.itemIdx, - viewdata.key, MAX_CHARS_PER_KEY_LINE, - viewdata.value, MAX_CHARS_PER_VALUE1_LINE, - viewdata.pageIdx, &viewdata.pageCount); - - if (err == tx_no_data) { - return view_no_data; + viewdata.pageCount = 1; + switch (viewdata.mode) { + case review_tx: { + CHECK_ZXERR(tx_getNumItems(&viewdata.itemCount)) + CHECK_ZXERR( + tx_getItem(viewdata.itemIdx, + viewdata.key, MAX_CHARS_PER_KEY_LINE, + viewdata.value, MAX_CHARS_PER_VALUE1_LINE, + viewdata.pageIdx, &viewdata.pageCount)) + if (viewdata.pageIdx > viewdata.pageCount) { + // try again and get last page + viewdata.pageIdx = viewdata.pageCount - 1; + CHECK_ZXERR( + tx_getItem(viewdata.itemIdx, + viewdata.key, MAX_CHARS_PER_KEY_LINE, + viewdata.value, MAX_CHARS_PER_VALUE1_LINE, + viewdata.pageIdx, &viewdata.pageCount)) + } + break; + } + case review_address: { + CHECK_ZXERR(addr_getNumItems(&viewdata.itemCount)) + CHECK_ZXERR(addr_getItem(viewdata.itemIdx, + viewdata.key, MAX_CHARS_PER_KEY_LINE, + viewdata.value, MAX_CHARS_PER_VALUE1_LINE, + viewdata.pageIdx, &viewdata.pageCount)) + if (viewdata.pageIdx > viewdata.pageCount) { + // try again and get last page + viewdata.pageIdx = viewdata.pageCount - 1; + CHECK_ZXERR( + addr_getItem(viewdata.itemIdx, + viewdata.key, MAX_CHARS_PER_KEY_LINE, + viewdata.value, MAX_CHARS_PER_VALUE1_LINE, + viewdata.pageIdx, &viewdata.pageCount)) + } + break; + } + default: + return zxerr_unknown; } + viewdata.itemCount++; - if (err != tx_no_error) { - return view_error_detected; + if (viewdata.pageCount > 1) { + uint8_t keyLen = strlen(viewdata.key); + if (keyLen < MAX_CHARS_PER_KEY_LINE) { + snprintf(viewdata.key + keyLen, MAX_CHARS_PER_KEY_LINE - keyLen, " [%d/%d]", viewdata.pageIdx + 1, viewdata.pageCount); + } } if (viewdata.pageCount == 0) { @@ -135,19 +190,11 @@ view_error_t h_review_update_data() { } while (viewdata.pageCount == 0); splitValueField(); - return view_no_error; + return zxerr_ok; } -view_error_t h_addr_update_item(uint8_t idx) { - MEMZERO(viewdata.value, MAX_CHARS_PER_VALUE1_LINE); - - switch (idx) { - case 0: return view_printAddr(); - case 1: return view_printPath(); - default: - return view_error_detected; - } -} +/////////////////////////////////// +// General void io_seproxyhal_display(const bagl_element_t *element) { io_seproxyhal_display_default((bagl_element_t *) element); @@ -157,23 +204,23 @@ void view_init(void) { UX_INIT(); } -void view_idle_show(unsigned int ignored) { - view_idle_show_impl(); +void view_idle_show(uint8_t item_idx) { + view_idle_show_impl(item_idx); } -void view_address_show(address_kind_e addressKind) { - viewdata.addrKind = addressKind; - viewdata.itemCount = VIEW_ADDRESS_ITEM_COUNT; // Address, path, etc. +void view_address_show() { + viewdata.mode = review_address; view_address_show_impl(); } +void view_sign_show() { + viewdata.mode = review_tx; + view_sign_show_impl(); +} + void view_error_show() { snprintf(viewdata.key, MAX_CHARS_PER_KEY_LINE, "ERROR"); snprintf(viewdata.value, MAX_CHARS_PER_VALUE1_LINE, "SHOWING DATA"); splitValueField(); view_error_show_impl(); } - -void view_sign_show() { - view_sign_show_impl(); -} diff --git a/deps/ledger-zxlib/app/common/view.h b/deps/ledger-zxlib/app/common/view.h index e9389a54..a95b4bc1 100644 --- a/deps/ledger-zxlib/app/common/view.h +++ b/deps/ledger-zxlib/app/common/view.h @@ -31,13 +31,13 @@ void view_init(); /// view_idle_show (idle view - main menu + status) -void view_idle_show(unsigned int ignored); +void view_idle_show(uint8_t item_idx); /// view_error (error view) void view_error_show(); // shows address in the screen -void view_address_show(address_kind_e addressKind); +void view_address_show(); // Shows review screen + later sign menu void view_sign_show(); diff --git a/deps/ledger-zxlib/app/common/view_internal.h b/deps/ledger-zxlib/app/common/view_internal.h index e5c39ad7..8a63920f 100644 --- a/deps/ledger-zxlib/app/common/view_internal.h +++ b/deps/ledger-zxlib/app/common/view_internal.h @@ -18,6 +18,7 @@ #include #include "coin.h" +#include "zxerror.h" #define CUR_FLOW G_ux.flow_stack[G_ux.stack_count-1] @@ -36,6 +37,11 @@ // This takes data from G_io_apdu_buffer that is prefilled with the address +typedef enum { + review_tx = 0, + review_address = 1 +} review_mode_e; + typedef struct { union { struct { @@ -49,7 +55,7 @@ typedef struct { char addr[MAX_CHARS_ADDR]; }; }; - address_kind_e addrKind; + review_mode_e mode; uint8_t itemIdx; uint8_t itemCount; uint8_t pageIdx; @@ -58,12 +64,6 @@ typedef struct { extern view_t viewdata; -typedef enum { - view_no_error = 0, - view_no_data = 1, - view_error_detected = 2 -} view_error_t; - #define print_title(...) snprintf(viewdata.title, sizeof(viewdata.title), __VA_ARGS__) #define print_key(...) snprintf(viewdata.key, sizeof(viewdata.key), __VA_ARGS__); #define print_value(...) snprintf(viewdata.value, sizeof(viewdata.value), __VA_ARGS__); @@ -83,7 +83,7 @@ void splitValueField(); /////////////////////////////////////////////// /////////////////////////////////////////////// -void view_idle_show_impl(); +void view_idle_show_impl(uint8_t item_idx); void view_address_show_impl(); @@ -101,16 +101,14 @@ void h_sign_reject(unsigned int _); void h_paging_init(); +uint8_t h_paging_can_increase(); + void h_paging_increase(); +uint8_t h_paging_can_decrease(); + void h_paging_decrease(); void h_paging_set_page_count(uint8_t pageCount); -view_error_t h_review_update_data(); - -view_error_t h_addr_update_item(uint8_t idx); - -view_error_t view_printAddr(); - -view_error_t view_printPath(); +zxerr_t h_review_update_data(); diff --git a/deps/ledger-zxlib/app/common/view_s.c b/deps/ledger-zxlib/app/common/view_s.c index d2f4fd6b..4aff4460 100644 --- a/deps/ledger-zxlib/app/common/view_s.c +++ b/deps/ledger-zxlib/app/common/view_s.c @@ -15,6 +15,7 @@ * limitations under the License. ********************************************************************************/ +#include "app_mode.h" #include "view.h" #include "view_internal.h" #include "actions.h" @@ -24,16 +25,19 @@ #include "zxmacros.h" #include "view_templates.h" #include "tx.h" +#include "addr.h" #include #include #if defined(TARGET_NANOS) +void h_expert_toggle(); +void h_expert_update(); void h_review_button_left(); void h_review_button_right(); void view_review_show(); -void view_sign_show_s(); +void view_review_decision_s(); ux_state_t ux; @@ -43,52 +47,27 @@ void os_exit(uint32_t id) { const ux_menu_entry_t menu_main[] = { {NULL, NULL, 0, &C_icon_app, MENU_MAIN_APP_LINE1, MENU_MAIN_APP_LINE2, 33, 12}, + {NULL, h_expert_toggle, 0, &C_icon_app, "Expert mode:", viewdata.value, 33, 12}, {NULL, NULL, 0, &C_icon_app, APPVERSION_LINE1, APPVERSION_LINE2, 33, 12}, - {NULL, NULL, 0, &C_icon_app, "Developed by", "Zondax.ch", 33, 12}, - {NULL, NULL, 0, &C_icon_app, "under Apache", "License 2.0", 33, 12}, + {NULL, NULL, 0, &C_icon_app, "Developed by:", "Zondax.ch", 33, 12}, + {NULL, NULL, 0, &C_icon_app, "License: ", "Apache 2.0", 33, 12}, {NULL, os_exit, 0, &C_icon_dashboard, "Quit", NULL, 50, 29}, UX_MENU_END }; -#if !defined(HAVE_UX_FLOW) -void h_addr_button_left(); -void h_addr_button_right(); -void h_addr_button_both(); -void view_addr_show(); - -static const bagl_element_t view_address[] = { - UI_BACKGROUND_LEFT_RIGHT_ICONS, - UI_LabelLine(UIID_LABEL + 0, 0, 8, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.key), - UI_LabelLine(UIID_LABEL + 0, 0, 19, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value), - UI_LabelLineScrolling(UIID_LABELSCROLL, 0, 30, 128, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value2), -}; -#else -UX_STEP_NOCB_INIT(ux_addr_flow_1_step, paging, - { h_addr_update_item(CUR_FLOW.index); }, - { .title = "Address", .text = viewdata.addr, }); -UX_STEP_NOCB_INIT(ux_addr_flow_2_step, paging, - { h_addr_update_item(CUR_FLOW.index); }, - { .title = "Path", .text = viewdata.addr, }); -UX_STEP_VALID(ux_addr_flow_3_step, pb, h_address_accept(0), { &C_icon_validate_14, "Ok"}); - -UX_FLOW( - ux_addr_flow, - &ux_addr_flow_1_step, - &ux_addr_flow_2_step, - &ux_addr_flow_3_step -); - -#endif - void h_review(unsigned int _) { UNUSED(_); view_sign_show_impl(); } -const ux_menu_entry_t menu_sign[] = { - {NULL, h_review, 0, NULL, "View transaction", NULL, 0, 0}, - {NULL, h_sign_accept, 0, NULL, "Sign transaction", NULL, 0, 0}, +const ux_menu_entry_t menu_decision_sign[] = { + {NULL, h_sign_accept, 0, NULL, "Approve", NULL, 0, 0}, {NULL, h_sign_reject, 0, NULL, "Reject", NULL, 0, 0}, UX_MENU_END }; +const ux_menu_entry_t menu_decision_address[] = { + {NULL, h_address_accept, 0, NULL, "Accept", NULL, 0, 0}, + UX_MENU_END +}; + static const bagl_element_t view_review[] = { UI_BACKGROUND_LEFT_RIGHT_ICONS, UI_LabelLine(UIID_LABEL + 0, 0, 8, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.key), @@ -104,28 +83,6 @@ static const bagl_element_t view_error[] = { UI_LabelLineScrolling(UIID_LABELSCROLL, 0, 30, 128, UI_11PX, UI_WHITE, UI_BLACK, viewdata.value2), }; -#if !defined(HAVE_UX_FLOW) -static unsigned int view_address_button(unsigned int button_mask, unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: - // Press both left and right buttons to quit - h_addr_button_both(); - break; - - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - // Press left to progress to the previous element - h_addr_button_left(); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - // Press right to progress to the next element - h_addr_button_right(); - break; - } - return 0; -} -#endif - static unsigned int view_error_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: @@ -141,8 +98,10 @@ static unsigned int view_error_button(unsigned int button_mask, unsigned int but static unsigned int view_review_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: - // Press both left and right buttons to quit - view_sign_show_s(); + if (app_mode_expert()) { + // Press both left and right buttons to quit + view_review_decision_s(); + } break; case BUTTON_EVT_RELEASED | BUTTON_LEFT: // Press left to progress to the previous element @@ -160,7 +119,15 @@ static unsigned int view_review_button(unsigned int button_mask, unsigned int bu const bagl_element_t *view_prepro(const bagl_element_t *element) { switch (element->component.userid) { case UIID_ICONLEFT: + if (!h_paging_can_decrease()){ + return NULL; + } + UX_CALLBACK_SET_INTERVAL(2000); + break; case UIID_ICONRIGHT: + if (!h_paging_can_increase()){ + return NULL; + } UX_CALLBACK_SET_INTERVAL(2000); break; case UIID_LABELSCROLL: @@ -175,16 +142,15 @@ const bagl_element_t *view_prepro(const bagl_element_t *element) { void h_review_button_left() { h_paging_decrease(); - view_error_t err = h_review_update_data(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: + case zxerr_ok: view_review_show(); UX_WAIT(); break; - case view_no_data: - view_sign_show_s(); + case zxerr_no_data: + view_review_decision_s(); break; - case view_error_detected: default: view_error_show(); UX_WAIT(); @@ -195,17 +161,16 @@ void h_review_button_left() { void h_review_button_right() { h_paging_increase(); - view_error_t err = h_review_update_data(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: + case zxerr_ok: view_review_show(); UX_WAIT(); break; - case view_no_data: - view_sign_show_s(); + case zxerr_no_data: + view_review_decision_s(); break; - case view_error_detected: default: view_error_show(); UX_WAIT(); @@ -228,123 +193,74 @@ void splitValueField() { ////////////////////////// ////////////////////////// -void view_idle_show_impl() { - UX_MENU_DISPLAY(0, menu_main, NULL); -} - -void view_address_show_impl() { -#if !defined(HAVE_UX_FLOW) - h_paging_init(); - - view_error_t err = h_addr_update_item(viewdata.itemIdx); - switch(err) { - case view_no_error: - view_addr_show(); - break; - case view_error_detected: - default: - view_error_show(); - break; - } -#else - ux_layout_paging_reset(); - if(G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_addr_flow, NULL); -#endif +void view_idle_show_impl(uint8_t item_idx) { + h_expert_update(); + UX_MENU_DISPLAY(item_idx, menu_main, NULL); } void view_error_show_impl() { UX_DISPLAY(view_error, view_prepro); } -void view_sign_show_impl() { - h_paging_init(); - - view_error_t err = h_review_update_data(); - switch(err) { - case view_no_error: - view_review_show(); - break; - case view_no_data: - view_sign_show_s(); - break; - case view_error_detected: - default: - view_error_show(); - break; - } -} - -void view_sign_show_s(void){ - UX_MENU_DISPLAY(0, menu_sign, NULL); +void view_review_decision_s(void){ + switch (viewdata.mode) { + case review_tx: { + UX_MENU_DISPLAY(0, menu_decision_sign, NULL); + break; + } + case review_address: { + UX_MENU_DISPLAY(0, menu_decision_address, NULL); + break; + } + } } void view_review_show() { UX_DISPLAY(view_review, view_prepro); } -#if !defined(HAVE_UX_FLOW) -void h_addr_button_left() { - h_paging_decrease(); - - view_error_t err = h_addr_update_item(viewdata.itemIdx); +void h_expert_toggle() { + app_mode_set_expert(!app_mode_expert()); + view_idle_show(1); +} - switch(err) { - case view_no_error: - view_addr_show(); - break; - case view_no_data: - // FIXME: - case view_error_detected: - default: - view_error_show(); - break; +void h_expert_update() { + strcpy(viewdata.value, "disabled"); + if (app_mode_expert()) { + strcpy(viewdata.value, "enabled"); } - - UX_WAIT(); } -void h_addr_button_right() { - h_paging_increase(); - view_error_t err = h_addr_update_item(viewdata.itemIdx); +void view_sign_show_impl() { + h_paging_init(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: - view_addr_show(); + case zxerr_ok: + view_review_show(); + break; + case zxerr_no_data: + view_review_decision_s(); break; - case view_no_data: - // FIXME: - case view_error_detected: default: view_error_show(); break; } - - UX_WAIT(); } -void h_addr_button_both() { - view_error_t err = h_addr_update_item(viewdata.itemIdx); - +void view_address_show_impl() { + h_paging_init(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: - h_address_accept(0); + case zxerr_ok: + view_review_show(); + break; + case zxerr_no_data: + view_review_decision_s(); break; - case view_no_data: - // FIXME: - case view_error_detected: default: view_error_show(); break; } - UX_WAIT(); -} - -void view_addr_show() { - UX_DISPLAY(view_address, view_prepro); } #endif - -#endif diff --git a/deps/ledger-zxlib/app/common/view_x.c b/deps/ledger-zxlib/app/common/view_x.c index 43b1bedd..7be12a1d 100644 --- a/deps/ledger-zxlib/app/common/view_x.c +++ b/deps/ledger-zxlib/app/common/view_x.c @@ -15,6 +15,7 @@ * limitations under the License. ********************************************************************************/ +#include "app_mode.h" #include "view.h" #include "view_internal.h" #include "actions.h" @@ -30,6 +31,8 @@ #if defined(TARGET_NANOX) +void h_expert_toggle(); +void h_expert_update(); void h_review_loop_start(); void h_review_loop_inside(); void h_review_loop_end(); @@ -39,35 +42,26 @@ ux_state_t G_ux; bolos_ux_params_t G_ux_params; uint8_t flow_inside_loop; + UX_FLOW_DEF_NOCB(ux_idle_flow_1_step, pbb, { &C_icon_app, MENU_MAIN_APP_LINE1, MENU_MAIN_APP_LINE2,}); -UX_FLOW_DEF_NOCB(ux_idle_flow_3_step, bn, { "Version", APPVERSION, }); -UX_FLOW_DEF_VALID(ux_idle_flow_4_step, pb, os_sched_exit(-1), { &C_icon_dashboard, "Quit",}); +UX_STEP_CB_INIT(ux_idle_flow_2_step, bn, h_expert_update(), h_expert_toggle(), { "Expert mode:", viewdata.value, }); +UX_FLOW_DEF_NOCB(ux_idle_flow_3_step, bn, { APPVERSION_LINE1, APPVERSION_LINE2, }); +UX_FLOW_DEF_NOCB(ux_idle_flow_4_step, bn, { "Developed by:", "Zondax.ch", }); +UX_FLOW_DEF_NOCB(ux_idle_flow_5_step, bn, { "License:", "Apache 2.0", }); +UX_FLOW_DEF_VALID(ux_idle_flow_6_step, pb, os_sched_exit(-1), { &C_icon_dashboard, "Quit",}); + const ux_flow_step_t *const ux_idle_flow [] = { &ux_idle_flow_1_step, + &ux_idle_flow_2_step, &ux_idle_flow_3_step, &ux_idle_flow_4_step, + &ux_idle_flow_5_step, + &ux_idle_flow_6_step, FLOW_END_STEP, }; /////////// -UX_STEP_NOCB_INIT(ux_addr_flow_1_step, bnnn_paging, - { h_addr_update_item(CUR_FLOW.index); }, - { .title = "Address", .text = viewdata.addr, }); -UX_STEP_NOCB_INIT(ux_addr_flow_2_step, bnnn_paging, - { h_addr_update_item(CUR_FLOW.index); }, - { .title = "Path", .text = viewdata.addr, }); -UX_STEP_VALID(ux_addr_flow_3_step, pb, h_address_accept(0), { &C_icon_validate_14, "Ok"}); - -UX_FLOW( - ux_addr_flow, - &ux_addr_flow_1_step, - &ux_addr_flow_2_step, - &ux_addr_flow_3_step -); - -/////////// - UX_STEP_NOCB(ux_error_flow_1_step, bnnn_paging, { .title = viewdata.key, .text = viewdata.value, }); UX_STEP_VALID(ux_error_flow_2_step, pb, h_error_accept(0), { &C_icon_validate_14, "Ok"}); @@ -78,24 +72,36 @@ UX_FLOW( ); /////////// -UX_STEP_NOCB(ux_sign_flow_1_step, pbb, { &C_icon_eye, "View", "Transaction" }); - -UX_STEP_INIT(ux_sign_flow_2_start_step, NULL, NULL, { h_review_loop_start(); }); -UX_STEP_NOCB_INIT(ux_sign_flow_2_step, bnnn_paging, { h_review_loop_inside(); }, { .title = viewdata.key, .text = viewdata.value, }); -UX_STEP_INIT(ux_sign_flow_2_end_step, NULL, NULL, { h_review_loop_end(); }); +UX_STEP_INIT(ux_review_flow_2_start_step, NULL, NULL, { h_review_loop_start(); }); +UX_STEP_NOCB_INIT(ux_review_flow_2_step, bnnn_paging, { h_review_loop_inside(); }, { .title = viewdata.key, .text = viewdata.value, }); +UX_STEP_INIT(ux_review_flow_2_end_step, NULL, NULL, { h_review_loop_end(); }); +UX_STEP_NOCB(ux_sign_flow_1_step, pbb, { &C_icon_eye, "View", "Transaction" }); UX_STEP_VALID(ux_sign_flow_3_step, pbb, h_sign_accept(0), { &C_icon_validate_14, "Sign", "Transaction" }); UX_STEP_VALID(ux_sign_flow_4_step, pbb, h_sign_reject(0), { &C_icon_crossmark, "Reject", "Transaction" }); + const ux_flow_step_t *const ux_sign_flow[] = { &ux_sign_flow_1_step, - &ux_sign_flow_2_start_step, - &ux_sign_flow_2_step, - &ux_sign_flow_2_end_step, + &ux_review_flow_2_step, + &ux_review_flow_2_step, + &ux_review_flow_2_step, &ux_sign_flow_3_step, &ux_sign_flow_4_step, FLOW_END_STEP, }; +UX_STEP_NOCB(ux_address_flow_1_step, pbb, { &C_icon_eye, "View", "Address" }); +UX_STEP_VALID(ux_address_flow_3_step, pbb, h_address_accept(0), { &C_icon_validate_14, "Accept", "Address" }); + +const ux_flow_step_t *const ux_address_flow[] = { + &ux_address_flow_1_step, + &ux_review_flow_2_step, + &ux_review_flow_2_step, + &ux_review_flow_2_step, + &ux_address_flow_3_step, + FLOW_END_STEP, +}; + ////////////////////////// ////////////////////////// ////////////////////////// @@ -117,12 +123,11 @@ void h_review_loop_start() { h_paging_init(); } - view_error_t err = h_review_update_data(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: - case view_no_data: + case zxerr_ok: + case zxerr_no_data: break; - case view_error_detected: default: view_error_show(); break; @@ -139,18 +144,17 @@ void h_review_loop_end() { if (flow_inside_loop) { // coming from left h_paging_increase(); - view_error_t err = h_review_update_data(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: + case zxerr_ok: ux_layout_bnnn_paging_reset(); break; - case view_no_data: { + case zxerr_no_data: { flow_inside_loop = 0; ux_flow_next(); return; } - case view_error_detected: default: view_error_show(); break; @@ -158,13 +162,12 @@ void h_review_loop_end() { } else { // coming from right h_paging_decrease(); - view_error_t err = h_review_update_data(); + zxerr_t err = h_review_update_data(); switch(err) { - case view_no_error: - case view_no_data: + case zxerr_ok: + case zxerr_no_data: break; - case view_error_detected: default: view_error_show(); break; @@ -184,13 +187,25 @@ void splitValueField() { } } +void h_expert_toggle() { + app_mode_set_expert(!app_mode_expert()); + ux_flow_init(0, ux_idle_flow, &ux_idle_flow_2_step); +} + +void h_expert_update() { + strcpy(viewdata.value, "disabled"); + if (app_mode_expert()) { + strcpy(viewdata.value, "enabled"); + } +} + ////////////////////////// ////////////////////////// ////////////////////////// ////////////////////////// ////////////////////////// -void view_idle_show_impl() { +void view_idle_show_impl(uint8_t item_idx) { if(G_ux.stack_count == 0) { ux_stack_push(); } @@ -198,19 +213,15 @@ void view_idle_show_impl() { } void view_address_show_impl() { - ux_layout_bnnn_paging_reset(); - if(G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_addr_flow, NULL); -} + h_paging_init(); + h_paging_decrease(); -void view_error_show_impl() { - ux_layout_bnnn_paging_reset(); + //// + flow_inside_loop = 0; if(G_ux.stack_count == 0) { ux_stack_push(); } - ux_flow_init(0, ux_error_flow, NULL); + ux_flow_init(0, ux_address_flow, NULL); } void view_sign_show_impl(){ @@ -224,4 +235,12 @@ void view_sign_show_impl(){ ux_flow_init(0, ux_sign_flow, NULL); } +void view_error_show_impl() { + ux_layout_bnnn_paging_reset(); + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_error_flow, NULL); +} + #endif diff --git a/deps/ledger-zxlib/app/common/zbuffer.c b/deps/ledger-zxlib/app/common/zbuffer.c new file mode 100644 index 00000000..86211aa5 --- /dev/null +++ b/deps/ledger-zxlib/app/common/zbuffer.c @@ -0,0 +1,88 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "zbuffer.h" +#include "zxmacros.h" + +typedef struct { + uint8_t *ptr; + uint16_t size; +} zbuffer_t; + +zbuffer_t _internal; + +#define CANARY_EXPECTED 0x987def82u + +zbuffer_error_e zb_get(uint8_t **buffer) { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + *buffer = NULL; + if (_internal.size == 0 || _internal.ptr == NULL) { + return zb_not_allocated; + } + *buffer = _internal.ptr; +#endif + return zb_no_error; +} + +zbuffer_error_e zb_init() { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + _internal.size = 0; + _internal.ptr = NULL; +#endif + return zb_no_error; +} + +zbuffer_error_e zb_allocate(uint16_t size) { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + if (size % 4 != 0) { + size += size % 4; + } + _internal.size = size; + _internal.ptr = (uint8_t * )(&app_stack_canary + 4); + + uint32_t *zb_canary = (uint32_t * )(_internal.ptr + _internal.size + 4); + *zb_canary = CANARY_EXPECTED; +#endif + return zb_no_error; +} + +zbuffer_error_e zb_deallocate() { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + if (_internal.size == 0) { + return zb_not_allocated; + } + + // Flush any information + MEMZERO(_internal.ptr, _internal.size); + + zb_init(); +#endif + return zb_no_error; +} + +zbuffer_error_e zb_check_canary() { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + CHECK_APP_CANARY(); + if (_internal.size != 0) { + // allocated + uint32_t *zb_canary = (uint32_t * )(_internal.ptr + _internal.size + 4); + if (*zb_canary != CANARY_EXPECTED) { + handle_stack_overflow(); + } + } +#endif + return zb_no_error; +} diff --git a/deps/ledger-zxlib/dockerized_build.mk b/deps/ledger-zxlib/dockerized_build.mk index 3fe7042b..146818ca 100644 --- a/deps/ledger-zxlib/dockerized_build.mk +++ b/deps/ledger-zxlib/dockerized_build.mk @@ -60,7 +60,7 @@ define run_docker -u $(USERID) \ -v $(shell pwd):/project \ $(DOCKER_IMAGE) \ - "COIN=$(COIN) $(2)" + "COIN=$(COIN) APP_TESTING=$(APP_TESTING) $(2)" endef all: build @@ -82,23 +82,32 @@ pull: build_rust: $(call run_docker,$(DOCKER_BOLOS_SDK),make -C $(DOCKER_APP_SRC) rust) +.PHONY: convert_icon +convert_icon: + @convert $(LEDGER_SRC)/tmp.gif -monochrome -size 16x16 -depth 1 $(LEDGER_SRC)/nanos_icon.gif + @convert $(LEDGER_SRC)/nanos_icon.gif -crop 14x14+1+1 +repage -negate $(LEDGER_SRC)/nanox_icon.gif + .PHONY: build -build: build_rust +build: $(info Replacing app icon) @cp $(LEDGER_SRC)/nanos_icon.gif $(LEDGER_SRC)/glyphs/icon_app.gif $(info calling make inside docker) - $(call run_docker,$(DOCKER_BOLOS_SDK),make -C $(DOCKER_APP_SRC)) + $(call run_docker,$(DOCKER_BOLOS_SDK),make -j `nproc` -C $(DOCKER_APP_SRC)) .PHONY: buildX buildX: build_rust @cp $(LEDGER_SRC)/nanos_icon.gif $(LEDGER_SRC)/glyphs/icon_app.gif @convert $(LEDGER_SRC)/nanos_icon.gif -crop 14x14+1+1 +repage -negate $(LEDGER_SRC)/nanox_icon.gif - $(call run_docker,$(DOCKER_BOLOS_SDKX),make -C $(DOCKER_APP_SRC)) + $(call run_docker,$(DOCKER_BOLOS_SDKX),make -j `nproc` -C $(DOCKER_APP_SRC)) .PHONY: clean clean: $(call run_docker,$(DOCKER_BOLOS_SDK),make -C $(DOCKER_APP_SRC) clean) +.PHONY: clean_rust +clean_rust: + $(call run_docker,$(DOCKER_BOLOS_SDK),make -C $(DOCKER_APP_SRC) rust_clean) + .PHONY: listvariants listvariants: $(call run_docker,$(DOCKER_BOLOS_SDK),make -C $(DOCKER_APP_SRC) listvariants) @@ -140,6 +149,11 @@ dev_init_secondary: check_python show_info_recovery_mode dev_ca: check_python @python -m ledgerblue.setupCustomCA --targetId 0x31100004 --public $(SCP_PUBKEY) --name zondax +# This target will setup a custom developer certificate +.PHONY: dev_caX +dev_caX: check_python + @python -m ledgerblue.setupCustomCA --targetId 0x33000004 --public $(SCP_PUBKEY) --name zondax + .PHONY: dev_ca_delete dev_ca_delete: check_python @python -m ledgerblue.resetCustomCA --targetId 0x31100004 @@ -199,5 +213,5 @@ rust_test: .PHONY: cpp_test cpp_test: - mkdir -p build && cd build && cmake -DDISABLE_DOCKER_BUILDS=ON -DCMAKE_BUILD_TYPE=Debug .. && make + mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. && make cd build && GTEST_COLOR=1 ASAN_OPTIONS=detect_leaks=0 ctest -VV diff --git a/deps/ledger-zxlib/include/base58.h b/deps/ledger-zxlib/include/base58.h new file mode 100644 index 00000000..301f4e7b --- /dev/null +++ b/deps/ledger-zxlib/include/base58.h @@ -0,0 +1,38 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2019 Zondax GmbH +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int decode_base58(const char *in, size_t length, + unsigned char *out, size_t *outlen); + +int encode_base58(const unsigned char *in, size_t length, + unsigned char *out, size_t *outlen); + +char encode_base58_clip(const unsigned char v); + +#ifdef __cplusplus +} +#endif diff --git a/deps/ledger-zxlib/include/bech32.h b/deps/ledger-zxlib/include/bech32.h index e3cb6ea7..bd9fd148 100644 --- a/deps/ledger-zxlib/include/bech32.h +++ b/deps/ledger-zxlib/include/bech32.h @@ -31,7 +31,8 @@ zxerr_t bech32EncodeFromBytes(char *out, size_t out_len, const char *hrp, const uint8_t *in, - size_t in_len); + size_t in_len, + uint8_t pad); #ifdef __cplusplus } diff --git a/deps/ledger-zxlib/include/timeutils.h b/deps/ledger-zxlib/include/timeutils.h new file mode 100644 index 00000000..bbc3aa4f --- /dev/null +++ b/deps/ledger-zxlib/include/timeutils.h @@ -0,0 +1,74 @@ +/******************************************************************************* +* (c) 2018 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "zxmacros.h" +#include "zxerror.h" + +__Z_INLINE const char *getMonth(uint8_t tm_mon) { + switch (tm_mon) { + case 1: + return "Jan"; + break; + case 2: + return "Feb"; + break; + case 3: + return "Mar"; + break; + case 4: + return "Apr"; + break; + case 5: + return "May"; + break; + case 6: + return "Jun"; + break; + case 7: + return "Jul"; + break; + case 8: + return "Aug"; + break; + case 9: + return "Sep"; + break; + case 10: + return "Oct"; + break; + case 11: + return "Nov"; + break; + case 12: + return "Dec"; + break; + default: + return "ERR"; + } +} + +zxerr_t printTime(char *out, uint16_t outLen, uint64_t t); + +#ifdef __cplusplus +} +#endif diff --git a/deps/ledger-zxlib/include/zbuffer.h b/deps/ledger-zxlib/include/zbuffer.h new file mode 100644 index 00000000..9322d88a --- /dev/null +++ b/deps/ledger-zxlib/include/zbuffer.h @@ -0,0 +1,38 @@ +/******************************************************************************* +* (c) 2020 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#include +#include + +typedef enum { + zb_no_error, + zb_misaligned_buffer, + zb_not_allocated +} zbuffer_error_e; + +// allocate a block at the end of the stack +// maximum size will not be checked +zbuffer_error_e zb_allocate(uint16_t size); + +// deallocate memory block as the end of the stack +zbuffer_error_e zb_deallocate(); + +// obtain a pointer to the allocated block +zbuffer_error_e zb_get(uint8_t **buffer); + +// check that the block boundary has not been corrupted +zbuffer_error_e zb_check_canary(); diff --git a/deps/ledger-zxlib/include/zxerror.h b/deps/ledger-zxlib/include/zxerror.h index e3edde76..59fdedd0 100644 --- a/deps/ledger-zxlib/include/zxerror.h +++ b/deps/ledger-zxlib/include/zxerror.h @@ -20,11 +20,17 @@ extern "C" { #endif +#define CHECK_ZXERR(CALL) { \ + zxerr_t err = CALL; \ + if (err!=zxerr_ok) return err;} + typedef enum { zxerr_ok, + zxerr_no_data, zxerr_buffer_too_small, zxerr_out_of_bounds, zxerr_encoding_failed, + zxerr_unknown } zxerr_t; #ifdef __cplusplus diff --git a/deps/ledger-zxlib/include/zxformat.h b/deps/ledger-zxlib/include/zxformat.h index b5fbb4ba..10af9975 100644 --- a/deps/ledger-zxlib/include/zxformat.h +++ b/deps/ledger-zxlib/include/zxformat.h @@ -195,11 +195,34 @@ __Z_INLINE uint8_t fpstr_to_str(char *out, uint16_t outLen, const char *number, return 0; } -__Z_INLINE void fpuint64_to_str(char *out, uint16_t outLen, const uint64_t value, uint8_t decimals) { +__Z_INLINE uint16_t fpuint64_to_str(char *out, uint16_t outLen, const uint64_t value, uint8_t decimals) { char buffer[30]; MEMZERO(buffer, sizeof(buffer)); int64_to_str(buffer, sizeof(buffer), value); fpstr_to_str(out, outLen, buffer, decimals); + uint16_t len = strlen(out); + return len; +} + +__Z_INLINE void number_inplace_trimming(char *s) { + const size_t len = strlen(s); + if (len == 0 || len == 1 || len > 1024) { + return; + } + + int16_t dec_point = -1; + for (int16_t i = 0; i < (int16_t) len && dec_point < 0; i++) { + if (s[i] == '.') { + dec_point = i; + } + } + if (dec_point < 0) { + return; + } + + for (int16_t i = (int16_t) len - 1; i > (dec_point + 1) && s[i] == '0'; i--) { + s[i] = 0; + } } __Z_INLINE uint64_t uint64_from_BEarray(const uint8_t data[8]) { @@ -217,7 +240,7 @@ __Z_INLINE uint32_t array_to_hexstr(char *dst, uint16_t dstLen, const uint8_t *s return 0; } - const char hexchars[] = "0123456789ABCDEF"; + const char hexchars[] = "0123456789abcdef"; for (uint8_t i = 0; i < count; i++, src++) { *dst++ = hexchars[*src >> 4u]; *dst++ = hexchars[*src & 0x0Fu]; diff --git a/deps/ledger-zxlib/include/zxmacros.h b/deps/ledger-zxlib/include/zxmacros.h index 067ec02c..43b2d000 100644 --- a/deps/ledger-zxlib/include/zxmacros.h +++ b/deps/ledger-zxlib/include/zxmacros.h @@ -25,7 +25,13 @@ extern "C" { #endif +void check_app_canary(); + +#include +#include +#include #include "string.h" + #ifndef __APPLE__ extern void explicit_bzero(void *__s, size_t __n) __THROW __nonnull ((1)); #endif @@ -37,18 +43,6 @@ void handle_stack_overflow(); #include "bolos_target.h" #endif -#if defined(TARGET_NANOX) -#define NV_CONST const -#define NV_VOL volatile -#else -#define NV_CONST -#define NV_VOL -#endif - -#ifndef PIC -#define PIC(x) (x) -#endif - #define NV_ALIGN __attribute__ ((aligned(64))) #if defined (TARGET_NANOS) || defined(TARGET_NANOX) @@ -59,11 +53,17 @@ void handle_stack_overflow(); #if defined(TARGET_NANOX) #include "ux.h" +#define NV_CONST const +#define NV_VOLATILE volatile +#define IS_UX_ALLOWED (G_ux_params.len != BOLOS_UX_IGNORE && G_ux_params.len != BOLOS_UX_CONTINUE) #else #include "os_io_seproxyhal.h" +#define NV_CONST +#define NV_VOLATILE +#define IS_UX_ALLOWED (ux.params.len != BOLOS_UX_IGNORE && ux.params.len != BOLOS_UX_CONTINUE) #endif -#define CHECK_APP_CANARY() { if (app_stack_canary != APP_STACK_CANARY_MAGIC) handle_stack_overflow(); } +#define CHECK_APP_CANARY() check_app_canary(); #define APP_STACK_CANARY_MAGIC 0xDEAD0031 extern unsigned int app_stack_canary; @@ -75,12 +75,6 @@ extern unsigned int app_stack_canary; io_seproxyhal_general_status(); \ WAIT_EVENT() -#if defined(TARGET_NANOX) -#define IS_UX_ALLOWED (G_ux_params.len != BOLOS_UX_IGNORE && G_ux_params.len != BOLOS_UX_CONTINUE) -#else -#define IS_UX_ALLOWED (ux.params.len != BOLOS_UX_IGNORE && ux.params.len != BOLOS_UX_CONTINUE) -#endif - #define MEMMOVE os_memmove #define MEMSET os_memset #define MEMCPY os_memcpy @@ -90,6 +84,10 @@ extern unsigned int app_stack_canary; #else +#ifndef PIC +#define PIC(x) (x) +#endif + #define CHECK_APP_CANARY() {} #define MEMMOVE memmove @@ -109,10 +107,6 @@ __Z_INLINE void __memzero(void *buffer, size_t s) { memset(buffer, 0, s); } #endif #endif -#include -#include -#include - #define SET_NV(DST, TYPE, VAL) { \ TYPE nvset_tmp=(VAL); \ MEMCPY_NV((void*) PIC(DST), (void *) PIC(&nvset_tmp), sizeof(TYPE)); \ @@ -135,6 +129,22 @@ __Z_INLINE void strncpy_s(char *dst, const char *src, size_t dstSize) { strncpy(dst, src, dstSize - 1); } +void zemu_log_stack(char *ctx); + +__Z_INLINE void zemu_log(char *buf) +{ +#if defined(ZEMU_LOGGING) + #if defined (TARGET_NANOS) || defined(TARGET_NANOX) + asm volatile ( + "movs r0, #0x04\n" + "movs r1, %0\n" + "svc 0xab\n" + :: "r"(buf) : "r0", "r1" + ); + #endif +#endif +} + #ifdef __cplusplus } #endif diff --git a/deps/ledger-zxlib/include/zxversion.h b/deps/ledger-zxlib/include/zxversion.h index d7d45776..cfdbfc15 100644 --- a/deps/ledger-zxlib/include/zxversion.h +++ b/deps/ledger-zxlib/include/zxversion.h @@ -15,6 +15,6 @@ ********************************************************************************/ #pragma once -#define ZXLIB_MAJOR 2 +#define ZXLIB_MAJOR 3 #define ZXLIB_MINOR 0 -#define ZXLIB_PATCH 0 +#define ZXLIB_PATCH 1 diff --git a/deps/ledger-zxlib/scripts/template.sh b/deps/ledger-zxlib/scripts/template.sh index 3816f5d8..8f0e7206 100755 --- a/deps/ledger-zxlib/scripts/template.sh +++ b/deps/ledger-zxlib/scripts/template.sh @@ -31,7 +31,7 @@ python3 -m ledgerblue.loadApp -h &>/dev/null; if [ $? -ne 0 ]; then echo echo "ERR: ledgerblue pip package not found." - echo "please install using 'pip3 install ledgerblue'" + echo "please install using 'pip install ledgerblue'" echo exit fi diff --git a/deps/ledger-zxlib/src/base58.c b/deps/ledger-zxlib/src/base58.c new file mode 100644 index 00000000..847b013a --- /dev/null +++ b/deps/ledger-zxlib/src/base58.c @@ -0,0 +1,153 @@ +/******************************************************************************* +* Adapted from Ledger App - Bitcoin Wallet +* (c) 2019 Zondax GmbH +* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "base58.h" +#include "zxmacros.h" + +#define MAX_DEC_INPUT_SIZE 164 +#define MAX_ENC_INPUT_SIZE 120 + +unsigned char const BASE58TABLE[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0x10, 0xff, 0x11, 0x12, 0x13, 0x14, 0x15, 0xff, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0xff, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff}; + +unsigned char const BASE58ALPHABET[] = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + +int decode_base58(const char *in, size_t length, + unsigned char *out, size_t *outlen) { + unsigned char tmp[MAX_DEC_INPUT_SIZE]; + unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; + unsigned char i; + unsigned char j; + unsigned char startAt; + unsigned char zeroCount = 0; + if (length > MAX_DEC_INPUT_SIZE) { + return -1; + } + MEMMOVE(tmp, in, length); + for (i = 0; i < length; i++) { + if (in[i] >= sizeof(BASE58TABLE)) { + return -1; + } + tmp[i] = BASE58TABLE[(int) in[i]]; + if (tmp[i] == 0xff) { + return -1; + } + } + while ((zeroCount < length) && (tmp[zeroCount] == 0)) { + ++zeroCount; + } + j = length; + startAt = zeroCount; + while (startAt < length) { + unsigned short remainder = 0; + unsigned char divLoop; + for (divLoop = startAt; divLoop < length; divLoop++) { + unsigned short digit256 = (unsigned short) (tmp[divLoop] & 0xff); + unsigned short tmpDiv = remainder * 58 + digit256; + tmp[divLoop] = (unsigned char) (tmpDiv / 256); + remainder = (tmpDiv % 256); + } + if (tmp[startAt] == 0) { + ++startAt; + } + buffer[--j] = (unsigned char) remainder; + } + while ((j < length) && (buffer[j] == 0)) { + ++j; + } + length = length - (j - zeroCount); + if (*outlen < length) { + return -1; + } + + MEMMOVE(out, buffer + j - zeroCount, length); + *outlen = length; + return 0; +} + +int encode_base58(const unsigned char *in, size_t length, + unsigned char *out, size_t *outlen) { + unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; + size_t i = 0, j; + size_t startAt, stopAt; + size_t zeroCount = 0; + size_t outputSize; + + if (length > MAX_ENC_INPUT_SIZE) { + return -1; + } + + while ((zeroCount < length) && (in[zeroCount] == 0)) { + ++zeroCount; + } + + outputSize = (length - zeroCount) * 138 / 100 + 1; + stopAt = outputSize - 1; + for (startAt = zeroCount; startAt < length; startAt++) { + int carry = in[startAt]; + for (j = outputSize - 1; (int) j >= 0; j--) { + carry += 256 * buffer[j]; + buffer[j] = carry % 58; + carry /= 58; + + if (j <= stopAt - 1 && carry == 0) { + break; + } + } + stopAt = j; + } + + j = 0; + while (j < outputSize && buffer[j] == 0) { + j += 1; + } + + if (*outlen < zeroCount + outputSize - j) { + *outlen = zeroCount + outputSize - j; + return -1; + } + + MEMSET(out, BASE58ALPHABET[0], zeroCount); + + i = zeroCount; + while (j < outputSize) { + out[i++] = BASE58ALPHABET[buffer[j++]]; + } + *outlen = i; + return 0; +} + +char encode_base58_clip(const unsigned char v) { + return BASE58ALPHABET[v % 58]; +} diff --git a/deps/ledger-zxlib/src/bech32.c b/deps/ledger-zxlib/src/bech32.c index 741b4d28..21fc639b 100644 --- a/deps/ledger-zxlib/src/bech32.c +++ b/deps/ledger-zxlib/src/bech32.c @@ -25,7 +25,8 @@ zxerr_t bech32EncodeFromBytes(char *out, size_t out_len, const char *hrp, const uint8_t *in, - size_t in_len) { + size_t in_len, + uint8_t pad) { MEMZERO(out, out_len); if (in_len > MAX_INPUT_SIZE) { @@ -34,15 +35,16 @@ zxerr_t bech32EncodeFromBytes(char *out, size_t hrplen = strlen(hrp); // We set a lower bound to ensure this is safe - if (out_len < hrplen + (in_len*2) + 7) { + if (out_len < hrplen + (in_len * 2) + 7) { return zxerr_buffer_too_small; } // Overestimate required size *2==(8/4) instead of *(8/5) uint8_t tmp_data[MAX_INPUT_SIZE * 2]; size_t tmp_size = 0; + MEMZERO(tmp_data, sizeof(tmp_data)); - convert_bits(tmp_data, &tmp_size, 5, in, in_len, 8, 0); + convert_bits(tmp_data, &tmp_size, 5, in, in_len, 8, pad); if (tmp_size >= out_len) { return zxerr_out_of_bounds; } diff --git a/deps/ledger-zxlib/src/bignum.c b/deps/ledger-zxlib/src/bignum.c index b4c3e483..59cb0459 100644 --- a/deps/ledger-zxlib/src/bignum.c +++ b/deps/ledger-zxlib/src/bignum.c @@ -68,7 +68,7 @@ void bignumLittleEndian_to_bcd(uint8_t *bcdOut, uint16_t bcdOutLen, // get bit const uint16_t byteIdx = bitIdx >> 3u; - const uint8_t mask = 0x80u >> (bitIdx & 0b111u); + const uint8_t mask = 0x80u >> (bitIdx & 0x7u); carry = (binValue[binValueLen - byteIdx - 1] & mask) > 0; // Shift bcd @@ -134,7 +134,7 @@ void bignumBigEndian_to_bcd(uint8_t *bcdOut, uint16_t bcdOutLen, // get bit const uint16_t byteIdx = bitIdx >> 3u; - const uint8_t mask = 0x80u >> (bitIdx & 0b111u); + const uint8_t mask = 0x80u >> (bitIdx & 0x7u); carry = (binValue[byteIdx] & mask) > 0; // Shift bcd diff --git a/deps/ledger-zxlib/src/timeutils.c b/deps/ledger-zxlib/src/timeutils.c new file mode 100644 index 00000000..138a8c26 --- /dev/null +++ b/deps/ledger-zxlib/src/timeutils.c @@ -0,0 +1,508 @@ +/******************************************************************************* +* (c) 2018 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "zxmacros.h" +#include "timeutils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +const uint8_t monthDays[] = { + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31 +}; + +const uint32_t yearLookup[] = { + 0, + 365, + 730, + 1096, + 1461, + 1826, + 2191, + 2557, + 2922, + 3287, + 3652, + 4018, + 4383, + 4748, + 5113, + 5479, + 5844, + 6209, + 6574, + 6940, + 7305, + 7670, + 8035, + 8401, + 8766, + 9131, + 9496, + 9862, + 10227, + 10592, + 10957, + 11323, + 11688, + 12053, + 12418, + 12784, + 13149, + 13514, + 13879, + 14245, + 14610, + 14975, + 15340, + 15706, + 16071, + 16436, + 16801, + 17167, + 17532, + 17897, + 18262, + 18628, + 18993, + 19358, + 19723, + 20089, + 20454, + 20819, + 21184, + 21550, + 21915, + 22280, + 22645, + 23011, + 23376, + 23741, + 24106, + 24472, + 24837, + 25202, + 25567, + 25933, + 26298, + 26663, + 27028, + 27394, + 27759, + 28124, + 28489, + 28855, + 29220, + 29585, + 29950, + 30316, + 30681, + 31046, + 31411, + 31777, + 32142, + 32507, + 32872, + 33238, + 33603, + 33968, + 34333, + 34699, + 35064, + 35429, + 35794, + 36160, + 36525, + 36890, + 37255, + 37621, + 37986, + 38351, + 38716, + 39082, + 39447, + 39812, + 40177, + 40543, + 40908, + 41273, + 41638, + 42004, + 42369, + 42734, + 43099, + 43465, + 43830, + 44195, + 44560, + 44926, + 45291, + 45656, + 46021, + 46387, + 46752, + 47117, + 47482, + 47847, + 48212, + 48577, + 48942, + 49308, + 49673, + 50038, + 50403, + 50769, + 51134, + 51499, + 51864, + 52230, + 52595, + 52960, + 53325, + 53691, + 54056, + 54421, + 54786, + 55152, + 55517, + 55882, + 56247, + 56613, + 56978, + 57343, + 57708, + 58074, + 58439, + 58804, + 59169, + 59535, + 59900, + 60265, + 60630, + 60996, + 61361, + 61726, + 62091, + 62457, + 62822, + 63187, + 63552, + 63918, + 64283, + 64648, + 65013, + 65379, + 65744, + 66109, + 66474, + 66840, + 67205, + 67570, + 67935, + 68301, + 68666, + 69031, + 69396, + 69762, + 70127, + 70492, + 70857, + 71223, + 71588, + 71953, + 72318, + 72684, + 73049, + 73414, + 73779, + 74145, + 74510, + 74875, + 75240, + 75606, + 75971, + 76336, + 76701, + 77067, + 77432, + 77797, + 78162, + 78528, + 78893, + 79258, + 79623, + 79989, + 80354, + 80719, + 81084, + 81450, + 81815, + 82180, + 82545, + 82911, + 83276, + 83641, + 84006, + 84371, + 84736, + 85101, + 85466, + 85832, + 86197, + 86562, + 86927, + 87293, + 87658, + 88023, + 88388, + 88754, + 89119, + 89484, + 89849, + 90215, + 90580, + 90945, + 91310, + 91676, + 92041, + 92406, + 92771, + 93137, + 93502, + 93867, + 94232, + 94598, + 94963, + 95328, + 95693, + 96059, + 96424, + 96789, + 97154, + 97520, + 97885, + 98250, + 98615, + 98981, + 99346, + 99711, + 100076, + 100442, + 100807, + 101172, + 101537, + 101903, + 102268, + 102633, + 102998, + 103364, + 103729, + 104094, + 104459, + 104825, + 105190, + 105555, + 105920, + 106286, + 106651, + 107016, + 107381, + 107747, + 108112, + 108477, + 108842, + 109208, + 109573, + 109938, + 110303, + 110669, + 111034, + 111399, + 111764, + 112130, + 112495, + 112860, + 113225, + 113591, + 113956, + 114321, + 114686, + 115052, + 115417, + 115782, + 116147, + 116513, + 116878, + 117243, + 117608, + 117974, + 118339, + 118704, + 119069, + 119435, + 119800, + 120165, + 120530, + 120895, + 121260, + 121625, + 121990, + 122356, + 122721, + 123086, + 123451, + 123817, + 124182, + 124547, + 124912, + 125278, + 125643, + 126008, + 126373, + 126739, + 127104, + 127469, + 127834, + 128200, + 128565, + 128930, + 129295, + 129661, + 130026, + 130391, + 130756, + 131122, + 131487, + 131852, + 132217, + 132583, + 132948, + 133313, + 133678, + 134044, + 134409, + 134774, + 135139, + 135505, + 135870, + 136235, + 136600, + 136966, + 137331, + 137696, + 138061, + 138427, + 138792, + 139157, + 139522, + 139888, + 140253, + 140618, + 140983, + 141349, + 141714, + 142079, + 142444, + 142810, + 143175, + 143540, + 143905, + 144271, + 144636, + 145001, + 145366, + 145732, +}; + +// ARM does not implement gmtime. This is a simple alternative implementation +// based on section 4.16 +// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html +zxerr_t printTime(char *out, uint16_t outLen, uint64_t t) { + uint8_t tm_sec = 0; + uint8_t tm_min = 0; + uint8_t tm_hour = 0; + uint16_t tm_day = 0; + uint8_t tm_mon = 0; + uint16_t tm_year = 0; + + tm_sec = t % 60; + t -= tm_sec; + t /= 60; + + tm_min = t % 60; + t -= tm_min; + t /= 60; + + tm_hour = t % 24; + t -= tm_hour; + t /= 24; + + // Look up tm_year + tm_year = 0; + const uint16_t yearLookupSize = sizeof(yearLookup)/sizeof(yearLookup[0]); + while (tm_year < yearLookupSize && yearLookup[tm_year] <= t) tm_year++; + + if (tm_year == 0 || tm_year == yearLookupSize) { + return zxerr_out_of_bounds; + } + tm_year--; + + tm_day = t - yearLookup[tm_year] + 1; + tm_year = 1970 + tm_year; + + // Get day/month + uint8_t leap = (tm_year % 4 == 0 && (tm_year % 100 != 0 || tm_year % 400 == 0) ? 1 : 0); + + for (tm_mon = 0; tm_mon < 12; tm_mon++) { + uint8_t tmp = monthDays[tm_mon]; + tmp += (tm_mon == 1 ? leap : 0); + if (tm_day <= tmp) { + break; + } + tm_day -= tmp; + } + tm_mon++; + + const char *monthName = getMonth(tm_mon); + + // YYYYmmdd HH:MM:SS + snprintf(out, outLen, "%02d%s%04d %02d:%02d:%02d", + tm_day, + monthName, + tm_year, + tm_hour, tm_min, tm_sec + ); + + return zxerr_ok; +} + +#ifdef __cplusplus +} +#endif diff --git a/deps/ledger-zxlib/src/zxmacros.c b/deps/ledger-zxlib/src/zxmacros.c index 7c6ca13e..8be855f9 100644 --- a/deps/ledger-zxlib/src/zxmacros.c +++ b/deps/ledger-zxlib/src/zxmacros.c @@ -16,8 +16,7 @@ #include "zxmacros.h" #include "utf8.h" -size_t asciify(char *utf8_in_ascii_out) -{ +size_t asciify(char *utf8_in_ascii_out) { return asciify_ext(utf8_in_ascii_out, utf8_in_ascii_out); } @@ -39,9 +38,32 @@ size_t asciify_ext(const char *utf8_in, char *ascii_only_out) { } void handle_stack_overflow() { + zemu_log("!!!!!!!!!!!!!!!!!!!!!! CANARY TRIGGERED!!! STACK OVERFLOW DETECTED\n"); #if defined (TARGET_NANOS) || defined(TARGET_NANOX) io_seproxyhal_se_reset(); #else - while(1); + while (1); +#endif +} + +void check_app_canary() { +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) + if (app_stack_canary != APP_STACK_CANARY_MAGIC) handle_stack_overflow(); +#endif +} + +void zemu_log_stack(char *ctx) { +#if defined(ZEMU_LOGGING) +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) +#define STACK_SHIFT 20 + void* p = NULL; + char buf[70]; + snprintf(buf, sizeof(buf), "|SP| %p %p (%d) : %s\n", + &app_stack_canary, + ((void*)&p)+STACK_SHIFT, + (uint32_t)((void*)&p)+STACK_SHIFT - (uint32_t)&app_stack_canary, + ctx); + zemu_log(buf); +#endif #endif } diff --git a/deps/ledger-zxlib/tests/bech32.cpp b/deps/ledger-zxlib/tests/bech32.cpp index 4d8f204e..4e791419 100644 --- a/deps/ledger-zxlib/tests/bech32.cpp +++ b/deps/ledger-zxlib/tests/bech32.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace { TEST(BECH32, hex_to_address) { @@ -25,15 +26,26 @@ namespace { uint8_t data1[] = {1, 3, 5}; uint8_t data2[] = {1, 3, 5, 7, 9, 11, 13}; - auto err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data1, sizeof(data1)); + auto err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data1, sizeof(data1), 0); ASSERT_EQ(err, zxerr_ok); std::cout << addr_out << std::endl; ASSERT_STREQ("zx1qypse825ac", addr_out); - err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data2, sizeof(data2)); + err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data2, sizeof(data2), 0); ASSERT_EQ(err, zxerr_ok); std::cout << addr_out << std::endl; ASSERT_STREQ("zx1qyps2pcfpvx20dk22", addr_out); + + /// + err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data1, sizeof(data1), 1); + ASSERT_EQ(err, zxerr_ok); + std::cout << addr_out << std::endl; + ASSERT_STREQ("zx1qyps2ucfnzd", addr_out); + + err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data2, sizeof(data2), 1); + ASSERT_EQ(err, zxerr_ok); + std::cout << addr_out << std::endl; + ASSERT_STREQ("zx1qyps2pcfpvxshamanz", addr_out); } TEST(BECH32, huge_input) { @@ -42,7 +54,7 @@ namespace { auto data = std::vector(1000, 0x55); - auto err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data.data(), data.size()); + auto err = bech32EncodeFromBytes(addr_out, sizeof(addr_out), hrp, data.data(), data.size(),0); ASSERT_EQ(err, zxerr_out_of_bounds); std::cout << addr_out << std::endl; @@ -59,7 +71,7 @@ namespace { // declare size to be smaller const size_t declared_size = 52; - auto err = bech32EncodeFromBytes(addr_out, declared_size, hrp, data.data(), data.size()); + auto err = bech32EncodeFromBytes(addr_out, declared_size, hrp, data.data(), data.size(), 0); ASSERT_EQ(err, zxerr_buffer_too_small); for (int i = declared_size; i < sizeof(addr_out); i++) { diff --git a/deps/ledger-zxlib/tests/macros.cpp b/deps/ledger-zxlib/tests/macros.cpp index 75b3042e..b3614384 100644 --- a/deps/ledger-zxlib/tests/macros.cpp +++ b/deps/ledger-zxlib/tests/macros.cpp @@ -198,6 +198,42 @@ namespace { EXPECT_EQ(std::string(output), "1.0"); } + TEST(FORMAT, number_trimming) { + char output[100]; + + strcpy(output, "0"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0"); + + strcpy(output, "10"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "10"); + + strcpy(output, "10.10"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "10.1"); + + strcpy(output, "0.0"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0.0"); + + strcpy(output, "0.00"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0.0"); + + strcpy(output, "0.01"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0.01"); + + strcpy(output, "0.010"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0.01"); + + strcpy(output, "0.010000"); + number_inplace_trimming(output); + EXPECT_EQ(std::string(output), "0.01"); + } + TEST(INT64_TO_STR, Zero) { char temp[10]; const char *error = int64_to_str(temp, sizeof(temp), int64_t(0)); @@ -306,7 +342,6 @@ namespace { EXPECT_EQ(1, error); } - TEST(STR_TO_INT8, DummyData_Positive) { char numberStr[] = "100b0"; char error = 0; diff --git a/deps/ledger-zxlib/tests/timeutils.cpp b/deps/ledger-zxlib/tests/timeutils.cpp new file mode 100644 index 00000000..797e32a1 --- /dev/null +++ b/deps/ledger-zxlib/tests/timeutils.cpp @@ -0,0 +1,95 @@ +/******************************************************************************* +* (c) 2018 Zondax GmbH +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include +#include +#include + +namespace { + TEST(TIMEUTILS, basic) { + uint64_t t = 1104937465; + char output[50]; + + zxerr_t err = printTime(output, sizeof(output), t); + + EXPECT_EQ(err, zxerr_ok); + EXPECT_STREQ(output, "05Jan2005 15:04:25"); + } + + TEST(TIMEUTILS, yearlookup) { + char output[50]; + char expected_output[50]; + + struct tm t = {0}; // Initalize to all 0's + for (uint64_t year = 70; year < 470; year++) { + t.tm_year = year; // This is year-1900, so 112 = 2012 + t.tm_mon = 0; + t.tm_mday = 1; + t.tm_hour = 0; + t.tm_min = 0; + t.tm_sec = 0; + setenv("TZ", "UTC", 1); + time_t timeSinceEpoch = mktime(&t); + + const uint32_t day = 60*60*24; + uint64_t daysSinceStart = timeSinceEpoch / day; + + std::cout << " " << daysSinceStart << ", " << std::endl; + } + } + + TEST(TIMEUTILS, loop) { + char output[50]; + char expected_output[50]; + + for (uint64_t t = 0; t < 8640000000; t += 1234567) { + zxerr_t err = printTime(output, sizeof(output), t); + EXPECT_EQ(err, zxerr_ok); + time_t tmp = t; + auto expected = gmtime(&tmp); + snprintf(expected_output, sizeof(expected_output), "%02d%s%d %02d:%02d:%02d", + expected->tm_mday, + getMonth(expected->tm_mon + 1), + expected->tm_year + 1900, + expected->tm_hour, + expected->tm_min, + expected->tm_sec + ); + + std::cout << t << " " << output << " " << expected_output << std::endl; + + EXPECT_STREQ(output, expected_output); + } + } + + TEST(TIMEUTILS, zero) { + uint64_t t = 0; + char output[50]; + + zxerr_t err = printTime(output, sizeof(output), t); + + EXPECT_EQ(err, zxerr_ok); + EXPECT_STREQ(output, "01Jan1970 00:00:00"); + } + + TEST(TIMEUTILS, huge) { + uint64_t t = 86400ULL * 365ULL * 5000ULL; + char output[50]; + + zxerr_t err = printTime(output, sizeof(output), t); + + EXPECT_EQ(err, zxerr_out_of_bounds); + } +} diff --git a/docs/img/clion_debugging.png b/docs/img/clion_debugging.png new file mode 100644 index 0000000000000000000000000000000000000000..f827acd356e3a3b70bafc788e8151ae1e60cad57 GIT binary patch literal 130508 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 literal 0 HcmV?d00001 diff --git a/tests/crypto.cpp b/tests/crypto.cpp index 6248391a..09899b5e 100644 --- a/tests/crypto.cpp +++ b/tests/crypto.cpp @@ -53,10 +53,10 @@ TEST(CRYPTO, fillAddress) { char *addrString = (char *) (addrByte + 21 + 1); EXPECT_THAT(std::string(pk), - ::testing::Eq("0466F2BDB19E90FD7C29E4BF63612EB98515E5163C97888042364BA777D818E88B765C649056BA4A62292AE4E2CCDABD71B845D8FA0991C140F664D2978AC0972A")); + ::testing::Eq("0466f2bdb19e90fd7c29e4bf63612eb98515e5163c97888042364ba777d818e88b765c649056ba4a62292ae4e2ccdabd71b845d8fa0991c140f664d2978ac0972a")); EXPECT_THAT(std::string(addrByteToHexStr), - ::testing::Eq("01DFE49184D46ADC8F89D44638BEB45F78FCAD2590")); + ::testing::Eq("01dfe49184d46adc8f89d44638beb45f78fcad2590")); EXPECT_THAT(std::string(addrString), @@ -87,10 +87,10 @@ TEST(CRYPTO, fillAddressTestMnemonic) { char *addrString = (char *) (addrByte + 21 + 1); EXPECT_THAT(std::string(pk), - ::testing::Eq("0466F2BDB19E90FD7C29E4BF63612EB98515E5163C97888042364BA777D818E88B765C649056BA4A62292AE4E2CCDABD71B845D8FA0991C140F664D2978AC0972A")); + ::testing::Eq("0466f2bdb19e90fd7c29e4bf63612eb98515e5163c97888042364ba777d818e88b765c649056ba4a62292ae4e2ccdabd71b845d8fa0991c140f664d2978ac0972a")); EXPECT_THAT(std::string(addrByteToHexStr), - ::testing::Eq("01DFE49184D46ADC8F89D44638BEB45F78FCAD2590")); + ::testing::Eq("01dfe49184d46adc8f89d44638beb45f78fcad2590")); EXPECT_THAT(std::string(addrString), ::testing::Eq("f137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizpy")); @@ -176,7 +176,7 @@ TEST(CRYPTO, prepareMessageDigest) { std::cout << message_digest << std::endl; EXPECT_THAT(std::string(message_digest), - ::testing::Eq("5A51287D2E5401B75014DA0F050C8DB96FE0BACDAD75FCE964520CA063B697E1")); + ::testing::Eq("5a51287d2e5401b75014da0f050c8db96fe0bacdad75fce964520ca063b697e1")); EXPECT_THAT(err, ::testing::Eq(0)); diff --git a/tests/testvectors.cpp b/tests/testvectors.cpp index cc4033af..ca9602a4 100644 --- a/tests/testvectors.cpp +++ b/tests/testvectors.cpp @@ -94,6 +94,8 @@ class VerifyTestVectors : public ::testing::TestWithParam { }; }; +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VerifyTestVectors); + INSTANTIATE_TEST_SUITE_P( KnownIssues, VerifyTestVectors, diff --git a/tests_zemu/snapshots/show-address/0.png b/tests_zemu/snapshots/show-address/0.png index a45dc73b9583956e07eb9a5ac514285e0dce94cb..3f2dfa2c714faec58e5db45e7c74c4b407fe9270 100644 GIT binary patch literal 1089 zcmXYxe@q)?7{`0o6o&U=LUgnzrlnAb88UKQI~vGrJt|`j-NHtoN}^rfG*{dZL*j73 zq%rX(amMQiTTbfM{a~A7SWPnr(Maa$b}pB$-C%=(OB%Fh5yup_09nN6?e@p@`riB8 z^L(Gr^L=k%r>_YWFaa z4A46vqy^d0;& z;wMw^=H9GApU_C9A;b?+%`m^9dWb+u#|g~qK-`se0p~(!%e%L~7^x+IpTumPxL8z1wuxoHvD*bKhd}ZyvMN6f$x;}7PDLx3vem9X?7)< zvld622wF8&gS&5nM-*u`)OSuS?cG5Ae(MV02oVX@H^W-{fy}MXDq@e;zHubeHTceS zylnX{8O2Ow;&nZ1?lQ8KVBF^&$x`sn`$x5lHYjL@^7V7$ZGiAgO8&xtA^b$nc90fW zgo>Q n1?K>oTYP+^Yx@A+!)GfG<}Ymi?PCf)4Z3EJuW{_vw?6zIx8BfJ literal 812 zcmXX_Z%7ky7~UM5A$KAa;+n@9~LO_7`#7pB>% zDBKtSv@%O_qkTxrB0H!PhD~LnqQd$xAymXgYD)IbgnRGDJ;(F@d7k&zl5a9#5k!PU zBEgKgIalGdL&%RI@Lp8fR1!&8(3q2b?Vfaf!rVy|ouDS-!`2%o{&=HOza|wU=)Cq9 z+I{A)@3?U-v$g(9i>Y4Ovb-9VZ(4lT)th^38;{(7p0Jkr*uE8sQGwU2qI!@P$8|C? z7Ng1?wCHsy+*)}sFMMTyw(fklrp<2NASncA^nzYE7q{C^j8u*eNpXVpSmrq#izOX2 z6&PfPiBE2sbIvwMTVu!y_^ZPpBf?L+6wMwSXQs3$uS56`DP9c|%};NhHLU2$wTW0k z%F@w^@=sVr@EcGeb-$FaP2W^w+VO`dDawAxGr#Y z?-Azy-Lma8J}Ew^Vk|q|_P2W{F>&8kwp|3D{?8jBMTDm1RZCW&!f?vx602aEM-a&{ zf9W9IG4={XED^Y|At_%PSC=Dj>9d!Wdkfv>B8L35aA{zKq z;2ojvJkpV6Uw{J|rYB^JUx^b_{|7ikf@t`L$}P&_sfGj&DL+i8EBk2?#X%78hsy@J zH4K;{CXyo5(ST-mCKJh6vV!5V%R{9@(2U*FcX2CjvPx`&{)zyxj1Ga>(F8Z(FKKU3 z@<~1obGtGoWG&0K5_$nBA0rzQNQYkyYtk{68+ZzxDXP0ruwdy89V!ToW&99peRlM4 zDXd`AKohG&aKci^^p4OS3$QSN)JEmkG&+HTL2^aV1yL1Vb9!CeNC)3wnVit5Q{KOp iIoGsoxa8Wi97ukf3&x%2f5Ih@NQ^pD&d8Or2mb)VRA8(C diff --git a/tests_zemu/snapshots/show-address/1.png b/tests_zemu/snapshots/show-address/1.png index 3a2c4b25b83936800716260997a4587229fa6bfb..0f02f5116287656c0be66e61613638fe3ff3e827 100644 GIT binary patch delta 594 zcmX@Z_KIbKay^rwr;B4q1>@U;jd`~s7+fw|Pka8~z9MYaq2SLV?OPf}cCr4J`55f4 z;>c`dp6QUbm~m!%mcz5{QWJiLFdOk-H#m90;ABjOLtC3?TE>i&b=MlsxM%xYT=eu; zDKwUpngB$VE7(#p9G=ZrH$LgZdjg1fjDnesPVn%WPh42fIP-g$=bW!D>b4V)#G3km zWPr%|uuAddw)m_cA%|6rO?*In5cOXNWZdSWYX#SY_j$LqIi_Vf0MRooBlBz^V}{g( znNnsc%h*!d+IVMj8~Ho7v89|7JC|~#-or`gzS`$-69wZF7d{B^n#5%6xKOZ}Eu|i) zSkFYESe*C7p2$jNXJ#Y+g%2O5=mA{^bS97+p6T$+oA<;WS7xL4x_i`}4+l?hWSjZF zm4{c_$fRZ^<4k>1u&vR(hw;u<(e;qJ1gSFfDFHW5BQ$^x0P?5Ck7IVWnO5377W6&BZe z=E{d$-V<+*o?4xK0~n@yC;o&TZacF%y3&;QL=GrS6^u=R2pCep@H?y>abq`Iido8p zo6W7^mm1DItm3W)M$EjmZyZ4Z$-_ID$H;`oXfhA4_j)&n%2c5LVwsK3=RMqz&D|a= z9Kg4GYr&1Jt%uj?%9Q0o1fwn9+&YwaU5sz{HlURJ>NoG#uF(GRivb8cUHx3vIVCg! E0G^ooumAu6 literal 844 zcmXX_eMl2=7@iDf=uRO+y|ZAOibM|OGgU7mw&$D0e>an9- zWJUVGPDyvn@6Dpc=&stuXtg6HG{7@-`s{aeOz~s3xn!&D!Jx#tqGy>iPf2b~F0`~7 z(+s6rs*a$ASQN_PqwU&HABkT2mWIt@861mq3ULZz6t=xJyE@<=rF#gbkK{UN%rb8m z%ZNm3D#kZVzgli?C|fGk60}PLw-1vxk`wu}%(6M%Fi3KHy#mNdWW{Vf$Bl*`U zoG5M@5>QRC*2YDXONX_)j7!Y2QABS8p$==N>_t48uQ zzg`)kxv!(9eoQNSO{5Jj4DMeR$K!>*y zaIYx_`a`+C;Y%Tmzn2E1fhf3PtZxI}I|Y0s2T|r_ytQWOCm&mW@Bzo9NQjBi3>b)-Dw$6s8Zev|(@U;7qesnd0Y-&KJ@E9|25}yfy5IJjviDKc;^-R$UI(U zW7!gD=IHsP4${D!2$1>}& zRacTbo8sqnZHmPg3{u`LVw`z#!vxC=2_qAolrr8EcP<@UYx+j&U%8Z+(Fp}( zsdbYi!L%6f_AiGPXI6wC4&^-o)aZ8DDGjItNIhF`YO|>~I?E#ChAGd?W}vyDhZiM+ z^a4$gIiUcuMvT{lXC}WXkX2^1_+gmYJ4d#eu7`I^*}1YwN|o`N#9Vba?8wYJU#h+%O+5PE<6O0-2<^Ia|VLyV8O^R~yc}>;i_yQ=ss4pqXoX zw@Xd1-0S=-`eY5aq|`m3fH+fy;$H`)CRA?yxQcP+Wqx(%!>fD4jZEg$?O;oZ%l+fk z)^?d6Xv}(+DL}0|yMczimEueJ7j@Y0nWBlp=WE>8PuQ@|j6FOZ7{vUp&t{3sxdMaG zxvdT8mI(_JPh8kA`KGB(O5N&*4sC6#f#DNwDs$q_foIBBnw`ctbI6UF!+P2uk6D%h<0wvqrw-i=oNq<-Syf$TD z&l#XG^VL3gn8`Js$*2ftHu~RrCSyS(NcqlHi5E9y1KB{A09CQ`_B%OP$^zps9~g-5 tG9Q1rV&>=X>tJcSw)b-IZ42A2^$d*~iZQoNI)RcVgQu&X%Q~loCIF$NEoJ}! diff --git a/tests_zemu/snapshots/show-address/3.png b/tests_zemu/snapshots/show-address/3.png index f9bd7db43636a43ec27e6c1a82ad69630975ec9d..66b03316d994c8024e78bfec91f8802f2279adfa 100644 GIT binary patch delta 504 zcmX@kGLdD1ay{b>PZ!6K3dXkw1M?n-iMSlR+*0+Q`(3}>LnVbX5oK>Wr(F0Pq5AKV zwP(z=MfVDq@4n~xXcHgf({;MLUe8t0%f3;uxIAW>(teI8ocOamC9LT28>zN4?NWRxWxVW0ixbs1XG<6@W|WjFGpg^Z@7|6XW*vO>D<5`iM^m!F$W~1rz6CaC8 z>HXi_)-HALR)yG1#rk4PpiB6qCRAoWj+Amc{8S|+LxT6jpS#C4pWvB!y7R<^hBM0M z^Ogb?)p;LoJagHUXXerqH7SpCQh>g delta 559 zcmbQpa-3y?ay=8Dr;B4q1>@U;fqAz*7+elsZ~66){at^bK?J|g#BWizI8IJlBlQ2p zTot|Ni|!RJ-+j;XQIQ(-tz=Mo=IzE@}|%J|en$}A=BlEDd?tA_$l+AM8s z+q|<-jaS>q`S2Bk6F$6?&rH;r)5&9Wf`_;Hj7syFt}}smEmpPF_qLtB)w_67WTr$) zTN}4dj9>0Uos>2NEgtV6K+nBOj!n`D`%dW*ZRM?Z934x9~0ZAo7k*<=pRuroh@Y_ z&>MO)>#sJPS=Y9(kxeQr1*qxgM7DYunY;WBkdsyMKi6k%_mYeVxP3AGW z4|Hzbn#2i_6CKksD%xAiGbE&zwXICdm>~re29kQ`cYowF3O=l0e9{LPtkYA%K)!so zeR5^znae5vTBPeY1Ko1L;jqf*WZvCU`+!adI#+Gx!o={yU1zL0G^T4@j@mKj)}g0Y k#PpVLE3n+!dV1wwrVWZulvnb6P-OrDPgg&ebxsLQ06(h&&j0`b diff --git a/tests_zemu/snapshots/show-address/4.png b/tests_zemu/snapshots/show-address/4.png deleted file mode 100644 index 9794a2c11ed34beb917ada3db1306974c3a22cff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^4M42G!3HF6DHW&!sc)Vxjv*C{Zx1>aNeA*cA7l@! z_|II-_L_TSDZs+%0Bg1qiQCikcWuuYE{T~Ugf(c=3l59UW zw2K`5b=rAW(%)wfm#MiDR_6EO#yH&47d;b;8Gn3K($vn7n=vu;d?G|f5D(>C?Y zs>BmLY$+KLC;y0Wr(bqByxf#WGR5sMQ0oZ=V~`m?ma?VPEn-hs{+!9Xx~;b@mUp+* zgq^e4Q7_Lc^K2raCq4ZMWsGZCL$qZR_F_JTq@|p182#V#AqeZud+H-tCho zEKD>}`0UT^K2g$WyYR$?j5BS)GXK4pc}>xjk%`PQ z#+k9a(ndgeGoUX(wx^k_NeSaUals(P4Co#0C<`ZMBa@odZHmojG91!Wn|X{DKb+g9 z2=?oZj2l-!yb|lXRKPLw;)aVGvKBnNEEUEp4fL{E%7mM$pI6E4QJQ(%Q0$z?GufH? zlOs#nTidmhGeAn;}2QV6-VV{#4HT|Xar$Yt3W8$bF)8!d+&MgeV+GupXc*_?`nCe z6(tc#DwPTq7v)!g!-=&MC|K#vZKj?L3!j0)@gu%rnTuZdQi+NHP zN?AHugp*}{O#IODE*Dc0ZH%Y2W(U( z^2l|&TvDf+Da6TPyT##5CaDy!X*AIdOFJl?1t&Km=}k7%!y|D76K6S@O(xsJV|wV? z^mf1|z2W4DvcIkY;$4ypPM2JiZd`GMIJxe{iWMS)7S%gxhtuehp<}|`2*>n71Up$0 z^b^9=74rmq#fR+P2>2TrD4dr=O}oWzaQ2!fAWyt7>LTGf>b-+@ugL(#?FnmV z(kS1}u*Rc7VX8V<0JvD==whnE4GJE%OEosS^$e0ypai(KzLRuRPwAT1<}B3S;=cd7 z-|{;HZA3?$z6<;oMAh6~G@yMm*WI9jaV0fUF3nEqF3L7`^0N6uIGbTBi4FgdgvJz= z0M24$3mV1&Lnq&zC?V9;B^ScdET=&VXeATT!xu!W-Hmw;g;9Y5PnjrTid71RSl|tk zf<*vb_20AHC9{5$Z^4n2+mYx6j)|Q@9t{ZGhOB^b6x0q{a8^PWhl#!6ri!4UIScz( jmrzCQG{|T@pqp>^WsKCuH($Zv|56nfl;#KaAMf}JS6+h% literal 873 zcmYL|e@GKy7{|9}SJ~c>D07$8Rcg^MxP!#&^U^Stk=qJkV0 zjYmr)5~R=7Z3kZm4>1>m_wY(fqC_G~*6TDoY|@Db&kio!Ezv!DQ$E#uy(m0>{NvI> zzSt3?j45JD4Zi{@t~M#(IB3zaO57Q4n&MJw22)%%Bl7LvE+aFiKU-4o#xIyN-2X9u zc$T1;SMbyhlDt)~IADajlWFudC zMjytEP1sgzg+bXqb*M7!c#`;OR)==YdeTf0)+@B@b+q)osjE7@YS_`4KVm(_X;@yd9gMQCMYv5cgMu0Wj}o$&{55=x3ts=)HddoN+7BD#hySbc#yzgf(@XjZf4QfHY{ zfji5LYS!tN@?dXWf4rX6Kp51x>BYQ9${WUSL*Y%Z;R&up%b};(@8t#=d19*|mh=z! z}6g#u&#q#L^`YGt_$9#ZH3>3Vi3j7G~p+rJ2*S z=2VZklf-*y7Z1)bZ_N*{lwTF;&UzU6MjLw%~qL zX|gR!J0S9~``4oRq>s=FFY4rEYrukP`>z5j8bojrcw7V?EDOwWAkR%huc?u;4(fbD zS0MR6P_1B>BdtJKJsGbEJQ4;-EAfhC6x2 z2q(Dq=7(z$NY3yr4wChuVwA%eMfnPF&y%SwrjqGpMl#fuBgDt?O@XYRk$aK@YWgb(it zn@oqaEQe>Of%xKt7L}?C3w4)YcVOnd%`7P;$9vCY&&$Tm+4T-=k|`NCmMOWB&Ad_>KSB;) z<=6*tfl|} delta 333 zcmZ3>{DNtMO1-|Pi(^OylYja$RYBb;1*egOef z88$1a-`6;Ba=yr%Ideqr0L}0+3wy%Cs;*wn1$6UdVUe20EUe{zVcRa=D-Js7R_*V| z+8lQ4SeM9yC*gkYMBMf)Wl&dVT`iOl_MCT?`*4M!hV%rbKNP?@l>#3a#Z7p&uL9V?78ENl`12 z^Mf^#NY+CFtB9gfix8Ath!Q^%-GBCyt+~UGsHN4jVbioWm|#;#N$|~4WAbKZXWrX+ zzxR8;IZ?cIGn$9z*=#oCEpUGcYX}B2hlct2^4ct$je6>J=YO@|{`b9j{qq8w``#~~ z|2Z@B^3WeI^Ugk7abFNx#)P)XqN2=viv4y#bXgC1AM4VYNIc{~t!B&_ZRn+?LpRVGa8wxkDNV zPgNMPkXe*6j(_{-*tie~CJp>*I_?TPka4?gf6gUZn%^UOEGJf<$%1tqt5bUtIq6u< zb7(a^c1;fo*7lm|LPcp`$1!y~kTG4I*vGzTCMd5|3V};vIPYVv?xWM~GdvUNqoo!( zvAa)H4;1L}xhvKb{dKa8i#hq2pnK2~zTu~Y3*D-`dG#=j>*Ip{NT3i`{saZUM%6T%|2^dNZQuyT^d@@IW^ErR6>VviUE zZmfPdn=IBh=`nJ%54kAFTE$gyqq`ERP}XoM#a8f4E)Pk3XeBZ_ABW6GA+u!ms{|;` z1&e~4aZ&6isMRrh6d4Jbg?i@1siw`qgUoUc_7?PFAG=N8g4NPf8eVhL;k+PN*g6uIl;uV}isH3ImLodJtSf=>1&kYTm}(yzs{>S0&F%F(eDAq4*sdJsroRVL z-}Eo;DxuiM%XY0X$#1f7fC+UHsw?=;tjLIy9Jusma|=;V8m1w=hShGn)<#4Jipfp~ z4=7N1Z>vjhZi0<0B&Psq#Ty8Akl*|tf@Y($wO+f{D~6MolB#33-AOb1H85HBEF`QO@`Vc f&<-EaJGAWQoy=foe8+$A)NNkRR`}|ae3#TowW+0bjhgjsaExh{wo-i7$N1>2 zRd8oh#f~qMT}f*<)oj=1bi!Giz{$p>(#j=5BsgA%$Gq^kRDC=B@Z|)w71W`hz?W{zTwG!<~$79)Ohe9JOw8a|56H00LWY=~G z9oTG6vSTH&n&EHIHlfEDIYX1Vd>2={GW|JG0?mPeJXX6DN{dyP`Lqfvt1FtNg3jUN ztaMwjV^$Rfu6B-k#dIP)4m{6Z=<+lC@3f?-X_&B>kOskq!2F={7Cl*Wt-em+I_e>iW)X(;`*775AWwyX`%+@Z@>^}S@CgRavC#qD?% zNU$E=04A&oQiT5cC*jpj*nmCBn!-bAQA-adDH|DcOn9y*!I|0O0+-)Y ziXg`aaX*7H54oUlzN?hB>PtiWdww_|jVeM%aJhauNYFdHrN@TKmk?4I3`YY>B4`#< z9y$5KKs=y~?gFmg`tSZhr=vvSVt`P4j~m2>jvBy`OF8sp9?WAw+^T{*V@tEf>Ip;^ zJk9HwT9$z}eUOnHz7KlRYa0wTOQ)QX{SFvrh7{Z;6DxB)bf)^-O7~#(ybqsx$C%u@ WFNcp+9V~~R)Z#5F^RzG8bmTiFX_#{W diff --git a/tests_zemu/snapshots/sign-basic/3.png b/tests_zemu/snapshots/sign-basic/3.png index dbd558cd984781eb1bdbf97e41be068e3923950f..92247b5947c5face3711b26d0857adb45c583fb1 100644 GIT binary patch delta 457 zcmeBTe#|^UrGAyCi(^Oy zoQZ<5iNfc%QWGlkryudGKdMzWMinQm;9xh{_*Ldba0|snUWeMZJfQJv2Fj=52wn~fL^oDswlNyzaSB4w_nP>HH<(C$e4HY+~#bD zvm%N>=OBGtYQ38?DcJ ze)Hr7gA+BKJiO&b`<<3P4CT-`y~S+W%3Ph`+Y!sQZS=`ao_Xt-(bnG7Ea}r%kR{%- YulutxRgDgXcg delta 367 zcmaFN+{HXWr9RNp#WAFU@$Es!yt@Vr&IjEO?)l%iGhuGOOUL9b9@Dp(DBt_4!YMUj z=i0XXlxf!+&V;|}oa|@o`RJO|gqw928qTCMom#1D^;MBD;hgp7ijjr4i9t2r|p<@4P;QNMz5rhCSY2{-SVDtvzU zpqYpF#GQF(zBRL@*h$x@IUoM!ze4nW^o!YkM;I=IwbV@2?!Nc`Z z^WG$c@}Bq;eE71gjpJbzW7C)uf1;R;Okzx8PTaY9@UE$XF%Ur8GfqR9wnG@58|y i8n-vG-M&N+{bOi)+vIm<&(&QFK;Y@>=d#Wzp$PztPO;$t diff --git a/tests_zemu/snapshots/sign-basic/8.png b/tests_zemu/snapshots/sign-basic/8.png index dae18a50f0dcadb5df981183c70f20bbf47bfd71..4aa28b6bfdc9668cf49edfe790ea290941e99f83 100644 GIT binary patch delta 418 zcmZo+-OW5fxt_7f)5S5Qg7NLai>stP8JrI;KKAQB|Fvc#lf)f;Z;$FUR@{kIt$Xb# zbUW$_GrMfngd^Md7@uAc1GCx=^4o6Eb#=Ho&Gg1JGc>eg5}VYv{pkgwyvy6(zTfeY zS4!@L4=;bpGPabA87a%!CZD-taI$`ml-kUd5Btt6myU5f+}y@)q<_-pYQgfvNi#tb ziCG|(o@_uR^D`?}JzRcp>IsF<)7qv>y*r`cd^ni*|H_9~91h#7J0G6QmQuH?P?cBS z|5@^h3k^KHC;nu9cq!#)bYhNF+@wm+XPPsYr+|!{G&99+8c^ECcn8 literal 644 zcmeAS@N?(olHy`uVBq!ia0vp^4M42G!3HF6DHW(PFfe(0x;TbZFupw)m?s@6;(YLM z+m8RNpPQ9qc;xO(6tM_Xk$$;O=>O}fDt^Zo#T71H9q0L|M26{9XmrU{ZO=JOFL%CeA$#lC%L`_H?b`~iw)9?Jm}|4Tv2AH%+eL@NFB{pU_FZlbpH#WB zP4V+%Q=XZw&vwUFENxTVZ1U#B1%ni~!xJQVozpTSq}q6RK>`^!CPqq4SeQ6blGoa3 zaiV+L@`nrC6rB%Gh?EkWxs*{7NT%oR2|hf*G0jB5SSrtiXQu2-SGJi;6W!S)fyVhU z8}Xl1*nC2v`Ai1LP@@wdPH{NM9&6qcHC~5fdF5j(rt$Ea=opzxO>1ihV*SaHQu8i> zTocP1f2|;#*{I&9jV)ywTZ-MT53(uumL;C(Y4e}FFflU%sHR`lnc2uh;q&U=@`*on zL6*BdyM038v!+qJTJiKV!6_LI&*t^+cTAgD>5*n~!QpUliW@U;`N}X7VBk6cLpo&| zP$qoW2R_~tf2N%Q3V{Or=EQ}Jpny!v1c!fQN*PeuQpTBc*;3wR0d+xCRZitzuVyUO lcILKejVH5__u>7|?5|%G_GmoX+y+ct44$rjF6*2UngDC22r2*o diff --git a/tests_zemu/tests/test.js b/tests_zemu/tests/test.js index 48e2eb96..89c6d5f8 100644 --- a/tests_zemu/tests/test.js +++ b/tests_zemu/tests/test.js @@ -1,3 +1,19 @@ +/** ****************************************************************************** + * (c) 2020 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************* */ + import jest, {expect} from "jest"; import Zemu from "@zondax/zemu"; import FilecoinApp from "@zondax/ledger-filecoin"; @@ -119,8 +135,6 @@ describe('Basic checks', function () { await sim.snapshot(`${snapshotPrefixTmp}${snapshotCount++}.png`); await sim.clickRight(`${snapshotPrefixTmp}${snapshotCount++}.png`); await sim.clickRight(`${snapshotPrefixTmp}${snapshotCount++}.png`); - await sim.clickRight(`${snapshotPrefixTmp}${snapshotCount++}.png`); - await sim.clickRight(`${snapshotPrefixTmp}${snapshotCount++}.png`); await sim.clickBoth(`${snapshotPrefixTmp}${snapshotCount++}.png`); const resp = await respRequest; @@ -169,7 +183,7 @@ describe('Basic checks', function () { // Reference window await sim.snapshot(`${snapshotPrefixTmp}${snapshotCount++}.png`); - for (let i = 0; i < 9; i++) { + for (let i = 0; i < 8; i++) { await sim.clickRight(Resolve(`${snapshotPrefixTmp}${snapshotCount++}.png`)); } await sim.clickBoth(); diff --git a/tests_zemu/tools/debug.mjs b/tests_zemu/tools/debug.mjs index 1dbea15b..f3ffe363 100644 --- a/tests_zemu/tools/debug.mjs +++ b/tests_zemu/tools/debug.mjs @@ -35,10 +35,17 @@ async function debugScenario(sim, app) { ); const signatureRequest = await app.sign(path, txBlob); - const signatureResponse = await signatureRequest; + const signatureResponse = signatureRequest; console.log(signatureResponse) } +async function debugScenario2(sim, app) { + await Zemu.default.sleep(20000); + + // const response = await app.getVersion(); + // console.log(response) +} + async function main() { await beforeStart(); @@ -55,7 +62,7 @@ async function main() { //////////// /// TIP you can use zemu commands here to take the app to the point where you trigger a breakpoint - await debugScenario(sim, app); + await debugScenario2(sim, app); /// TIP