From fc4b7b293f83cc216eae199e75f054cb14dee4e1 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Thu, 21 Dec 2023 09:57:05 -0300 Subject: [PATCH 1/8] fixes --- app/Makefile | 3 - app/src/apdu_handler.c | 2 +- app/src/coin.h | 2 +- app/src/crypto_helper.c | 27 ++++---- app/src/leb128.c | 1 - app/src/parser_impl_txn.c | 78 ++++++++++++++++++--- app/src/parser_print_common.c | 61 ----------------- app/src/parser_types.h | 2 +- docs/APDUSPEC.md | 124 +++++++++++++++++++++++----------- tests/parser_impl.cpp | 2 +- 10 files changed, 170 insertions(+), 132 deletions(-) diff --git a/app/Makefile b/app/Makefile index 34bef69c..09300dad 100755 --- a/app/Makefile +++ b/app/Makefile @@ -74,9 +74,6 @@ INCLUDES_PATH += $(BOLOS_SDK)/lib_cxng/src rust: @echo "No rust code" -# Before linking, we need to be sure rust lib is there -bin/app.elf: rust - .PHONY: rust_clean rust_clean: @echo "No rust code" diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index d8b4dd6b..a04f55a8 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -111,7 +111,7 @@ __Z_INLINE void handleSignTransaction(volatile uint32_t *flags, volatile uint32_ CHECK_APP_CANARY() if (error_msg != NULL) { - int error_msg_length = strlen(error_msg); + const int error_msg_length = strnlen(error_msg, sizeof(G_io_apdu_buffer)); memcpy(G_io_apdu_buffer, error_msg, error_msg_length); *tx += (error_msg_length); THROW(APDU_CODE_DATA_INVALID); diff --git a/app/src/coin.h b/app/src/coin.h index 21b10d07..107df827 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -25,7 +25,7 @@ extern "C" { #define HDPATH_0_DEFAULT (0x80000000u | 0x2cu) //44 #define HDPATH_1_DEFAULT (0x80000000u | 0x36d) //877 -#define HDPATH_1_TESTNET (0x80000000u | 0x36d) //877 +#define HDPATH_1_TESTNET (0x80000000u | 0x01) //1 #define HDPATH_2_DEFAULT (0x80000000u | 0u) #define HDPATH_3_DEFAULT (0u) diff --git a/app/src/crypto_helper.c b/app/src/crypto_helper.c index 1ca2d11f..3822ae79 100644 --- a/app/src/crypto_helper.c +++ b/app/src/crypto_helper.c @@ -125,6 +125,7 @@ zxerr_t crypto_hashExtraDataSection(const section_t *extraData, uint8_t *output, return zxerr_invalid_crypto_settings; } + const uint32_t extraDataTagLen = extraData->tag.len; #if defined(TARGET_NANOS) || defined(TARGET_NANOS2) || defined(TARGET_NANOX) || defined(TARGET_STAX) cx_sha256_t sha256 = {0}; cx_sha256_init(&sha256); @@ -133,8 +134,8 @@ zxerr_t crypto_hashExtraDataSection(const section_t *extraData, uint8_t *output, CHECK_CX_OK(cx_sha256_update(&sha256, extraData->bytes.ptr, extraData->bytes.len)); uint8_t has_tag = (extraData->tag.ptr == NULL) ? 0 : 1; CHECK_CX_OK(cx_sha256_update(&sha256, &has_tag, 1)); - CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &extraData->tag.len, has_tag*sizeof(extraData->tag.len))); - CHECK_CX_OK(cx_sha256_update(&sha256, extraData->tag.ptr, has_tag*extraData->tag.len)); + CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &extraDataTagLen, has_tag*sizeof(extraDataTagLen))); + CHECK_CX_OK(cx_sha256_update(&sha256, extraData->tag.ptr, has_tag*extraDataTagLen)); CHECK_CX_OK(cx_sha256_final(&sha256, output)); #else picohash_ctx_t sha256 = {0}; @@ -144,8 +145,8 @@ zxerr_t crypto_hashExtraDataSection(const section_t *extraData, uint8_t *output, picohash_update(&sha256, extraData->bytes.ptr, extraData->bytes.len); uint8_t has_tag = (extraData->tag.ptr == NULL) ? 0 : 1; picohash_update(&sha256, &has_tag, 1); - picohash_update(&sha256, (uint8_t*) &extraData->tag.len, has_tag*sizeof(extraData->tag.len)); - picohash_update(&sha256, extraData->tag.ptr, has_tag*extraData->tag.len); + picohash_update(&sha256, (uint8_t*) &extraDataTagLen, has_tag*sizeof(extraDataTagLen)); + picohash_update(&sha256, extraData->tag.ptr, has_tag*extraDataTagLen); picohash_final(&sha256, output); #endif @@ -157,21 +158,22 @@ zxerr_t crypto_hashDataSection(const section_t *data, uint8_t *output, uint32_t return zxerr_no_data; } + const uint32_t dataBytesLen = data->bytes.len; #if defined(TARGET_NANOS) || defined(TARGET_NANOS2) || defined(TARGET_NANOX) || defined(TARGET_STAX) cx_sha256_t sha256 = {0}; cx_sha256_init(&sha256); CHECK_CX_OK(cx_sha256_update(&sha256, &data->discriminant, 1)); CHECK_CX_OK(cx_sha256_update(&sha256, data->salt.ptr, data->salt.len)); - CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &data->bytes.len, sizeof(data->bytes.len))); - CHECK_CX_OK(cx_sha256_update(&sha256, data->bytes.ptr, data->bytes.len)); + CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &dataBytesLen, sizeof(dataBytesLen))); + CHECK_CX_OK(cx_sha256_update(&sha256, data->bytes.ptr, dataBytesLen)); CHECK_CX_OK(cx_sha256_final(&sha256, output)); #else picohash_ctx_t sha256 = {0}; picohash_init_sha256(&sha256); picohash_update(&sha256, &data->discriminant, 1); picohash_update(&sha256, data->salt.ptr, data->salt.len); - picohash_update(&sha256, (uint8_t*) &data->bytes.len, sizeof(data->bytes.len)); - picohash_update(&sha256, data->bytes.ptr, data->bytes.len); + picohash_update(&sha256, (uint8_t*) &dataBytesLen, sizeof(dataBytesLen)); + picohash_update(&sha256, data->bytes.ptr, dataBytesLen); picohash_final(&sha256, output); #endif @@ -183,6 +185,7 @@ zxerr_t crypto_hashCodeSection(const section_t *code, uint8_t *output, uint32_t return zxerr_invalid_crypto_settings; } + const uint32_t codeTagLen = code->tag.len; #if defined(TARGET_NANOS) || defined(TARGET_NANOS2) || defined(TARGET_NANOX) || defined(TARGET_STAX) cx_sha256_t sha256 = {0}; cx_sha256_init(&sha256); @@ -191,8 +194,8 @@ zxerr_t crypto_hashCodeSection(const section_t *code, uint8_t *output, uint32_t CHECK_CX_OK(cx_sha256_update(&sha256, code->bytes.ptr, code->bytes.len)); uint8_t has_tag = (code->tag.ptr == NULL) ? 0 : 1; CHECK_CX_OK(cx_sha256_update(&sha256, &has_tag, 1)); - CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &code->tag.len, has_tag*sizeof(code->tag.len))); - CHECK_CX_OK(cx_sha256_update(&sha256, code->tag.ptr, has_tag*code->tag.len)); + CHECK_CX_OK(cx_sha256_update(&sha256, (uint8_t*) &codeTagLen, has_tag*sizeof(codeTagLen))); + CHECK_CX_OK(cx_sha256_update(&sha256, code->tag.ptr, has_tag*codeTagLen)); CHECK_CX_OK(cx_sha256_final(&sha256, output)); #else picohash_ctx_t sha256 = {0}; @@ -202,8 +205,8 @@ zxerr_t crypto_hashCodeSection(const section_t *code, uint8_t *output, uint32_t picohash_update(&sha256, code->bytes.ptr, code->bytes.len); uint8_t has_tag = (code->tag.ptr == NULL) ? 0 : 1; picohash_update(&sha256, &has_tag, 1); - picohash_update(&sha256, (uint8_t*) &code->tag.len, has_tag*sizeof(code->tag.len)); - picohash_update(&sha256, code->tag.ptr, has_tag*code->tag.len); + picohash_update(&sha256, (uint8_t*) &codeTagLen, has_tag*sizeof(codeTagLen)); + picohash_update(&sha256, code->tag.ptr, has_tag*codeTagLen); picohash_final(&sha256, output); #endif diff --git a/app/src/leb128.c b/app/src/leb128.c index d6c1fdd3..a9ca3270 100644 --- a/app/src/leb128.c +++ b/app/src/leb128.c @@ -53,7 +53,6 @@ zxerr_t decodeLEB128(const uint8_t *input, uint16_t inputSize, uint8_t *consumed if (!(input[i] & 0x80u)) { *consumed = i + 1; return zxerr_ok; - // return i + 1; } shift += 7; diff --git a/app/src/parser_impl_txn.c b/app/src/parser_impl_txn.c index d2328dc7..958b14a0 100644 --- a/app/src/parser_impl_txn.c +++ b/app/src/parser_impl_txn.c @@ -200,8 +200,13 @@ static parser_error_t readBecomeValidatorTxn(bytes_t *data, const section_t *ext // Max commission rate change CHECK_ERROR(readUint256(&ctx, &v->becomeValidator.max_commission_rate_change)); + uint32_t tmpValue = 0; // The validator email - CHECK_ERROR(readUint32(&ctx, &v->becomeValidator.email.len)) + CHECK_ERROR(readUint32(&ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->becomeValidator.email.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(&ctx, &v->becomeValidator.email.ptr, v->becomeValidator.email.len)) /// The validator description @@ -209,8 +214,16 @@ static parser_error_t readBecomeValidatorTxn(bytes_t *data, const section_t *ext v->becomeValidator.description.len = 0; uint8_t has_description = 0; CHECK_ERROR(readByte(&ctx, &has_description)) + if (has_description != 0 && has_description != 1) { + return parser_value_out_of_range; + } + if (has_description) { - CHECK_ERROR(readUint32(&ctx, &v->becomeValidator.description.len)) + CHECK_ERROR(readUint32(&ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->becomeValidator.description.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(&ctx, &v->becomeValidator.description.ptr, v->becomeValidator.description.len)) } @@ -220,7 +233,11 @@ static parser_error_t readBecomeValidatorTxn(bytes_t *data, const section_t *ext uint8_t has_website; CHECK_ERROR(readByte(&ctx, &has_website)) if (has_website) { - CHECK_ERROR(readUint32(&ctx, &v->becomeValidator.website.len)) + CHECK_ERROR(readUint32(&ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->becomeValidator.website.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(&ctx, &v->becomeValidator.website.ptr, v->becomeValidator.website.len)) } @@ -230,7 +247,11 @@ static parser_error_t readBecomeValidatorTxn(bytes_t *data, const section_t *ext uint8_t has_discord_handle; CHECK_ERROR(readByte(&ctx, &has_discord_handle)) if (has_discord_handle) { - CHECK_ERROR(readUint32(&ctx, &v->becomeValidator.discord_handle.len)) + CHECK_ERROR(readUint32(&ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->becomeValidator.discord_handle.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(&ctx, &v->becomeValidator.discord_handle.ptr, v->becomeValidator.discord_handle.len)) } @@ -652,10 +673,15 @@ static parser_error_t readTransferTxn(const bytes_t *data, parser_tx_t *v) { // Amount denomination CHECK_ERROR(readByte(&ctx, &v->transfer.amount_denom)) + uint32_t tmpValue = 0; // Key, check if it is there CHECK_ERROR(readByte(&ctx, &v->transfer.has_key)) if (v->transfer.has_key){ - CHECK_ERROR(readUint32(&ctx, &v->transfer.key.len)) + CHECK_ERROR(readUint32(&ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->transfer.key.len = (uint16_t)tmpValue; // we are not displaying these bytes ctx.offset += v->transfer.key.len; } @@ -701,7 +727,6 @@ static parser_error_t readBondUnbondTxn(const bytes_t *data, parser_tx_t *v) { } __Z_INLINE parser_error_t readTimestamp(parser_context_t *ctx, timestamp_t *timestamp) { - // uint64_t timestampSize = 0; uint8_t consumed = 0; uint64_t tmp = 0; @@ -780,7 +805,6 @@ static parser_error_t readIBCTxn(const bytes_t *data, parser_tx_t *v) { return parser_ok; } -// WrapperTx header parser_error_t readHeader(parser_context_t *ctx, parser_tx_t *v) { if (ctx == NULL || v == NULL) { return parser_unexpected_value; @@ -804,8 +828,14 @@ parser_error_t readHeader(parser_context_t *ctx, parser_tx_t *v) { CHECK_ERROR(readUint32(ctx, &expiration_len)) ctx->offset += expiration_len; } + + uint32_t tmpValue = 0; // Timestamp - CHECK_ERROR(readUint32(ctx, &v->transaction.timestamp.len)) + CHECK_ERROR(readUint32(ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + v->transaction.timestamp.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(ctx, &v->transaction.timestamp.ptr, v->transaction.timestamp.len)) // Code hash @@ -876,8 +906,17 @@ static parser_error_t readExtraDataSection(parser_context_t *ctx, section_t *ext extraData->tag.len = 0; uint8_t has_tag = 0; CHECK_ERROR(readByte(ctx, &has_tag)) + if (has_tag != 0 && has_tag != 1) { + return parser_value_out_of_range; + } + + uint32_t tmpValue = 0; if (has_tag) { - CHECK_ERROR(readUint32(ctx, &extraData->tag.len)) + CHECK_ERROR(readUint32(ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + extraData->tag.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(ctx, &extraData->tag.ptr, extraData->tag.len)) } @@ -964,7 +1003,12 @@ static parser_error_t readDataSection(parser_context_t *ctx, section_t *data) { return parser_unexpected_value; } CHECK_ERROR(readSalt(ctx, &data->salt)) - CHECK_ERROR(readUint32(ctx, &data->bytes.len)) + uint32_t tmpValue = 0; + CHECK_ERROR(readUint32(ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + data->bytes.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(ctx, &data->bytes.ptr, data->bytes.len)) // Must make sure that header dataHash refers to this section's hash @@ -998,8 +1042,17 @@ static parser_error_t readCodeSection(parser_context_t *ctx, section_t *code) { code->tag.len = 0; uint8_t has_tag = 0; CHECK_ERROR(readByte(ctx, &has_tag)) + if (has_tag != 0 && has_tag != 1) { + return parser_value_out_of_range; + } + if (has_tag) { - CHECK_ERROR(readUint32(ctx, &code->tag.len)) + uint32_t tmpValue = 0; + CHECK_ERROR(readUint32(ctx, &tmpValue)); + if (tmpValue > UINT16_MAX) { + return parser_value_out_of_range; + } + code->tag.len = (uint16_t)tmpValue; CHECK_ERROR(readBytes(ctx, &code->tag.ptr, code->tag.len)) } @@ -1049,6 +1102,9 @@ parser_error_t readSections(parser_context_t *ctx, parser_tx_t *v) { v->transaction.sections.signaturesLen = 0; for (uint32_t i = 0; i < v->transaction.sections.sectionLen; i++) { + if (ctx->offset >= ctx->bufferLen) { + return parser_unexpected_error; + } const uint8_t discriminant = *(ctx->buffer + ctx->offset); switch (discriminant) { case DISCRIMINANT_DATA: { diff --git a/app/src/parser_print_common.c b/app/src/parser_print_common.c index 3cb6fe17..75035fc4 100644 --- a/app/src/parser_print_common.c +++ b/app/src/parser_print_common.c @@ -164,67 +164,6 @@ static parser_error_t printAmount64( uint64_t amount, uint8_t amountDenom, const return parser_ok; } -parser_error_t decimal_to_string(int64_t num, uint32_t scale, char* strDec, size_t bufferSize) { - - if (strDec == NULL || bufferSize == 0) { - return parser_invalid_output_buffer; // Invalid output buffer - } - - // Initialize the output buffer - MEMZERO(strDec, bufferSize); - - // Handle negative value - if (num < 0) { - strDec[0] = '-'; - num = -num; - } - - // Convert the integer part to string - size_t index = (num < 0) ? 1 : 0; - int64_t divisor = 1; - for (uint32_t i = 0; i < scale; i++) { - divisor *= 10; - } - - int64_t integerPart = num / divisor; - int64_t fractionalPart = num % divisor; - - if (integerPart == 0) { - CHECK_PTR_BOUNDS(index, bufferSize); - strDec[index++] = '0'; - } else { - int64_t tmp_int = integerPart; - while (tmp_int > 0 && index < bufferSize - 1) { - CHECK_PTR_BOUNDS(index, bufferSize); - strDec[index++] = '0' + (tmp_int % 10); - tmp_int /= 10; - } - - // Reverse the integer part - for (size_t i = (num < 0) ? 1 : 0, j = index - 1; i < j; i++, j--) { - char tmp_char = strDec[i]; - strDec[i] = strDec[j]; - strDec[j] = tmp_char; - } - } - - // Append the decimal point - if (scale > 0 && index < bufferSize - 1) { - CHECK_PTR_BOUNDS(index, bufferSize); - strDec[index++] = '.'; - } - - // Convert the fractional part to string with leading zeros - while (scale > 0 && index < bufferSize - 1) { - divisor /= 10; - CHECK_PTR_BOUNDS(index, bufferSize); - strDec[index++] = '0' + (fractionalPart / divisor); - fractionalPart %= divisor; - scale--; - } - return parser_ok; -} - parser_error_t printPublicKey( const bytes_t *pubkey, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { diff --git a/app/src/parser_types.h b/app/src/parser_types.h index 5ecaaab2..b7281215 100644 --- a/app/src/parser_types.h +++ b/app/src/parser_types.h @@ -65,7 +65,7 @@ typedef struct { typedef struct { const uint8_t *ptr; - uint32_t len; + uint16_t len; } bytes_t; typedef struct { diff --git a/docs/APDUSPEC.md b/docs/APDUSPEC.md index fa530a39..a3f02236 100644 --- a/docs/APDUSPEC.md +++ b/docs/APDUSPEC.md @@ -22,22 +22,51 @@ The general structure of commands and responses is as follows: | ANSWER | byte (?) | Answer | depends on the command | | SW1-SW2 | byte (2) | Return code | see list of return codes | -### Return codes +#### Return codes | Return code | Description | | ----------- | ----------------------- | | 0x6400 | Execution Error | +| 0x6400 | 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 | ---- +## New API + +### GET_DEVICE_INFO + +#### Command -## Command definition +| 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 @@ -53,14 +82,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 | --- @@ -69,31 +99,38 @@ Gets the ED25519 public key and corresponding address #### Command -| Field | Type | Content | Expected | -| ------- | -------- | ------------------------- | ---------- | -| CLA | byte (1) | Application Identifier | 0x57 | -| INS | byte (1) | Instruction ID | 0x01 | -| P1 | byte (1) | Request User confirmation | No = 0 | -| P2 | byte (1) | Signature scheme | Ed25519 = 0 / Secp256k1 = 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 | 434 | -| 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 | 0x57 | +| INS | byte (1) | Instruction ID | 0x01 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | +| L | byte (1) | Bytes in payload | 21 bytes | +| PathLength | byte (1) | Path length | 5 | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 | 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 | 877 | +| Path[2] | byte (4) | Derivation Path Data | ? | +| Path[3] | byte (4) | Derivation Path Data | ? | +| Path[4] | byte (4) | Derivation Path Data | ? | #### Response | Field | Type | Content | Note | | ------- | --------- | ----------- | ------------------------ | | PK | byte (32) | Public Key | | -| ADDR | byte (??) | address | Testnet: 84 / Mainnet: 80 | -| SW1-SW2 | byte (2) | Return code | see list of return codes | + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| Pubkey | byte (33) | Public key | prefix* + pubkey (32) | +| ADDR | byte (45) | Address | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +*prefix is ED25519: 0 | SECP256K1: 1 --- -### INS_SIGN_WRAPPER -Sign wrapper transaction with Ed25519 +### INS_SIGN +Sign transaction with Ed25519 #### Command @@ -113,15 +150,14 @@ 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 | 434 | -| Path[2] | byte (4) | Derivation Path Data | ? | -| Path[3] | byte (4) | Derivation Path Data | ? | -| Path[4] | byte (4) | Derivation Path Data | ? | -| CodeSize | byte (4) | Bytes of Code | ? | -| DataSize | byte (4) | Bytes of Data | ? | +| Field | Type | Content | Expected | +| ------------- | -------- | ------------------------- | ---------------- | +| PathLength | byte (1) | Path length | 5 | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 | 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 | 877 | +| Path[2] | byte (4) | Derivation Path Data | ? | +| Path[3] | byte (4) | Derivation Path Data | ? | +| Path[4] | byte (4) | Derivation Path Data | ? | ##### Other Chunks/Packets @@ -131,8 +167,16 @@ All other packets/chunks contain data chunks that are described below #### Response -| Field | Type | Content | Note | -| ------- | --------- | ----------- | ------------------------ | -| SIG | byte (64) | Signature | | -| SW1-SW2 | byte (2) | Return code | see list of return codes | +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| Pubkey | byte (33) | Public key | prefix* + pubkey (32) | +| RawSalt | byte (8) | raw salt | | +| RawSignature | byte (65) | Raw signature | prefix* + signature(64) | +| WrapperSalt | byte (8) | raw salt | | +| WrapperSignature | byte (65) | Raw signature | prefix* + signature(64) | +| RawIndices | variable | indices for verify raw signature | | +| WrapperIndices | variable | indices for verify wrapper signature | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +*prefix is ED25519: 0 | SECP256K1: 1 diff --git a/tests/parser_impl.cpp b/tests/parser_impl.cpp index b6a71256..9c6d8866 100644 --- a/tests/parser_impl.cpp +++ b/tests/parser_impl.cpp @@ -93,7 +93,7 @@ TEST(LEB128, LEB128Encoding) { for (const auto& testcase : leb128_encoding) { uint8_t encoded[MAX_LEB128_OUTPUT] = {0}; uint8_t bytes = 0; - zxerr_t err = encodeLEB128(testcase.input, (uint8_t*) &encoded, MAX_LEB128_OUTPUT, &bytes); + const zxerr_t err = encodeLEB128(testcase.input, (uint8_t*) &encoded, MAX_LEB128_OUTPUT, &bytes); ASSERT_EQ(err, zxerr_ok); ASSERT_EQ(testcase.consumed, bytes); From ca94352a407989697a50995097db880793f1863e Mon Sep 17 00:00:00 2001 From: ftheirs Date: Thu, 21 Dec 2023 10:03:05 -0300 Subject: [PATCH 2/8] bump version & update snapshots --- app/Makefile.version | 2 +- tests_zemu/snapshots/s-mainmenu/00004.png | Bin 428 -> 429 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 428 -> 429 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 360 -> 364 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 360 -> 364 bytes tests_zemu/snapshots/st-mainmenu/00001.png | Bin 13471 -> 13434 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 360 -> 364 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 360 -> 364 bytes 8 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index f284f298..8c902c71 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=0 # This is the `spec_version` field of `Runtime` APPVERSION_N=0 # This is the patch version of this release -APPVERSION_P=13 +APPVERSION_P=14 diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index 176b46dfe6383c5c67373b58c428315f06bbae9e..113542c5c98a356dd4ce44a41b07365f87fb6150 100644 GIT binary patch delta 403 zcmV;E0c`%P1FZv)B!6^CL_t(|ob8#*5`!=ZMYW^<|G_TWMOumpAgGCPyl1+oF%RVx zg2Mm+0N|;Njn;WDzXj+2W%^%ftxA)h&Fkt1csf(-1>Z|sN`bh``0nBAJ%G&9Z=u={ZGR3;-W=aKKz!9u2cQt&gn3eEHv$Jz2r@*e z3A)S_0b%BBg#!2q$biI6SvJtfx6HGiIBj#z}~uqG-!%&v0)W!48%Y?6`YNt+!)ja?E{fR^ppdq$?G6Hi9> z5wu4993bkz76jGcc!l{CM9*+0a(%F?8hVp=y9HO*f=-7vCw|#6trQUY6uh}f7#;W* x7|&W);|oFcYRFuaVjgUF00000008&o1EKuM;T2|+-V6W$002ovPDHLkV1nZQw%-5% delta 402 zcmV;D0d4-R1FQp(B!6>BL_t(|ob8#*5`r)cMbUx(|6muosK$~eAwgQ=aL>3<=mYX< z5~m3O0Kiqb4ch1V_-wd*f0pl^_Ug3w(cI5|fU7f)-thV0wn@%0Rc2d;ku8f3#HO(8 z#^RYs-~qSg{h8MCB2~3I6Q_ugM_W7%V?ChQG84oOx!9Ke+c2{>G((B;tUeM(krGU_1!JCIf?*3W` wUkK{gL#{Z|sN`bh``0nBAJ%G&9Z=u={ZGR3;-W=aKKz!9u2cQt&gn3eEHv$Jz2r@*e z3A)S_0b%BBg#!2q$biI6SvJtfx6HGiIBj#z}~uqG-!%&v0)W!48%Y?6`YNt+!)ja?E{fR^ppdq$?G6Hi9> z5wu4993bkz76jGcc!l{CM9*+0a(%F?8hVp=y9HO*f=-7vCw|#6trQUY6uh}f7#;W* x7|&W);|oFcYRFuaVjgUF00000008&o1EKuM;T2|+-V6W$002ovPDHLkV1nZQw%-5% delta 402 zcmV;D0d4-R1FQp(B!6>BL_t(|ob8#*5`r)cMbUx(|6muosK$~eAwgQ=aL>3<=mYX< z5~m3O0Kiqb4ch1V_-wd*f0pl^_Ug3w(cI5|fU7f)-thV0wn@%0Rc2d;ku8f3#HO(8 z#^RYs-~qSg{h8MCB2~3I6Q_ugM_W7%V?ChQG84oOx!9Ke+c2{>G((B;tUeM(krGU_1!JCIf?*3W` wUkK{gL#{^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T)1)DVh delta 333 zcmV-T0kZz=0_XyeB!4eSL_t(|obB0Ba)Tfc08rcMO}zh+yh}f58G~qv7TGrMeVM4p z?6Nq*Gywnr000000A0L|ef+X4>0qAc{4*VQdRC{#PkSHTfmio2x&vR9WhusHE{1sidW=_2)i!6uBtw(avn`zjPFh>w*C2vVDQc5d&_-Yt9Y=cgL~Ek8UlNc8`=-5`tp zZ7QJ_{hP_bNM@mtyoX2HhIjC4Xp4hY%=S~osu8V^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T)1)DVh delta 333 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 diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index 0dfb566ac23599114048affd3fd079a580f672ac..081371a5233898b70718863812598461247a717c 100644 GIT binary patch delta 337 zcmaFC^oD7IO1-hCi(^Q|oVPclg_;$390G5>^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T)1)DVh delta 333 zcmV-T0kZz=0_XyeB!4eSL_t(|obB0Ba)Tfc08rcMO}zh+yh}f58G~qv7TGrMeVM4p z?6Nq*Gywnr000000A0L|ef+X4>0qAc{4*VQdRC{#PkSHTfmio2x&vR9WhusHE{1sidW=_2)i!6uBtw(avn`zjPFh>w*C2vVDQc5d&_-Yt9Y=cgL~Ek8UlNc8`=-5`tp zZ7QJ_{hP_bNM@mtyoX2HhIjC4Xp4hY%=S~osu8V^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T)1)DVh delta 333 zcmV-T0kZz=0_XyeB!4eSL_t(|obB0Ba)Tfc08rcMO}zh+yh}f58G~qv7TGrMeVM4p z?6Nq*Gywnr000000A0L|ef+X4>0qAc{4*VQdRC{#PkSHTfmio2x&vR9WhusHE{1sidW=_2)i!6uBtw(avn`zjPFh>w*C2vVDQc5d&_-Yt9Y=cgL~Ek8UlNc8`=-5`tp zZ7QJ_{hP_bNM@mtyoX2HhIjC4Xp4hY%=S~osu8V Date: Thu, 21 Dec 2023 10:45:41 -0300 Subject: [PATCH 3/8] update deps --- deps/ledger-secure-sdk | 2 +- deps/ledger-zxlib | 2 +- js/package.json | 12 ++++++------ tests_zemu/package.json | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/deps/ledger-secure-sdk b/deps/ledger-secure-sdk index 00e153de..86e20d8d 160000 --- a/deps/ledger-secure-sdk +++ b/deps/ledger-secure-sdk @@ -1 +1 @@ -Subproject commit 00e153de17b5f2be271aa09518358b5412d63a18 +Subproject commit 86e20d8dbcee181e11bc2ad7ac3f638eb7dc7b08 diff --git a/deps/ledger-zxlib b/deps/ledger-zxlib index 0a865227..df81cb76 160000 --- a/deps/ledger-zxlib +++ b/deps/ledger-zxlib @@ -1 +1 @@ -Subproject commit 0a865227e4ea08a035cfacb255d5cbb1cad61bfd +Subproject commit df81cb767d464995327218f0fb92eaa2dd3b4db3 diff --git a/js/package.json b/js/package.json index b8e278b4..a087c5f6 100644 --- a/js/package.json +++ b/js/package.json @@ -32,21 +32,21 @@ "url": "https://github.com/zondax/ledger-namada/issues" }, "dependencies": { - "@ledgerhq/hw-transport": "^6.30.0" + "@ledgerhq/hw-transport": "^6.30.1" }, "devDependencies": { "@types/ledgerhq__hw-transport": "^4.21.8", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", "bip32": "^4.0.0", "bip39": "^3.1.0", "core-js": "^3.34.0", "crypto-js": "4.2.0", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-prettier": "^5.1.0", "jest": "^29.7.0", "leb128": "^0.0.5", "prettier": "^3.1.1", diff --git a/tests_zemu/package.json b/tests_zemu/package.json index 165402ab..6a7e3abf 100644 --- a/tests_zemu/package.json +++ b/tests_zemu/package.json @@ -24,16 +24,16 @@ "devDependencies": { "@types/jest": "^29.5.11", "@types/ledgerhq__hw-transport": "^4.21.6", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", "blakejs": "^1.1.1", "crypto-js": "4.2.0", "ed25519-supercop": "^2.0.1", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.4.3", - "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-prettier": "^5.1.0", "jest": "29.7.0", "js-sha256": "0.10.1", "jssha": "^3.3.1", From 9c35a6b978ef22529fd136374bacb1394917118f Mon Sep 17 00:00:00 2001 From: ftheirs Date: Fri, 22 Dec 2023 11:53:53 -0300 Subject: [PATCH 4/8] fix APDUSPEC --- docs/APDUSPEC.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/APDUSPEC.md b/docs/APDUSPEC.md index a3f02236..5b88d1bb 100644 --- a/docs/APDUSPEC.md +++ b/docs/APDUSPEC.md @@ -27,7 +27,7 @@ The general structure of commands and responses is as follows: | Return code | Description | | ----------- | ----------------------- | | 0x6400 | Execution Error | -| 0x6400 | Wrong buffer length | +| 0x6700 | Wrong buffer length | | 0x6982 | Empty buffer | | 0x6983 | Output buffer too small | | 0x6984 | Data is invalid | @@ -107,12 +107,14 @@ Gets the ED25519 public key and corresponding address | P2 | byte (1) | Parameter ignored | | | L | byte (1) | Bytes in payload | 21 bytes | | PathLength | byte (1) | Path length | 5 | -| Path[0] | byte (4) | Derivation Path Data | 0x80000000 | 44 | -| Path[1] | byte (4) | Derivation Path Data | 0x80000000 | 877 | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 \| 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 \| 877* | | Path[2] | byte (4) | Derivation Path Data | ? | | Path[3] | byte (4) | Derivation Path Data | ? | | Path[4] | byte (4) | Derivation Path Data | ? | +*Use 877 for Mainnet and 1 for Testnet + #### Response | Field | Type | Content | Note | @@ -153,12 +155,14 @@ All other packets/chunks contain data chunks that are described below | Field | Type | Content | Expected | | ------------- | -------- | ------------------------- | ---------------- | | PathLength | byte (1) | Path length | 5 | -| Path[0] | byte (4) | Derivation Path Data | 0x80000000 | 44 | -| Path[1] | byte (4) | Derivation Path Data | 0x80000000 | 877 | +| Path[0] | byte (4) | Derivation Path Data | 0x80000000 \| 44 | +| Path[1] | byte (4) | Derivation Path Data | 0x80000000 \| 877* | | Path[2] | byte (4) | Derivation Path Data | ? | | Path[3] | byte (4) | Derivation Path Data | ? | | Path[4] | byte (4) | Derivation Path Data | ? | +*Use 877 for Mainnet and 1 for Testnet + ##### Other Chunks/Packets | Field | Type | Content | Expected | From 35d397ac622b3ca88bc613d2f12f919c7a0f473b Mon Sep 17 00:00:00 2001 From: ftheirs Date: Fri, 22 Dec 2023 11:54:04 -0300 Subject: [PATCH 5/8] bump version & update snapshots --- app/Makefile.version | 2 +- tests_zemu/snapshots/s-mainmenu/00004.png | Bin 429 -> 422 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 429 -> 422 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 364 -> 363 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 364 -> 363 bytes tests_zemu/snapshots/st-mainmenu/00001.png | Bin 13434 -> 13497 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 364 -> 363 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 364 -> 363 bytes 8 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index 8c902c71..46b0b685 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=0 # This is the `spec_version` field of `Runtime` APPVERSION_N=0 # This is the patch version of this release -APPVERSION_P=14 +APPVERSION_P=15 diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index 113542c5c98a356dd4ce44a41b07365f87fb6150..f8cc8a5cff9314fd817211e0c5752a7437244a0f 100644 GIT binary patch delta 396 zcmV;70dxMX1EvFzB!6v5L_t(|ob8#(7J@JgMZp9A|G_MDQH>>SLQ-fc@a}P;*a0#% z3Bv#Y0N|;NjrMsjzYXXA&+xs{UX>Ocu_*c5hM zS-dAY@PKjteulNYNL8uMvQx5=M_Rla+Im2+WhRIMx#*U@bAR!+*c9M>47;<(W^3HV zKBZvs<}?pMl>%{>@!i7NX8@U}-9n`)()sLKyg9ZyAp5AU0YJci2**jGei0bRg&;+g zlAzN}5fEz5mM9>ufD}mFlw|`6CeO98t`$K4xpV+FA$caDB2obRPtgG@P!att1bHS_ zJFP~fb855MtADXHbEJZ+Hy_R2Pf;s^wO@*1f|L4m$^hvedK0~jvk;TA9sSH;rO<(u z(eGNoy@)v)FD^P3(oEZJ)TwyaJ>rNJS6(=ueq>=pn5&z qSd`g3SRasb7sUVo0002on-3g>!|5Jj$z1>d002ovP6b4+LSTXb@4CAH delta 403 zcmV;E0c`%J1FZv)B!6^CL_t(|ob8#*5`!=ZMYW^<|G_TWMOumpAgGCPyl1+oF%RVx zg2Mm+0N|;Njn;WDzXj+2W%^%ftxA)h&Fkt1csf(-1>Z|sN`bh``0nBAJ%G&9Z=u={ZGR3;-W=aKKz!9u2cQt&gn3eEHv$Jz2r@*e z3A)S_0b%BBg#!2q$biI6SvJtfx6HGiIBj#z}~uqG-!%&v0)W!48%Y?6`YNt+!)ja?E{fR^ppdq$?G6Hi9> z5wu4993bkz76jGcc!l{CM9*+0a(%F?8hVp=y9HO*f=-7vCw|#6trQUY6uh}f7#;W* x7|&W);|oFcYRFuaVjgUF00000008&o1EKuM;T2|+-V6W$002ovPDHLkV1n6>SLQ-fc@a}P;*a0#% z3Bv#Y0N|;NjrMsjzYXXA&+xs{UX>Ocu_*c5hM zS-dAY@PKjteulNYNL8uMvQx5=M_Rla+Im2+WhRIMx#*U@bAR!+*c9M>47;<(W^3HV zKBZvs<}?pMl>%{>@!i7NX8@U}-9n`)()sLKyg9ZyAp5AU0YJci2**jGei0bRg&;+g zlAzN}5fEz5mM9>ufD}mFlw|`6CeO98t`$K4xpV+FA$caDB2obRPtgG@P!att1bHS_ zJFP~fb855MtADXHbEJZ+Hy_R2Pf;s^wO@*1f|L4m$^hvedK0~jvk;TA9sSH;rO<(u z(eGNoy@)v)FD^P3(oEZJ)TwyaJ>rNJS6(=ueq>=pn5&z qSd`g3SRasb7sUVo0002on-3g>!|5Jj$z1>d002ovP6b4+LSTXb@4CAH delta 403 zcmV;E0c`%J1FZv)B!6^CL_t(|ob8#*5`!=ZMYW^<|G_TWMOumpAgGCPyl1+oF%RVx zg2Mm+0N|;Njn;WDzXj+2W%^%ftxA)h&Fkt1csf(-1>Z|sN`bh``0nBAJ%G&9Z=u={ZGR3;-W=aKKz!9u2cQt&gn3eEHv$Jz2r@*e z3A)S_0b%BBg#!2q$biI6SvJtfx6HGiIBj#z}~uqG-!%&v0)W!48%Y?6`YNt+!)ja?E{fR^ppdq$?G6Hi9> z5wu4993bkz76jGcc!l{CM9*+0a(%F?8hVp=y9HO*f=-7vCw|#6trQUY6uh}f7#;W* x7|&W);|oFcYRFuaVjgUF00000008&o1EKuM;T2|+-V6W$002ovPDHLkV1n6sN==^8W8X)}l z^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T-_?tKY diff --git a/tests_zemu/snapshots/sp-mainmenu/00010.png b/tests_zemu/snapshots/sp-mainmenu/00010.png index 081371a5233898b70718863812598461247a717c..acebea87e7b4532d3e948605030e1364ea485036 100644 GIT binary patch delta 336 zcmaFE^qOgcO1+V%i(^Q|oVPavg_;xu8WOX1aelWKDu3CS!qXTKQ+D=$^(K)NF|q7Y zJ_ZEnsCaSDu0?=<&-a(fHe$P`2Rv`L-O652uK$*?rbS@W)|rzIubq~=M`!KRB&Jl~ zP4A`WuHG=4vF_o%$5WSOS*IUWJ34pywVyR=Mhf-op6Up&Ke`n6vUx7I;Vj0?o8R8^ z|Mlf7(K~*Mh2!WUr;gj7I1MJv&Mbc?@4wdb?aw`{KX3lCWAVfn|F>sN==^8W8X)}l z^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T-_?tKY diff --git a/tests_zemu/snapshots/st-mainmenu/00001.png b/tests_zemu/snapshots/st-mainmenu/00001.png index 7c353af9595a0e901e82ed1fed0cc0420a2f2c38..888c8556342320e911412b7b36b82fea8c91bd2d 100644 GIT binary patch literal 13497 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 diff --git a/tests_zemu/snapshots/x-mainmenu/00010.png b/tests_zemu/snapshots/x-mainmenu/00010.png index 081371a5233898b70718863812598461247a717c..acebea87e7b4532d3e948605030e1364ea485036 100644 GIT binary patch delta 336 zcmaFE^qOgcO1+V%i(^Q|oVPavg_;xu8WOX1aelWKDu3CS!qXTKQ+D=$^(K)NF|q7Y zJ_ZEnsCaSDu0?=<&-a(fHe$P`2Rv`L-O652uK$*?rbS@W)|rzIubq~=M`!KRB&Jl~ zP4A`WuHG=4vF_o%$5WSOS*IUWJ34pywVyR=Mhf-op6Up&Ke`n6vUx7I;Vj0?o8R8^ z|Mlf7(K~*Mh2!WUr;gj7I1MJv&Mbc?@4wdb?aw`{KX3lCWAVfn|F>sN==^8W8X)}l z^t3}Z1y!J|tm&QHJECx4Gh=<7MD-6`qwf}UPCHe{+#iuYr>C^)^!-#+4}f}49o$?b1H z7w+|NfBHDW^T2|L2#&(oSq#d_!D-LGeVfuX<=XSusq<4G_qi>y-<~v~^IxjbLbYGw z%Ivddw3=+>%l@_hLztY{ZvDB}cDz*mZMj=7m3i%_H}UCDeSiFLo1n4x?>h7MIvXZ6 zJiYg+!{cVpzRg~f8*cA%Wl9NMp~D~LQ^VgeZT>F5^^tvN&$+6l*q>IJe>h5SZGGN6 ec7*2{CRZ{W|9`#XFmJILNYvBS&t;ucLK6T-_?tKY From 58a7e1b6002a52ed680ce8e494f751574170c992 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Fri, 22 Dec 2023 12:08:23 -0300 Subject: [PATCH 6/8] remove rust code --- app/rust/.gitignore | 1 - app/rust/Cargo.toml | 47 ------- app/rust/include/rslib.h | 8 -- app/rust/src/bolos.rs | 84 ------------ app/rust/src/lib.rs | 281 --------------------------------------- 5 files changed, 421 deletions(-) delete mode 100644 app/rust/.gitignore delete mode 100644 app/rust/Cargo.toml delete mode 100644 app/rust/include/rslib.h delete mode 100644 app/rust/src/bolos.rs delete mode 100644 app/rust/src/lib.rs diff --git a/app/rust/.gitignore b/app/rust/.gitignore deleted file mode 100644 index 2f7896d1..00000000 --- a/app/rust/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/app/rust/Cargo.toml b/app/rust/Cargo.toml deleted file mode 100644 index 08fcd9f2..00000000 --- a/app/rust/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -authors = ["Zondax AG "] -name = "rslib" -version = "0.1.0" -edition = "2018" -readme = "README.md" - -[lib] -name = "rslib" -crate-type = ["staticlib"] - -[dependencies] -rand={ version = "0.7.3", default-features = false} -merlin = {version = "2.0.0", default-features=false} -zeroize = {version = "1.1.1", default-features=false} - -[target.'cfg(target_arch = "x86_64")'.dependencies] -getrandom = {version="0.1.14", default-features=false} - -[dependencies.curve25519-dalek] -version = "3.0.0" -default-features = false -features=["u32_backend"] - -[dependencies.schnorrkel] -version = "0.9.1" -default-features = false -features=["u32_backend"] - -[dev-dependencies] -hex-literal = "0.2.1" -hex = "0.4.2" -env_logger = "0.7.1" -log = "0.4.8" - -[target.thumbv6m-none-eabi.dev-dependencies] -panic-halt = "0.2.0" - -[profile.release] -lto=false -codegen-units = 1 -debug=true -opt-level = "s" - -[profile.dev] -panic = "abort" - diff --git a/app/rust/include/rslib.h b/app/rust/include/rslib.h deleted file mode 100644 index 8e26766e..00000000 --- a/app/rust/include/rslib.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -void get_sr25519_sk(uint8_t *sk_ed25519_expanded); - -void sign_sr25519_phase1(const uint8_t *sk_ed25519_expanded, const uint8_t *pk, const uint8_t *context_ptr, uint32_t context_len, const uint8_t *msg_ptr, uint32_t msg_len, uint8_t *sig_ptr); -void sign_sr25519_phase2(const uint8_t *sk_ed25519_expanded, const uint8_t *pk, const uint8_t *context_ptr, uint32_t context_len, const uint8_t *msg_ptr, uint32_t msg_len, uint8_t *sig_ptr); diff --git a/app/rust/src/bolos.rs b/app/rust/src/bolos.rs deleted file mode 100644 index 5a1a48b5..00000000 --- a/app/rust/src/bolos.rs +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* -* (c) 2018 - 2022 Zondax AG -* -* 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. -********************************************************************************/ -//! Rust interfaces to Ledger SDK APIs. -#[cfg(test)] -use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; -use curve25519_dalek::scalar::Scalar; -#[cfg(test)] -#[cfg(target_arch = "x86_64")] -use getrandom::getrandom; -use merlin::TranscriptRng; -use rand::{CryptoRng, RngCore}; - -extern "C" { - fn cx_rng(buffer: *mut u8, len: u32); - fn zemu_log_stack(buffer: *const u8); - fn check_app_canary(); -} - -#[cfg(not(test))] -pub fn c_zemu_log_stack(s: &[u8]) { - unsafe { zemu_log_stack(s.as_ptr()) } -} - -#[cfg(test)] -pub fn c_zemu_log_stack(s: &[u8]) {} - -pub fn c_check_app_canary() { - unsafe { check_app_canary() } -} - -pub struct Trng; - -impl RngCore for Trng { - fn next_u32(&mut self) -> u32 { - let mut out = [0; 4]; - self.fill_bytes(&mut out); - u32::from_le_bytes(out) - } - - fn next_u64(&mut self) -> u64 { - let mut out = [0; 8]; - self.fill_bytes(&mut out); - u64::from_le_bytes(out) - } - - #[cfg(not(target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - c_zemu_log_stack(b"fill_bytes\x00".as_ref()); - - unsafe { - cx_rng(dest.as_mut_ptr(), dest.len() as u32); - } - } - - #[cfg(target_arch = "x86_64")] - #[cfg(test)] - fn fill_bytes(&mut self, dest: &mut [u8]) { - getrandom(dest); - } - - #[cfg(target_arch = "x86_64")] - #[cfg(not(test))] - fn fill_bytes(&mut self, _dest: &mut [u8]) {} - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { - self.fill_bytes(dest); - Ok(()) - } -} - -impl CryptoRng for Trng {} diff --git a/app/rust/src/lib.rs b/app/rust/src/lib.rs deleted file mode 100644 index 7e5afe27..00000000 --- a/app/rust/src/lib.rs +++ /dev/null @@ -1,281 +0,0 @@ -/******************************************************************************* -* (c) 2018 - 2022 Zondax AG -* -* 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. -********************************************************************************/ -#![no_std] -#![no_builtins] -#![allow(dead_code, unused_imports)] - -extern crate core; -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -use core::convert::TryInto; -use core::mem; -use core::panic::PanicInfo; -use core::slice::{from_raw_parts, from_raw_parts_mut}; - -use curve25519_dalek::scalar::Scalar; -use merlin::{Transcript, TranscriptRng, TranscriptRngBuilder}; -use rand::RngCore; -use schnorrkel::context::{SigningContext, SigningTranscript}; -use schnorrkel::{PublicKey, SecretKey}; -use zeroize::Zeroize; - -use crate::bolos::*; - -mod bolos; - -fn debug(_msg: &str) {} - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -#[inline(never)] -fn mult_with_secret(k: &mut Scalar, sk: &[u8]) { - let mut skbytes = [0u8; 32]; - skbytes.copy_from_slice(&sk[0..32]); - let s = Scalar::from_bits(skbytes); - *k *= s; -} - -#[inline(never)] -fn add_witness(k: &mut Scalar, x: [u8; 32]) -> [u8; 32] { - let r = Scalar::from_bits(x); - *k += r; - k.to_bytes() -} - -#[inline(never)] -fn get_challenge_scalar(k: &mut Scalar, tr: &mut Transcript) { - let mut kbytes = [0u8; 64]; - tr.challenge_bytes(b"sign:c", &mut kbytes); - *k += Scalar::from_bytes_mod_order_wide(&kbytes); -} - -#[inline(never)] -fn get_witness_bytes_custom(br: &mut Transcript, nonce_seeds: &[&[u8]]) -> [u8; 32] { - c_zemu_log_stack(b"witness_bytes\x00".as_ref()); - let mut x = [0u8; 32]; - for ns in nonce_seeds { - br.append_message(b"nonce-bytes", ns); - } - { - let random_bytes = { - let mut bytes = [0u8; 32]; - Trng.fill_bytes(&mut bytes); - bytes - }; - br.append_message(b"rng", &random_bytes); - } - br.challenge_bytes(b"witness-bytes", &mut x); - br.zeroize(); - x -} - -#[no_mangle] -pub extern "C" fn sign_sr25519_phase1( - sk_ristretto_expanded_ptr: *const u8, - pk_ptr: *const u8, - context_ptr: *const u8, - context_len: usize, - msg_ptr: *const u8, - msg_len: usize, - sig_ptr: *mut u8, -) { - c_zemu_log_stack(b"sign_sr25519\x00".as_ref()); - - let sk_ristretto_expanded = - unsafe { from_raw_parts(sk_ristretto_expanded_ptr as *const u8, 64) }; - let pk = unsafe { from_raw_parts(pk_ptr as *const u8, 32) }; - let context = unsafe { from_raw_parts(context_ptr as *const u8, context_len) }; - let message = unsafe { from_raw_parts(msg_ptr as *const u8, msg_len) }; - let signature = unsafe { from_raw_parts_mut(sig_ptr as *mut u8, 64) }; - - let mut signtranscript = Transcript::new(b"SigningContext"); - signtranscript.append_message(b"", context); - signtranscript.append_message(b"sign-bytes", message); - signtranscript.append_message(b"proto-name", b"Schnorr-sig"); //proto name - signtranscript.append_message(b"sign:pk", pk); //commitpoint: pk - - let x = get_witness_bytes_custom(&mut signtranscript, &[&sk_ristretto_expanded[32..]]); - signature[32..64].copy_from_slice(&x); -} - -#[no_mangle] -pub extern "C" fn sign_sr25519_phase2( - sk_ristretto_expanded_ptr: *const u8, - pk_ptr: *const u8, - context_ptr: *const u8, - context_len: usize, - msg_ptr: *const u8, - msg_len: usize, - sig_ptr: *mut u8, -) { - c_zemu_log_stack(b"sign_sr25519\x00".as_ref()); - - let sk_ristretto_expanded = - unsafe { from_raw_parts(sk_ristretto_expanded_ptr as *const u8, 64) }; - let pk = unsafe { from_raw_parts(pk_ptr as *const u8, 32) }; - let context = unsafe { from_raw_parts(context_ptr as *const u8, context_len) }; - let message = unsafe { from_raw_parts(msg_ptr as *const u8, msg_len) }; - let signature = unsafe { from_raw_parts_mut(sig_ptr as *mut u8, 64) }; - - let mut signtranscript = Transcript::new(b"SigningContext"); - signtranscript.append_message(b"", context); - signtranscript.append_message(b"sign-bytes", message); - signtranscript.append_message(b"proto-name", b"Schnorr-sig"); //proto name - signtranscript.append_message(b"sign:pk", pk); //commitpoint: pk - signtranscript.append_message(b"sign:R", &signature[0..32]); //commitpoint: pk - - let mut x = [0u8; 32]; - x.copy_from_slice(&signature[32..64]); - - let mut k = Scalar::zero(); - get_challenge_scalar(&mut k, &mut signtranscript); - - mult_with_secret(&mut k, sk_ristretto_expanded); - signature[32..].copy_from_slice(&add_witness(&mut k, x)); - signature[63] |= 128; -} - -#[no_mangle] -pub extern "C" fn get_sr25519_sk(sk_ed25519_expanded_ptr: *mut u8) { - let sk_ed25519_expanded = unsafe { from_raw_parts_mut(sk_ed25519_expanded_ptr as *mut u8, 64) }; - let secret: SecretKey = SecretKey::from_ed25519_bytes(&sk_ed25519_expanded[..]).unwrap(); - sk_ed25519_expanded.copy_from_slice(&secret.to_bytes()); -} - -#[cfg(test)] -mod tests { - use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; - use curve25519_dalek::edwards::EdwardsPoint; - use curve25519_dalek::scalar::Scalar; - use log::{debug, info}; - use schnorrkel::{context::*, Keypair, PublicKey, SecretKey, Signature}; - - use crate::*; - use core::ops::Mul; - - fn init_logging() { - let _ = env_logger::builder().is_test(true).try_init(); - } - - fn ristretto_scalarmult(sk: &[u8], pk: &mut [u8]) { - let mut seckey = [0u8; 32]; - seckey.copy_from_slice(&sk[0..32]); - let pubkey = RISTRETTO_BASEPOINT_POINT - .mul(Scalar::from_bits(seckey)) - .compress() - .0; - pk.copy_from_slice(&pubkey); - } - - #[test] - fn test_sign_verify() { - let mut sk_ed25519_expanded = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - ]; - - let pk_expected = "b65abc66a8fdeac1197d03daa6c3791d0c0799a52db6b7127b1cd12d46e34364"; - - let secret = SecretKey::from_ed25519_bytes(&sk_ed25519_expanded).unwrap(); - - let mut pk = [0u8; 32]; - get_sr25519_sk(sk_ed25519_expanded.as_mut_ptr()); - - ristretto_scalarmult(&sk_ed25519_expanded, &mut pk); - - assert_eq!(hex::encode(pk), pk_expected); - - let context = b"good"; - let msg = b"test message"; - let mut signature = [0u8; 64]; - - sign_sr25519_phase1( - secret.to_bytes().as_ptr(), - pk.as_ptr(), - context.as_ptr(), - context.len(), - msg.as_ptr(), - msg.len(), - signature.as_mut_ptr(), - ); - - let mut x = [0u8; 32]; - x.copy_from_slice(&signature[32..64]); - - ristretto_scalarmult(&x, &mut signature[0..32]); - - sign_sr25519_phase2( - secret.to_bytes().as_ptr(), - pk.as_ptr(), - context.as_ptr(), - context.len(), - msg.as_ptr(), - msg.len(), - signature.as_mut_ptr(), - ); - - let keypair: Keypair = Keypair::from(secret); - - let mut sigledger = [0u8; 64]; - hex::decode_to_slice("48fdbe5cf3524bdd078ac711565d658a3053d10660749959883c4710f49d9948b2d5f829bea6800897dc6ea0150ca11075cc36b75bfcf3712aafb8e1bd10bf8f",&mut sigledger).expect("dec"); - - let self_sig = Signature::from_bytes(&signature).unwrap(); - let self_sig_ledger = Signature::from_bytes(&sigledger).unwrap(); - - let vers = signing_context(context); - - assert!( - keypair.verify(vers.bytes(msg), &self_sig).is_ok(), - "Verification of a valid signature failed!" - ); - assert!( - keypair.verify(vers.bytes(msg), &self_sig_ledger).is_ok(), - "Verification of a valid signature from ledger failed!" - ); - } - - #[test] - fn get_public_key_c() { - init_logging(); - - let mut sk_ed25519_expanded = [ - 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, - 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, - 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, - 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, - 04, 0x5, 0x06, 0x07, - ]; - - let pk_expected = "b65abc66a8fdeac1197d03daa6c3791d0c0799a52db6b7127b1cd12d46e34364"; - - let mut pk = [0u8; 32]; - get_sr25519_sk(sk_ed25519_expanded.as_mut_ptr()); - - ristretto_scalarmult(&sk_ed25519_expanded, &mut pk); - - info!("{:?}", hex::encode(pk)); - assert_eq!(hex::encode(pk), pk_expected); - } -} From e633494094fe575698fb13a1e951a867291643a9 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Wed, 3 Jan 2024 13:44:41 -0300 Subject: [PATCH 7/8] add testnet derivation path --- app/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile b/app/Makefile index 09300dad..a344ded2 100755 --- a/app/Makefile +++ b/app/Makefile @@ -42,7 +42,7 @@ ifeq ($(COIN),NAM) # Main app configuration DEFINES += APP_STANDARD APPNAME = "Namada" -APPPATH = "44'/877'" +APPPATH = "44'/877'" --path "44'/1'" else define error_message From 9bc975be831fa41f2c7d68c5f2146593c43d3023 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Wed, 3 Jan 2024 13:44:54 -0300 Subject: [PATCH 8/8] bump version & update snapshots --- app/Makefile.version | 2 +- tests_zemu/snapshots/s-mainmenu/00004.png | Bin 422 -> 422 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 422 -> 422 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 363 -> 363 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 363 -> 363 bytes tests_zemu/snapshots/st-mainmenu/00001.png | Bin 13497 -> 13521 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 363 -> 363 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 363 -> 363 bytes 8 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index 46b0b685..c4e0175c 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=0 # This is the `spec_version` field of `Runtime` APPVERSION_N=0 # This is the patch version of this release -APPVERSION_P=15 +APPVERSION_P=16 diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index f8cc8a5cff9314fd817211e0c5752a7437244a0f..dc7d1913482655252c0c4abb9efd535ac89e1676 100644 GIT binary patch delta 386 zcmV-|0e$|a1EvFzEq~D#f*=frv7_(*z+Th^wQ!6%P;lk{oi0jY=r#uYg#Z8m;I2%A z#(A!v0hjO3_`TCuos6H&vJM-uPpDWKznj9fX+t`e9S)4$u3%jlu_k@EPFfH#- z*!qh?mB&o%B37P~aW{;e0Wp`EBO3goXZk_oW3dIG_BHI2J%3GG<0$qn4aSEvyaaVB z#4hW*g{#*9N>6)+mb#SI=PKjFv7H0NSFLIQ3e+#c>84P>2nk!alD|Ox3^1l) z3Tbeu!h8y%h8nz8j+REdT%j07*qoM6N<$f>q?Tx&QzG delta 386 zcmV-|0e$|a1EvFzEq}=tf-nq4!2|#Q!7Ox9jU{bDQfMjg?s1{m0WviS!vFvP;Hiv_ z_IWSA4d?&Q@V(Mrl@>pm*V#Albf(rDz87wr?rC{;qG!H?Q z0&$n|-NM;t0GX%VLZvCv`RrP}Ikq|=`>3t~K)`-_&h7<0o>mHQy$aquB>L{Jxv+(xdOhS=l-WF3ACPhv g#Q*>R007*Z4;+NU=^kOpT>t<807*qoM6N<$g7|i}ivR!s diff --git a/tests_zemu/snapshots/s-mainmenu/00010.png b/tests_zemu/snapshots/s-mainmenu/00010.png index f8cc8a5cff9314fd817211e0c5752a7437244a0f..dc7d1913482655252c0c4abb9efd535ac89e1676 100644 GIT binary patch delta 386 zcmV-|0e$|a1EvFzEq~D#f*=frv7_(*z+Th^wQ!6%P;lk{oi0jY=r#uYg#Z8m;I2%A z#(A!v0hjO3_`TCuos6H&vJM-uPpDWKznj9fX+t`e9S)4$u3%jlu_k@EPFfH#- z*!qh?mB&o%B37P~aW{;e0Wp`EBO3goXZk_oW3dIG_BHI2J%3GG<0$qn4aSEvyaaVB z#4hW*g{#*9N>6)+mb#SI=PKjFv7H0NSFLIQ3e+#c>84P>2nk!alD|Ox3^1l) z3Tbeu!h8y%h8nz8j+REdT%j07*qoM6N<$f>q?Tx&QzG delta 386 zcmV-|0e$|a1EvFzEq}=tf-nq4!2|#Q!7Ox9jU{bDQfMjg?s1{m0WviS!vFvP;Hiv_ z_IWSA4d?&Q@V(Mrl@>pm*V#Albf(rDz87wr?rC{;qG!H?Q z0&$n|-NM;t0GX%VLZvCv`RrP}Ikq|=`>3t~K)`-_&h7<0o>mHQy$aquB>L{Jxv+(xdOhS=l-WF3ACPhv g#Q*>R007*Z4;+NU=^kOpT>t<807*qoM6N<$g7|i}ivR!s diff --git a/tests_zemu/snapshots/sp-mainmenu/00004.png b/tests_zemu/snapshots/sp-mainmenu/00004.png index acebea87e7b4532d3e948605030e1364ea485036..09f644da94f18f1c5b08c4951969651421e6735b 100644 GIT binary patch delta 327 zcmaFO^qOgcZhf>^lY&4);;Svf-}kG0yTp8Q<3k~@$38#n{bx1Kkvt&f%zy;6^0sa7 zH(b`78u=;HDs0#Epy%y(*RmIs^1o)>b423koip9aIm>c?Ma?^Xl~rX{$9e0yvp?)+ znig8oAMO`Ab92_@SLZIj`ctD9<}mBDk^uXoOY`erPM)h>xQpr27TNpq$7ajCi0Pls zqH*+)bI0!#ra5cQ?y>IgUw(DT*P44*e{QeYv3T-}|J&0hbpFfKTB!C*U73B_jaHqH zGTTDhuJ4etS`>WrPN}CzpMlGilCoGKQI)ld=RSV&w-7O$#d(weY@s{njcLQQ$TfJ)E%*?;@UdF7NS5=MVbp{4o|FU_v UvRYTSRe^*(UHx3vIVCg!01DNa^Z)<= delta 327 zcmaFO^qOgcZhfFolY&4)V%9Fs@Ag9FFB?;M8Utd=&i=37B$6T~mR-unfB+p8FYej3 z2=MRu{xaD{Y}fRF=k2yz*$c|`-!j&;2yEIqbJF3p({lIdtbLlql2(r>ar~B^rLD==PtkYvqsHGVck<50rp3i;$GG_&*e6p#h7{X+k5`MzI-Km$4{|v z96jXJar+ae!KB%l_J2OfQ6pSt`51h-0j=r=2W)OG%thc+S8}GON(P7 z=G=a(Abj-#XO{y%GdEA_0o$9W8ou7vd%N*Y=*P1@Z@>FI4*BSn{hJ@*cZLa{*|_)J UH#GKl>jH^-y85}Sb4q9e0P2^O`v3p{ diff --git a/tests_zemu/snapshots/sp-mainmenu/00010.png b/tests_zemu/snapshots/sp-mainmenu/00010.png index acebea87e7b4532d3e948605030e1364ea485036..09f644da94f18f1c5b08c4951969651421e6735b 100644 GIT binary patch delta 327 zcmaFO^qOgcZhf>^lY&4);;Svf-}kG0yTp8Q<3k~@$38#n{bx1Kkvt&f%zy;6^0sa7 zH(b`78u=;HDs0#Epy%y(*RmIs^1o)>b423koip9aIm>c?Ma?^Xl~rX{$9e0yvp?)+ znig8oAMO`Ab92_@SLZIj`ctD9<}mBDk^uXoOY`erPM)h>xQpr27TNpq$7ajCi0Pls zqH*+)bI0!#ra5cQ?y>IgUw(DT*P44*e{QeYv3T-}|J&0hbpFfKTB!C*U73B_jaHqH zGTTDhuJ4etS`>WrPN}CzpMlGilCoGKQI)ld=RSV&w-7O$#d(weY@s{njcLQQ$TfJ)E%*?;@UdF7NS5=MVbp{4o|FU_v UvRYTSRe^*(UHx3vIVCg!01DNa^Z)<= delta 327 zcmaFO^qOgcZhfFolY&4)V%9Fs@Ag9FFB?;M8Utd=&i=37B$6T~mR-unfB+p8FYej3 z2=MRu{xaD{Y}fRF=k2yz*$c|`-!j&;2yEIqbJF3p({lIdtbLlql2(r>ar~B^rLD==PtkYvqsHGVck<50rp3i;$GG_&*e6p#h7{X+k5`MzI-Km$4{|v z96jXJar+ae!KB%l_J2OfQ6pSt`51h-0j=r=2W)OG%thc+S8}GON(P7 z=G=a(Abj-#XO{y%GdEA_0o$9W8ou7vd%N*Y=*P1@Z@>FI4*BSn{hJ@*cZLa{*|_)J UH#GKl>jH^-y85}Sb4q9e0P2^O`v3p{ diff --git a/tests_zemu/snapshots/st-mainmenu/00001.png b/tests_zemu/snapshots/st-mainmenu/00001.png index 888c8556342320e911412b7b36b82fea8c91bd2d..e9f10b43e96ae8387077caa8516892f9dfde6cc3 100644 GIT binary patch literal 13521 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 literal 13497 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 UvRYTSRe^*(UHx3vIVCg!01DNa^Z)<= delta 327 zcmaFO^qOgcZhfFolY&4)V%9Fs@Ag9FFB?;M8Utd=&i=37B$6T~mR-unfB+p8FYej3 z2=MRu{xaD{Y}fRF=k2yz*$c|`-!j&;2yEIqbJF3p({lIdtbLlql2(r>ar~B^rLD==PtkYvqsHGVck<50rp3i;$GG_&*e6p#h7{X+k5`MzI-Km$4{|v z96jXJar+ae!KB%l_J2OfQ6pSt`51h-0j=r=2W)OG%thc+S8}GON(P7 z=G=a(Abj-#XO{y%GdEA_0o$9W8ou7vd%N*Y=*P1@Z@>FI4*BSn{hJ@*cZLa{*|_)J UH#GKl>jH^-y85}Sb4q9e0P2^O`v3p{ diff --git a/tests_zemu/snapshots/x-mainmenu/00010.png b/tests_zemu/snapshots/x-mainmenu/00010.png index acebea87e7b4532d3e948605030e1364ea485036..09f644da94f18f1c5b08c4951969651421e6735b 100644 GIT binary patch delta 327 zcmaFO^qOgcZhf>^lY&4);;Svf-}kG0yTp8Q<3k~@$38#n{bx1Kkvt&f%zy;6^0sa7 zH(b`78u=;HDs0#Epy%y(*RmIs^1o)>b423koip9aIm>c?Ma?^Xl~rX{$9e0yvp?)+ znig8oAMO`Ab92_@SLZIj`ctD9<}mBDk^uXoOY`erPM)h>xQpr27TNpq$7ajCi0Pls zqH*+)bI0!#ra5cQ?y>IgUw(DT*P44*e{QeYv3T-}|J&0hbpFfKTB!C*U73B_jaHqH zGTTDhuJ4etS`>WrPN}CzpMlGilCoGKQI)ld=RSV&w-7O$#d(weY@s{njcLQQ$TfJ)E%*?;@UdF7NS5=MVbp{4o|FU_v UvRYTSRe^*(UHx3vIVCg!01DNa^Z)<= delta 327 zcmaFO^qOgcZhfFolY&4)V%9Fs@Ag9FFB?;M8Utd=&i=37B$6T~mR-unfB+p8FYej3 z2=MRu{xaD{Y}fRF=k2yz*$c|`-!j&;2yEIqbJF3p({lIdtbLlql2(r>ar~B^rLD==PtkYvqsHGVck<50rp3i;$GG_&*e6p#h7{X+k5`MzI-Km$4{|v z96jXJar+ae!KB%l_J2OfQ6pSt`51h-0j=r=2W)OG%thc+S8}GON(P7 z=G=a(Abj-#XO{y%GdEA_0o$9W8ou7vd%N*Y=*P1@Z@>FI4*BSn{hJ@*cZLa{*|_)J UH#GKl>jH^-y85}Sb4q9e0P2^O`v3p{