diff --git a/.gitmodules b/.gitmodules index 0087d7bd..005ec08c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,7 @@ url = https://github.com/LedgerHQ/ledger-secure-sdk [submodule "deps/blake2"] path = deps/blake2 - url = https://github.com/Zondax/BLAKE2.git \ No newline at end of file + url = https://github.com/Zondax/BLAKE2.git +[submodule "js"] + path = js + url = https://github.com/Zondax/ledger-namada-js diff --git a/app/Makefile.version b/app/Makefile.version index 7986a844..822fe8aa 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -1,6 +1,6 @@ # This is the `transaction_version` field of `Runtime` -APPVERSION_M=0 +APPVERSION_M=1 # This is the `spec_version` field of `Runtime` APPVERSION_N=0 # This is the patch version of this release -APPVERSION_P=28 +APPVERSION_P=0 diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index 8d6f139a..7c2678e1 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -121,6 +121,7 @@ __Z_INLINE void handleSignTransaction(volatile uint32_t *flags, volatile uint32_ CHECK_APP_CANARY() view_review_init(tx_getItem, tx_getNumItems, app_sign); view_review_show(REVIEW_TXN); + transaction_reset(); *flags |= IO_ASYNCH_REPLY; } diff --git a/app/src/common/actions.h b/app/src/common/actions.h index 4efa5534..23410cfd 100644 --- a/app/src/common/actions.h +++ b/app/src/common/actions.h @@ -67,6 +67,10 @@ __Z_INLINE zxerr_t app_fill_randomness(masp_type_e type) { zemu_log("app_fill_randomness\n"); MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (get_state() != STATE_INITIAL && get_state() != STATE_PROCESSED_RANDOMNESS) { + return zxerr_unknown; + } + cmdResponseLen = 0; zxerr_t err = crypto_computeRandomness(type, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, &cmdResponseLen); @@ -75,6 +79,7 @@ __Z_INLINE zxerr_t app_fill_randomness(masp_type_e type) { THROW(APDU_CODE_DATA_INVALID); } + set_state(STATE_PROCESSED_RANDOMNESS); return err; } diff --git a/app/src/crypto.c b/app/src/crypto.c index 1678fd3c..e18abd82 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -412,6 +412,11 @@ zxerr_t crypto_sign(const parser_tx_t *txObj, uint8_t *output, uint16_t outputLe // Include Masp hash in the signature if it's there if (txObj->transaction.isMasp) { +#if !defined(APP_TESTING) + if (get_state() != STATE_EXTRACT_SPENDS) { + return zxerr_unknown; + } +#endif const uint8_t *maspSection = txObj->transaction.sections.maspTx.masptx_ptr; uint64_t maspSectionLen = txObj->transaction.sections.maspTx.masptx_len; uint8_t *maspHash = section_hashes.hashes.ptr + (section_hashes.hashesLen * HASH_LEN); @@ -723,7 +728,7 @@ zxerr_t crypto_sign_spends_sapling(const parser_tx_t *txObj, keys_t *keys) { } zxerr_t crypto_extract_spend_signature(uint8_t *buffer, uint16_t bufferLen, uint16_t *cmdResponseLen) { - if (!spend_signatures_more_extract()) { + if (!spend_signatures_more_extract() || (get_state() != STATE_SIGNED_SPENDS && get_state() != STATE_EXTRACT_SPENDS)) { zemu_log_stack("crypto_extract_spend_signature: no more signatures"); return zxerr_unknown; } @@ -733,19 +738,33 @@ zxerr_t crypto_extract_spend_signature(uint8_t *buffer, uint16_t bufferLen, uint return get_next_spend_signature(buffer); } -parser_error_t checkSpends(const parser_tx_t *txObj, keys_t *keys, parser_context_t *builder_spends_ctx, parser_context_t *tx_spends_ctx) { +parser_error_t checkSpends(const parser_tx_t *txObj, keys_t *keys, parser_context_t *builder_spends_ctx, parser_context_t *tx_spends_ctx, parser_context_t *indices_ctx) { if (txObj == NULL || keys == NULL) { return parser_unexpected_error; } - if (txObj->transaction.sections.maspBuilder.builder.sapling_builder.n_spends != txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_spends) { + if (txObj->transaction.sections.maspBuilder.metadata.n_spends_indices != txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_spends) { return parser_invalid_number_of_spends; } - for (uint32_t i = 0; i < txObj->transaction.sections.maspBuilder.builder.sapling_builder.n_spends; i++) { + for (uint64_t indice = 0; indice < txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_spends; indice++) { + // Find the spend descriptor information object corresponding to this + // spend descriptor + uint32_t i; + for (i = 0; i < txObj->transaction.sections.maspBuilder.metadata.n_spends_indices; i++) { + uint64_t curr_indice; + CHECK_ERROR(readUint64(indices_ctx, &curr_indice)); + if (curr_indice == indice) break; + } + + CTX_CHECK_AND_ADVANCE(tx_spends_ctx, SHIELDED_SPENDS_LEN * indice); + spend_item_t *item = spendlist_retrieve_rand_item(indice); + + if(i > txObj->transaction.sections.maspBuilder.metadata.n_spends_indices) { + return parser_invalid_number_of_spends; + } + CHECK_ERROR(getNextSpendDescription(builder_spends_ctx, i)); - CTX_CHECK_AND_ADVANCE(tx_spends_ctx, SHIELDED_SPENDS_LEN * i); - spend_item_t *item = spendlist_retrieve_rand_item(i); //check cv computation validaded in cpp_tests uint8_t cv[KEY_LENGTH] = {0}; @@ -782,29 +801,38 @@ parser_error_t checkOutputs(const parser_tx_t *txObj, parser_context_t *builder_ return parser_unexpected_error; } - if (txObj->transaction.sections.maspBuilder.builder.sapling_builder.n_outputs != txObj->transaction.sections.maspBuilder.metadata.n_outputs_indices) { + if (txObj->transaction.sections.maspBuilder.metadata.n_outputs_indices != txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_outputs) { return parser_invalid_number_of_outputs; } - for (uint32_t i = 0; i < txObj->transaction.sections.maspBuilder.metadata.n_outputs_indices; i++) { - CHECK_ERROR(getNextOutputDescription(builder_outputs_ctx, i)); - - uint64_t indice = 0; - CHECK_ERROR(readUint64(indices_ctx, &indice)); - + for (uint64_t indice = 0; indice < txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_outputs; indice++) { + // Find the output descriptor information object corresponding to this + // output descriptor + uint32_t i; + for (i = 0; i < txObj->transaction.sections.maspBuilder.metadata.n_outputs_indices; i++) { + uint64_t curr_indice; + CHECK_ERROR(readUint64(indices_ctx, &curr_indice)); + if (curr_indice == indice) break; + } CTX_CHECK_AND_ADVANCE(tx_outputs_ctx, SHIELDED_OUTPUTS_LEN * indice); output_item_t *item = outputlist_retrieve_rand_item(indice); - - //check cv computation validaded in cpp_tests - uint8_t cv[KEY_LENGTH] = {0}; - uint8_t identifier[IDENTIFIER_LEN] = {0}; uint64_t value = 0; + // Use the dummy note identifier as the default + uint8_t identifier[IDENTIFIER_LEN] = DEFAULT_IDENTIFIER; + + if (i > txObj->transaction.sections.maspBuilder.metadata.n_outputs_indices) { + return parser_invalid_number_of_outputs; + } + + CHECK_ERROR(getNextOutputDescription(builder_outputs_ctx, i)); uint8_t has_ovk = 0; CHECK_ERROR(readByte(builder_outputs_ctx, &has_ovk)); CTX_CHECK_AND_ADVANCE(builder_outputs_ctx, (has_ovk ? 32 : 0) + DIVERSIFIER_LEN + PAYMENT_ADDR_LEN); CHECK_ERROR(readBytesSize(builder_outputs_ctx, identifier, IDENTIFIER_LEN)); CHECK_ERROR(readUint64(builder_outputs_ctx, &value)); + //check cv computation validaded in cpp_tests + uint8_t cv[KEY_LENGTH] = {0}; CHECK_ERROR(computeValueCommitment(value, item->rcv, identifier, cv)); if(MEMCMP(cv, tx_outputs_ctx->buffer + tx_outputs_ctx->offset, CV_LEN) != 0) { return parser_invalid_cv; @@ -812,39 +840,47 @@ parser_error_t checkOutputs(const parser_tx_t *txObj, parser_context_t *builder_ builder_outputs_ctx->offset = 0; tx_outputs_ctx->offset = 0; + indices_ctx->offset = 0; } return parser_ok; } -parser_error_t checkConverts(const parser_tx_t *txObj, parser_context_t *builder_converts_ctx, parser_context_t *tx_converts_ctx) { +parser_error_t checkConverts(const parser_tx_t *txObj, parser_context_t *builder_converts_ctx, parser_context_t *tx_converts_ctx, parser_context_t *indices_ctx) { if (txObj == NULL) { return parser_unexpected_error; } - if(txObj->transaction.sections.maspBuilder.builder.sapling_builder.n_converts != txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_converts) { - return parser_invalid_number_of_outputs; + + if (txObj->transaction.sections.maspBuilder.metadata.n_converts_indices != txObj->transaction.sections.maspTx.data.sapling_bundle.n_shielded_converts) { + return parser_invalid_number_of_converts; } for (uint32_t i = 0; i < txObj->transaction.sections.maspBuilder.builder.sapling_builder.n_converts; i++) { CHECK_ERROR(getNextConvertDescription(builder_converts_ctx, i)); - CTX_CHECK_AND_ADVANCE(tx_converts_ctx, SHIELDED_CONVERTS_LEN * i); - convert_item_t *item = convertlist_retrieve_rand_item(i); + uint64_t indice = 0; + CHECK_ERROR(readUint64(indices_ctx, &indice)); + CTX_CHECK_AND_ADVANCE(tx_converts_ctx, SHIELDED_CONVERTS_LEN * indice); + convert_item_t *item = convertlist_retrieve_rand_item(indice); + //check cv (computation validaded in cpp_tests uint8_t cv[KEY_LENGTH] = {0}; - uint8_t identifier[IDENTIFIER_LEN] = {0}; + uint8_t generator[IDENTIFIER_LEN] = {0}; uint64_t value = 0; - CTX_CHECK_AND_ADVANCE(builder_converts_ctx, TAG_LEN); - CHECK_ERROR(readBytesSize(builder_converts_ctx, identifier, IDENTIFIER_LEN)); - CTX_CHECK_AND_ADVANCE(builder_converts_ctx, ASSET_ID_LEN + INT_128_LEN + sizeof(uint64_t)); + uint64_t tmp_64 = 0; + CHECK_ERROR(readCompactSize(builder_converts_ctx, &tmp_64)); + uint16_t len = tmp_64 * (ASSET_ID_LEN + INT_128_LEN); + CTX_CHECK_AND_ADVANCE(builder_converts_ctx, len); + CHECK_ERROR(readBytesSize(builder_converts_ctx, generator, IDENTIFIER_LEN)); CHECK_ERROR(readUint64(builder_converts_ctx, &value)); - CHECK_ERROR(computeValueCommitment(value, item->rcv, identifier, cv)); + CHECK_ERROR(computeConvertValueCommitment(value, item->rcv, generator, cv)); if(MEMCMP(cv, tx_converts_ctx->buffer + tx_converts_ctx->offset, CV_LEN) != 0) { return parser_invalid_cv; } builder_converts_ctx->offset = 0; + tx_converts_ctx->offset = 0; } return parser_ok; } @@ -864,7 +900,11 @@ zxerr_t crypto_check_masp(const parser_tx_t *txObj, keys_t *keys) { .bufferLen = txObj->transaction.sections.maspTx.data.sapling_bundle.shielded_spends.len, .offset = 0, .tx_obj = NULL}; - CHECK_PARSER_OK(checkSpends(txObj, keys, &builder_spends_ctx, &tx_spends_ctx)); + parser_context_t spends_indices_ctx = {.buffer = txObj->transaction.sections.maspBuilder.metadata.spends_indices.ptr, + .bufferLen = txObj->transaction.sections.maspBuilder.metadata.spends_indices.len, + .offset = 0, + .tx_obj = NULL}; + CHECK_PARSER_OK(checkSpends(txObj, keys, &builder_spends_ctx, &tx_spends_ctx, &spends_indices_ctx)); // Check outputs parser_context_t builder_outputs_ctx = {.buffer = txObj->transaction.sections.maspBuilder.builder.sapling_builder.outputs.ptr, @@ -875,11 +915,11 @@ zxerr_t crypto_check_masp(const parser_tx_t *txObj, keys_t *keys) { .bufferLen = txObj->transaction.sections.maspTx.data.sapling_bundle.shielded_outputs.len, .offset = 0, .tx_obj = NULL}; - parser_context_t indices_ctx = {.buffer = txObj->transaction.sections.maspBuilder.metadata.outputs_indices.ptr, + parser_context_t output_indices_ctx = {.buffer = txObj->transaction.sections.maspBuilder.metadata.outputs_indices.ptr, .bufferLen = txObj->transaction.sections.maspBuilder.metadata.outputs_indices.len, .offset = 0, .tx_obj = NULL}; - CHECK_PARSER_OK(checkOutputs(txObj, &builder_outputs_ctx, &tx_outputs_ctx, &indices_ctx)); + CHECK_PARSER_OK(checkOutputs(txObj, &builder_outputs_ctx, &tx_outputs_ctx, &output_indices_ctx)); // Check converts parser_context_t builder_converts_ctx = {.buffer = txObj->transaction.sections.maspBuilder.builder.sapling_builder.converts.ptr, @@ -890,7 +930,11 @@ zxerr_t crypto_check_masp(const parser_tx_t *txObj, keys_t *keys) { .bufferLen = txObj->transaction.sections.maspTx.data.sapling_bundle.shielded_converts.len, .offset = 0, .tx_obj = NULL}; - CHECK_PARSER_OK(checkConverts(txObj, &builder_converts_ctx, &tx_converts_ctx)); + parser_context_t converts_indices_ctx = {.buffer = txObj->transaction.sections.maspBuilder.metadata.converts_indices.ptr, + .bufferLen = txObj->transaction.sections.maspBuilder.metadata.converts_indices.len, + .offset = 0, + .tx_obj = NULL}; + CHECK_PARSER_OK(checkConverts(txObj, &builder_converts_ctx, &tx_converts_ctx, &converts_indices_ctx)); return zxerr_ok; } @@ -908,6 +952,10 @@ zxerr_t crypto_sign_masp_spends(parser_tx_t *txObj, uint8_t *output, uint16_t ou return zxerr_unknown; } + if (get_state() != STATE_PROCESSED_RANDOMNESS) { + return zxerr_unknown; + } + // Get keys uint8_t sapling_seed[KEY_LENGTH] = {0}; keys_t keys = {0}; @@ -929,6 +977,11 @@ zxerr_t crypto_sign_masp_spends(parser_tx_t *txObj, uint8_t *output, uint16_t ou MEMZERO(sapling_seed, sizeof(sapling_seed)); MEMZERO(&keys, sizeof(keys)); + + if (err == zxerr_ok) { + set_state(STATE_SIGNED_SPENDS); + } + return err; } @@ -949,29 +1002,49 @@ zxerr_t crypto_computeRandomness(masp_type_e type, uint8_t *out, uint16_t outLen return zxerr_unknown; } MEMZERO(out, outLen); - uint8_t tmp_rnd[RANDOM_LEN] = {0}; #ifdef APP_TESTING - uint8_t out_tmp_rnd2[RANDOM_LEN] = {0x71, 0x11, 0x60, 0x47, 0xe5, 0xe8, 0xb5, 0x0a, 0x5c, - 0x74, 0x69, 0x8a, 0xc2, 0x9b, 0x73, 0x5c, 0xc9, 0xe2, - 0xfa, 0xf7, 0x94, 0x37, 0xb8, 0x15, 0xa2, 0xb7, 0x0b, - 0x07, 0xec, 0x24, 0xf9, 0x08}; - -uint8_t out_tmp_rnd[RANDOM_LEN] = {0x4b, 0xd4, 0xe9, 0x74, 0xdd, 0x7b, 0xa7, 0x59, 0x25, 0x25, - 0xdc, 0x92, 0xfe, 0xe9, 0xa4, 0x3b, 0x6d, 0xb1, 0xde, 0x93, - 0x12, 0x5b, 0x76, 0xfa, 0x22, 0x4e, 0xb2, 0xf0, 0x41, 0x04, - 0xe1, 0x02}; - - uint8_t spend_tmp_rnd[RANDOM_LEN] = {0x78,0xbf, 0x5c, 0xd8, 0x3b, 0x81, 0xaf,0x94, 0xc7, - 0xa5, 0xeb, 0x68,0x9e,0xc5,0x24,0xd2,0xda, 0x98, - 0x0c,0x84,0x73,0x55,0x49, 0x2f,0xd0,0x8e,0x1d,0x79, - 0x41,0x3e,0x6b,0x08}; + uint8_t out_tmp_rnd[RANDOM_LEN] = {0xb1, 0x85, 0x95, 0x9d, 0xdb, 0x84, 0x1a, 0x7f, 0x97, 0x40, + 0x9b, 0x22, 0xec, 0x0e, 0xf8, 0x52, 0xce, 0x98, 0xc9, 0x6a, + 0xf0, 0xa0, 0x62, 0xa4, 0xdc, 0xff, 0x0a, 0xe7, 0x77, 0x10, + 0xf0, 0x0c}; + + uint8_t out_tmp_rnd2[RANDOM_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}; + + uint8_t out1_tmp_rnd[RANDOM_LEN] = {0x9c, 0xf4, 0x3f, 0x46, 0xb1, 0xa6, 0x1d, 0xae, 0xf8, 0x41, + 0x32, 0xdb, 0xca, 0xe7, 0xea, 0x88, 0xa3, 0xe1, 0x2c, 0x66, + 0xe0, 0x71, 0x05, 0x47, 0xc9, 0x6d, 0x84, 0xf3, 0xc4, 0x24, + 0xa0, 0x0d}; + + uint8_t out1_tmp_rnd2[RANDOM_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}; + + uint8_t spend_tmp_rnd[RANDOM_LEN] = {0x22, 0xc9, 0x0b, 0xa7, 0x43, 0x91, 0x6e, 0x04, 0xd2, 0xfe, + 0xea, 0x70, 0x7a, 0xbb, 0xac, 0x40, 0xdb, 0x36, 0x05, 0xa8, + 0x7c, 0xa6, 0x71, 0xab, 0x23, 0xda, 0xc3, 0x01, 0x72, 0xbb, + 0x03, 0x0d}; - uint8_t spend_tmp_rnd2[RANDOM_LEN] = {0x5e, 0x0e, 0xdd, 0x60, 0x7d, 0x43, 0x4e, 0x34, 0x76, - 0x6b, 0xdb, 0x07, 0x13, 0xe2, 0xef, 0xdd, 0x27, 0x5a, - 0x0d, 0x50, 0x73, 0x47, 0x9f, 0xda, 0x02, 0x0c, 0xfc, - 0x6f, 0x03, 0x97, 0x53, 0x07}; + uint8_t spend_tmp_rnd2[RANDOM_LEN] = {0xc8, 0x06, 0x96, 0x04, 0x94, 0xf8, 0x5d, 0x02, 0x13, 0x61, + 0xcb, 0x07, 0x97, 0x8d, 0x6e, 0x71, 0xec, 0xa5, 0xc0, 0xbf, + 0xe4, 0xc8, 0xe9, 0x3d, 0x0a, 0x10, 0x85, 0x74, 0xe5, 0x04, + 0x94, 0x06}; + + uint8_t convert_tmp_rnd[RANDOM_LEN] = {0x22, 0xf4, 0x88, 0x3d, 0xdc, 0x2d, 0x8e, 0x47, 0xbd, 0xfc, + 0xb3, 0xb5, 0x44, 0x2c, 0x04, 0x1c, 0xa5, 0xeb, 0x1d, 0x97, + 0x76, 0xea, 0x1c, 0xcd, 0xef, 0x05, 0x1b, 0xd0, 0xce, 0x30, + 0xd8, 0x03}; + + uint8_t convert_tmp_rnd2[RANDOM_LEN] = {0x03, 0xd8, 0x30, 0xce, 0xd0, 0x1b, 0x05, 0xef, 0xcd, 0x1c, + 0xea, 0x76, 0x97, 0x1d, 0xeb, 0xa5, 0x1c, 0x04, 0x2c, 0x44, + 0xb5, 0xb3, 0xfc, 0xbd, 0x47, 0x8e, 0x2d, 0xdc, 0x3d, 0x88, + 0xf4, 0x22}; #else + uint8_t tmp_rnd[RANDOM_LEN] = {0}; uint8_t tmp_rnd2[RANDOM_LEN] = {0}; #endif @@ -996,6 +1069,7 @@ uint8_t out_tmp_rnd[RANDOM_LEN] = {0x4b, 0xd4, 0xe9, 0x74, 0xdd, 0x7b, 0xa7, 0x5 MEMCPY(out, out_tmp_rnd, RANDOM_LEN); MEMCPY(out + RANDOM_LEN, out_tmp_rnd2, RANDOM_LEN); CHECK_ZXERR(output_append_rand_item(out_tmp_rnd, out_tmp_rnd2)); + CHECK_ZXERR(output_append_rand_item(out1_tmp_rnd, out1_tmp_rnd2)); #else CHECK_ZXERR(random_fr(tmp_rnd, RANDOM_LEN)); MEMCPY(out, tmp_rnd, RANDOM_LEN); @@ -1007,10 +1081,16 @@ uint8_t out_tmp_rnd[RANDOM_LEN] = {0x4b, 0xd4, 0xe9, 0x74, 0xdd, 0x7b, 0xa7, 0x5 *replyLen = 2 * RANDOM_LEN; break; case convert: +#ifdef APP_TESTING + MEMCPY(out, convert_tmp_rnd, RANDOM_LEN); + CHECK_ZXERR(convert_append_rand_item(convert_tmp_rnd)); + CHECK_ZXERR(convert_append_rand_item(convert_tmp_rnd2)); +#else CHECK_ZXERR(random_fr(tmp_rnd, RANDOM_LEN)); MEMCPY(out, tmp_rnd, RANDOM_LEN); CHECK_ZXERR(convert_append_rand_item(tmp_rnd)); +#endif *replyLen = RANDOM_LEN; break; default: diff --git a/app/src/crypto_helper.c b/app/src/crypto_helper.c index 1ddb8ebe..5dfce2a9 100644 --- a/app/src/crypto_helper.c +++ b/app/src/crypto_helper.c @@ -625,6 +625,21 @@ parser_error_t computeValueCommitment(uint64_t value, uint8_t *rcv, uint8_t *ide return parser_ok; } +parser_error_t computeConvertValueCommitment(uint64_t value, uint8_t *rcv, uint8_t *generator, uint8_t *cv) { + if(rcv == NULL || generator == NULL || cv == NULL) { + return parser_unexpected_error; + } + + uint8_t value_bytes[32] = {0}; + u64_to_bytes(value, value_bytes); + + uint8_t scalar[32] = {0}; + CHECK_ERROR(parser_scalar_multiplication(rcv, ValueCommitmentRandomnessGenerator, scalar)); + CHECK_ERROR(add_points(generator, value_bytes, scalar, cv)); + + return parser_ok; +} + parser_error_t computeRk(keys_t *keys, uint8_t *alpha, uint8_t *rk) { if(keys == NULL || alpha == NULL || rk == NULL) { diff --git a/app/src/crypto_helper.h b/app/src/crypto_helper.h index 909c40ff..1d104130 100644 --- a/app/src/crypto_helper.h +++ b/app/src/crypto_helper.h @@ -73,6 +73,7 @@ parser_error_t h_star(uint8_t *a, uint16_t a_len, uint8_t *b, uint16_t b_len, ui parser_error_t parser_scalar_multiplication(const uint8_t input[32], constant_key_t key, uint8_t output[32]); parser_error_t parser_compute_sbar(const uint8_t s[32], uint8_t r[32], uint8_t rsk[32], uint8_t sbar[32]); parser_error_t parser_randomized_secret_from_seed(const uint8_t ask[32], const uint8_t alpha[32], uint8_t output[32]); +parser_error_t computeConvertValueCommitment(uint64_t value, uint8_t *rcv, uint8_t *generator, uint8_t *cv); #ifdef __cplusplus } #endif diff --git a/app/src/keys_def.h b/app/src/keys_def.h index f95f7d1c..9fc1d928 100644 --- a/app/src/keys_def.h +++ b/app/src/keys_def.h @@ -50,6 +50,13 @@ typedef uint8_t d_t[DIVERSIFIER_LENGTH]; typedef uint8_t public_address_t[KEY_LENGTH]; +typedef struct { + char viewKey[2*KEY_LENGTH]; + char ovk[KEY_LENGTH]; + char ivk[KEY_LENGTH]; + char dk[KEY_LENGTH]; +} KeyData; + typedef struct { spending_key_t spendingKey; ask_t ask; diff --git a/app/src/nvdata.c b/app/src/nvdata.c index 6dab42e7..9f93d5af 100644 --- a/app/src/nvdata.c +++ b/app/src/nvdata.c @@ -120,42 +120,53 @@ uint8_t transaction_get_n_converts() { } bool spend_signatures_more_extract() { - return transaction_header.spends_sign_index > 0; + return transaction_header.spends_sign_index < transaction_header.spends_sign_len; } zxerr_t spend_signatures_append(uint8_t *signature) { - if (transaction_header.spends_sign_index >= + if (transaction_header.spends_sign_len >= transaction_header.spendlist_len) { return zxerr_unknown; } MEMCPY_NV((void *)&N_transactioninfo - .spend_signatures[transaction_header.spends_sign_index], + .spend_signatures[transaction_header.spends_sign_len], signature, SIGNATURE_SIZE); - transaction_header.spends_sign_index++; + transaction_header.spends_sign_len++; return zxerr_ok; } zxerr_t get_next_spend_signature(uint8_t *result) { - const uint8_t index = transaction_header.spendlist_len - transaction_header.spends_sign_index; - if (index >= transaction_header.spendlist_len) { - return zxerr_unknown; - } - MEMCPY(result, (void *)&N_transactioninfo.spend_signatures[index], SIGNATURE_SIZE); - transaction_header.spends_sign_index--; if (!spend_signatures_more_extract()) { - transaction_reset(); + return zxerr_unknown; } + const uint8_t index = transaction_header.spends_sign_index; + MEMCPY(result, (void *)&N_transactioninfo.spend_signatures[index], SIGNATURE_SIZE); + transaction_header.spends_sign_index++; + set_state(STATE_EXTRACT_SPENDS); return zxerr_ok; } +uint8_t get_state() { + return transaction_header.state; +} + +void set_state(uint8_t state) { + transaction_header.state = state; +} + +void state_reset() { + transaction_header.state = STATE_INITIAL; +} + void zeroize_signatures() { uint8_t sig[SIGNATURE_SIZE] = {0}; - transaction_header.spends_sign_index = 0; + transaction_header.spends_sign_len = 0; for (int i = 0; i < SPEND_LIST_SIZE; i++) { spend_signatures_append(sig); } + transaction_header.spends_sign_len = 0; transaction_header.spends_sign_index = 0; } @@ -197,5 +208,6 @@ void transaction_reset() { zeroize_outputs(); zeroize_converts(); zeroize_signatures(); + set_state(STATE_INITIAL); } diff --git a/app/src/nvdata.h b/app/src/nvdata.h index 3b4c2b25..eee3f3c5 100644 --- a/app/src/nvdata.h +++ b/app/src/nvdata.h @@ -25,6 +25,12 @@ #define SPEND_LIST_SIZE 15 #define SIGNATURE_SIZE 64 +// Possible states +#define STATE_INITIAL 0x00 +#define STATE_PROCESSED_RANDOMNESS 0x01 +#define STATE_SIGNED_SPENDS 0x02 +#define STATE_EXTRACT_SPENDS 0x03 + typedef struct { uint8_t rcv[RANDOM_LEN]; uint8_t alpha[RANDOM_LEN]; @@ -53,7 +59,9 @@ typedef struct { uint8_t spendlist_len; uint8_t outputlist_len; uint8_t convertlist_len; + uint8_t spends_sign_len; uint8_t spends_sign_index; + uint8_t state; } transaction_header_t; typedef struct { @@ -74,3 +82,7 @@ uint8_t transaction_get_n_converts(); zxerr_t get_next_spend_signature(uint8_t *result); zxerr_t spend_signatures_append(uint8_t *signature); bool spend_signatures_more_extract(); + +uint8_t get_state(); +void state_reset(); +void set_state(uint8_t state); diff --git a/app/src/parser_impl.c b/app/src/parser_impl.c index be41ea50..dffe807b 100644 --- a/app/src/parser_impl.c +++ b/app/src/parser_impl.c @@ -27,7 +27,9 @@ parser_error_t _read(parser_context_t *ctx, parser_tx_t *v) { CHECK_ERROR(validateTransactionParams(v)) - CHECK_ERROR(verifyShieldedHash(ctx)) + if(ctx->tx_obj->transaction.isMasp || ctx->tx_obj->ibc.is_ibc) { + CHECK_ERROR(verifyShieldedHash(ctx)) + } if (ctx->offset != ctx->bufferLen) { return parser_unexpected_unparsed_bytes; diff --git a/app/src/parser_impl_masp.c b/app/src/parser_impl_masp.c index d28c50d3..aa26628c 100644 --- a/app/src/parser_impl_masp.c +++ b/app/src/parser_impl_masp.c @@ -170,9 +170,11 @@ static parser_error_t readSpendDescriptionInfo(parser_context_t *ctx, masp_sapli CHECK_ERROR(readUint32(ctx, &builder->n_spends)) #if defined(LEDGER_SPECIFIC) && !defined(APP_TESTING) - uint32_t rnd_spends = (uint32_t)transaction_get_n_spends(); - if (rnd_spends != builder->n_spends) { - return parser_invalid_number_of_spends; + if (G_io_apdu_buffer[OFFSET_INS] == INS_SIGN_MASP_SPENDS) { + uint32_t rnd_spends = (uint32_t)transaction_get_n_spends(); + if (rnd_spends < builder->n_spends) { + return parser_invalid_number_of_spends; + } } #endif @@ -240,7 +242,7 @@ parser_error_t getNextOutputDescription(parser_context_t *output, uint8_t index) for (int i = 0; i < index; i++) { uint8_t has_ovk = 0; CHECK_ERROR(readByte(output, &has_ovk)); - CTX_CHECK_AND_ADVANCE(output, (has_ovk ? 32 : 0) + DIVERSIFIER_LEN + PAYMENT_ADDR_LEN + NOTE_LEN + MEMO_LEN); + CTX_CHECK_AND_ADVANCE(output, (has_ovk ? 32 : 0) + DIVERSIFIER_LEN + PAYMENT_ADDR_LEN + OUT_NOTE_LEN + MEMO_LEN); } return parser_ok; } @@ -273,7 +275,7 @@ parser_error_t getNextConvertDescription(parser_context_t *convert, uint8_t inde allowed_size = (uint64_t)tag; } CTX_CHECK_AND_ADVANCE(convert, allowed_size * (ASSET_ID_LEN + INT_128_LEN) + sizeof(uint64_t)); - + CTX_CHECK_AND_ADVANCE(convert, 32); CHECK_ERROR(readByte(convert, &merkel_size)); CTX_CHECK_AND_ADVANCE(convert, merkel_size * (32 + 1) + sizeof(uint64_t)); } @@ -288,9 +290,11 @@ static parser_error_t readConvertDescriptionInfo(parser_context_t *ctx, masp_sap CHECK_ERROR(readUint32(ctx, &builder->n_converts)) #if defined(LEDGER_SPECIFIC) && !defined(APP_TESTING) - uint32_t rnd_converts = (uint32_t)transaction_get_n_converts(); - if (rnd_converts < builder->n_converts) { - return parser_invalid_number_of_converts; + if (G_io_apdu_buffer[OFFSET_INS] == INS_SIGN_MASP_SPENDS) { + uint32_t rnd_converts = (uint32_t)transaction_get_n_converts(); + if (rnd_converts < builder->n_converts) { + return parser_invalid_number_of_converts; + } } #endif @@ -332,6 +336,14 @@ static parser_error_t readSaplingOutputDescriptionInfo(parser_context_t *ctx, ma } CHECK_ERROR(readUint32(ctx, &builder->n_outputs)) +#if defined(LEDGER_SPECIFIC) && !defined(APP_TESTING) + if (G_io_apdu_buffer[OFFSET_INS] == INS_SIGN_MASP_SPENDS) { + uint32_t rnd_outputs = (uint32_t)transaction_get_n_outputs(); + if (rnd_outputs < builder->n_outputs) { + return parser_invalid_number_of_outputs; + } + } +#endif // Get start pointer and offset to later calculate the size of the outputs builder->outputs.ptr = ctx->buffer + ctx->offset; diff --git a/app/src/parser_impl_masp.h b/app/src/parser_impl_masp.h index 20087552..e5368587 100644 --- a/app/src/parser_impl_masp.h +++ b/app/src/parser_impl_masp.h @@ -26,6 +26,7 @@ extern "C" { #define MASPV5_TX_VERSION 0x02 #define MASPV5_VERSION_GROUP_ID 0x26A7270A #define BRANCH_ID_IDENTIFIER 0xE9FF75A6 +#define DEFAULT_IDENTIFIER {156, 229, 191, 54, 209, 138, 169, 235, 234, 174, 120, 186, 142, 34, 183, 118, 64, 243, 100, 134, 234, 27, 248, 27, 36, 245, 9, 146, 30, 110, 203, 169} parser_error_t readMaspTx(parser_context_t *ctx, masp_tx_section_t *maspTx); parser_error_t readMaspBuilder(parser_context_t *ctx, masp_builder_section_t *maspBuilder); diff --git a/app/src/parser_impl_txn.c b/app/src/parser_impl_txn.c index c0cb2871..c46fe772 100644 --- a/app/src/parser_impl_txn.c +++ b/app/src/parser_impl_txn.c @@ -1432,6 +1432,14 @@ parser_error_t verifyShieldedHash(parser_context_t *ctx) { return parser_invalid_target_hash; } } + + if (ctx->tx_obj->transfer.has_shielded_hash && memcmp(ctx->tx_obj->transfer.shielded_hash.ptr, tx_id_hash, HASH_LEN) != 0) { + return parser_invalid_target_hash; + } + + if(ctx->tx_obj->ibc.transfer.has_shielded_hash && memcmp(ctx->tx_obj->ibc.transfer.shielded_hash.ptr, tx_id_hash, HASH_LEN) != 0) { + return parser_invalid_target_hash; + } #endif return parser_ok; diff --git a/app/src/parser_txdef.h b/app/src/parser_txdef.h index 3e3b209e..101429ff 100644 --- a/app/src/parser_txdef.h +++ b/app/src/parser_txdef.h @@ -27,7 +27,7 @@ extern "C" { #define MAX_EXTRA_DATA_SECS 4 #define MAX_SIGNATURE_SECS 3 - +#define OFFSET_INS 1 #define ASSET_ID_LEN 32 #define ANCHOR_LEN 32 #define SHIELDED_OUTPUTS_LEN 788 diff --git a/app/src/review_keys.c b/app/src/review_keys.c index 0a423f8f..f633936e 100644 --- a/app/src/review_keys.c +++ b/app/src/review_keys.c @@ -115,26 +115,23 @@ zxerr_t getItemViewKey(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char uint8_t *pageCount) { ZEMU_LOGF(50, "[addr_getItem] %d/%d\n", displayIdx, pageIdx) + const KeyData* keyData = (const KeyData*)G_io_apdu_buffer; switch (displayIdx) { case 0: snprintf(outKey, outKeyLen, "ViewKey"); - const char* viewKey = (const char*)G_io_apdu_buffer; - pageStringHex(outVal, outValLen, viewKey, 2 * KEY_LENGTH, pageIdx, pageCount); + pageStringHex(outVal, outValLen, keyData->viewKey, 2 * KEY_LENGTH, pageIdx, pageCount); break; case 1: snprintf(outKey, outKeyLen, "IVK"); - const char* ivk = (const char*)G_io_apdu_buffer + 3 * KEY_LENGTH; - pageStringHex(outVal, outValLen, ivk, KEY_LENGTH, pageIdx, pageCount); + pageStringHex(outVal, outValLen, keyData->ivk, KEY_LENGTH, pageIdx, pageCount); break; case 2: snprintf(outKey, outKeyLen, "OVK"); - const char* ovk = (const char*)G_io_apdu_buffer + 2 * KEY_LENGTH; - pageStringHex(outVal, outValLen, ovk, KEY_LENGTH, pageIdx, pageCount); + pageStringHex(outVal, outValLen, keyData->ovk, KEY_LENGTH, pageIdx, pageCount); break; case 3: snprintf(outKey, outKeyLen, "DK"); - const char* dk = (const char*)G_io_apdu_buffer + 4 * KEY_LENGTH; - pageStringHex(outVal, outValLen, dk, KEY_LENGTH, pageIdx, pageCount); + pageStringHex(outVal, outValLen, keyData->dk, KEY_LENGTH, pageIdx, pageCount); break; case 4: { snprintf(outKey, outKeyLen, "HD Path"); diff --git a/docs/APDUSPEC.md b/docs/APDUSPEC.md index 5b88d1bb..f76b9e6f 100644 --- a/docs/APDUSPEC.md +++ b/docs/APDUSPEC.md @@ -40,8 +40,6 @@ The general structure of commands and responses is as follows: | 0x6F01 | Sign / verify error | | 0x9000 | Success | -## New API - ### GET_DEVICE_INFO #### Command @@ -95,6 +93,7 @@ The general structure of commands and responses is as follows: --- ### INS_GET_ADDR + Gets the ED25519 public key and corresponding address #### Command @@ -123,7 +122,8 @@ Gets the ED25519 public key and corresponding address | Field | Type | Content | Note | | ----------------- | ------------- | ------------- | ------------------------ | -| Pubkey | byte (33) | Public key | prefix* + pubkey (32) | +| Raw Pubkey | byte (33) | Public key | prefix* + pubkey (32) | +| Encoded Pubkey | byte (?) | Encoded pubkey | | | ADDR | byte (45) | Address | | | SW1-SW2 | byte (2) | Return code | see list of return codes | @@ -132,6 +132,7 @@ Gets the ED25519 public key and corresponding address --- ### INS_SIGN + Sign transaction with Ed25519 #### Command @@ -184,3 +185,179 @@ All other packets/chunks contain data chunks that are described below *prefix is ED25519: 0 | SECP256K1: 1 +### MASP Transaction Instructions + +### INS_GET_KEYS + +Gets the view key, ivk, ovk, dk for the given address. + +| Field | Type | Content | Expected | +| ------- | -------- | ------------------------- | ---------------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x03 | +| 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 | +| ----------------- | ------------- | ------------- | ------------------------ | +| ViewKey | byte (64) | View key | | +| OVK | byte (32) | OVK | | +| IVK | byte (32) | IVK | | +| DK | byte (32) | DK | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +*prefix is ED25519: 0 | SECP256K1: 1 + +### INS_GET_SPEND_RAND + +Get spend randomness values to be used in transation creation. + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x04 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| Rcv | byte (32) | Rcv | | +| Alpha | byte (32) | Alpha | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +### INS_GET_OUTPUT_RAND + +Get output randomness values to be used in transation creation. + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x05 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| Rcv | byte (32) | Rcv | | +| Rcm | byte (32) | Rcm | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +### INS_GET_CONVERT_RAND + +Get convert randomness values to be used in transation creation. + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x06 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| Rcv | byte (32) | Rcv | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +### INS_SIGN_MASP_SPENDS + +Sign MASP spends. + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x07 | +| P1 | byte (1) | Payload desc | 0 = init | +| | | | 1 = add | +| | | | 2 = last | +| P2 | byte (1) | ---- | not used | +| L | byte (1) | Bytes in payload | (depends) | + +The first packet/chunk includes the derivation path and size for Code and Data fields + +All other packets/chunks contain data chunks that are described below + +##### First Packet + +| 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 + +| Field | Type | Content | Expected | +| ------- | -------- | --------------- | -------- | +| Message | bytes... | Message to Sign | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| hash | byte (32) | transaction hash | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +### INS_EXTRACT_SPEND_SIGN + +Extract the spend signatures computed in INS_SIGN_MASP_SPENDS. + +#### Command +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x08 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| rbar | byte (32) | rbar | | +| sbar | byte (32) | sbar | | +| SW1-SW2 | byte (2) | Return code | see list of return codes | + +### INS_CLEAN_RANDOMNESS_BUFFERS + +Clean the randomness buffers. + +#### Command + +| Field | Type | Content | Expected | +| ----- | -------- | ---------------------- | --------- | +| CLA | byte (1) | Application Identifier | 0x57 | +| INS | byte (1) | Instruction ID | 0x09 | +| P1 | byte (1) | Request User confirmation | No = 0 | +| P2 | byte (1) | Parameter ignored | | + +#### Response + +| Field | Type | Content | Note | +| ----------------- | ------------- | ------------- | ------------------------ | +| SW1-SW2 | byte (2) | Return code | see list of return codes | diff --git a/js b/js new file mode 160000 index 00000000..30169370 --- /dev/null +++ b/js @@ -0,0 +1 @@ +Subproject commit 30169370f623918ec80f6a64ed62773607190e28 diff --git a/js/.editorconfig b/js/.editorconfig deleted file mode 100644 index 4a7ea303..00000000 --- a/js/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/js/.eslintrc.js b/js/.eslintrc.js deleted file mode 100644 index caf98057..00000000 --- a/js/.eslintrc.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'jest'], - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:jest/recommended', 'prettier'], - env: { - browser: true, - es6: true, - node: true, - }, - settings: {}, - globals: { - Atomics: 'readonly', - SharedArrayBuffer: 'readonly', - }, - parserOptions: {}, - rules: { - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-var-requires': 0, - '@typescript-eslint/ban-ts-comment': 'off', - }, -} diff --git a/js/.gitignore b/js/.gitignore deleted file mode 100644 index db6a98d3..00000000 --- a/js/.gitignore +++ /dev/null @@ -1,72 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# next.js build output -.next - -\.idea/ - -.vscode - -TODO\.md - -\dist -/certs/cert.pem -/certs/server.cert -/certs/server.key diff --git a/js/.npmignore b/js/.npmignore deleted file mode 100644 index 3c3629e6..00000000 --- a/js/.npmignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/js/.prettierignore b/js/.prettierignore deleted file mode 100644 index de4d1f00..00000000 --- a/js/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules diff --git a/js/.prettierrc b/js/.prettierrc deleted file mode 100644 index 6523ceb1..00000000 --- a/js/.prettierrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "trailingComma": "all", - "singleQuote": true, - "arrowParens": "avoid", - "semi": false, - "useTabs": false, - "printWidth": 140, - "tabWidth": 2 -} diff --git a/js/LICENSE b/js/LICENSE deleted file mode 100644 index 9259c4d1..00000000 --- a/js/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 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. diff --git a/js/README.md b/js/README.md deleted file mode 100644 index 4171ca07..00000000 --- a/js/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# @zondax/ledger-namada - -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![npm version](https://badge.fury.io/js/%40zondax%2Fledger-namada.svg)](https://badge.fury.io/js/%40zondax%2Fledger-namada) - -This package provides a basic client library to communicate with the Namada App running in a Ledger Nano S/X - -We recommend using the npmjs package in order to receive updates/fixes. - -## Notes - -Use `yarn install` to avoid issues. diff --git a/js/package.json b/js/package.json deleted file mode 100644 index 0d0cda9f..00000000 --- a/js/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "@zondax/ledger-namada", - "author": "Zondax AG", - "license": "Apache-2.0", - "version": "0.0.1", - "description": "Node API for the Namada App (Ledger Nano S/X/S+)", - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "types": "./dist/index.d.ts", - "homepage": "https://github.com/zondax/ledger-namada", - "repository": { - "type": "git", - "url": "git+https://github.com/zondax/ledger-namada.git" - }, - "keywords": [ - "Zondax", - "Ledger", - "Javascript", - "Namada" - ], - "scripts": { - "build": "tsc", - "copy-files": "copyfiles -u 0 src/**/*.proto dist/", - "test:integration": "yarn build && jest -t 'Integration'", - "test:key-derivation": "yarn build && jest -t 'KeyDerivation'", - "supported": "ts-node src/cmd/cli.ts supported", - "linter": "eslint --max-warnings 0 .", - "linter:fix": "yarn linter --fix", - "format": "prettier -w ." - }, - "bugs": { - "url": "https://github.com/zondax/ledger-namada/issues" - }, - "dependencies": { - "@ledgerhq/hw-transport": "^6.30.6" - }, - "devDependencies": { - "@types/ledgerhq__hw-transport": "^4.21.8", - "@typescript-eslint/eslint-plugin": "^8.4.0", - "@typescript-eslint/parser": "^8.4.0", - "bip32": "^5.0.0-rc.0", - "bip39": "^3.1.0", - "core-js": "^3.38.1", - "crypto-js": "4.2.0", - "eslint": "^9.10.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.30.0", - "eslint-plugin-jest": "^28.8.3", - "eslint-plugin-prettier": "^5.2.1", - "jest": "^29.7.0", - "leb128": "^0.0.5", - "prettier": "^3.3.3", - "secp256k1": "^5.0.0", - "typescript": "^5.5.4" - }, - "moduleDirectories": [ - "node_modules", - "dist" - ], - "postcss": { - "plugins": { - "autoprefixer": {} - } - }, - "browserslist": [ - "> 1%", - "last 2 versions" - ], - "files": [ - "dist/*", - "LICENSE", - "yarn.lock" - ], - "publishConfig": { - "access": "public" - } -} diff --git a/js/src/common.ts b/js/src/common.ts deleted file mode 100644 index aa125ba3..00000000 --- a/js/src/common.ts +++ /dev/null @@ -1,173 +0,0 @@ -/** ****************************************************************************** - * (c) 2018 - 2023 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. - ******************************************************************************* */ -export const CHUNK_SIZE = 250 - -export const PAYLOAD_TYPE = { - INIT: 0x00, - ADD: 0x01, - LAST: 0x02, -} - -export const P1_VALUES = { - ONLY_RETRIEVE: 0x00, - SHOW_ADDRESS_IN_DEVICE: 0x01, -} - -export const P2_VALUES = { - DEFAULT: 0x00, -} - -// noinspection JSUnusedGlobalSymbols -export const SIGN_VALUES_P2 = { - DEFAULT: 0x00, -} - -export const ERROR_CODE = { - NoError: 0x9000, -} - -export enum LedgerError { - U2FUnknown = 1, - U2FBadRequest = 2, - U2FConfigurationUnsupported = 3, - U2FDeviceIneligible = 4, - U2FTimeout = 5, - Timeout = 14, - NoErrors = 0x9000, - DeviceIsBusy = 0x9001, - ErrorDerivingKeys = 0x6802, - ExecutionError = 0x6400, - WrongLength = 0x6700, - EmptyBuffer = 0x6982, - OutputBufferTooSmall = 0x6983, - DataIsInvalid = 0x6984, - ConditionsNotSatisfied = 0x6985, - TransactionRejected = 0x6986, - BadKeyHandle = 0x6a80, - InvalidP1P2 = 0x6b00, - InstructionNotSupported = 0x6d00, - AppDoesNotSeemToBeOpen = 0x6e01, - UnknownError = 0x6f00, - SignVerifyError = 0x6f01, -} - -export const ERROR_DESCRIPTION = { - [LedgerError.U2FUnknown]: 'U2F: Unknown', - [LedgerError.U2FBadRequest]: 'U2F: Bad request', - [LedgerError.U2FConfigurationUnsupported]: 'U2F: Configuration unsupported', - [LedgerError.U2FDeviceIneligible]: 'U2F: Device Ineligible', - [LedgerError.U2FTimeout]: 'U2F: Timeout', - [LedgerError.Timeout]: 'Timeout', - [LedgerError.NoErrors]: 'No errors', - [LedgerError.DeviceIsBusy]: 'Device is busy', - [LedgerError.ErrorDerivingKeys]: 'Error deriving keys', - [LedgerError.ExecutionError]: 'Execution Error', - [LedgerError.WrongLength]: 'Wrong Length', - [LedgerError.EmptyBuffer]: 'Empty Buffer', - [LedgerError.OutputBufferTooSmall]: 'Output buffer too small', - [LedgerError.DataIsInvalid]: 'Data is invalid', - [LedgerError.ConditionsNotSatisfied]: 'Conditions not satisfied', - [LedgerError.TransactionRejected]: 'Transaction rejected', - [LedgerError.BadKeyHandle]: 'Bad key handle', - [LedgerError.InvalidP1P2]: 'Invalid P1/P2', - [LedgerError.InstructionNotSupported]: 'Instruction not supported', - [LedgerError.AppDoesNotSeemToBeOpen]: 'App does not seem to be open', - [LedgerError.UnknownError]: 'Unknown error', - [LedgerError.SignVerifyError]: 'Sign/verify error', -} - -export function errorCodeToString(statusCode: LedgerError) { - if (statusCode in ERROR_DESCRIPTION) return ERROR_DESCRIPTION[statusCode] - return `Unknown Status Code: ${statusCode}` -} - -function isDict(v: any) { - return typeof v === 'object' && v !== null && !(v instanceof Array) && !(v instanceof Date) -} - -export function processErrorResponse(response: any) { - if (response) { - if (isDict(response)) { - if (Object.prototype.hasOwnProperty.call(response, 'statusCode')) { - return { - returnCode: response.statusCode, - errorMessage: errorCodeToString(response.statusCode), - } - } - - if (Object.prototype.hasOwnProperty.call(response, 'returnCode') && Object.prototype.hasOwnProperty.call(response, 'errorMessage')) { - return response - } - } - return { - returnCode: 0xffff, - errorMessage: response.toString(), - } - } - - return { - returnCode: 0xffff, - errorMessage: response.toString(), - } -} - -const HARDENED = 0x80000000 -const DEFAULT_DER_PATH_LEN = 6 -const IDENTITY_DER_PATH_LEN = 4 // m/888'/0'/ - -export function serializePath(path: string) { - if (!path.startsWith('m')) { - throw new Error(`Path should start with "m" (e.g "m/44'/5757'/5'/0/3")`) - } - - const pathArray = path.split('/') - - let allocSize = 0 - - if (pathArray.length === DEFAULT_DER_PATH_LEN || pathArray.length === IDENTITY_DER_PATH_LEN) { - allocSize = (pathArray.length - 1) * 4 + 1 - } else { - throw new Error(`Invalid path. (e.g "m/44'/134'/0/0/0"`) - } - - const buf = Buffer.alloc(allocSize) - buf.writeUInt8(pathArray.length - 1, 0) - - for (let i = 1; i < pathArray.length; i += 1) { - let value = 0 - let child = pathArray[i] - if (child.endsWith("'")) { - value += HARDENED - child = child.slice(0, -1) - } - - const childNumber = Number(child) - - if (Number.isNaN(childNumber)) { - throw new Error(`Invalid path : ${child} is not a number. (e.g "m/44'/461'/5'/0/3")`) - } - - if (childNumber >= HARDENED) { - throw new Error('Incorrect child value (bigger or equal to 0x80000000)') - } - - value += childNumber - - buf.writeUInt32LE(value, 4 * (i - 1) + 1) - } - - return buf -} diff --git a/js/src/config.ts b/js/src/config.ts deleted file mode 100644 index 4e87248b..00000000 --- a/js/src/config.ts +++ /dev/null @@ -1,35 +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. - ******************************************************************************* */ -export const CLA = 0x57 -export const INS = { - GET_VERSION: 0x00, - GET_TRANSPARENT_ADDRESS: 0x01, - SIGN: 0x02, - - GET_KEYS: 0x03, - GET_SPEND_RAND: 0x04, - GET_OUTPUT_RAND: 0x05, - GET_CONVERT_RAND: 0x06, - SIGN_MASP_SPENDS: 0x07, - EXTRACT_SPEND_SIGN: 0x08, - CLEAN_RANDOMNESS_BUFFERS: 0x09, -} -export const SALT_LEN = 8 -export const HASH_LEN = 32 -export const PK_LEN_PLUS_TAG = 33 -export const SIG_LEN_PLUS_TAG = 65 -export const KEY_LENGTH = 32 -export const RANDOMNESS_LENGTH = 32 diff --git a/js/src/index.ts b/js/src/index.ts deleted file mode 100644 index 7ae3eaca..00000000 --- a/js/src/index.ts +++ /dev/null @@ -1,16 +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. - ******************************************************************************* */ -export * from './namadaApp' diff --git a/js/src/namadaApp.ts b/js/src/namadaApp.ts deleted file mode 100644 index 750dcea2..00000000 --- a/js/src/namadaApp.ts +++ /dev/null @@ -1,332 +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. - ******************************************************************************* */ -import Transport from '@ledgerhq/hw-transport' -import { - KeyResponse, - NamadaKeys, - ResponseAddress, - ResponseAppInfo, - ResponseBase, - ResponseGetConvertRandomness, - ResponseGetOutputRandomness, - ResponseGetSpendRandomness, - ResponseSign, - ResponseSignMasp, - ResponseVersion, -} from './types' - -import { CHUNK_SIZE, errorCodeToString, LedgerError, P1_VALUES, PAYLOAD_TYPE, processErrorResponse, serializePath } from './common' - -import { CLA, INS } from './config' -import { - getSignatureResponse, - processConvertRandomnessResponse, - processGetAddrResponse, - processGetKeysResponse, - processMaspSign, - processOutputRandomnessResponse, - processSpendRandomnessResponse, - processSpendSignResponse, -} from './processResponses' - -export { LedgerError } -export * from './types' - -export class NamadaApp { - transport: Transport - - constructor(transport: Transport) { - if (!transport) { - throw new Error('Transport has not been defined') - } - - this.transport = transport - } - - async prepareChunks(serializedPath: Buffer, message: Buffer) { - const chunks = [] - - chunks.push(serializedPath) - for (let i = 0; i < message.length; i += CHUNK_SIZE) { - let end = i + CHUNK_SIZE - if (i > message.length) { - end = message.length - } - chunks.push(message.subarray(i, end)) - } - - return chunks - } - - async getVersion(): Promise { - return this.transport.send(CLA, INS.GET_VERSION, 0, 0).then((response: any) => { - const errorCodeData = response.slice(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - let targetId = 0 - if (response.length >= 9) { - /* eslint-disable no-bitwise */ - targetId = (response[5] << 24) + (response[6] << 16) + (response[7] << 8) + (response[8] << 0) - /* eslint-enable no-bitwise */ - } - - return { - returnCode: returnCode, - errorMessage: errorCodeToString(returnCode), - // /// - testMode: response[0] !== 0, - major: response[1], - minor: response[2], - patch: response[3], - deviceLocked: response[4] === 1, - targetId: targetId.toString(16), - } - }, processErrorResponse) - } - - async getAppInfo(): Promise { - return this.transport.send(0xb0, 0x01, 0, 0).then(response => { - const errorCodeData = response.slice(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - const result: { errorMessage?: string; returnCode?: LedgerError } = {} - - let appName = 'err' - let appVersion = 'err' - let flagLen = 0 - let flagsValue = 0 - - if (response[0] !== 1) { - // Ledger responds with format ID 1. There is no spec for any format != 1 - result.errorMessage = 'response format ID not recognized' - result.returnCode = LedgerError.DeviceIsBusy - } else { - const appNameLen = response[1] - appName = response.slice(2, 2 + appNameLen).toString('ascii') - let idx = 2 + appNameLen - const appVersionLen = response[idx] - idx += 1 - appVersion = response.slice(idx, idx + appVersionLen).toString('ascii') - idx += appVersionLen - const appFlagsLen = response[idx] - idx += 1 - flagLen = appFlagsLen - flagsValue = response[idx] - } - - return { - returnCode, - errorMessage: errorCodeToString(returnCode), - // - appName, - appVersion, - flagLen, - flagsValue, - flagRecovery: (flagsValue & 1) !== 0, - // eslint-disable-next-line no-bitwise - flagSignedMcuCode: (flagsValue & 2) !== 0, - // eslint-disable-next-line no-bitwise - flagOnboarded: (flagsValue & 4) !== 0, - // eslint-disable-next-line no-bitwise - flagPINValidated: (flagsValue & 128) !== 0, - } - }, processErrorResponse) - } - - async getAddressAndPubKey(path: string): Promise { - const serializedPath = serializePath(path) - return this.transport - .send(CLA, INS.GET_TRANSPARENT_ADDRESS, P1_VALUES.ONLY_RETRIEVE, 0, serializedPath, [LedgerError.NoErrors]) - .then(processGetAddrResponse, processErrorResponse) - } - - async showAddressAndPubKey(path: string): Promise { - const serializedPath = serializePath(path) - return this.transport - .send(CLA, INS.GET_TRANSPARENT_ADDRESS, P1_VALUES.SHOW_ADDRESS_IN_DEVICE, 0, serializedPath, [LedgerError.NoErrors]) - .then(processGetAddrResponse, processErrorResponse) - } - - async signSendChunk(chunkIdx: number, chunkNum: number, chunk: Buffer, ins: number): Promise { - let payloadType = PAYLOAD_TYPE.ADD - const p2 = 0 - if (chunkIdx === 1) { - payloadType = PAYLOAD_TYPE.INIT - } - if (chunkIdx === chunkNum) { - payloadType = PAYLOAD_TYPE.LAST - } - - return this.transport - .send(CLA, ins, payloadType, p2, chunk, [ - LedgerError.NoErrors, - LedgerError.DataIsInvalid, - LedgerError.BadKeyHandle, - LedgerError.SignVerifyError, - ]) - .then((response: Buffer) => { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - let errorMessage = errorCodeToString(returnCode) - - if ( - returnCode === LedgerError.BadKeyHandle || - returnCode === LedgerError.DataIsInvalid || - returnCode === LedgerError.SignVerifyError - ) { - errorMessage = `${errorMessage} : ${response.subarray(0, response.length - 2).toString('ascii')}` - } - - if (returnCode === LedgerError.NoErrors && response.length > 2) { - return { - signature: getSignatureResponse(response), - returnCode, - errorMessage, - } - } - - return { - returnCode: returnCode, - errorMessage: errorMessage, - } as ResponseSign - }, processErrorResponse) - } - - async signSendMaspChunk(chunkIdx: number, chunkNum: number, chunk: Buffer, ins: number): Promise { - let payloadType = PAYLOAD_TYPE.ADD - const p2 = 0 - if (chunkIdx === 1) { - payloadType = PAYLOAD_TYPE.INIT - } - if (chunkIdx === chunkNum) { - payloadType = PAYLOAD_TYPE.LAST - } - - return this.transport - .send(CLA, ins, payloadType, p2, chunk, [ - LedgerError.NoErrors, - LedgerError.DataIsInvalid, - LedgerError.BadKeyHandle, - LedgerError.SignVerifyError, - ]) - .then((response: Buffer) => { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - let errorMessage = errorCodeToString(returnCode) - - if ( - returnCode === LedgerError.BadKeyHandle || - returnCode === LedgerError.DataIsInvalid || - returnCode === LedgerError.SignVerifyError - ) { - errorMessage = `${errorMessage} : ${response.subarray(0, response.length - 2).toString('ascii')}` - } - - if (returnCode === LedgerError.NoErrors && response.length > 2) { - return processMaspSign(response); - } - - return { - returnCode: returnCode, - errorMessage: errorMessage, - } as ResponseSignMasp - }, processErrorResponse) - } - - async sign(path: string, message: Buffer): Promise { - const serializedPath = serializePath(path) - - return this.prepareChunks(serializedPath, message).then(chunks => { - return this.signSendChunk(1, chunks.length, chunks[0], INS.SIGN).then(async response => { - let result: ResponseSign = { - returnCode: response.returnCode, - errorMessage: response.errorMessage, - } - - for (let i = 1; i < chunks.length; i++) { - result = await this.signSendChunk(1 + i, chunks.length, chunks[i], INS.SIGN) - if (result.returnCode !== LedgerError.NoErrors) { - break - } - } - return result - }, processErrorResponse) - }, processErrorResponse) - } - - async retrieveKeys(path: string, keyType: NamadaKeys, showInDevice: boolean): Promise { - const serializedPath = serializePath(path) - const p1 = showInDevice ? P1_VALUES.SHOW_ADDRESS_IN_DEVICE : P1_VALUES.ONLY_RETRIEVE - return this.transport - .send(CLA, INS.GET_KEYS, p1, keyType, serializedPath, [LedgerError.NoErrors]) - .then(result => processGetKeysResponse(result, keyType) as KeyResponse, processErrorResponse) - } - - async signMaspSpends(path: string, masp: Buffer): Promise { - const serializedPath = serializePath(path) - return this.prepareChunks(serializedPath, masp).then(chunks => { - return this.signSendMaspChunk(1, chunks.length, chunks[0], INS.SIGN_MASP_SPENDS).then(async response => { - let result: ResponseSign = { - returnCode: response.returnCode, - errorMessage: response.errorMessage, - } - - for (let i = 1; i < chunks.length; i++) { - result = await this.signSendMaspChunk(1 + i, chunks.length, chunks[i], INS.SIGN_MASP_SPENDS) - if (result.returnCode !== LedgerError.NoErrors) { - break - } - } - return result - }, processErrorResponse) - }, processErrorResponse) - } - - async getSpendRandomness(): Promise { - return this.transport - .send(CLA, INS.GET_SPEND_RAND, P1_VALUES.ONLY_RETRIEVE, 0, Buffer.from([]), [0x9000]) - .then(processSpendRandomnessResponse, processErrorResponse); - } - - async getOutputRandomness(): Promise { - return this.transport - .send(CLA, INS.GET_OUTPUT_RAND, P1_VALUES.ONLY_RETRIEVE, 0, Buffer.from([]), [0x9000]) - .then(processOutputRandomnessResponse, processErrorResponse); - } - - async getConvertRandomness(): Promise { - return this.transport - .send(CLA, INS.GET_CONVERT_RAND, P1_VALUES.ONLY_RETRIEVE, 0, Buffer.from([]), [0x9000]) - .then(processConvertRandomnessResponse, processErrorResponse); - } - - async getSpendSignature() { - return this.transport - .send(CLA, INS.EXTRACT_SPEND_SIGN, P1_VALUES.ONLY_RETRIEVE, 0, Buffer.from([]), [0x9000]) - .then(processSpendSignResponse, processErrorResponse); - } - - async cleanRandomnessBuffers() { - return this.transport - .send(CLA, INS.CLEAN_RANDOMNESS_BUFFERS, 0, 0, Buffer.from([]), [0x9000]) - .then(() => { - return { - returnCode: LedgerError.NoErrors, - errorMessage: errorCodeToString(LedgerError.NoErrors), - } - }, processErrorResponse); - } -} diff --git a/js/src/processResponses.ts b/js/src/processResponses.ts deleted file mode 100644 index 42302360..00000000 --- a/js/src/processResponses.ts +++ /dev/null @@ -1,212 +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. - ******************************************************************************* */ - -import { errorCodeToString } from './common' -import { KEY_LENGTH, PK_LEN_PLUS_TAG, RANDOMNESS_LENGTH, SALT_LEN, SIG_LEN_PLUS_TAG } from './config' -import { ISignature, KeyResponse, NamadaKeys, ResponseGetConvertRandomness, ResponseGetOutputRandomness, ResponseGetSpendRandomness, ResponseSignMasp, ResponseSpendSign } from './types' - -export function getSignatureResponse(response: Buffer): ISignature { - // App sign response: [ rawPubkey(33) | raw_salt(8) | raw_signature(65) | wrapper_salt(8) | wrapper_signature(65) | - // raw_indices_len(1) | wrapper_indices_len(1) | indices(wrapper_indices_len) ] - - let offset = 0 - const rawPubkey = Buffer.from(response.subarray(offset, offset + PK_LEN_PLUS_TAG)) - - offset += PK_LEN_PLUS_TAG - const raw_salt = Buffer.from(response.subarray(offset, offset + SALT_LEN)) - offset += SALT_LEN - const raw_signature = Buffer.from(response.subarray(offset, offset + SIG_LEN_PLUS_TAG)) - - offset += SIG_LEN_PLUS_TAG - const wrapper_salt = Buffer.from(response.subarray(offset, offset + SALT_LEN)) - offset += SALT_LEN - const wrapper_signature = Buffer.from(response.subarray(offset, offset + SIG_LEN_PLUS_TAG)) - - offset += SIG_LEN_PLUS_TAG - const raw_indices_len = response[offset] - offset += 1 - const raw_indices = Buffer.from(response.subarray(offset, offset + raw_indices_len)) - offset += raw_indices_len - - const wrapper_indices_len = response[offset] - offset += 1 - const wrapper_indices = Buffer.from(response.subarray(offset, offset + wrapper_indices_len)) - offset += wrapper_indices_len - - return { - rawPubkey, - raw_salt, - raw_signature, - wrapper_salt, - wrapper_signature, - raw_indices, - wrapper_indices, - } -} - -export function processGetAddrResponse(response: Buffer) { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - const rawPubkey = response.subarray(0, PK_LEN_PLUS_TAG) - response = response.subarray(PK_LEN_PLUS_TAG) - - const pubkeyLen = response[0] - const pubkey = response.subarray(1, pubkeyLen + 1) - response = response.subarray(pubkeyLen + 1) - - const addressLen = response[0] - const address = response.subarray(1, addressLen + 1) - - console.log(pubkey.toString()) - console.log(address.toString()) - - return { - rawPubkey, - pubkey, - address, - returnCode, - errorMessage: errorCodeToString(returnCode), - } -} - -export function processGetKeysResponse(response: Buffer, keyType: NamadaKeys): KeyResponse { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - let requestedKey: KeyResponse = { - returnCode: returnCode, - errorMessage: errorCodeToString(returnCode), - } - - switch (keyType) { - case NamadaKeys.PublicAddress: { - const publicAddress = Buffer.from(response.subarray(0, KEY_LENGTH)) - requestedKey = { - ...requestedKey, - publicAddress, - } - break - } - - case NamadaKeys.ViewKey: { - const viewKey = Buffer.from(response.subarray(0, 2 * KEY_LENGTH)) - response = response.subarray(2 * KEY_LENGTH) - - const ovk = Buffer.from(response.subarray(0, KEY_LENGTH)) - response = response.subarray(KEY_LENGTH) - - const ivk = Buffer.from(response.subarray(0, KEY_LENGTH)) - response = response.subarray(KEY_LENGTH) - - const dk = Buffer.from(response.subarray(0, KEY_LENGTH)) - response = response.subarray(KEY_LENGTH) - - requestedKey = { - ...requestedKey, - viewKey, - ovk, - ivk, - dk, - } - break - } - - case NamadaKeys.ProofGenerationKey: { - const ak = Buffer.from(response.subarray(0, KEY_LENGTH)) - response = response.subarray(KEY_LENGTH) - - const nsk = Buffer.from(response.subarray(0, KEY_LENGTH)) - response = response.subarray(KEY_LENGTH) - - requestedKey = { - ...requestedKey, - ak, - nsk, - } - break - } - } - - return requestedKey -} - -export function processSpendRandomnessResponse( - response: Buffer, -): ResponseGetSpendRandomness { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - return { - rcv: Buffer.from(response.subarray(0, RANDOMNESS_LENGTH)), - alpha: Buffer.from(response.subarray(RANDOMNESS_LENGTH, 2 * RANDOMNESS_LENGTH)), - returnCode, - errorMessage: errorCodeToString(returnCode), - } -} - -export function processOutputRandomnessResponse( - response: Buffer, -): ResponseGetOutputRandomness { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - return { - rcv: Buffer.from(response.subarray(0, RANDOMNESS_LENGTH)), - rcm: Buffer.from(response.subarray(RANDOMNESS_LENGTH, 2 * RANDOMNESS_LENGTH)), - returnCode, - errorMessage: errorCodeToString(returnCode), - } -} - -export function processConvertRandomnessResponse( - response: Buffer, -): ResponseGetConvertRandomness { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - - return { - rcv: Buffer.from(response.subarray(0, RANDOMNESS_LENGTH)), - returnCode, - errorMessage: errorCodeToString(returnCode), - } -} - -export function processMaspSign( - response: Buffer, -): ResponseSignMasp { - const errorCodeData = response.subarray(-2) - const returnCode = errorCodeData[0] * 256 + errorCodeData[1] - let hash = Buffer.from(response.subarray(0, 32)) - - return { - hash, - returnCode, - errorMessage: errorCodeToString(returnCode), - } -} - -export function processSpendSignResponse(response: Buffer): ResponseSpendSign { - const errorCodeData = response.slice(-2); - const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; - - return { - rbar: Buffer.from(response.subarray(0, 32)), - sbar: Buffer.from(response.subarray(32, 64)), - returnCode, - errorMessage: errorCodeToString(returnCode), - }; -} diff --git a/js/src/types.ts b/js/src/types.ts deleted file mode 100644 index 656ca6d6..00000000 --- a/js/src/types.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { LedgerError } from './common' - -export interface ResponseBase { - errorMessage: string - returnCode: LedgerError -} - -export type KeyResponse = ResponseAddress | ResponseViewKey | ResponseProofGenKey; - -export interface ResponseAddress extends ResponseBase { - rawPubkey: Buffer - pubkey: Buffer - address: Buffer -} - -export interface ResponseVersion extends ResponseBase { - testMode: boolean - major: number - minor: number - patch: number - deviceLocked: boolean - targetId: string -} - -export interface ResponseAppInfo extends ResponseBase { - appName: string - appVersion: string - flagLen: number - flagsValue: number - flagRecovery: boolean - flagSignedMcuCode: boolean - flagOnboarded: boolean - flagPINValidated: boolean -} - -export interface ResponseDeviceInfo extends ResponseBase { - targetId: string - seVersion: string - flag: string - mcuVersion: string -} - -export interface ResponseAddress extends ResponseBase { - publicAddress?: Buffer; -} - -export interface ResponseViewKey extends ResponseBase { - viewKey?: Buffer; - ivk?: Buffer; - ovk?: Buffer; - dk?: Buffer; -} - - export interface ResponseProofGenKey extends ResponseBase { - ak?: Buffer; - nsk?: Buffer; -} - -export interface ISignature { - rawPubkey: Buffer - raw_salt: Buffer - raw_signature: Buffer - wrapper_salt: Buffer - wrapper_signature: Buffer - raw_indices: Buffer - wrapper_indices: Buffer -} -export class Signature implements ISignature { - rawPubkey: Buffer - raw_salt: Buffer - raw_signature: Buffer - wrapper_salt: Buffer - wrapper_signature: Buffer - raw_indices: Buffer - wrapper_indices: Buffer - isFilled: boolean - - constructor(signature?: ISignature) { - if (signature == null) { - this.isFilled = false - this.rawPubkey = Buffer.from([]) - this.raw_salt = Buffer.from([]) - this.raw_signature = Buffer.from([]) - this.wrapper_salt = Buffer.from([]) - this.wrapper_signature = Buffer.from([]) - this.raw_indices = Buffer.from([]) - this.wrapper_indices = Buffer.from([]) - } else { - this.isFilled = true - this.rawPubkey = signature.rawPubkey - this.raw_salt = signature.raw_salt - this.raw_signature = signature.raw_signature - this.wrapper_salt = signature.wrapper_salt - this.wrapper_signature = signature.wrapper_signature - this.raw_indices = signature.raw_indices - this.wrapper_indices = signature.wrapper_indices - } - } -} - -export interface ResponseSign extends ResponseBase { - signature?: Signature -} - -export interface ResponseSpendSign extends ResponseBase { - rbar: Buffer - sbar: Buffer -} - -export interface ResponseSignMasp extends ResponseBase { - hash: Buffer -} - -export interface ResponseGetSpendRandomness extends ResponseBase { - rcv: Buffer - alpha: Buffer -} - -export interface ResponseGetOutputRandomness extends ResponseBase { - rcv: Buffer - rcm: Buffer -} - -export interface ResponseGetConvertRandomness extends ResponseBase { - rcv: Buffer -} -export enum NamadaKeys { - PublicAddress = 0x00, - ViewKey = 0x01, - ProofGenerationKey = 0x02, -} diff --git a/js/tsconfig.json b/js/tsconfig.json deleted file mode 100644 index bf24a795..00000000 --- a/js/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", - "target": "es2020", - "strict": true, - "esModuleInterop": true, - "declaration": true, - "skipLibCheck": true, - "outDir": "./dist", - "sourceMap": true, - "inlineSources": true - }, - "exclude": ["./dist/**"] -} diff --git a/rs/src/lib.rs b/rs/src/lib.rs index b40bb3bf..f47a9391 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -624,24 +624,20 @@ where } /// Clean buffers - pub async fn clean_randomness_buffers( - &self, - path: &BIP44Path, - blob: &[u8], - ) -> Result<(), NamError> { - let first_chunk = path.serialize_path().unwrap(); - - let start_command = APDUCommand { + pub async fn clean_randomness_buffers(&self) -> Result<(), NamError> { + let arr: &[u8] = &[]; + let command = APDUCommand { cla: CLA, ins: InstructionCode::CleanBuffers as _, p1: ChunkPayloadType::Init as u8, p2: 0x00, - data: first_chunk, + data: arr, // Send empty data }; - let response = - >::send_chunks(&self.apdu_transport, start_command, blob).await?; - + self.apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; Ok(()) } } diff --git a/tests_zemu/snapshots/fl-mainmenu/00004.png b/tests_zemu/snapshots/fl-mainmenu/00004.png index 7ec55234..9c6f0139 100644 Binary files a/tests_zemu/snapshots/fl-mainmenu/00004.png and b/tests_zemu/snapshots/fl-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00000.png b/tests_zemu/snapshots/fl-sign_masp_spends/00000.png index fe7c156f..ce222be2 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00000.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00000.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00001.png b/tests_zemu/snapshots/fl-sign_masp_spends/00001.png index 15b8f38f..bdf9cf74 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00001.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00001.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00002.png b/tests_zemu/snapshots/fl-sign_masp_spends/00002.png index 82069d2f..b63dfd38 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00002.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00002.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00003.png b/tests_zemu/snapshots/fl-sign_masp_spends/00003.png index 65c58f0d..a318e4e9 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00003.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00003.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00004.png b/tests_zemu/snapshots/fl-sign_masp_spends/00004.png index d50626f1..ccaac837 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00004.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00004.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00005.png b/tests_zemu/snapshots/fl-sign_masp_spends/00005.png index e90a7ec7..eeeb9ce3 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00005.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00005.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00006.png b/tests_zemu/snapshots/fl-sign_masp_spends/00006.png index acb507e5..a14f9312 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00006.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00006.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00007.png b/tests_zemu/snapshots/fl-sign_masp_spends/00007.png index dd22c834..1fcf19d5 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00007.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00007.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00008.png b/tests_zemu/snapshots/fl-sign_masp_spends/00008.png index 0b6d04cc..6afdc1eb 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00008.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00008.png differ diff --git a/tests_zemu/snapshots/fl-sign_masp_spends/00009.png b/tests_zemu/snapshots/fl-sign_masp_spends/00009.png index b17cb95c..583b94c3 100644 Binary files a/tests_zemu/snapshots/fl-sign_masp_spends/00009.png and b/tests_zemu/snapshots/fl-sign_masp_spends/00009.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index fa411bfc..83807a0f 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00004.png and b/tests_zemu/snapshots/s-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00010.png b/tests_zemu/snapshots/s-mainmenu/00010.png index fa411bfc..83807a0f 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00010.png and b/tests_zemu/snapshots/s-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00004.png b/tests_zemu/snapshots/sp-mainmenu/00004.png index 249c9c56..c335c4a2 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00004.png and b/tests_zemu/snapshots/sp-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00010.png b/tests_zemu/snapshots/sp-mainmenu/00010.png index 249c9c56..c335c4a2 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00010.png and b/tests_zemu/snapshots/sp-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00002.png b/tests_zemu/snapshots/sp-sign_masp_spends/00002.png index 38cac443..0c167d5a 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00002.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00002.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00003.png b/tests_zemu/snapshots/sp-sign_masp_spends/00003.png index 655b0fbf..d3d542c4 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00003.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00003.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00004.png b/tests_zemu/snapshots/sp-sign_masp_spends/00004.png index 5eff068f..09cf700d 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00004.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00004.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00005.png b/tests_zemu/snapshots/sp-sign_masp_spends/00005.png index 31b1f420..8f5a5f6f 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00005.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00005.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00006.png b/tests_zemu/snapshots/sp-sign_masp_spends/00006.png index 16028403..5c844a55 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00006.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00006.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00007.png b/tests_zemu/snapshots/sp-sign_masp_spends/00007.png index e541119e..b3bf1734 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00007.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00007.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00008.png b/tests_zemu/snapshots/sp-sign_masp_spends/00008.png index ef53e705..33000f4e 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00008.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00008.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00009.png b/tests_zemu/snapshots/sp-sign_masp_spends/00009.png index 4c265b13..57ffa881 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00009.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00009.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00010.png b/tests_zemu/snapshots/sp-sign_masp_spends/00010.png index 85b03f02..e551c832 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00010.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00010.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00011.png b/tests_zemu/snapshots/sp-sign_masp_spends/00011.png index 79dca0de..a039a47c 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00011.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00011.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00012.png b/tests_zemu/snapshots/sp-sign_masp_spends/00012.png index af326f49..e6da1a0e 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00012.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00012.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00013.png b/tests_zemu/snapshots/sp-sign_masp_spends/00013.png index 2f0e41a2..426445f1 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00013.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00013.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00014.png b/tests_zemu/snapshots/sp-sign_masp_spends/00014.png index ff4aca02..d96a2141 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00014.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00014.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00015.png b/tests_zemu/snapshots/sp-sign_masp_spends/00015.png index c98f2d0b..67c1ce88 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00015.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00015.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00016.png b/tests_zemu/snapshots/sp-sign_masp_spends/00016.png index d0ad35f0..e6da1a0e 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00016.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00016.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00017.png b/tests_zemu/snapshots/sp-sign_masp_spends/00017.png index b742791b..a17d4b5b 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00017.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00017.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00018.png b/tests_zemu/snapshots/sp-sign_masp_spends/00018.png index d2840312..1e4be699 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00018.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00018.png differ diff --git a/tests_zemu/snapshots/sp-sign_masp_spends/00019.png b/tests_zemu/snapshots/sp-sign_masp_spends/00019.png index 1b4d7069..7e7f71bd 100644 Binary files a/tests_zemu/snapshots/sp-sign_masp_spends/00019.png and b/tests_zemu/snapshots/sp-sign_masp_spends/00019.png differ diff --git a/tests_zemu/snapshots/st-mainmenu/00004.png b/tests_zemu/snapshots/st-mainmenu/00004.png index 4fd54bcb..979b340a 100644 Binary files a/tests_zemu/snapshots/st-mainmenu/00004.png and b/tests_zemu/snapshots/st-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00000.png b/tests_zemu/snapshots/st-sign_masp_spends/00000.png index 282207c2..d887ba8b 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00000.png and b/tests_zemu/snapshots/st-sign_masp_spends/00000.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00001.png b/tests_zemu/snapshots/st-sign_masp_spends/00001.png index 75bd58a0..fbfe2770 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00001.png and b/tests_zemu/snapshots/st-sign_masp_spends/00001.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00002.png b/tests_zemu/snapshots/st-sign_masp_spends/00002.png index c88be09d..aaba032a 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00002.png and b/tests_zemu/snapshots/st-sign_masp_spends/00002.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00003.png b/tests_zemu/snapshots/st-sign_masp_spends/00003.png index d2edfbc0..269d3090 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00003.png and b/tests_zemu/snapshots/st-sign_masp_spends/00003.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00004.png b/tests_zemu/snapshots/st-sign_masp_spends/00004.png index e0cfe1b4..3831c442 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00004.png and b/tests_zemu/snapshots/st-sign_masp_spends/00004.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00005.png b/tests_zemu/snapshots/st-sign_masp_spends/00005.png index ff29dda1..1b26c92c 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00005.png and b/tests_zemu/snapshots/st-sign_masp_spends/00005.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00006.png b/tests_zemu/snapshots/st-sign_masp_spends/00006.png index f561a803..8984821e 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00006.png and b/tests_zemu/snapshots/st-sign_masp_spends/00006.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00007.png b/tests_zemu/snapshots/st-sign_masp_spends/00007.png index 8130a2e6..c074a73c 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00007.png and b/tests_zemu/snapshots/st-sign_masp_spends/00007.png differ diff --git a/tests_zemu/snapshots/st-sign_masp_spends/00008.png b/tests_zemu/snapshots/st-sign_masp_spends/00008.png index 4bf680d0..bb35228c 100644 Binary files a/tests_zemu/snapshots/st-sign_masp_spends/00008.png and b/tests_zemu/snapshots/st-sign_masp_spends/00008.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index 249c9c56..c335c4a2 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00004.png and b/tests_zemu/snapshots/x-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00010.png b/tests_zemu/snapshots/x-mainmenu/00010.png index 249c9c56..c335c4a2 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00010.png and b/tests_zemu/snapshots/x-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00002.png b/tests_zemu/snapshots/x-sign_masp_spends/00002.png index 38cac443..0c167d5a 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00002.png and b/tests_zemu/snapshots/x-sign_masp_spends/00002.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00003.png b/tests_zemu/snapshots/x-sign_masp_spends/00003.png index 655b0fbf..d3d542c4 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00003.png and b/tests_zemu/snapshots/x-sign_masp_spends/00003.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00004.png b/tests_zemu/snapshots/x-sign_masp_spends/00004.png index 5eff068f..09cf700d 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00004.png and b/tests_zemu/snapshots/x-sign_masp_spends/00004.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00005.png b/tests_zemu/snapshots/x-sign_masp_spends/00005.png index 31b1f420..8f5a5f6f 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00005.png and b/tests_zemu/snapshots/x-sign_masp_spends/00005.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00006.png b/tests_zemu/snapshots/x-sign_masp_spends/00006.png index 16028403..5c844a55 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00006.png and b/tests_zemu/snapshots/x-sign_masp_spends/00006.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00007.png b/tests_zemu/snapshots/x-sign_masp_spends/00007.png index e541119e..b3bf1734 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00007.png and b/tests_zemu/snapshots/x-sign_masp_spends/00007.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00008.png b/tests_zemu/snapshots/x-sign_masp_spends/00008.png index ef53e705..33000f4e 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00008.png and b/tests_zemu/snapshots/x-sign_masp_spends/00008.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00009.png b/tests_zemu/snapshots/x-sign_masp_spends/00009.png index 4c265b13..57ffa881 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00009.png and b/tests_zemu/snapshots/x-sign_masp_spends/00009.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00010.png b/tests_zemu/snapshots/x-sign_masp_spends/00010.png index 85b03f02..e551c832 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00010.png and b/tests_zemu/snapshots/x-sign_masp_spends/00010.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00011.png b/tests_zemu/snapshots/x-sign_masp_spends/00011.png index 79dca0de..a039a47c 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00011.png and b/tests_zemu/snapshots/x-sign_masp_spends/00011.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00012.png b/tests_zemu/snapshots/x-sign_masp_spends/00012.png index af326f49..e6da1a0e 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00012.png and b/tests_zemu/snapshots/x-sign_masp_spends/00012.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00013.png b/tests_zemu/snapshots/x-sign_masp_spends/00013.png index 2f0e41a2..426445f1 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00013.png and b/tests_zemu/snapshots/x-sign_masp_spends/00013.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00014.png b/tests_zemu/snapshots/x-sign_masp_spends/00014.png index ff4aca02..d96a2141 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00014.png and b/tests_zemu/snapshots/x-sign_masp_spends/00014.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00015.png b/tests_zemu/snapshots/x-sign_masp_spends/00015.png index c98f2d0b..67c1ce88 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00015.png and b/tests_zemu/snapshots/x-sign_masp_spends/00015.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00016.png b/tests_zemu/snapshots/x-sign_masp_spends/00016.png index d0ad35f0..e6da1a0e 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00016.png and b/tests_zemu/snapshots/x-sign_masp_spends/00016.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00017.png b/tests_zemu/snapshots/x-sign_masp_spends/00017.png index b742791b..a17d4b5b 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00017.png and b/tests_zemu/snapshots/x-sign_masp_spends/00017.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00018.png b/tests_zemu/snapshots/x-sign_masp_spends/00018.png index d2840312..1e4be699 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00018.png and b/tests_zemu/snapshots/x-sign_masp_spends/00018.png differ diff --git a/tests_zemu/snapshots/x-sign_masp_spends/00019.png b/tests_zemu/snapshots/x-sign_masp_spends/00019.png index 1b4d7069..7e7f71bd 100644 Binary files a/tests_zemu/snapshots/x-sign_masp_spends/00019.png and b/tests_zemu/snapshots/x-sign_masp_spends/00019.png differ diff --git a/tests_zemu/tests/common.ts b/tests_zemu/tests/common.ts index 08c33696..8205dedd 100644 --- a/tests_zemu/tests/common.ts +++ b/tests_zemu/tests/common.ts @@ -38,7 +38,7 @@ export const expectedKeys: ExpectedValues = { dk: "73c3174b1da27fac251ab502d5874bf14a813d12f39def55b98f2eaa8de45103", } -export const MASP_TRANSFER_TX = "150000005470655f3635467456785f5151437765455f5f5f5f0023000000393438302d31302d32335430353a33343a35372e3437393130313032372b30303a30300100000079b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26100000000000000000000000000000000000000000000000000000000000000000001efea3e1f11cc2f0b000000000000000000000000000000000000000000000000f90025bb32ca01580961be84ce307b9a61a90acb3b8c00fb2099dab5546e4cb122ed7204d0d334de930ba4f946ce4892562605e688559e83ff0a0bea63bcdc06000000022e1637aa4062b46c004d20381a4ea0f2e226a89d96a12e6dbfe999117b9e3b6bfc483ad9608719db1a011000000074785f7472616e736665722e7761736d00d6cd4bfade149c76290000000000000000000000010903dc1f3246f6dc11c423b63af54a8dcbc4669ac2ddc6474159b90f56a7d5c704020000000a27a726a675ffe90000000042864ae90000015a963918c623d53eefd5299d5539a462ee8f0d44bba874af01477677c51bf99ecfac7e5a8222a5506464d41ff45bf1d441997bf9f940fb11c6733031442441517d9d1d8cd30b1e26100d85ccc6acf8cdd8de2f90e0deb64660e47eccfe23e2020002696aab971e409a78348da5386e5b1e0140661681f9c46424d06c9d61fcfd1015db1655b60c7834aebfe133695f92956eb2980ebf7480819581032c2e9449e072303fd2544b939e290d0eb701f6c49ee0f59d153bb117ded8fffdb98c923f1d08f72af0e1df8eaf28a757476fc71d8cfb6bf484631dc6f65f4dc0dcbac231c8834058255b1b2860ed799ca952ebfe96352475f595f2787b54a2741b6558e66207c35a7e27629ea52670c860c0fc7dc0a0a488942c1d2e4078265da8efd524d9a5c9dc1cb3423bb8da6adba0984b156fafe774521da3e67c90607de6c9eec02d21bda68b7914f5d78a93536fac3fdcea020b8f6d79d686bfd905b2800a38c55008587a416e21d21329cc57bb038b67f5184640b5974b13f749265fff9a6b49e057b186865545d1e28e0a85e756404c36a831f13932396da5da0ecf45e8bcc4e2f40eb8dc06c3029fc726eddf556f6e3acf6b5f6de4a5d30f22c23ff131d9105795879b18b3f73375140d989cfe388aea4232b7610b9476f8cac497b2b7cc886430f304edbd79b6b051253f24da83ebbd3ab46840255039bc264671aa648884c3f2297a54746c0f5ab0ec0462f2840abd47203e84541c74ab9fbf0129722f7be59c82c0f06a59dd645f9c8b3188e3c4c69eef926aca45e58d811afaa12623508f48e62f78e243187c3b291d214e132c9531d66f822597b4967bab0999fb4763fba369fe3ec1435665b896d3156a2dc06c74388afcf31bef9b6da0ad5ad4a7a37e4125cd82857fdd7f2f9959d98b97a4a851807e48917e02ac38c2eb3ea20eaf610276b34da046bc7be2a61a43149e234881fb23b6ede9b0a1476f9452fe86d4e1de0212f26adfa10f992303a9da93dc3be636ed3048583a93139124238366cbc9e43c282826304ae655bde0f24582819edc119879bf24eb63a363565e02b868f647148d7c3736a7628cc41e7d967a51509bc316fe895ff405449d712ae0a33269450163561a4697116d109a8532e528ca9b79240ab32503b52ea91694bb5dce7828c4556c9e77337d45c41810861ec1aa38a018f62496d7cbf33a80ae81b4b86ada85a4faf96c9f2d03a95c128e54602a4b459ddf38300bdd66631e40a4a5521cc80677420c5468be8c579ce1e089b8739965967334b438188cd2662f3faa85af6b88cacab00d250091c7233d92e7569a5d1526b82ea806f9b7680f32b4436e62c2c4028aa1152b619a6baa0f8bc6472f17dbe2e7b6288254c52bfcb146b3279690472f92f89fc86589736b660f3734d52251463f63cb52d0db17d2dec3c87ba1f99a43fb5f0084719ae306aa0bf21deea925d3945afce2fb0d361760d6baa68936d10364a471a44276a47fb879927c7612c957700359f4a40bec31eca10d901e3ada7816c346723d16d445403ccd9ebfcd0e5c58f066d9686f8a352aa174846e358f191dd265e165ac9a62d6c3f0c2d177ee598fcb3589cb4a94e95a6b3dabca7e833f854f4bdb6243492fad78432543c689b2161ec80c9f3db6b01693fe01e64cb10e50e561e8ff5309d428f972f23c856b4aca8e73a6ac11648c2ffd8c3de167370b8a9eb0b7034e4b517e77742fc66e67269825fcbdb294a98efc59c8371bf01eb7f0a764a9d7b7692cc22a3e586f1a73fbcf8d62d4d9badbcf9aefdfcbb2394fc3382572b3b7e2cddaa0a2ecb6ac035e2e2867ead7af1410746ed43839a2aa00e6af303cd48f9681bacd26033541d85ec47816ba455d193421c7dae04eebf54cf92cc3b3577fa17d04ea4a063093c07d8c8e23b3e361c4c30cdcd623aa94dedf703d0b5605dc4a884e09ab63fb744c8959137f55820a290adb38d9d6a4ffe613e57c5fbdab9f8b5a07663cdb644adffb02fda036fbb7cc222869cae509928aa73480e79e440ec3fe5f4adea8764cb03669454054f653ba93e54703d4b62161db55a9b57ea0d013b64b283fd8c9df4f2e7349147feccefd48c6088f1deb3653fcc03512ccbdfff076a70dfd9453e7703890e022aa22ae752833987c16eeb695dfeed0dfb4b31fdacf8d127634cd718ce1dd414d1aa172be28074ea5f8bf2db8672fcd45a24105ea3deafc67323f9d12ea12489c818b1c0ae7dd79d8ad8ceb3a301254c966a82da54c7611c7c5677c307432727f7902898837a2490db693b25f56512cb3618ab24cd2a1d5e0b07c5b8de5dbe69e5c6cd3a1b5d9262b942f93356ca3e7a33d785d3100194712c4b62f4f95b49cc3129bcf867a486df43793999649dd580bcfefa7182697f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb9ef0b395bfc0bc14bde3cf7d4591eb66096944af394f6171debaf8efcdbf4a434f851210eb394899802c91b0e88afac3c564ba641a5dd8c24a7bff12b59d120697f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb6e8647b704ba7bdb643b5409cbc1623f52ce7acfd3ff4a3a4cb12a5548161a57856ddc809f34df26774326ac7bc4937a852c3aed01b12a81e096f9516b53db03050903dc1f3246f6dc11c423b63af54a8dcbc4669ac2ddc6474159b90f56a7d5c70100000002089fe2c139ce51f0ca36115e113c8fd60a41248132f0030118ae2a75e04246d5010000000000000000000000000000000100000000000000000000002e864ae942864ae9000000000000000001194712c4b62f4f95b49cc3129bcf867a486df43793999649dd580bcfefa718262e864ae90000010000000000000000000000009980aef6a062435f203fd1dba8cc1570bc84720519361351766d13625205ad07f71fa3b0f8e439251eb7f7931dbd08f5489c14b063df7bb51f110af9f34ac75ac53f49bb1035144d3d348ea1c39062727e9d208351204539254df29257dd04d7887ae5c99ef2e3e06ebcc172c2383aca81272da1f482abd1a1a91182a0bf475120487240083a18b885f9db835a41782832513402948e78f74a27ea8d4ac0db53123d58b6551d4430a6aa73090cb40a3928ba64f4c2414a3551dea5f599506d12795a06583ee8d676a3dba83c000000000000003e7a3f5fffe13ef1d78e5f3875d6992b6ccb760135bcb5be06d3f608af61e5000823bd80954a39a49d89d6255743dad368a7eb6f3073cacc2f6d9878b07d395f02472f4be8a7d92ca5a32908b12bc3b7d9f771678e744df7b0e2166147e35c7e0e2020de43f9cb72ec5b01c93aff1981a6cb7765b3e0c60ecdd4f0ddc1f1dda252ff0e20ad15f9b7057e4431f40b17d3cc76194d8339b1ddd9d80b20352002634663642e2089fd643bbfeef5b486e4e29e1c99d72c29944791c32fc225396b59318681b633208ef64e2cbb03d5af593244b253abc3e94db3b9150596e17303940d4eb2d5781a20a5461d4e8bd352703204beb6277e50a2c27e7779f7ab98fd45ceb0bba5c1b901203b52fb113249110b4566887d79a9693c3be69572a5b90b690702066e97ef155c204b07ba48cb4a793c01dfeb6392195b6493f3ceed52b5cea7df7279220e967e47204147f5d495d644e9c246093bdba51a94d44de39bb435f3410b52969570babe6d20b522e12ee1a1aa449be27411bbf4f8bdf90a8a816b7144f28991fa307644541b20d88bbcd3447046ef164ce336bdb9d6d29f4367d2f8aa7d39644e87c9c1ecca05202d7708b49a8ab745c2f51f638649c6a455842a6f4e040aae4d9885546337245920897423682b6d8f56fce75bf9c4a7f70f35dfa7386e554e7c561a62a835c3a3662049c2d8eff3e9c0a5a2017de57ab4e2c12eea2cf06228127f26580f4fa9af5623206ed767be9c66da7d6f7eba511871d9da61456026b7f310e15e3359ac41ec926020dd0e078b30ad16780690abae311be0130c2a9a030d0d65c8f12aec3264ed853b208934595bab6108f9b2e6fa75d4e1d285eb79791c5e7610358acd626a4b17022120b93879c9b8476d6b3952933c83a07ac6aeeb01f6bc971b6740da7614a47da958203a6ac56a4149e8c9bd8119e3ab6fa7780bda6fc14d6119c416a11a1bc1c0b60d2048917eaa9b4c094d69ec54970475d3df466a984ee9aed707970c69bc958f6e61209eed88e4f9bb67d455f9aebdb6ab4ef8b566b03f230804c7f58214043bd4e471202cd2e15a6e521b4ff874c7261fcba80b7782526f236bf73435ce20eb136d4c33203ea72374fe684e6a8eb5d4980633218da196cab396fcdddf6831953298f3e45520798e3416956611fa66571e10e50b8b2c0abf537f16afc725ced4ece6b279142420806ab1a3c089454e16575ceece1e3aefee2a6184255e18a2343fb7feb86b7e6d204e8e59d04c3f4469e9d58483fc8539db868cf2334f4257121ad6f80db6c9702d204c66cea9b58243efbe2e62d1da3a03a48cfbce68ef212b3c77acb1e12c5ab962205b5714543c02aa922a6620e12e901943fc5b03bb9ae1586c002d639570326707203aa41a68aac5b5e125616c1c4efb4a00e08ca4f8e65e66a1470d7c47c72a140f2039cf8d1399cea0bbb22c31ff1ed14be62acb70e75f13aa0757c29d76b943a53e206772ffd2b185aac6d10dc02551d9de9e7094b5548e9e13a833da8dc477a1022020325aea4964041359acb6d15fa724089dd7242a7a61b1d9db50983e402d88ff1d2001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000cbb7d0983d49b7c16f336f2a866d51582bf12100a546969c93b781cfe64d9e79923a1614f6653111eb06db090cb40a3928ba64f4c2414a3551dea5f599506d12795a06583ee8d676a3dba83c00000000000000d2dee78dacb6403454640abb0606e2fe1bfb18b72e4f597b21213506cfc4c51d2a866d51582bf12100a546969c93b781cfe64d9e79923a1614f6653111eb06dbf600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030500000050f0e1d591ae077b20a0b9641c22ae484ff6d16049a7869208cef66b6eff627e79b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26158ff6c68e7f4be532aa04b365224038dc1a5d095babf111537b7ffe69dde9ecf08e0961f7133564f30146128683dab4cea1de52334f7fed4d01711700be34a09000147b37cc9e907a9da3286a95cf5498c6948bda0fc02000000d00058a4a0f36e326f08285414ee29a749ddd339500b20045f27914f92585ecc7910b13645bad82237df33aa1b69e82476cac0817d2ff508f3b39c22a77e99d9ea07da00b4f150a8c7af85018135957c8d3759347ee3253b125b0804da0df1aa5f1a9228fc55131a4a62cfb730598362f1b55b66c3dfc890a443e7a5e90b2c5f7105d205030500000050f0e1d591ae077b20a0b9641c22ae484ff6d16049a7869208cef66b6eff627e79b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26158ff6c68e7f4be532aa04b365224038dc1a5d095babf111537b7ffe69dde9ecf08e0961f7133564f30146128683dab4cea1de52334f7fed4d01711700be34a09010200000000a370c8f505aad79664fbb008b27087a8e17bcffe8b7cdeab8fb69e19ce4b5ccc0095a32d9c0dc20017f3c71abb18d92db850041366731e71ee4b4a5665331458680200000000008dbe1d23a2fd1a9d2c189b52615e684920b6d30e2b1072cf0fa396502fc9aaec0768871336b49f2dbb90bf343cf020f32302c34c19d2bbee38f02b2cea300606010027fd72c8570620578263bdcb3f95434887b914315d776008b136dfed41f6ac77a635554823a7b5e9269fefbe982d67562efe7c471476b687d28d59590f656f03"; +export const MASP_TRANSFER_TX = "1e0000006c6f63616c2e6137336433373336643636323630376361616538373632320123000000323032342d30392d31325431353a33393a35322e3730373635323032392b30303a303023000000323032342d30392d31325431343a33393a35322e3730373635393233322b30303a303001000000b1c7286d2a3d091c233c40c06360df3d2c1dcc07339a5e4874d83b89dbca092140c7fe6ca4424e52625e2468a7788a7b6dfffa443844b58aa5c94a5c6bb5d072000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000060090977b64655b77827dadc0f3351af9bde48bfe6e0028a69a99515ee25fd34357a771ab2368f57d1afcea523111608bec9e4a1f386af0490200000000000400000004020000000a27a726a675ffe9000000008e2500000000012b9527b7d7257528033453e54b1667f5c9846ed1fbd562567cad60dca332668c89050e1c2b51e7a34e3ac365f5c83ddccb69faa8d94679cbeab74570166d165c8e7bbcb2ed09960f7dc397983e71f7add76fcc15eadbe60a56fadd85acd7a1e601bd745a9a0d736eaa4764df81264da4bb7a8e82a0d54a907ee44ccc03faf6b4ae0239644fb6a20aa476ea475122ad2e76b35da4c9985b08db04c820d5e6748a8971c8ed2649d79766fc5bd281d53d24a83f8f6c9c05ee663a886b58bb7d90044f176858ea45f2915c0db84f0eba4d22e8109ac70e0ca821f057cc7938432b253ceacfee6a941ff28e4438753086757a67e493698b6016bef59a7093d42d701b1b1ad7820a6b783ca3aa733f5ad9590347d30321db88b3e53f036efdb9798be4e4b8c05cf4c8603650752dc6533cb5a984e22f9d36a4db78d3742ccb841bdc473b80feab12f6597601d8543e3b5b2551c5a89dbb2ba1678789898dc79d4d453bed425c644bcd253d5cba5add57b74387c46345121d8b1791306b2dfa80d321a93c1987010a673a5bde9b1e3ac875716bf7ba7ae1bdfb57452eadd09c5a9d57743ca3ed3f8bbf41786177955f2cbe4ea007e38063f0abd4fc24b4c6001f36822e7289f55e9bed9a022a2962d4cb5cf59e370e07eae672eb392af01eb412e6d94cc07f0b811dc50c028c40ba746427b757d5b5658094ff9687395647b7778323045c8ae45e2a115655b65574fc0fb5dfa90edc6f9779dc5454d3d208d70e4fb3d483c4cb1aa955dc1cd3f66c206bdfe96129a078903953f72a64eb9a3cdfe895c338edc64d79ea97f3bd289cae732f769b8a4c9cb3def0a8cc5fe5c6fa6004e3f001074c7fc655acef4acbf9eb964deb8974dc0afac9f9356dc03e38185c028a3cd843ad5816d7ee55937d2ea73323f2c5e158483d96c652417bed6e2ccb9911e8c9da3be510cedb794e607901d878bdccae8c9445e409696fc2e5716fd0818fb50b092a4cce6d78171c4e5720d89d5d70439fd10b9d6d3a2d38cac2d231b9820d4819c13ddbcb5d38b949f9ef443ce16fc28a1bdfd06f02ee496d689fb8c2f9ebb24a30d5d58a680b7ca52d4a680af6d39b73bbe6f69c8feeb1d8cbb664eb1a140e2075ac45cf9d9fb64ba9b41909f2edd45ccbd19ff266ed13ac35d41c0e723d3b4649e5498b0d515d1c2e4e85f18a3762d32464efbfd83273de384398b7df74ad00ce969046ea03ef335565d1a0f74a2903cb4f3ef94f0fde196902de74e109f0a083ab50fbefae694541e197a946753daef3670642448e54d59dcb908f79402c9debcca96664a339ba1261120fa20ef24751a12cb6c1347dcf846a18b3663c2fc3d04b135636538c65f862bc4960fbd84b43f6b94ca09f38438637364a11595a861bfa62d2f29c9fb19cc13c87f9ee7d699463f202be3f2a92818cf59bda0f61142781123f647bf7b2db3a7a76bd48654cc7fde341c023eb56965d77fb5cf2e189e0b14a4c9fcdaac04f4c113984773cb1c6e971f0e9729f8df7b1b04dd779d5a6ecd44f924013020c96844c3f8a201225b46b4c39e1ce671fa41c6a6c25973bd22ab7f6296ff1df56f26979536f399f78bd4341c96d4ddbbdb1b247858cffee88340e73714e5b68197ff70179b1f1cd138ae731a003a2d11842961a0d0b3054940e5290d3737af0548cc324bfdbdb719cbaddcd7acc59353b0ddacee94be1d2c1a5dfb700e836d41adc491461dad774c858707fafe199fbff4e923053943aa15800b3db3e6608b32294c93d63a4636bef48180a308819368719dcd0424ae5e0d75cc148628d7d3f01327fdd5f7e1d7ea96120691ebef5a5ecde0a0a98fab8c642f3299d90eee79451fe7d781e18cef2f7a1931daaebc80853393d8e7ceb572b1fdc5289ed0f086e4742cf168bb07de45b30aa97d8b1a0d459afef545b96ca7ec506f4cd260fe7517ccdcb76622fea472696b161249f1dda45f4ce415f3b64829105697f0a75dbb9ddf66dbccb8fbc16ab6c8287354a218d0dd93c380da2bfeb28f95e5401ccd3c22c3bc874adddebda4b98a42dae326e5ee1cb0648be2350df683258458d84ebc39d45cd3246d107466f40b8ac96e58e867b0acf7e85c7be118089974efdecfafeddc8e054becb943f9ffa1031b8e45d7276eddf9673d05d43a8ee169e414d11a134fceb4852347b0fd9d9d1383826fc08d2ac6e118bf07f24e97d8e24d330ed641f901fe6121f79fb1bb89e884f4d74b7fd059f93de3869666a7930bee65ee94860c9518c950aae69a9b63496586016852c242bd974d72538268812b10a88707bce2db234d4ce4191dd5eca3438fcacae9573a2e14dd8da2b3ea23b098d69d2effa12b81131ec3b80e8464ace3f5750fea1881f1f5f3fce901334048aee6506ee690035341a6d237e1447bc07189e507e5279e5938c9dd1d0c2a729cdd8a1354f7c71c79410e732900b142e0af99643055e69a3324d6947d00d98031b2ca46b02e13f97e33c6621b91b57258f78ec0adabcf0c90c98ed5939a18cd8c3a557d07301ea4b7854715ef69fc6605b59b7a04b5b1793074040c63556a719498d4378adc29679bf3354445097eb7c7348d456d52575f49885ecd896a02d66fc5e8bb7fb3962004f7d837949d19fde8e5622f2f2480ca3eaec64f6096d31735d1daf32d91be79997cae4060048e9b617c71e7ce37ffaa77bef9827a4ed0a1f940ef191a37cdc2dfa742a5757a72a19c2d0d7bfa4fb53b342c496e41adb80a59cedd8d02824746f9b45608394bf0ac6bb08062bf3a1d3a5c6bda4778fa4c27126b2470222c1e2127945c8fa9b02db209db4f5c9024e6576ba013ba74517b1668cbb649c913c028ec2c1dd0bafde60952913fd270b24dc89654003b9472b19642a3ffce7ac489a8a694466684e21c6850fd3b98698007f95c1e1b143ac07a2d68bac2e555b0925879207f0401ee8b31889247f2b1b8337ad85e8ddc82ba3b6def35cdac1e463ed0315939bedbcfa6a070b3211b095b7f6f8a499839e1ca76e502e7a4387b8ea51afbac88260087011397b7a6be5ad81b6b4f2d2bfae3b256c6165ec324897ad21f12588b9be1818bb88b9fddcdf8935447f2eb456a79cca1b7195a233102f979ab182ca7545835f4213c9cee05b25cc6ffcf0a935efb199bb999910bd521257826e28decc530762173fde7a7a25247fc5973603f4494970f9e9cb663f64c86abfdfb0eff30b11610ff972c4b17dd3831b0a7a143958b5ca192899636901a30dc4033fc7f75209896f74e07344c42d4ce88965cca1c526e798aac3362e842e0ccd49ecb5b13c56cb4b8d23e997d1eb0270a9b80e58d3dc482f07aa964fd532a69eee0050166f439888cdd6292ab2cc5b456310e426c9244a9aca1dc033d321503e8e6a28e5d8831c71dfeeed3698310af9bbcacd01d43f101fea650291d549f9142b0a8ae97c721ea9d0994fdf4f682a8580212bd9dbefdb09b1df5fbdb3128d5b74f129dc97befe8b551f657a5df754ea8d44396701aa1d9b5b2b23bff67926070c0a7f6bec016abbbda786115883aa38d3ada15ba87d9426f75d0b641f580a0d79a3eb5adf3bd16f8feadd5ba83ce60c8e18a4009c9442d4824016332342319b6956c885c2ac788c21cec551bf3d2b78713da586f3d79e8f503bbf6f1dd4e8b79b2b15beebd7c8eab34b9be8eb921df8afef3918c29e25fa356453552f61fda7ec621321d43ae04968c73d0cd206121f5db2d41f80df5ec962f31bf0334e6f0a0573c0e7da648c3460c2c287cc4038a409fabff41ba93b12d04990674ec8dfa5c8020000000090977b64655b77827dadc0f3351af9bde48bfe6e06000119000000000000000090977b64655b77827dadc0f3351af9bde48bfe6e060001f30100000000000001000000000000000000000001000000000000000000000002000000000000000000000001000000000000007a2500008e25000000000000000000000135341a6d237e1447bc07189e507e5279e5938c9dd1d0c2a729cdd8a1354f7c717a2500000001c79410e732900b142e0af99643055e69a3324d6947d00d98031b2ca46b02e13f0100000003bc4834ed00000080fe5f31e2d3bd521177e96903bafaeea1ff38afbfc87bc92ffd8bafa9f8f939c7031b9d3d838fb0343ac264aeb78ba909e5a731cd7a3b4d601af55bfde40e2b6df0c1485f8201ab1675c00d1201cb18f0eea8c9e92d26189fc9738544c2e4143d90790db1d8232c742fa3c4437e958276951958bb2392c9debd325f306582daa6ad0a2591b6c6ad459fa2d181005eeef982e378b807eb109275ae89f288f866971d09790d6dcb39f724d939bf5152b299faca52827cc6ff59099929b266b8d9b9e98dcd8be58c2b77f8c4c240787d01000000007b2ae458492b721c85fba7a2a108d3f5d0dec604ca6f403f9ba7f348188bc1726b231922cfec3a8cbff3f55002a8b2f11aba9f5ba984659dc12f4ed14598ab1b02798719369c0dca960107b928687a87a9696bccb586a8ad90aa44099b8af5ad662020de43f9cb72ec5b01c93aff1981a6cb7765b3e0c60ecdd4f0ddc1f1dda252ff0e20ad15f9b7057e4431f40b17d3cc76194d8339b1ddd9d80b20352002634663642e2089fd643bbfeef5b486e4e29e1c99d72c29944791c32fc225396b59318681b633208ef64e2cbb03d5af593244b253abc3e94db3b9150596e17303940d4eb2d5781a20a5461d4e8bd352703204beb6277e50a2c27e7779f7ab98fd45ceb0bba5c1b901203b52fb113249110b4566887d79a9693c3be69572a5b90b690702066e97ef155c204b07ba48cb4a793c01dfeb6392195b6493f3ceed52b5cea7df7279220e967e47204147f5d495d644e9c246093bdba51a94d44de39bb435f3410b52969570babe6d20b522e12ee1a1aa449be27411bbf4f8bdf90a8a816b7144f28991fa307644541b20d88bbcd3447046ef164ce336bdb9d6d29f4367d2f8aa7d39644e87c9c1ecca05202d7708b49a8ab745c2f51f638649c6a455842a6f4e040aae4d9885546337245920897423682b6d8f56fce75bf9c4a7f70f35dfa7386e554e7c561a62a835c3a3662049c2d8eff3e9c0a5a2017de57ab4e2c12eea2cf06228127f26580f4fa9af5623206ed767be9c66da7d6f7eba511871d9da61456026b7f310e15e3359ac41ec926020dd0e078b30ad16780690abae311be0130c2a9a030d0d65c8f12aec3264ed853b208934595bab6108f9b2e6fa75d4e1d285eb79791c5e7610358acd626a4b17022120b93879c9b8476d6b3952933c83a07ac6aeeb01f6bc971b6740da7614a47da958203a6ac56a4149e8c9bd8119e3ab6fa7780bda6fc14d6119c416a11a1bc1c0b60d2048917eaa9b4c094d69ec54970475d3df466a984ee9aed707970c69bc958f6e61209eed88e4f9bb67d455f9aebdb6ab4ef8b566b03f230804c7f58214043bd4e471202cd2e15a6e521b4ff874c7261fcba80b7782526f236bf73435ce20eb136d4c33203ea72374fe684e6a8eb5d4980633218da196cab396fcdddf6831953298f3e45520798e3416956611fa66571e10e50b8b2c0abf537f16afc725ced4ece6b279142420806ab1a3c089454e16575ceece1e3aefee2a6184255e18a2343fb7feb86b7e6d204e8e59d04c3f4469e9d58483fc8539db868cf2334f4257121ad6f80db6c9702d204c66cea9b58243efbe2e62d1da3a03a48cfbce68ef212b3c77acb1e12c5ab962205b5714543c02aa922a6620e12e901943fc5b03bb9ae1586c002d639570326707203aa41a68aac5b5e125616c1c4efb4a00e08ca4f8e65e66a1470d7c47c72a140f2039cf8d1399cea0bbb22c31ff1ed14be62acb70e75f13aa0757c29d76b943a53e206772ffd2b185aac6d10dc02551d9de9e7094b5548e9e13a833da8dc477a1022020325aea4964041359acb6d15fa724089dd7242a7a61b1d9db50983e402d88ff1d20e5cd164efedb1035c6f0cb517cd8996fc80dd544f304a86fb9312726163dae3600000000000000000100000002878d869ea222c71608507c1aea1d310e0c6c00a2cc85a0223c195fb301307cf5e8030000000000000000000000000000bf5152b299faca52827cc6ff59099929b266b8d9b9e98dcd8be58c2b77f8c4c218fcfffffffffffffffffffffffffffff69d9d78cb39263b1d54e6018ef6be952e22e75559fe175e7daa856d73ab2794a8610000000000002020de43f9cb72ec5b01c93aff1981a6cb7765b3e0c60ecdd4f0ddc1f1dda252ff0e20ad15f9b7057e4431f40b17d3cc76194d8339b1ddd9d80b20352002634663642e2089fd643bbfeef5b486e4e29e1c99d72c29944791c32fc225396b59318681b633208ef64e2cbb03d5af593244b253abc3e94db3b9150596e17303940d4eb2d5781a20a5461d4e8bd352703204beb6277e50a2c27e7779f7ab98fd45ceb0bba5c1b901203b52fb113249110b4566887d79a9693c3be69572a5b90b690702066e97ef155c204b07ba48cb4a793c01dfeb6392195b6493f3ceed52b5cea7df7279220e967e47204147f5d495d644e9c246093bdba51a94d44de39bb435f3410b52969570babe6d20b522e12ee1a1aa449be27411bbf4f8bdf90a8a816b7144f28991fa307644541b20d88bbcd3447046ef164ce336bdb9d6d29f4367d2f8aa7d39644e87c9c1ecca05202d7708b49a8ab745c2f51f638649c6a455842a6f4e040aae4d9885546337245920897423682b6d8f56fce75bf9c4a7f70f35dfa7386e554e7c561a62a835c3a3662049c2d8eff3e9c0a5a2017de57ab4e2c12eea2cf06228127f26580f4fa9af5623206ed767be9c66da7d6f7eba511871d9da61456026b7f310e15e3359ac41ec926020dd0e078b30ad16780690abae311be0130c2a9a030d0d65c8f12aec3264ed853b208934595bab6108f9b2e6fa75d4e1d285eb79791c5e7610358acd626a4b17022120b93879c9b8476d6b3952933c83a07ac6aeeb01f6bc971b6740da7614a47da958203a6ac56a4149e8c9bd8119e3ab6fa7780bda6fc14d6119c416a11a1bc1c0b60d20f19253a9d91aef85cbe9c689b24e73ef15b16a4a95353abf538df1249fe6bd7020d29e92acfd3503b6a3e28876fc0ec59abc3c3874e235db68b5cf8d029910a65020a516e5771aae3a670dfdeb9633720850bfe93633817ee4929a870d66212348672066d8e7e812ad34de1feb91bb0380e167a1c34360b23df81209ea23ba7f11486820b8af362aeb60a32f9ae9ee9e7e94334bfddb0ae57fb2de3dea6a8463260e6767205ded46b9334150ee5a84defb9646fcccb2c3ce88540223d27de7025a08cdaf482075bd4d694e2117c47b4e4657b6ff280f85101de6e47ba7f2d04d1ee4aa83c23c2072df04856f403e0f1fd5fad2fc152ed6b59edd68529be02a6ac659100287ef56203ca68806f711c2c01e6b190f3f56fffdab3a669dd5da9ab02c202d4f7767ee1b2034228f84a203c9da1e44ddd106f9d927a049151be693935882c30f36cff0130520dccea169455fa685d7f3c114dc110c7cfd80be9d7c7d267e1a45a42791c2765520c35752598f56c0a746afaa8c709821a273e010902240c21d028fe4c78efc6f4820439323687688191cb7f0cc56b57390951944297b735cb0779d9aae35466f836520725407df68111707ff39d436d6dd53b1bb3c4d5bc2be9475443d50eb3ac8ad6eee28000000000000020000000190790db1d8232c742fa3c4437e958276951958bb2392c9debd325f306582daa6debaabddc8ecea1eafa3459568552793ccba7d910f2bf549e29d7bd4e985cc9755f54cd8b4b3d949bc42c7878d869ea222c71608507c1aea1d310e0c6c00a2cc85a0223c195fb301307cf580841e00000000008456c8d47038e2171841667efd82c09b014d421b6a92f085c4f4169186edb7d39568552793ccba7d910f2bf549e29d7bd4e985cc9755f54cd8b4b3d949bc42c7f6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000190790db1d8232c742fa3c4437e958276951958bb2392c9debd325f306582daa66a7f03e2c2987f9478d2c9b7609e27fa70a6a0f3575d451054df6d58dc1e3552df5992af900897263937f2878d869ea222c71608507c1aea1d310e0c6c00a2cc85a0223c195fb301307cf5c0f35e0100000000bdcc096706805b24ba253feaf3c4e5092ae0e798a1a71ce6d9481cb45116b459b7609e27fa70a6a0f3575d451054df6d58dc1e3552df5992af900897263937f2f60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d5f319eb62696a5500229acd77dad5df3f9bcbd1783575d7dd62959416d40f261137d5e3a301bd50e1011000000074785f7472616e736665722e7761736d00563bf544b26f13cb2900000000000000000000000173c0e7da648c3460c2c287cc4038a409fabff41ba93b12d04990674ec8dfa5c8"; export const MASP_TRANSFER_SIGNING_TX = "1400000062516537785f5f614b305f5f725f5944337668340123000000363938362d30372d31385431383a31353a32302e3331373837313536362b30303a303023000000353937302d30392d32385430323a35313a30302e3339373138323839362b30303a3030010000001f07d555db2430f5dbf51e1f70ce0852affeb8d5791a6957a9895b40ce79e72620b9054f4e22fdaeda9d89999fee8c91493873ccaa268df016e0fe86e55de363000000000000000000000000000000000000000000000000000000000000000001010bb3ba0d7dd361880000000000000000000000000000000000000000000000001a004b04c8b2e677e5df568b1e0beef56ee0b0ce188901036368871d14536b0c2dcfb6ee44d6791ae0100278573b36342d549dbcb6a65352e3c68b9da22c439a0600000002e1484984b9fbc499000c6c2db27b3f8571aefe0bd11b40a26aa71e57926c21ef7bfd8f304b2de2c7cb011000000074785f7472616e736665722e7761736d00981d0e7b1ef47f76ac00000001000000020c018394a88c44805593285020d87e3a5ef20d607e4a62000000000000000000000000000000000000000000000000000000000000005101000000007f767a630a6decf676cb0aafd04f369e9c443953018394a88c44805593285020d87e3a5ef20d607e4a62000000000000000000000000000000000000000000000000000000000000005101bc6e54f9452f694cdded81cf8ba238ae25b5b084287c5eb12712f2673345c18804020000000a27a726a675ffe900000000073fe6bc000187c788987c12823543407a6d55b37f2d590b8616190d866e42c96a40f98f7a556200000000000000a849755d16a2bcd5ff040ac30e20cc2b627eb3ea01b2d28eb51263ccc19efc6b54465f492c7b2e135f1a3029690eedeeef89083516c7dce8cf0ff658a3d5a1abd95a6b311baeb331a8bd02c554c584fd2dc7895b0dd80791e81d6b24aa386e318201fd1fbb2e4510e7a52c05032b83c31d06171f710002c717cc7c6751ffa2787876e20d99a84e97bb565128d7313b54170a1c72b8a94ebc1019168462a03ce3df9d7ae9fbb3cf80595fd98a38e1148ead733b0806df1a86cc829c85c874d94d99c5a531b19ac030ea1725eb7b3d1c32c3aaed9521b5c697751febe6e29a5d6ed31483f43729b3195b3a43386c7a79bb5a2304bdcd63338ce8eb806a8ec33c142f1022e0620692c31a04fc5991582d7330cc0fd07ed436ebee6efbaab5affb91cb400dae53320b2a7741163900014747b01b5e90404ffd1bb41450462987cfdb024bf1e29b64f99ec3158b53ce41cb78a71127503b177ef318f5d0f963d775208e9f79c7c044628fc55927744dfcf535afda0d23c15e969d79d3a1663b301ca1b7ff539e21b25c7403c2748a4c1bac4b0deb6fa763b979aaaed9bcbe534f9f232d26b7e590ad6335e5966cead90d16b88fbaab3d9bf05b236647da874c58121023604e19fb79f8b2ae3fedbc6d3c131383ee7d5d27e5ed31d5f19f02c8736acc13f0cbe2df12f37488e4bfcf52737f2b4540625753707e4482d57f4d08f1929657bc10930625d840071c9ea85c6492577830f680edc51f445bfd84c3bc723128c0cd6b618c3f9d93153057bdef85522e97117db5020d57d57122d74560f817e77ac3203b8e5d04da87a2adf97e52114e3dcf8d97f6700d2cb785c5578e4a0526ed08512a273efb1f581bdc695ce7f6bfd3e95a178da7aad206ab4bb0c2d373ef346e112152c0fb9af56a88b2ee89d6dca22082a17eadb69ff0fb4a276e564d9bbbf25491f9722167a03451bc9dd72600b7eb0baba4d19120d68a44851f1c3e4d7bc8d3aaf964228a5b93c1657c18fa844fe3f3e51325c6636e88bf48093495354bc951cb0f4464ee0f867f3f0748555adeffda5b3dfc3119ab874f6ae3ca4839a564030d60510f5d3202c5a71575b77be5f22fb2f24e3ab29a23440561d99baffb8e4485d58750f6bdc239eee337c4fa8b6f80b071f3972642b7f14a6d41ab3a0a0b33ba40a3c87f3e7716d065a7ad414fa9116463ff30df79633e6792b1149bf2a4fad65300b6ea471d469a86353dc4eed7df65e1a9f2eeebdb57c6ec8cb1d59c076599af5d9b6e966c99957ba4b2db3eb19c2236a2a491b32d14f7cfd37fd4aec720157a4e02720d72942f46a1ab3252cdd5d4cde653549ca5f5244ca233a567f2ea2e7d4aa27d01b620c4da6e33f5e168d8913c66cc419a0041ba7f27698712b6e826abdb79b62b760e6958d14a35c4241e6d35772268bbac4db5b115eb334100b3e0e3c5e323785126a80955460d8f9573b2c01f4be1f11ad9c5a454a4ead989f7cddcbd968cf9aa16226c7d0c5236ce4187d36a8b3bfd93590d4c87e605e437f5a774a053682fe483440b268d1a7aa33f473ae86535cfe094ad4c997aedfbece3395451caf9e215c823e58ad5106a9578d04ed0bd877d1c6f43e681b01a872c00fa87062b73a424e91ea3222c3b2f172108779765606442d6c470dd1edf44d0746cf84264e589f8e84a34a7d21e0dd589a534b0fd3cf2da21c6c5446fae5ca64252cc8ac3adb6e4fa7c04314da22701a1ef1843ae88f9a130450984a56e059329f5442428ab86edb1f7a13afbc4a5bfba5488bb5dcd6d45c1d0d1449e90b91af539a98969d0043343b0ccbdb8ade63b78b6963f729b2128e19b045e2978ce335a2514bf16431cd6f467a5a454b51861f482b8e980b62daaa94232e3135df8e51b6f0d14a259a561fea40d8b86854a9a5505d3c671a4225d92a2c90486ffd7ee6944fa22795ac766525355d53964e12b7be7bed0f702500ce883695ccb63852ea8ca9dc93b3bc32b45a5763b359aa85d04dcd1880226f261fcdf5466f56211e1dd6c7640f5eae1e1e17443ed4b0ab589db759bcb556a13bce25b77a4c4f13d34a6af95c03b5b0c379a494ce05fd6f8d6bb7ae24559752860c8b0db4fc73d312af2052897aea028793384caf5e67dfe2ef19b12595cac8fcae69ca2ed169f9cb79dcc9cf1ced46dc007f763180086799b94ccd41cc4998e927bcd5c66be0c97f63a29d5b7e7dfb7d5e72cb69c1aba6731393ded0f01feb5a71dad3a40c47041c7a0571ae172d742400d63771eece8061f07d034bf91fa17dc1d32a815b89ecb8694e1c37934d393aa35bc4c2b53adebec36ae76adf5c0c55b8b1b52ad9bd70cb3082a581ed36267d904670f62622d8526a5cafed1b93540a68feb0ba5e50187c788987c12823543407a6d55b37f2d590b8616190d866e42c96a40f98f7a5562000000000000000000000000000000748451dab93113bdc54a37e1ae4f9042cd40a790c89a1f397f0c1489d783363a97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb1f60ef2b7ae7d4b03ea93687a3705671ba78305e3d5f793fa35cedd28e07f9253d9a33e817f099d61a5d4e814571c8986d1dac6bd1ba602a4309bced68ed600d97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00ed2a52e5fbb06a2b9f8c4a0fba6d5f94e16c1e4434d51d6472a4f7bbff61a0bdb5a31cb8532c2e9a820dcff633808f2318420fa0fa8ae484b8a2215644630b05bc6e54f9452f694cdded81cf8ba238ae25b5b084287c5eb12712f2673345c18801000000018394a88c44805593285020d87e3a5ef20d607e4a51000162b7de5dcbda020f0100000000000000000000000000000000000000f33ee6bc073fe6bc000000000100000087c788987c12823543407a6d55b37f2d590b8616190d866e42c96a40f98f7a556200000000000000a849755d16a2bcd5ff040ac30e20cc2b627eb3ea01748451dab93113bdc54a37e1ae4f9042cd40a790c89a1f397f0c1489d783363af33ee6bc0187c788987c12823543407a6d55b37f2d590b8616190d866e42c96a40f98f7a5562000000000000000000000000000000000100000000000000000000000082fe9e2d25621a062e55d2c084a291b6d801ae862421325bd3caf5511c36a1bcceb77f278e14b34cad6fdf9d3412782159ed2c7b53be86f28d8f8d883bb8beab9b14009b7585e3bb80163ffff5d28f6230f3ddef7c8fb46ee8967254790be4a140542879ab209e9d0e6ea9b4cf02811b6784e5808b61518846580321dabb0588791fe17ab0b7dc3df1091b00d3f8c2c5655c190734fc5e1210efc3b42c4feb4e5ca866c565057557c90e5787c788987c12823543407a6d55b37f2d590b8616190d866e42c96a40f98f7a556200000000000000a9bbce962b5886a36bd4eeef897ea67d1d6b3f9a4159a308c2fdda396db34c1b43ae48a86b15f2eb5dea4700a37bd61cf1b67dbfdb549c45754bb0151fe30497029b7727f675bc6e29c5b0bb236f90d148e9a5e28aa7614a73bee277221c8addd82020de43f9cb72ec5b01c93aff1981a6cb7765b3e0c60ecdd4f0ddc1f1dda252ff0e20ad15f9b7057e4431f40b17d3cc76194d8339b1ddd9d80b20352002634663642e2089fd643bbfeef5b486e4e29e1c99d72c29944791c32fc225396b59318681b633208ef64e2cbb03d5af593244b253abc3e94db3b9150596e17303940d4eb2d5781a20a5461d4e8bd352703204beb6277e50a2c27e7779f7ab98fd45ceb0bba5c1b901203b52fb113249110b4566887d79a9693c3be69572a5b90b690702066e97ef155c204b07ba48cb4a793c01dfeb6392195b6493f3ceed52b5cea7df7279220e967e47204147f5d495d644e9c246093bdba51a94d44de39bb435f3410b52969570babe6d20b522e12ee1a1aa449be27411bbf4f8bdf90a8a816b7144f28991fa307644541b20d88bbcd3447046ef164ce336bdb9d6d29f4367d2f8aa7d39644e87c9c1ecca05202d7708b49a8ab745c2f51f638649c6a455842a6f4e040aae4d9885546337245920897423682b6d8f56fce75bf9c4a7f70f35dfa7386e554e7c561a62a835c3a3662049c2d8eff3e9c0a5a2017de57ab4e2c12eea2cf06228127f26580f4fa9af5623206ed767be9c66da7d6f7eba511871d9da61456026b7f310e15e3359ac41ec926020dd0e078b30ad16780690abae311be0130c2a9a030d0d65c8f12aec3264ed853b208934595bab6108f9b2e6fa75d4e1d285eb79791c5e7610358acd626a4b17022120b93879c9b8476d6b3952933c83a07ac6aeeb01f6bc971b6740da7614a47da958203a6ac56a4149e8c9bd8119e3ab6fa7780bda6fc14d6119c416a11a1bc1c0b60d2048917eaa9b4c094d69ec54970475d3df466a984ee9aed707970c69bc958f6e61209eed88e4f9bb67d455f9aebdb6ab4ef8b566b03f230804c7f58214043bd4e471202cd2e15a6e521b4ff874c7261fcba80b7782526f236bf73435ce20eb136d4c33203ea72374fe684e6a8eb5d4980633218da196cab396fcdddf6831953298f3e45520798e3416956611fa66571e10e50b8b2c0abf537f16afc725ced4ece6b279142420806ab1a3c089454e16575ceece1e3aefee2a6184255e18a2343fb7feb86b7e6d204e8e59d04c3f4469e9d58483fc8539db868cf2334f4257121ad6f80db6c9702d204c66cea9b58243efbe2e62d1da3a03a48cfbce68ef212b3c77acb1e12c5ab962205b5714543c02aa922a6620e12e901943fc5b03bb9ae1586c002d639570326707203aa41a68aac5b5e125616c1c4efb4a00e08ca4f8e65e66a1470d7c47c72a140f2039cf8d1399cea0bbb22c31ff1ed14be62acb70e75f13aa0757c29d76b943a53e206772ffd2b185aac6d10dc02551d9de9e7094b5548e9e13a833da8dc477a1022020325aea4964041359acb6d15fa724089dd7242a7a61b1d9db50983e402d88ff1d200100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000305000000af859437564c2c660a42903d9dca0686f1229cf4039894cf2b4cc4529decde6f1f07d555db2430f5dbf51e1f70ce0852affeb8d5791a6957a9895b40ce79e72620b9054f4e22fdaeda9d89999fee8c91493873ccaa268df016e0fe86e55de363a4fa85bd4b2205d4fd51e438bf65c95edf3503236ec0ffbe3a471524af2efa240cadb91730d8d5904469534807019c50300e492afd8aa118d91482c5c8f7d6570001ce1e73182adea659bd9b99f1fc3acb5726b36f640100000057009bab96d9614e7beb712cd5b26a0e52d76d3aa5e895560da93308558241e9b89998eed9d9d41066c5ceeca963a274bcc9703feb5b92e6624f451456db8559f1070305000000af859437564c2c660a42903d9dca0686f1229cf4039894cf2b4cc4529decde6f1f07d555db2430f5dbf51e1f70ce0852affeb8d5791a6957a9895b40ce79e72620b9054f4e22fdaeda9d89999fee8c91493873ccaa268df016e0fe86e55de363a4fa85bd4b2205d4fd51e438bf65c95edf3503236ec0ffbe3a471524af2efa240cadb91730d8d5904469534807019c50300e492afd8aa118d91482c5c8f7d65701010000000034773cc1d70501ada4fcb6ff2d859f9bd4b76b9807f653dc64229b3fd78db2d301000000000048b5dd76f57617d09291417f2a7bc5cab2f72b88f9da6e131183d0fa117037728e85b645a6ee80c00b71b8d18623f704e4c8173cdef7894c43447e2dec1cd301"; diff --git a/tests_zemu/tests/masp.test.ts b/tests_zemu/tests/masp.test.ts index 38e41994..f75911e6 100644 --- a/tests_zemu/tests/masp.test.ts +++ b/tests_zemu/tests/masp.test.ts @@ -81,12 +81,11 @@ describe('Masp', function () { const respSpend = await app.getSpendRandomness() expect(respSpend.returnCode).toEqual(0x9000) expect(respSpend.errorMessage).toEqual('No errors') + const respConvert = await app.getConvertRandomness() + expect(respConvert.errorMessage).toEqual('No errors') const respOutput = await app.getOutputRandomness() expect(respOutput.returnCode).toEqual(0x9000) expect(respOutput.errorMessage).toEqual('No errors') - const respOutput2 = await app.getOutputRandomness() - expect(respOutput2.returnCode).toEqual(0x9000) - expect(respOutput2.errorMessage).toEqual('No errors') const msg = Buffer.from(MASP_TRANSFER_TX, 'hex') @@ -196,4 +195,59 @@ describe('Masp', function () { await sim.close() } }) + + test.concurrent.each(MASP_MODELS)('Wrong MASP starting instruction', async function (m) { + const sim = new Zemu(m.path) + try { + await sim.start({ ...defaultOptions, model: m.name }) + const app = new NamadaApp(sim.getTransport()) + + const respClean = await app.cleanRandomnessBuffers() + console.log(respClean) + expect(respClean.returnCode).toEqual(0x9000) + + // Wrong MASP starting INS no randomness was computed or spends signed + const resp = await app.getSpendSignature() + + // Expect the specific return code and error message + expect(resp.returnCode).toEqual(27012) + expect(resp.errorMessage).toEqual('Data is invalid') + } finally { + await sim.close() + } + }) + + test.concurrent.each(MASP_MODELS)('Wrong MASP sequence', async function (m) { + const sim = new Zemu(m.path) + try { + await sim.start({ ...defaultOptions, model: m.name }) + const app = new NamadaApp(sim.getTransport()) + + // First step: compute randomness + const respSpend = await app.getSpendRandomness() + console.log(respSpend) + expect(respSpend.returnCode).toEqual(0x9000) + expect(respSpend.errorMessage).toEqual('No errors') + + const respOutput = await app.getOutputRandomness() + console.log(respOutput) + expect(respOutput.returnCode).toEqual(0x9000) + expect(respOutput.errorMessage).toEqual('No errors') + + const respRandomness = await app.getConvertRandomness() + console.log(respRandomness) + expect(respRandomness.returnCode).toEqual(0x9000) + expect(respRandomness.errorMessage).toEqual('No errors') + + // Missing spend signature and trying to extract the signatures + const resp = await app.getSpendSignature() + console.log(resp) + + // Expect the specific return code and error message + expect(resp.returnCode).toEqual(27012) + expect(resp.errorMessage).toEqual('Data is invalid') + } finally { + await sim.close() + } + }) })