diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml new file mode 100644 index 00000000..3d403ec7 --- /dev/null +++ b/.github/workflows/build_and_functional_tests.yml @@ -0,0 +1,35 @@ +name: Build and run functional tests using ragger through reusable workflow + +# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation. +# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the +# resulting binaries. +# It then calls another reusable workflow to run the Ragger tests on the compiled application binary. +# +# The build part of this workflow is mandatory, this ensures that the app will be deployable in the Ledger App Store. +# While the test part of this workflow is optional, having functional testing on your application is mandatory and this workflow and +# tooling environment is meant to be easy to use and adapt after forking your application + +on: + workflow_dispatch: + inputs: + golden_run: + type: choice + required: true + default: 'Raise an error (default)' + description: CI behavior if the test snapshots are different than expected. + options: + - 'Raise an error (default)' + - 'Open a PR' + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + build_application: + name: Build application using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "app_waves_binaries" diff --git a/.gitignore b/.gitignore index 199a053c..b3984162 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,11 @@ dkms.conf # Project-level stuff debug/ .DS_Store -*.pyc \ No newline at end of file +*.pyc + +# Glyphs gen files +src/glyphs.c +src/glyphs.h + +# Build dir +bin diff --git a/Makefile b/Makefile index 211cebb8..d3bc6389 100755 --- a/Makefile +++ b/Makefile @@ -23,20 +23,18 @@ include $(BOLOS_SDK)/Makefile.defines # Main app configuration APPVERSION_M=1 -APPVERSION_N=1 -APPVERSION_P=0 +APPVERSION_N=2 +APPVERSION_P=1 APPNAME = "Waves" APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) ifeq ($(TARGET_NAME),TARGET_BLUE) ICONNAME=blue_app_waves.gif +else ifeq ($(TARGET_NAME),TARGET_NANOS) +ICONNAME=nanos_app_waves.gif else - ifeq ($(TARGET_NAME),TARGET_NANOX) -ICONNAME=nanox_app_waves.gif - else -ICONNAME = nanos_app_waves.gif - endif +ICONNAME = nanox_app_waves.gif endif APP_LOAD_PARAMS = --appFlags 0x240 --path "44'/5741564'" --curve secp256k1 --curve ed25519 $(COMMON_LOAD_PARAMS) @@ -48,16 +46,11 @@ APP_SOURCE_PATH += src SDK_SOURCE_PATH += lib_stusb #qrcode #use the SDK U2F+HIDGEN USB profile SDK_SOURCE_PATH += lib_u2f lib_stusb_impl +SDK_SOURCE_PATH += lib_ux +DEFINES += HAVE_UX_FLOW ifeq ($(TARGET_NAME),TARGET_NANOX) SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -SDK_SOURCE_PATH += lib_ux -DEFINES += HAVE_UX_FLOW -endif - -ifeq ($(TARGET_NAME),TARGET_NANOS) -SDK_SOURCE_PATH += lib_ux -DEFINES += HAVE_UX_FLOW endif DEFINES += APPVERSION=\"$(APPVERSION)\" @@ -83,28 +76,30 @@ DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" ifeq ($(TARGET_NAME),TARGET_NANOX) -DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE +endif +ifeq ($(TARGET_NAME),TARGET_NANOS) +DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 +else +DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_GLO096 DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -else -DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 endif # Enabling debug PRINTF DEBUG = 0 ifneq ($(DEBUG),0) - ifeq ($(TARGET_NAME),TARGET_NANOX) - DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf - else + ifeq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_PRINTF PRINTF=screen_printf + else + DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf endif else DEFINES += PRINTF\(...\)= diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..7aa821e7 --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,4 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanox", "nanos+"] diff --git a/src/crypto/stream_eddsa_sign.c b/src/crypto/stream_eddsa_sign.c index 48a3c1d7..262cf865 100644 --- a/src/crypto/stream_eddsa_sign.c +++ b/src/crypto/stream_eddsa_sign.c @@ -20,69 +20,52 @@ #include "stream_eddsa_sign.h" -static uint8_t const C_cx_Ed25519_a[] = { - 0x7f, 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, 0xec}; +static uint8_t const C_cx_Ed25519_a[] = {0x7f, 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, 0xec}; static uint8_t const C_cx_Ed25519_d[] = { // d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3 - 0x52, 0x03, 0x6c, 0xee, 0x2b, 0x6f, 0xfe, 0x73, 0x8c, 0xc7, 0x40, - 0x79, 0x77, 0x79, 0xe8, 0x98, 0x00, 0x70, 0x0a, 0x4d, 0x41, 0x41, - 0xd8, 0xab, 0x75, 0xeb, 0x4d, 0xca, 0x13, 0x59, 0x78, 0xa3}; + 0x52, 0x03, 0x6c, 0xee, 0x2b, 0x6f, 0xfe, 0x73, 0x8c, 0xc7, 0x40, 0x79, 0x77, 0x79, 0xe8, 0x98, + 0x00, 0x70, 0x0a, 0x4d, 0x41, 0x41, 0xd8, 0xab, 0x75, 0xeb, 0x4d, 0xca, 0x13, 0x59, 0x78, 0xa3}; static uint8_t const C_cx_Ed25519_q[] = { // q: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed - 0x7f, 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, 0xed}; + 0x7f, 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, 0xed}; static uint8_t const C_cx_Ed25519_Hq[] = { // Hq: 0x00000000000000000000000000000000000000000000000000000000000005a4 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xa4}; -static uint8_t const C_cx_Ed25519_Bx[] = { - 0x21, 0x69, 0x36, 0xd3, 0xcd, 0x6e, 0x53, 0xfe, 0xc0, 0xa4, 0xe2, - 0x31, 0xfd, 0xd6, 0xdc, 0x5c, 0x69, 0x2c, 0xc7, 0x60, 0x95, 0x25, - 0xa7, 0xb2, 0xc9, 0x56, 0x2d, 0x60, 0x8f, 0x25, 0xd5, 0x1a}; -static uint8_t const C_cx_Ed25519_By[] = { - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x58}; -static uint8_t const C_cx_Ed25519_l[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xa4}; +static uint8_t const C_cx_Ed25519_Bx[] = {0x21, 0x69, 0x36, 0xd3, 0xcd, 0x6e, 0x53, 0xfe, 0xc0, 0xa4, 0xe2, + 0x31, 0xfd, 0xd6, 0xdc, 0x5c, 0x69, 0x2c, 0xc7, 0x60, 0x95, 0x25, + 0xa7, 0xb2, 0xc9, 0x56, 0x2d, 0x60, 0x8f, 0x25, 0xd5, 0x1a}; +static uint8_t const C_cx_Ed25519_By[] = {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x58}; +static uint8_t const C_cx_Ed25519_l[] = { // l: 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, - 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED}; + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED}; static uint8_t const C_cx_Ed25519_Hl[] = { // Hl: 0x0399411b7c309a3dceec73d217f5be65d00e1ba768859347a40611e3449c0f01 - 0x03, 0x99, 0x41, 0x1b, 0x7c, 0x30, 0x9a, 0x3d, 0xce, 0xec, 0x73, - 0xd2, 0x17, 0xf5, 0xbe, 0x65, 0xd0, 0x0e, 0x1b, 0xa7, 0x68, 0x85, - 0x93, 0x47, 0xa4, 0x06, 0x11, 0xe3, 0x44, 0x9c, 0x0f, 0x01}; -static uint8_t const C_cx_Ed25519_I[] = { - // I: 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0 - 0x2b, 0x83, 0x24, 0x80, 0x4f, 0xc1, 0xdf, 0x0b, 0x2b, 0x4d, 0x00, - 0x99, 0x3d, 0xfb, 0xd7, 0xa7, 0x2f, 0x43, 0x18, 0x06, 0xad, 0x2f, - 0xe4, 0x78, 0xc4, 0xee, 0x1b, 0x27, 0x4a, 0x0e, 0xa0, 0xb0}; -static uint8_t const C_cx_Ed25519_Qplus3div8[] = { - // q3: 0x0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe - 0x0f, 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, 0xfe}; + 0x03, 0x99, 0x41, 0x1b, 0x7c, 0x30, 0x9a, 0x3d, 0xce, 0xec, 0x73, 0xd2, 0x17, 0xf5, 0xbe, 0x65, + 0xd0, 0x0e, 0x1b, 0xa7, 0x68, 0x85, 0x93, 0x47, 0xa4, 0x06, 0x11, 0xe3, 0x44, 0x9c, 0x0f, 0x01}; + #define C_cx_Ed25519_h 8 -cx_curve_twisted_edward_t const C_cx_Ed25519 = { - CX_CURVE_Ed25519, - 256, - 32, - (uint8_t *)C_cx_Ed25519_q, - (uint8_t *)C_cx_Ed25519_Hq, - (uint8_t *)C_cx_Ed25519_Bx, - (uint8_t *)C_cx_Ed25519_By, - (uint8_t *)C_cx_Ed25519_l, - (uint8_t *)C_cx_Ed25519_Hl, - C_cx_Ed25519_h, - (uint8_t *)C_cx_Ed25519_a, - (uint8_t *)C_cx_Ed25519_d, - (uint8_t *)C_cx_Ed25519_I, - (uint8_t *)C_cx_Ed25519_Qplus3div8, + +cx_curve_twisted_edwards_t const C_cx_Ed25519 = { + .curve = CX_CURVE_Ed25519, + .bit_size = 256, + .length = 32, + + .a = C_cx_Ed25519_a, + .b = C_cx_Ed25519_d, + .p = C_cx_Ed25519_q, + .Gx = C_cx_Ed25519_Bx, + .Gy = C_cx_Ed25519_By, + .n = C_cx_Ed25519_l, + .h = C_cx_Ed25519_h, + .Hp = C_cx_Ed25519_Hq, + .Hn = C_cx_Ed25519_Hl, }; /* ----------------------------------------------------------------------- */ @@ -120,12 +103,12 @@ static void cx_compress(unsigned char *P, int size) { /* ----------------------------------------------------------------------- */ /* */ /* ----------------------------------------------------------------------- */ -static void cx_eddsa_get_public_key_internal( +static void l_cx_eddsa_get_public_key_internal( const cx_ecfp_private_key_t *pv_key, cx_md_t hashID, cx_ecfp_public_key_t *pu_key, unsigned char *a, unsigned int a_len, unsigned char *h, unsigned int h_len, unsigned char *scal /*tmp*/) { - cx_curve_twisted_edward_t *domain = - (cx_curve_twisted_edward_t *)&C_cx_Ed25519; + cx_curve_twisted_edwards_t *domain = + (cx_curve_twisted_edwards_t *)&C_cx_Ed25519; cx_sha512_t hash_ctx; unsigned int size; @@ -179,14 +162,14 @@ static void cx_eddsa_get_public_key_internal( void stream_eddsa_sign_step1(streamEddsaContext_t *eddsa_context, const cx_ecfp_private_key_t *pv_key) { os_memset((unsigned char *)eddsa_context, 0, sizeof(streamEddsaContext_t)); - cx_curve_twisted_edward_t *domain = - (cx_curve_twisted_edward_t *)&C_cx_Ed25519; + cx_curve_twisted_edwards_t *domain = + (cx_curve_twisted_edwards_t *)&C_cx_Ed25519; unsigned int size = domain->length; unsigned char scal[64]; // retrieve public key,private scalar a, and private prefix h (stored in r) - cx_eddsa_get_public_key_internal( + l_cx_eddsa_get_public_key_internal( pv_key, CX_SHA512, (cx_ecfp_public_key_t *)&eddsa_context->u.internal_pu_key, eddsa_context->a, sizeof(eddsa_context->a), eddsa_context->r, @@ -223,8 +206,8 @@ void stream_eddsa_sign_step2(streamEddsaContext_t *eddsa_context, void stream_eddsa_sign_step3(streamEddsaContext_t *eddsa_context) { unsigned char scal[64]; - cx_curve_twisted_edward_t *domain = - (cx_curve_twisted_edward_t *)&C_cx_Ed25519; + cx_curve_twisted_edwards_t *domain = + (cx_curve_twisted_edwards_t *)&C_cx_Ed25519; unsigned int size = domain->length; unsigned int hsize = 2 * size; @@ -266,8 +249,8 @@ void stream_eddsa_sign_step4(streamEddsaContext_t *eddsa_context, int stream_eddsa_sign_step5(streamEddsaContext_t *eddsa_context, unsigned char *sig) { unsigned char scal[64]; - cx_curve_twisted_edward_t *domain = - (cx_curve_twisted_edward_t *)&C_cx_Ed25519; + cx_curve_twisted_edwards_t *domain = + (cx_curve_twisted_edwards_t *)&C_cx_Ed25519; unsigned int size = domain->length; unsigned int hsize = 2 * size; @@ -293,4 +276,4 @@ int stream_eddsa_sign_step5(streamEddsaContext_t *eddsa_context, os_memset((unsigned char *)eddsa_context, 0, sizeof(streamEddsaContext_t)); return 2 * size; -} \ No newline at end of file +} diff --git a/src/main.c b/src/main.c index 55bb5ca4..9f18972c 100644 --- a/src/main.c +++ b/src/main.c @@ -41,7 +41,7 @@ internal_storage_t const N_storage_real; // SPI Buffer for io_event unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -#if !defined(TARGET_NANOS) && !defined(TARGET_BLUE) && !defined(TARGET_NANOX) +#if !defined(TARGET_NANOS) && !defined(TARGET_BLUE) && !defined(TARGET_NANOX) && !defined(TARGET_NANOS2) #error This application only supports the Ledger Nano S, Nano X and the Ledger Blue #endif @@ -217,7 +217,7 @@ void handle_apdu(volatile unsigned int *flags, volatile unsigned int *tx, BEGIN_TRY { TRY { - if (os_global_pin_is_validated() == 0) { + if (os_global_pin_is_validated() != BOLOS_UX_OK) { THROW(SW_DEVICE_IS_LOCKED); } @@ -479,10 +479,10 @@ __attribute__((section(".boot"))) int main(void) { io_seproxyhal_init(); -#ifdef TARGET_NANOX +#ifdef HAVE_BLE // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX +#endif // HAVE_BLE init_context(); @@ -496,13 +496,13 @@ __attribute__((section(".boot"))) int main(void) { USB_power(0); USB_power(1); - ui_idle(); - #ifdef HAVE_BLE BLE_power(0, NULL); BLE_power(1, "Nano X"); #endif // HAVE_BLE + ui_idle(); + // set menu bar colour for blue #if defined(TARGET_BLUE) UX_SET_STATUS_BAR_COLOR(COLOR_BG_1, COLOR_APP); diff --git a/src/main.h b/src/main.h index 813ca30f..97349564 100644 --- a/src/main.h +++ b/src/main.h @@ -22,6 +22,7 @@ #define __MAIN_H__ #include "os.h" #include "cx.h" +#include "ux.h" #include "stream_eddsa_sign.h" #include diff --git a/src/ui/blue/ui_menus_blue_prepro.h b/src/ui/blue/ui_menus_blue_prepro.h index befe4ea5..3c717690 100644 --- a/src/ui/blue/ui_menus_blue_prepro.h +++ b/src/ui/blue/ui_menus_blue_prepro.h @@ -22,6 +22,7 @@ #define __UI_MENUS_BLUE_PREPRO_H__ #include "os_io_seproxyhal.h" +#include "ux.h" const bagl_element_t *ui_address_blue_prepro(const bagl_element_t *element); const bagl_element_t *ui_idle_blue_prepro(const bagl_element_t *element); diff --git a/src/ui/ui.c b/src/ui/ui.c index bb2046b6..2a2642eb 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -20,7 +20,7 @@ #include "ui.h" #include -#include "../glyphs.h" +#include "glyphs.h" #include "../main.h" #include "../crypto/waves.h" #include "transactions/transfer.h" diff --git a/src/ui/ui_logic.h b/src/ui/ui_logic.h index 2132344e..ab33b8d9 100644 --- a/src/ui/ui_logic.h +++ b/src/ui/ui_logic.h @@ -22,6 +22,7 @@ #define __UI_LOGIC_H__ #include "os_io_seproxyhal.h" +#include "ux.h" unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e); unsigned int io_seproxyhal_cancel(const bagl_element_t *e);