From 6845b9f5eb263497c9c92abb1514b052e0e16ff2 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:47:20 +0100 Subject: [PATCH 1/9] update zxlib and sdks --- cmake/cmake-modules | 2 +- deps/ledger-zxlib | 2 +- deps/nanos-secure-sdk | 2 +- deps/nanosplus-secure-sdk | 2 +- deps/nanox-secure-sdk | 2 +- deps/stax-secure-sdk | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/cmake-modules b/cmake/cmake-modules index 877bab9d..fb7d2a3f 160000 --- a/cmake/cmake-modules +++ b/cmake/cmake-modules @@ -1 +1 @@ -Subproject commit 877bab9dd1b17468c5d939cacaa2ad7ba99d1977 +Subproject commit fb7d2a3f9c060b6ce42aa6f8c796b4ba5b0b9dd3 diff --git a/deps/ledger-zxlib b/deps/ledger-zxlib index 52dfdeae..42e82e91 160000 --- a/deps/ledger-zxlib +++ b/deps/ledger-zxlib @@ -1 +1 @@ -Subproject commit 52dfdeae81bb0b50cf3332f4690ed5c978f15f27 +Subproject commit 42e82e9115de2727696e8508c47f65eae87acbfe diff --git a/deps/nanos-secure-sdk b/deps/nanos-secure-sdk index 30189cfd..0532bf20 160000 --- a/deps/nanos-secure-sdk +++ b/deps/nanos-secure-sdk @@ -1 +1 @@ -Subproject commit 30189cfd070040e5c144d4dab103d549302dcfff +Subproject commit 0532bf20fbbb11dd08dada62060f8337097b6078 diff --git a/deps/nanosplus-secure-sdk b/deps/nanosplus-secure-sdk index 45ccba9c..6465d692 160000 --- a/deps/nanosplus-secure-sdk +++ b/deps/nanosplus-secure-sdk @@ -1 +1 @@ -Subproject commit 45ccba9cd72eaae0d1305b9d519d3702fb4e138b +Subproject commit 6465d6927d3df40f46b182d00713844ec534fede diff --git a/deps/nanox-secure-sdk b/deps/nanox-secure-sdk index 2d6e2e0d..54c134d5 160000 --- a/deps/nanox-secure-sdk +++ b/deps/nanox-secure-sdk @@ -1 +1 @@ -Subproject commit 2d6e2e0d2eda2a09bc79bdf57b6b2e3d708eec1d +Subproject commit 54c134d533126c0ac8e500e75af0ef26cc2a7a14 diff --git a/deps/stax-secure-sdk b/deps/stax-secure-sdk index cabc1590..dbca919e 160000 --- a/deps/stax-secure-sdk +++ b/deps/stax-secure-sdk @@ -1 +1 @@ -Subproject commit cabc159007c6d257636ce8fb5b779b7b69f78c91 +Subproject commit dbca919e21c5b48166ea368bb2e56f7f9dddfe91 From 90137a9dd35b579172f5984e7aa2c95bc5fa0ceb Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:51:28 +0100 Subject: [PATCH 2/9] move to new ledger guidelines ci --- .github/workflows/guidelines_enforcer.yml | 2 -- ledger_app.toml | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 ledger_app.toml diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml index e2dae281..fdaf9f27 100644 --- a/.github/workflows/guidelines_enforcer.yml +++ b/.github/workflows/guidelines_enforcer.yml @@ -21,5 +21,3 @@ jobs: guidelines_enforcer: name: Call Ledger guidelines_enforcer uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 - with: - relative_app_directory: app diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..3e4cbb1f --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,7 @@ +[app] +build_directory = "./app/" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"] + +[tests] +unit_directory = "./tests/" From ced7cc904a1d8e384a49dda82c9f016efccd6c03 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 17:00:07 +0100 Subject: [PATCH 3/9] remove custom linker scripts and stackSize def --- app/Makefile | 2 - app/script_s2.ld | 170 --------------------------------------------- app/script_x.ld | 175 ----------------------------------------------- 3 files changed, 347 deletions(-) delete mode 100644 app/script_s2.ld delete mode 100644 app/script_x.ld diff --git a/app/Makefile b/app/Makefile index 8911618e..f6a16748 100755 --- a/app/Makefile +++ b/app/Makefile @@ -80,8 +80,6 @@ endif APP_LOAD_PARAMS = --curve ed25519 $(COMMON_LOAD_PARAMS) --path $(APPPATH) -NANOS_STACK_SIZE := 3128 - include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.devices $(info TARGET_NAME = [$(TARGET_NAME)]) diff --git a/app/script_s2.ld b/app/script_s2.ld deleted file mode 100644 index db3150b3..00000000 --- a/app/script_s2.ld +++ /dev/null @@ -1,170 +0,0 @@ -/******************************************************************************* -* Ledger Blue - Secure firmware -* (c) 2016, 2017, 2018, 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. -********************************************************************************/ - -/** - * Global chip memory layout and constants - * - */ - -MEMORY -{ - DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M - - FLASH (rx) : ORIGIN = 0xc0de0000, LENGTH = 400K - DATA (r) : ORIGIN = 0xc0de0000, LENGTH = 400K - SRAM (rwx) : ORIGIN = 0xda7a0000, LENGTH = 30K -} - -PAGE_SIZE = 512; -STACK_SIZE = 8192; -END_STACK = ORIGIN(SRAM) + LENGTH(SRAM); - -ENTRY(main); - -SECTIONS -{ - /****************************************************************/ - /* This section locates the code in FLASH */ - /****************************************************************/ - - /** put text in Flash memory, VMA will be equal to LMA */ - .text : - { - /* provide start code symbol, shall be zero */ - _text = .; - _nvram_start = .; - - /* ensure main is always @ 0xC0D00000 */ - *(.boot*) - - /* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */ - *(.text*) - *(.rodata) - *(.rodata.[^N]*) /*.data.rel.ro* not here to detect invalid PIC usage */ - *(.rodata.N[^_]*) - - . = ALIGN(4); - - /* all code placed */ - _etext = .; - - . = ALIGN(PAGE_SIZE); - - _nvram_data = .; - - /* NVM data (ex-filesystem) */ - *(.bss.N_* .rodata.N_*) - - . = ALIGN(PAGE_SIZE); - _envram_data = .; - - _install_parameters = .; - _nvram_end = .; - } > FLASH = 0x00 - - .data (NOLOAD): - { - . = ALIGN(4); - - /** - * Place RAM initialized variables - */ - _data = .; - - *(vtable) - *(.data*) - - _edata = .; - - } > DISCARD /*> SRAM AT>FLASH = 0x00 */ - - .bss : - { - /** - * Place RAM uninitialized variables - */ - _bss = .; - *(.bss*) - _ebss = .; - - - /** - * Reserve stack size - */ - . = ALIGN(4); - app_stack_canary = .; - PROVIDE(app_stack_canary = .); - . += 4; - _stack_validation = .; - . = _stack_validation + STACK_SIZE; - _stack = ABSOLUTE(END_STACK) - STACK_SIZE; - PROVIDE( _stack = ABSOLUTE(END_STACK) - STACK_SIZE); - _estack = ABSOLUTE(END_STACK); - PROVIDE( _estack = ABSOLUTE(END_STACK) ); - - } > SRAM = 0x00 - - /****************************************************************/ - /* DEBUG */ - /****************************************************************/ - - /* remove the debugging information from the standard libraries */ - DEBUG (NOLOAD) : - { - libc.a ( * ) - libm.a ( * ) - libgcc.a ( * ) - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > DISCARD - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} - -PROVIDE(_nvram = ABSOLUTE(_nvram_start)); -PROVIDE(_envram = ABSOLUTE(_nvram_end)); \ No newline at end of file diff --git a/app/script_x.ld b/app/script_x.ld deleted file mode 100644 index 0d174c46..00000000 --- a/app/script_x.ld +++ /dev/null @@ -1,175 +0,0 @@ -/******************************************************************************* -* Ledger Blue - Secure firmware -* (c) 2016, 2017, 2018, 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. -********************************************************************************/ - -/** - * Global chip memory layout and constants - * - */ - -MEMORY -{ - DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M - - FLASH (rx) : ORIGIN = 0xc0de0000, LENGTH = 400K - DATA (r) : ORIGIN = 0xc0de0000, LENGTH = 400K - SRAM (rwx) : ORIGIN = 0xda7a0000, LENGTH = 30K -} - -PAGE_SIZE = 256; -STACK_SIZE = 8192; -END_STACK = ORIGIN(SRAM) + LENGTH(SRAM); - -ENTRY(main) - -SECTIONS -{ - - /****************************************************************/ - /* This section locates the code in FLASH */ - /****************************************************************/ - - /** put text in Flash memory, VMA will be equal to LMA */ - .text : - { - /* provide start code symbol, shall be zero */ - _text = .; - _nvram = .; - PROVIDE(_nvram = . + ORIGIN(FLASH)); - - PROVIDE(_setjmp = setjmp); /*thanks clang*/ - - /* ensure main is always @ 0xC0D00000 */ - *(.boot*) - - /* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */ - *(.text*) - *(.rodata) - *(.rodata.[^N]*) /*.data.rel.ro* not here to detect invalid PIC usage */ - *(.rodata.N[^_]*) - - . = ALIGN(4); - - /* all code placed */ - _etext = .; - - . = ALIGN(PAGE_SIZE); - - _nvram_data = .; - - /* NVM data (ex-filesystem) */ - *(.bss.N_* .rodata.N_*) - - . = ALIGN(PAGE_SIZE); - _envram_data = .; - /* _nvram_data_size = _envram_data - _nvram_data; */ - _install_parameters = .; - PROVIDE(N_install_parameters = .); - _envram = .; - PROVIDE(_envram = . + ORIGIN(FLASH)); - - } > FLASH = 0x00 - - .data (NOLOAD): - { - . = ALIGN(4); - - /** - * Place RAM initialized variables - */ - _data = .; - - *(vtable) - *(.data*) - - _edata = .; - - } > DISCARD /*> SRAM AT>FLASH = 0x00 */ - - .bss : - { - /** - * Place RAM uninitialized variables - */ - _bss = .; - *(.bss*) - _ebss = .; - - - /** - * Reserve stack size - */ - . = ALIGN(4); - app_stack_canary = .; - PROVIDE(app_stack_canary = .); - . += 4; - _stack_validation = .; - . = _stack_validation + STACK_SIZE; - _stack = ABSOLUTE(END_STACK) - STACK_SIZE; - PROVIDE( _stack = ABSOLUTE(END_STACK) - STACK_SIZE); - _estack = ABSOLUTE(END_STACK); - PROVIDE( _estack = ABSOLUTE(END_STACK) ); - - } > SRAM = 0x00 - - /****************************************************************/ - /* DEBUG */ - /****************************************************************/ - - /* remove the debugging information from the standard libraries */ - DEBUG (NOLOAD) : - { - libc.a ( * ) - libm.a ( * ) - libgcc.a ( * ) - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > DISCARD - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - -} From 135750f8b92204e398900eafa71a8c2f7266ad1b Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:47:47 +0100 Subject: [PATCH 4/9] add some sanity checks --- app/src/apdu_handler.c | 5 ++++- app/src/crypto.c | 17 ++++++++++------- app/src/crypto.h | 3 --- app/src/crypto_helper.c | 12 ++++++------ app/src/crypto_helper.h | 4 ++-- app/src/ristretto.c | 1 - app/src/substrate/substrate_dispatch.c | 4 ++-- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index 4f9daeee..881a34b8 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -119,7 +119,9 @@ __Z_INLINE void handle_getversion(__Z_UNUSED volatile uint32_t *flags, volatile G_io_apdu_buffer[5] = (LEDGER_PATCH_VERSION >> 8) & 0xFF; G_io_apdu_buffer[6] = (LEDGER_PATCH_VERSION >> 0) & 0xFF; - G_io_apdu_buffer[7] = !IS_UX_ALLOWED; + // sdk won't pass the apdu message if device is locked + // keeping it for backwards compatibility + G_io_apdu_buffer[7] = 0; G_io_apdu_buffer[8] = (TARGET_ID >> 24) & 0xFF; G_io_apdu_buffer[9] = (TARGET_ID >> 16) & 0xFF; @@ -187,6 +189,7 @@ __Z_INLINE void handleSign(volatile uint32_t *flags, volatile uint32_t *tx, uint case key_sr25519: { zxerr_t err = app_sign_sr25519(); if (err != zxerr_ok) { + *tx = 0; THROW(APDU_CODE_DATA_INVALID); } if (G_swap_state.called_from_swap) { diff --git a/app/src/crypto.c b/app/src/crypto.c index 5ebc1260..75a12c06 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -31,7 +31,7 @@ uint32_t hdPath[HDPATH_LEN_DEFAULT]; static zxerr_t crypto_extractPublicKey(key_kind_e addressKind, uint8_t *pubKey, uint16_t pubKeyLen, uint32_t *hdPath_to_use) { if (pubKey == NULL || pubKeyLen < PK_LEN_25519) { - return zxerr_invalid_crypto_settings; + return zxerr_buffer_too_small; } zxerr_t error = zxerr_unknown; @@ -87,8 +87,8 @@ static zxerr_t crypto_extractPublicKey(key_kind_e addressKind, uint8_t *pubKey, } zxerr_t crypto_sign_ed25519(uint8_t *signature, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen) { - if (signature == NULL || message == NULL || signatureMaxlen < SIG_PLUS_TYPE_LEN) { - return zxerr_unknown; + if (signature == NULL || message == NULL || signatureMaxlen < SIG_PLUS_TYPE_LEN || messageLen == 0) { + return zxerr_buffer_too_small; } cx_ecfp_private_key_t cx_privateKey; uint8_t privateKeyData[SK_LEN_25519] = {0}; @@ -148,7 +148,7 @@ void zeroize_sr25519_signdata(void) { } zxerr_t copy_sr25519_signdata(uint8_t *buffer, uint16_t bufferLen) { - if (SIG_PLUS_TYPE_LEN > bufferLen) { + if (buffer == NULL || SIG_PLUS_TYPE_LEN > bufferLen) { return zxerr_buffer_too_small; } @@ -157,6 +157,9 @@ zxerr_t copy_sr25519_signdata(uint8_t *buffer, uint16_t bufferLen) { } static zxerr_t crypto_sign_sr25519_helper(const uint8_t *data, size_t len) { + if (data == NULL || len == 0) { + return zxerr_buffer_too_small; + } uint8_t privateKeyData[SK_LEN_25519] = {0}; uint8_t pubkey[PK_LEN_25519] = {0}; @@ -194,8 +197,8 @@ static zxerr_t crypto_sign_sr25519_helper(const uint8_t *data, size_t len) { } zxerr_t crypto_sign_sr25519(const uint8_t *message, size_t messageLen) { - if (message == NULL) { - return zxerr_unknown; + if (message == NULL || messageLen == 0) { + return zxerr_buffer_too_small; } uint8_t messageDigest[BLAKE2B_DIGEST_SIZE] = {0}; @@ -219,7 +222,7 @@ zxerr_t crypto_sign_sr25519(const uint8_t *message, size_t messageLen) { // Helper function to fill a crypto address using a given hdPath static zxerr_t crypto_fillAddress_helper(key_kind_e addressKind, uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen, uint32_t *hdPath_to_use) { if (bufferLen < PK_LEN_25519 + SS58_ADDRESS_MAX_LEN) { - return zxerr_unknown; + return zxerr_buffer_too_small; } MEMZERO(buffer, bufferLen); CHECK_ZXERR(crypto_extractPublicKey(addressKind, buffer, bufferLen, hdPath_to_use)) diff --git a/app/src/crypto.h b/app/src/crypto.h index 73a9e22b..6eb69f43 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -34,9 +34,6 @@ extern "C" { extern uint32_t hdPath[HDPATH_LEN_DEFAULT]; -uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, - uint16_t addressType, const uint8_t *pubkey); - zxerr_t crypto_fillAddress(key_kind_e addressKind, uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen); zxerr_t crypto_fillAddress_standalone(uint8_t* params, uint8_t paramsSize, key_kind_e addressKind, uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen); diff --git a/app/src/crypto_helper.c b/app/src/crypto_helper.c index fdf1b95c..a7af7c62 100644 --- a/app/src/crypto_helper.c +++ b/app/src/crypto_helper.c @@ -62,8 +62,8 @@ uint8_t crypto_SS58CalculatePrefix(uint16_t addressType, uint8_t *prefixBytes) { return 1; } -uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, - uint16_t addressType, const uint8_t *pubkey) { +uint16_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, + uint16_t addressType, const uint8_t *pubkey) { // based on https://docs.substrate.io/v3/advanced/ss58/ if (buffer == NULL || buffer_len < SS58_ADDRESS_MAX_LEN) { return 0; @@ -73,8 +73,8 @@ uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, } MEMZERO(buffer, buffer_len); - uint8_t hash[64]; - uint8_t unencoded[36]; + uint8_t hash[64] = {0}; + uint8_t unencoded[36] = {0}; const uint8_t prefixSize = crypto_SS58CalculatePrefix(addressType, unencoded); if (prefixSize == 0) { @@ -83,7 +83,7 @@ uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, memcpy(unencoded + prefixSize, pubkey, 32); // account id if (ss58hash((uint8_t *) unencoded, 32 + prefixSize, hash, 64) != CX_OK) { - MEMZERO(buffer, buffer_len); + MEMZERO(unencoded, sizeof(unencoded)); return 0; } unencoded[32 + prefixSize] = hash[0]; @@ -91,7 +91,7 @@ uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, size_t outLen = buffer_len; if (encode_base58(unencoded, 34 + prefixSize, buffer, &outLen) != 0) { - MEMZERO(buffer, buffer_len); + MEMZERO(unencoded, sizeof(unencoded)); return 0; } diff --git a/app/src/crypto_helper.h b/app/src/crypto_helper.h index d7b0f68c..05b83f3d 100644 --- a/app/src/crypto_helper.h +++ b/app/src/crypto_helper.h @@ -32,8 +32,8 @@ extern "C" { uint8_t crypto_SS58CalculatePrefix(uint16_t addressType, uint8_t *prefixBytes); -uint8_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, - uint16_t addressType, const uint8_t *pubkey); +uint16_t crypto_SS58EncodePubkey(uint8_t *buffer, uint16_t buffer_len, + uint16_t addressType, const uint8_t *pubkey); #ifdef __cplusplus } diff --git a/app/src/ristretto.c b/app/src/ristretto.c index af4ca1de..166a2687 100644 --- a/app/src/ristretto.c +++ b/app/src/ristretto.c @@ -169,7 +169,6 @@ static cx_err_t ristretto255_sqrt_ratio_m1_sdk(fe25519_sdk x, const fe25519_sdk CHECK_CXERROR(fe25519_add_sdk(p_root_check, vxx, u)) /* vx^2+u */ CHECK_CXERROR(fe25519_mul_sdk(f_root_check, u, fe25519_sqrtm1_sdk)) /* u*sqrt(-1) */ CHECK_CXERROR(fe25519_add_sdk(f_root_check, vxx, f_root_check)) /* vx^2+u*sqrt(-1) */ - fe25519_iszero_sdk(m_root_check); has_p_root = fe25519_iszero_sdk(p_root_check); has_f_root = fe25519_iszero_sdk(f_root_check); CHECK_CXERROR(fe25519_mul_sdk(x_sqrtm1,x, fe25519_sqrtm1_sdk)) diff --git a/app/src/substrate/substrate_dispatch.c b/app/src/substrate/substrate_dispatch.c index 3a50c872..96dcd535 100644 --- a/app/src/substrate/substrate_dispatch.c +++ b/app/src/substrate/substrate_dispatch.c @@ -43,7 +43,7 @@ uint8_t _getMethod_NumItems(uint32_t transactionVersion, uint8_t moduleIdx, uint case 23: return _getMethod_NumItems_V23(moduleIdx, callIdx); default: - return parser_tx_version_not_supported; + return 0; } } @@ -67,7 +67,7 @@ const char* _getMethod_Name(uint32_t transactionVersion, uint8_t moduleIdx, uint case 23: return _getMethod_Name_V23(moduleIdx, callIdx); default: - return 0; + return NULL; } } From be30221264287a23c00f1776fa450f65a5ca9c9f Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Tue, 28 Nov 2023 14:17:20 +0100 Subject: [PATCH 5/9] Small improvements in handle_check_address guards Closes #205 --- app/src/swap/handle_check_address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/swap/handle_check_address.c b/app/src/swap/handle_check_address.c index e2c02c3b..20d0030f 100644 --- a/app/src/swap/handle_check_address.c +++ b/app/src/swap/handle_check_address.c @@ -22,7 +22,7 @@ void handle_check_address(check_address_parameters_t* params) { - if (params == NULL || params->address_to_check == 0) { + if (params == NULL || params->address_to_check == NULL || params->address_parameters_length < 2) { return; } params->result = 0; From c597830a9843a2e2df6a6801f735c9ed0288573a Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:49:19 +0100 Subject: [PATCH 6/9] add nesting for some methods Closes #199 Closes #204 --- app/src/substrate/substrate_dispatch_V24.c | 29 ++++------ app/src/substrate/substrate_methods_V24.h | 64 +++++++++++----------- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/app/src/substrate/substrate_dispatch_V24.c b/app/src/substrate/substrate_dispatch_V24.c index 824587f7..f5c25fa4 100644 --- a/app/src/substrate/substrate_dispatch_V24.c +++ b/app/src/substrate/substrate_dispatch_V24.c @@ -2101,7 +2101,7 @@ parser_error_t _readMethod_V24( CHECK_ERROR(_readMethod_balances_transfer_keep_alive_V24(c, &method->nested.balances_transfer_keep_alive_V24)) break; case 1284: /* module 5 call 4 */ - CHECK_ERROR(_readMethod_balances_transfer_all_V24(c, &method->basic.balances_transfer_all_V24)) + CHECK_ERROR(_readMethod_balances_transfer_all_V24(c, &method->nested.balances_transfer_all_V24)) break; case 1287: /* module 5 call 7 */ CHECK_ERROR(_readMethod_balances_transfer_V24(c, &method->nested.balances_transfer_V24)) @@ -2119,7 +2119,7 @@ parser_error_t _readMethod_V24( CHECK_ERROR(_readMethod_staking_withdraw_unbonded_V24(c, &method->nested.staking_withdraw_unbonded_V24)) break; case 1796: /* module 7 call 4 */ - CHECK_ERROR(_readMethod_staking_validate_V24(c, &method->basic.staking_validate_V24)) + CHECK_ERROR(_readMethod_staking_validate_V24(c, &method->nested.staking_validate_V24)) break; case 1797: /* module 7 call 5 */ CHECK_ERROR(_readMethod_staking_nominate_V24(c, &method->nested.staking_nominate_V24)) @@ -2134,16 +2134,16 @@ parser_error_t _readMethod_V24( CHECK_ERROR(_readMethod_staking_set_controller_V24(c, &method->nested.staking_set_controller_V24)) break; case 1810: /* module 7 call 18 */ - CHECK_ERROR(_readMethod_staking_payout_stakers_V24(c, &method->basic.staking_payout_stakers_V24)) + CHECK_ERROR(_readMethod_staking_payout_stakers_V24(c, &method->nested.staking_payout_stakers_V24)) break; case 1811: /* module 7 call 19 */ CHECK_ERROR(_readMethod_staking_rebond_V24(c, &method->nested.staking_rebond_V24)) break; case 2304: /* module 9 call 0 */ - CHECK_ERROR(_readMethod_session_set_keys_V24(c, &method->basic.session_set_keys_V24)) + CHECK_ERROR(_readMethod_session_set_keys_V24(c, &method->nested.session_set_keys_V24)) break; case 2305: /* module 9 call 1 */ - CHECK_ERROR(_readMethod_session_purge_keys_V24(c, &method->basic.session_purge_keys_V24)) + CHECK_ERROR(_readMethod_session_purge_keys_V24(c, &method->nested.session_purge_keys_V24)) break; case 6656: /* module 26 call 0 */ CHECK_ERROR(_readMethod_utility_batch_V24(c, &method->basic.utility_batch_V24)) @@ -6351,12 +6351,12 @@ parser_error_t _getMethod_ItemValue_V24( switch (itemIdx) { case 0: /* balances_transfer_all_V24 - dest */; return _toStringAccountIdLookupOfT( - &m->basic.balances_transfer_all_V24.dest, + &m->nested.balances_transfer_all_V24.dest, outValue, outValueLen, pageIdx, pageCount); case 1: /* balances_transfer_all_V24 - keep_alive */; return _toStringbool( - &m->basic.balances_transfer_all_V24.keep_alive, + &m->nested.balances_transfer_all_V24.keep_alive, outValue, outValueLen, pageIdx, pageCount); default: @@ -6426,7 +6426,7 @@ parser_error_t _getMethod_ItemValue_V24( switch (itemIdx) { case 0: /* staking_validate_V24 - prefs */; return _toStringValidatorPrefs( - &m->basic.staking_validate_V24.prefs, + &m->nested.staking_validate_V24.prefs, outValue, outValueLen, pageIdx, pageCount); default: @@ -6466,12 +6466,12 @@ parser_error_t _getMethod_ItemValue_V24( switch (itemIdx) { case 0: /* staking_payout_stakers_V24 - validator_stash */; return _toStringAccountId( - &m->basic.staking_payout_stakers_V24.validator_stash, + &m->nested.staking_payout_stakers_V24.validator_stash, outValue, outValueLen, pageIdx, pageCount); case 1: /* staking_payout_stakers_V24 - era */; return _toStringEraIndex( - &m->basic.staking_payout_stakers_V24.era, + &m->nested.staking_payout_stakers_V24.era, outValue, outValueLen, pageIdx, pageCount); default: @@ -6491,12 +6491,12 @@ parser_error_t _getMethod_ItemValue_V24( switch (itemIdx) { case 0: /* session_set_keys_V24 - keys */; return _toStringKeys( - &m->basic.session_set_keys_V24.keys, + &m->nested.session_set_keys_V24.keys, outValue, outValueLen, pageIdx, pageCount); case 1: /* session_set_keys_V24 - proof */; return _toStringBytes( - &m->basic.session_set_keys_V24.proof, + &m->nested.session_set_keys_V24.proof, outValue, outValueLen, pageIdx, pageCount); default: @@ -9894,11 +9894,9 @@ bool _getMethod_IsNestingSupported_V24(uint8_t moduleIdx, uint8_t callIdx) case 1026: // Indices:Free case 1027: // Indices:Force transfer case 1028: // Indices:Freeze - case 1284: // Balances:Transfer all case 1285: // Balances:Force unreserve case 1286: // Balances:Upgrade accounts case 1288: // Balances:Force set balance - case 1796: // Staking:Validate case 1801: // Staking:Set validator count case 1802: // Staking:Increase validator count case 1803: // Staking:Scale validator count @@ -9908,15 +9906,12 @@ bool _getMethod_IsNestingSupported_V24(uint8_t moduleIdx, uint8_t callIdx) case 1807: // Staking:Force unstake case 1808: // Staking:Force new era always case 1809: // Staking:Cancel deferred slash - case 1810: // Staking:Payout stakers case 1812: // Staking:Reap stash case 1813: // Staking:Kick case 1814: // Staking:Set staking configs case 1815: // Staking:Chill other case 1816: // Staking:Force apply min commission case 1817: // Staking:Set min commission - case 2304: // Session:Set keys - case 2305: // Session:Purge keys case 3600: // Democracy:Blacklist case 3602: // Democracy:Set metadata case 3840: // Council:Set members diff --git a/app/src/substrate/substrate_methods_V24.h b/app/src/substrate/substrate_methods_V24.h index 62c8dc32..028d6a2b 100644 --- a/app/src/substrate/substrate_methods_V24.h +++ b/app/src/substrate/substrate_methods_V24.h @@ -65,33 +65,6 @@ extern "C" { #define PD_CALL_CROWDLOAN_V24 73 #define PD_CALL_XCMPALLET_V24 99 -#define PD_CALL_BALANCES_TRANSFER_ALL_V24 4 -typedef struct { - pd_AccountIdLookupOfT_t dest; - pd_bool_t keep_alive; -} pd_balances_transfer_all_V24_t; - -#define PD_CALL_STAKING_VALIDATE_V24 4 -typedef struct { - pd_ValidatorPrefs_t prefs; -} pd_staking_validate_V24_t; - -#define PD_CALL_STAKING_PAYOUT_STAKERS_V24 18 -typedef struct { - pd_AccountId_t validator_stash; - pd_EraIndex_t era; -} pd_staking_payout_stakers_V24_t; - -#define PD_CALL_SESSION_SET_KEYS_V24 0 -typedef struct { - pd_Keys_t keys; - pd_Bytes_t proof; -} pd_session_set_keys_V24_t; - -#define PD_CALL_SESSION_PURGE_KEYS_V24 1 -typedef struct { -} pd_session_purge_keys_V24_t; - #define PD_CALL_UTILITY_BATCH_V24 0 typedef struct { pd_VecCall_t calls; @@ -1157,11 +1130,6 @@ typedef struct { #endif typedef union { - pd_balances_transfer_all_V24_t balances_transfer_all_V24; - pd_staking_validate_V24_t staking_validate_V24; - pd_staking_payout_stakers_V24_t staking_payout_stakers_V24; - pd_session_set_keys_V24_t session_set_keys_V24; - pd_session_purge_keys_V24_t session_purge_keys_V24; pd_utility_batch_V24_t utility_batch_V24; pd_utility_batch_all_V24_t utility_batch_all_V24; pd_utility_force_batch_V24_t utility_force_batch_V24; @@ -1375,6 +1343,12 @@ typedef struct { pd_CompactBalance_t amount; } pd_balances_transfer_keep_alive_V24_t; +#define PD_CALL_BALANCES_TRANSFER_ALL_V24 4 +typedef struct { + pd_AccountIdLookupOfT_t dest; + pd_bool_t keep_alive; +} pd_balances_transfer_all_V24_t; + #define PD_CALL_BALANCES_TRANSFER_V24 7 typedef struct { pd_AccountIdLookupOfT_t dest; @@ -1402,6 +1376,11 @@ typedef struct { pd_u32_t num_slashing_spans; } pd_staking_withdraw_unbonded_V24_t; +#define PD_CALL_STAKING_VALIDATE_V24 4 +typedef struct { + pd_ValidatorPrefs_t prefs; +} pd_staking_validate_V24_t; + #define PD_CALL_STAKING_NOMINATE_V24 5 typedef struct { pd_VecAccountIdLookupOfT_t targets; @@ -1420,11 +1399,27 @@ typedef struct { typedef struct { } pd_staking_set_controller_V24_t; +#define PD_CALL_STAKING_PAYOUT_STAKERS_V24 18 +typedef struct { + pd_AccountId_t validator_stash; + pd_EraIndex_t era; +} pd_staking_payout_stakers_V24_t; + #define PD_CALL_STAKING_REBOND_V24 19 typedef struct { pd_CompactBalance_t amount; } pd_staking_rebond_V24_t; +#define PD_CALL_SESSION_SET_KEYS_V24 0 +typedef struct { + pd_Keys_t keys; + pd_Bytes_t proof; +} pd_session_set_keys_V24_t; + +#define PD_CALL_SESSION_PURGE_KEYS_V24 1 +typedef struct { +} pd_session_purge_keys_V24_t; + #ifdef SUBSTRATE_PARSER_FULL #ifndef TARGET_NANOS #endif @@ -1770,16 +1765,21 @@ typedef union { pd_balances_transfer_allow_death_V24_t balances_transfer_allow_death_V24; pd_balances_force_transfer_V24_t balances_force_transfer_V24; pd_balances_transfer_keep_alive_V24_t balances_transfer_keep_alive_V24; + pd_balances_transfer_all_V24_t balances_transfer_all_V24; pd_balances_transfer_V24_t balances_transfer_V24; pd_staking_bond_V24_t staking_bond_V24; pd_staking_bond_extra_V24_t staking_bond_extra_V24; pd_staking_unbond_V24_t staking_unbond_V24; pd_staking_withdraw_unbonded_V24_t staking_withdraw_unbonded_V24; + pd_staking_validate_V24_t staking_validate_V24; pd_staking_nominate_V24_t staking_nominate_V24; pd_staking_chill_V24_t staking_chill_V24; pd_staking_set_payee_V24_t staking_set_payee_V24; pd_staking_set_controller_V24_t staking_set_controller_V24; + pd_staking_payout_stakers_V24_t staking_payout_stakers_V24; pd_staking_rebond_V24_t staking_rebond_V24; + pd_session_set_keys_V24_t session_set_keys_V24; + pd_session_purge_keys_V24_t session_purge_keys_V24; #ifdef SUBSTRATE_PARSER_FULL #ifndef TARGET_NANOS #endif From 5ccf9f19ab76e57dd03cabcc9bb34a0deb178265 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:51:20 +0100 Subject: [PATCH 7/9] bump version --- app/Makefile.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index 3c9c435a..84dc36ac 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=24 # This is the `spec_version` field of `Runtime` APPVERSION_N=9430 # This is the patch version of this release -APPVERSION_P=3 +APPVERSION_P=4 From 6207549c7dd22bf58a113855ad8645b2a6a727ac Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:51:16 +0100 Subject: [PATCH 8/9] update docs --- README.md | 14 ++--- docs/APDUSPEC.md | 102 +++++++++++++++++++++++------------- docs/supported_24.9430.x.md | 14 ++--- docs/supported_latest.md | 14 ++--- 4 files changed, 88 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 18cd71da..6ceb5e7e 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Please: | Set balance deprecated | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`who
`CompactBalance`new_free
`CompactBalance`old_reserved
| | Force transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`source
`AccountIdLookupOfT`dest
`CompactBalance`amount
| | Transfer keep alive | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| -| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`dest
`bool`keep_alive
| +| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`bool`keep_alive
| | Force unreserve | | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`who
`Balance`amount
| | Upgrade accounts | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountId`who
| | Transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| @@ -109,7 +109,7 @@ Please: | Bond extra | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Unbond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Withdraw Unbonded | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `u32`num_slashing_spans
| -| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `ValidatorPrefs`prefs
| +| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `ValidatorPrefs`prefs
| | Nominate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `VecAccountIdLookupOfT`targets
| | Chill | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | Set payee | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `RewardDestination`payee
| @@ -123,7 +123,7 @@ Please: | Force unstake | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Force new era always | | :heavy_check_mark: | :heavy_check_mark: | | | | Cancel deferred slash | | :heavy_check_mark: | :heavy_check_mark: | | `EraIndex`era
`Vecu32`slash_indices
| -| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`validator_stash
`EraIndex`era
| +| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountId`validator_stash
`EraIndex`era
| | Rebond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Reap stash | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Kick | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountIdLookupOfT`who
| @@ -134,10 +134,10 @@ Please: ## Session -| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | -| ---------- | ------------------ | ------------------ | ------------------ | ------- | -------------------------------- | -| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `Keys`keys
`Bytes`proof
| -| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | +| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | +| ---------- | ------------------ | ------------------ | ------------------ | ------------------ | -------------------------------- | +| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `Keys`keys
`Bytes`proof
| +| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | ## Grandpa diff --git a/docs/APDUSPEC.md b/docs/APDUSPEC.md index 365d0712..b0e0dec0 100644 --- a/docs/APDUSPEC.md +++ b/docs/APDUSPEC.md @@ -27,18 +27,49 @@ The general structure of commands and responses is as follows: | Return code | Description | | ----------- | ----------------------- | | 0x6400 | Execution Error | +| 0x6700 | Wrong buffer length | | 0x6982 | Empty buffer | | 0x6983 | Output buffer too small | +| 0x6984 | Data is invalid | | 0x6986 | Command not allowed | +| 0x6987 | Tx is not initialized | +| 0x6B00 | P1/P2 are invalid | | 0x6D00 | INS not supported | | 0x6E00 | CLA not supported | | 0x6F00 | Unknown | +| 0x6F01 | Sign / verify error | | 0x9000 | Success | --- ## Command definition +### GET_DEVICE_INFO + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | -------- | +| CLA | byte (1) | Application Identifier | 0xE0 | +| INS | byte (1) | Instruction ID | 0x01 | +| P1 | byte (1) | Parameter 1 | 0x00 | +| P2 | byte (1) | Parameter 2 | 0x00 | +| L | byte (1) | Bytes in payload | 0x00 | + +#### Response + +| Field | Type | Content | Note | +| --------- | -------- | ------------------ | ------------------------ | +| TARGET_ID | byte (4) | Target Id | | +| OS_LEN | byte (1) | OS version length | 0..64 | +| OS | byte (?) | OS version | Non terminated string | +| FLAGS_LEN | byte (1) | Flags length | 0 | +| MCU_LEN | byte (1) | MCU version length | 0..64 | +| MCU | byte (?) | MCU version | Non terminated string | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +--- + ### GET_VERSION #### Command @@ -53,14 +84,15 @@ The general structure of commands and responses is as follows: #### Response -| Field | Type | Content | Note | -| ------- | -------- | ---------------- | ------------------------------- | -| TEST | byte (1) | Test Mode | 0xFF means test mode is enabled | -| MAJOR | byte (2) | Version Major | 0..65535 | -| MINOR | byte (2) | Version Minor | 0..65535 | -| PATCH | byte (2) | Version Patch | 0..65535 | -| LOCKED | byte (1) | Device is locked | | -| SW1-SW2 | byte (2) | Return code | see list of return codes | +| Field | Type | Content | Note | +| --------- | -------- | ---------------- | ------------------------------- | +| TEST | byte (1) | Test Mode | 0x01 means test mode is enabled | +| MAJOR | byte (2) | Version Major | 0..65535 | +| MINOR | byte (2) | Version Minor | 0..65535 | +| PATCH | byte (2) | Version Patch | 0..65535 | +| LOCKED | byte (1) | Device is locked | It'll always be 0 | +| TARGET_ID | byte (4) | Target Id | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | --- @@ -68,19 +100,19 @@ The general structure of commands and responses is as follows: #### Command -| Field | Type | Content | Expected | | -| ------- | -------- | ------------------------- | ----------- | --- | -| CLA | byte (1) | Application Identifier | 0x90 | | -| INS | byte (1) | Instruction ID | 0x01 | | -| P1 | byte (1) | Request User confirmation | No = 0 | | -| P2 | byte (1) | Signature scheme | Ed25519 = 0 | | -| | | | Sr25519 = 1 | | -| L | byte (1) | Bytes in payload | (depends) | | -| Path[0] | byte (4) | Derivation Path Data | 0x80000000 | 44 | -| Path[1] | byte (4) | Derivation Path Data | 0x80000000 | 354 | -| Path[2] | byte (4) | Derivation Path Data | ? | | -| Path[3] | byte (4) | Derivation Path Data | ? | | -| Path[4] | byte (4) | Derivation Path Data | ? | | +| Field | Type | Content | Expected | +| ------- | -------- | ------------------------- | ----------------- | +| CLA | byte (1) | Application Identifier | 0x90 | +| INS | byte (1) | Instruction ID | 0x01 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Signature scheme | Ed25519 = 0 | +| | | | Sr25519 = 1 | +| L | byte (1) | Bytes in payload | (depends) | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 \| 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 \| 354 | +| Path[2] | byte (4) | Derivation Path Data | ? | +| Path[3] | byte (4) | Derivation Path Data | ? | +| Path[4] | byte (4) | Derivation Path Data | ? | #### Response @@ -113,13 +145,13 @@ All other packets/chunks contain data chunks that are described below ##### First Packet -| Field | Type | Content | Expected | -| ------- | -------- | -------------------- | -------- | -| Path[0] | byte (4) | Derivation Path Data | 44 | -| Path[1] | byte (4) | Derivation Path Data | 354 | -| Path[2] | byte (4) | Derivation Path Data | ? | -| Path[3] | byte (4) | Derivation Path Data | ? | -| Path[4] | byte (4) | Derivation Path Data | ? | +| Field | Type | Content | Expected | +| ------- | -------- | -------------------- | ----------------- | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 \| 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 \| 354 | +| Path[2] | byte (4) | Derivation Path Data | ? | +| Path[3] | byte (4) | Derivation Path Data | ? | +| Path[4] | byte (4) | Derivation Path Data | ? | ##### Other Chunks/Packets @@ -157,13 +189,13 @@ All other packets/chunks contain data chunks that are described below ##### First Packet -| Field | Type | Content | Expected | -| ------- | -------- | -------------------- | -------- | -| Path[0] | byte (4) | Derivation Path Data | 44 | -| Path[1] | byte (4) | Derivation Path Data | 354 | -| Path[2] | byte (4) | Derivation Path Data | ? | -| Path[3] | byte (4) | Derivation Path Data | ? | -| Path[4] | byte (4) | Derivation Path Data | ? | +| Field | Type | Content | Expected | +| ------- | -------- | -------------------- | ----------------- | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 \| 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 \| 354 | +| Path[2] | byte (4) | Derivation Path Data | ? | +| Path[3] | byte (4) | Derivation Path Data | ? | +| Path[4] | byte (4) | Derivation Path Data | ? | ##### Other Chunks/Packets diff --git a/docs/supported_24.9430.x.md b/docs/supported_24.9430.x.md index a49ebb81..c78b9634 100644 --- a/docs/supported_24.9430.x.md +++ b/docs/supported_24.9430.x.md @@ -65,7 +65,7 @@ | Set balance deprecated | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`who
`CompactBalance`new_free
`CompactBalance`old_reserved
| | Force transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`source
`AccountIdLookupOfT`dest
`CompactBalance`amount
| | Transfer keep alive | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| -| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`dest
`bool`keep_alive
| +| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`bool`keep_alive
| | Force unreserve | | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`who
`Balance`amount
| | Upgrade accounts | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountId`who
| | Transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| @@ -79,7 +79,7 @@ | Bond extra | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Unbond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Withdraw Unbonded | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `u32`num_slashing_spans
| -| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `ValidatorPrefs`prefs
| +| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `ValidatorPrefs`prefs
| | Nominate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `VecAccountIdLookupOfT`targets
| | Chill | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | Set payee | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `RewardDestination`payee
| @@ -93,7 +93,7 @@ | Force unstake | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Force new era always | | :heavy_check_mark: | :heavy_check_mark: | | | | Cancel deferred slash | | :heavy_check_mark: | :heavy_check_mark: | | `EraIndex`era
`Vecu32`slash_indices
| -| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`validator_stash
`EraIndex`era
| +| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountId`validator_stash
`EraIndex`era
| | Rebond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Reap stash | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Kick | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountIdLookupOfT`who
| @@ -104,10 +104,10 @@ ## Session -| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | -| ---------- | ------------------ | ------------------ | ------------------ | ------- | -------------------------------- | -| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `Keys`keys
`Bytes`proof
| -| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | +| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | +| ---------- | ------------------ | ------------------ | ------------------ | ------------------ | -------------------------------- | +| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `Keys`keys
`Bytes`proof
| +| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | ## Grandpa diff --git a/docs/supported_latest.md b/docs/supported_latest.md index a49ebb81..c78b9634 100644 --- a/docs/supported_latest.md +++ b/docs/supported_latest.md @@ -65,7 +65,7 @@ | Set balance deprecated | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`who
`CompactBalance`new_free
`CompactBalance`old_reserved
| | Force transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`source
`AccountIdLookupOfT`dest
`CompactBalance`amount
| | Transfer keep alive | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| -| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`dest
`bool`keep_alive
| +| Transfer all | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`bool`keep_alive
| | Force unreserve | | :heavy_check_mark: | :heavy_check_mark: | | `AccountIdLookupOfT`who
`Balance`amount
| | Upgrade accounts | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountId`who
| | Transfer | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountIdLookupOfT`dest
`CompactBalance`amount
| @@ -79,7 +79,7 @@ | Bond extra | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Unbond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Withdraw Unbonded | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `u32`num_slashing_spans
| -| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `ValidatorPrefs`prefs
| +| Validate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `ValidatorPrefs`prefs
| | Nominate | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `VecAccountIdLookupOfT`targets
| | Chill | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | Set payee | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `RewardDestination`payee
| @@ -93,7 +93,7 @@ | Force unstake | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Force new era always | | :heavy_check_mark: | :heavy_check_mark: | | | | Cancel deferred slash | | :heavy_check_mark: | :heavy_check_mark: | | `EraIndex`era
`Vecu32`slash_indices
| -| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`validator_stash
`EraIndex`era
| +| Payout stakers | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `AccountId`validator_stash
`EraIndex`era
| | Rebond | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `CompactBalance`amount
| | Reap stash | | :heavy_check_mark: | :heavy_check_mark: | | `AccountId`stash
`u32`num_slashing_spans
| | Kick | | :heavy_check_mark: | :heavy_check_mark: | | `VecAccountIdLookupOfT`who
| @@ -104,10 +104,10 @@ ## Session -| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | -| ---------- | ------------------ | ------------------ | ------------------ | ------- | -------------------------------- | -| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | `Keys`keys
`Bytes`proof
| -| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | +| Name | Nano S | Nano S XL | Nano SP/X - Stax | Nesting | Arguments | +| ---------- | ------------------ | ------------------ | ------------------ | ------------------ | -------------------------------- | +| Set keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | `Keys`keys
`Bytes`proof
| +| Purge keys | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | ## Grandpa From 6d9ad142bc2baa9b354ddb78475d927b382a7d36 Mon Sep 17 00:00:00 2001 From: Carlo Sala Date: Wed, 6 Dec 2023 16:58:11 +0100 Subject: [PATCH 9/9] update snapshots --- tests_zemu/package.json | 4 ++-- tests_zemu/snapshots/s-mainmenu/00004.png | Bin 466 -> 465 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 466 -> 465 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 420 -> 426 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 420 -> 426 bytes tests_zemu/snapshots/st-mainmenu/00001.png | Bin 14241 -> 14263 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 420 -> 426 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 420 -> 426 bytes 8 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests_zemu/package.json b/tests_zemu/package.json index cc620be3..9235b001 100644 --- a/tests_zemu/package.json +++ b/tests_zemu/package.json @@ -18,8 +18,8 @@ "test": "yarn clean && jest --maxConcurrency 3" }, "dependencies": { - "@zondax/ledger-substrate": "^0.41.1", - "@zondax/zemu": "^0.44.2" + "@zondax/ledger-substrate": "^0.41.3", + "@zondax/zemu": "^0.46.0" }, "devDependencies": { "@types/jest": "^29.5.0", diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index 8e002d15ea76525a80e7e4475948f8bf20125601..3a578519968a7a76393a89dd55bd1b00b3c68902 100644 GIT binary patch delta 439 zcmV;o0Z9JR1JMJJB!8GmL_t(|ob8#(62dSDK%=Ao|G_=fLmW)m0$oB>-grwwmj)Z%(&0DILMqJOK}p+5*)3G&{$6kNxH z&X_dcLtF`>&d}Yan41-}>klRL8Q|?T*X1L^_O;5NZS`k01YtV|u=lD2=9IBEC!raT z@DAv9BPfffY3U|K?Z=1%YMq^9>;=p^3+j%B=r~9c)MrQfDew9k;Gc%l`C|7j z*^tcMsgyD(1KKFFWHeVRO-O=m$9!DdsT^>?S*LlgX?DyKx}_$L=##K?NI}IK(Ux_W zp!dek(k3(NjaY5Mq+mzwZ$)}?0PK{FU1^6tpDyl#Y%mVEX#3qS2#qf?(c-f8R$Iif h9Y~TSNs=TP%L_VO^Vtte(P#hw002ovPDHLkV1o2p*5m*H delta 440 zcmV;p0Z0DP1JVPKB!8JnL_t(|ob8#>*1{kNfUQ&S|G>Lg7k0=YAlN4Se|)El)dUTY zAuAwt~{LQ2V2O#>9<8MMVb}q zhp%Ba%Gw=(;LJ)618&dvr;H3LWHZp<%~}VvrtB>)X9loW&3_@XstNs0=u(h%>0EGq zA9Tu1^LOw|LA^6%w+ZGZ1@-z}aeW3@Yt4Q8h>&%y@MD|(Nexcu&H?0Fg}@9MYcX-% z0SWDZVKstwahQ@WC}KU9{w7rL}ty3lli0q?r?sx={``}zC z>zA1-h-=7jEq@xN=3Yc7PvyCgpr&`kDdFy(N7P=>ur<`TgE&FCcf=Lbq|^o2yP_K(_v8S`E*m*g&+<2AIxz=aw4mu1gvuA0XmB}tt4(5l iWoVKlNs=VVZ}I|M=JEF#wtfZx0000-grwwmj)Z%(&0DILMqJOK}p+5*)3G&{$6kNxH z&X_dcLtF`>&d}Yan41-}>klRL8Q|?T*X1L^_O;5NZS`k01YtV|u=lD2=9IBEC!raT z@DAv9BPfffY3U|K?Z=1%YMq^9>;=p^3+j%B=r~9c)MrQfDew9k;Gc%l`C|7j z*^tcMsgyD(1KKFFWHeVRO-O=m$9!DdsT^>?S*LlgX?DyKx}_$L=##K?NI}IK(Ux_W zp!dek(k3(NjaY5Mq+mzwZ$)}?0PK{FU1^6tpDyl#Y%mVEX#3qS2#qf?(c-f8R$Iif h9Y~TSNs=TP%L_VO^Vtte(P#hw002ovPDHLkV1o2p*5m*H delta 440 zcmV;p0Z0DP1JVPKB!8JnL_t(|ob8#>*1{kNfUQ&S|G>Lg7k0=YAlN4Se|)El)dUTY zAuAwt~{LQ2V2O#>9<8MMVb}q zhp%Ba%Gw=(;LJ)618&dvr;H3LWHZp<%~}VvrtB>)X9loW&3_@XstNs0=u(h%>0EGq zA9Tu1^LOw|LA^6%w+ZGZ1@-z}aeW3@Yt4Q8h>&%y@MD|(Nexcu&H?0Fg}@9MYcX-% z0SWDZVKstwahQ@WC}KU9{w7rL}ty3lli0q?r?sx={``}zC z>zA1-h-=7jEq@xN=3Yc7PvyCgpr&`kDdFy(N7P=>ur<`TgE&FCcf=Lbq|^o2yP_K(_v8S`E*m*g&+<2AIxz=aw4mu1gvuA0XmB}tt4(5l iWoVKlNs=VVZ}I|M=JEF#wtfZx00008}fKv6oHov{BUc`x%36(Jr5hQ=nrBm@8e00000000000C03!{W8t68eSn16EzEuIvTuw&@Wd+QiR-YZv(j5X!4_wgs9{L6@|kn^Yr^mSiitJp;Rpv^*1w9!u`7`z_d4QQ+`<=7<7vbUAkMo}a*TL`wWU;$B9HDi| ubREj4(RYq?00000000000000G!XJj)QN>Kj0gM0u00{s|MNUMnLSTa9ZoMu5 delta 394 zcmV;50d@YW1Ed3xB!6p3L_t(|obB0La>F1DKvAdDov{BUX)pa?LMR9UwT*D+p0A`u zFcuFx@^JtF00000000000DxP(yapDL{A&ooZW$ZopQi?z3R&sPclaIhA|l0VSn1nq z;FgpNdv5A&QAeq1E&5Miy*7&T4k)zJsy0i)+tEv?ahjzb7JqY|fIO9T#_f|KT|8}$NcnHd$>bq zh$n90$7v>+>@TCFn(Qye9C+ds^2B}EQ=MM7YG`Cve$rE>8r2O^J8#7f)}a0^wN7AH z6wZW<7n<(2?thnXabfm#w$}c&Av;)C3ko6RKV0oMFjr-Ns>tk8k>28cz--3HPl=KF z{#)a#_)kD_!7;h{VO^x7zQ=Y$@G(-jKl9(m-GsN;0r5lk9b{49>@M@VWxNj^zqiqB ow*UYD0000000000;1PZR#h^QrmhTI)00000NkvXXt^-0~f8}fKv6oHov{BUc`x%36(Jr5hQ=nrBm@8e00000000000C03!{W8t68eSn16EzEuIvTuw&@Wd+QiR-YZv(j5X!4_wgs9{L6@|kn^Yr^mSiitJp;Rpv^*1w9!u`7`z_d4QQ+`<=7<7vbUAkMo}a*TL`wWU;$B9HDi| ubREj4(RYq?00000000000000G!XJj)QN>Kj0gM0u00{s|MNUMnLSTa9ZoMu5 delta 394 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�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 literal 14241 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 delta 394 zcmV;50d@YW1Ed3xB!6p3L_t(|obB0La>F1DKvAdDov{BUX)pa?LMR9UwT*D+p0A`u zFcuFx@^JtF00000000000DxP(yapDL{A&ooZW$ZopQi?z3R&sPclaIhA|l0VSn1nq z;FgpNdv5A&QAeq1E&5Miy*7&T4k)zJsy0i)+tEv?ahjzb7JqY|fIO9T#_f|KT|8}$NcnHd$>bq zh$n90$7v>+>@TCFn(Qye9C+ds^2B}EQ=MM7YG`Cve$rE>8r2O^J8#7f)}a0^wN7AH z6wZW<7n<(2?thnXabfm#w$}c&Av;)C3ko6RKV0oMFjr-Ns>tk8k>28cz--3HPl=KF z{#)a#_)kD_!7;h{VO^x7zQ=Y$@G(-jKl9(m-GsN;0r5lk9b{49>@M@VWxNj^zqiqB ow*UYD0000000000;1PZR#h^QrmhTI)00000NkvXXt^-0~f8}fKv6oHov{BUc`x%36(Jr5hQ=nrBm@8e00000000000C03!{W8t68eSn16EzEuIvTuw&@Wd+QiR-YZv(j5X!4_wgs9{L6@|kn^Yr^mSiitJp;Rpv^*1w9!u`7`z_d4QQ+`<=7<7vbUAkMo}a*TL`wWU;$B9HDi| ubREj4(RYq?00000000000000G!XJj)QN>Kj0gM0u00{s|MNUMnLSTa9ZoMu5 delta 394 zcmV;50d@YW1Ed3xB!6p3L_t(|obB0La>F1DKvAdDov{BUX)pa?LMR9UwT*D+p0A`u zFcuFx@^JtF00000000000DxP(yapDL{A&ooZW$ZopQi?z3R&sPclaIhA|l0VSn1nq z;FgpNdv5A&QAeq1E&5Miy*7&T4k)zJsy0i)+tEv?ahjzb7JqY|fIO9T#_f|KT|8}$NcnHd$>bq zh$n90$7v>+>@TCFn(Qye9C+ds^2B}EQ=MM7YG`Cve$rE>8r2O^J8#7f)}a0^wN7AH z6wZW<7n<(2?thnXabfm#w$}c&Av;)C3ko6RKV0oMFjr-Ns>tk8k>28cz--3HPl=KF z{#)a#_)kD_!7;h{VO^x7zQ=Y$@G(-jKl9(m-GsN;0r5lk9b{49>@M@VWxNj^zqiqB ow*UYD0000000000;1PZR#h^QrmhTI)00000NkvXXt^-0~f