diff --git a/Makefile b/Makefile index a200c0f..9249d3a 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ APPNAME = "Aleo" # Application version APPVERSION_M = 1 APPVERSION_N = 0 -APPVERSION_P = 1 +APPVERSION_P = 2 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" # Application source files diff --git a/doc/SIGN_TRANSACTION.md b/doc/SIGN_TRANSACTION.md index fce2351..bbfde09 100644 --- a/doc/SIGN_TRANSACTION.md +++ b/doc/SIGN_TRANSACTION.md @@ -113,6 +113,7 @@ Serialized TLV data: | `network_id` | 0xc3 | 2 | u16 | Network ID (big endian) (0 : mainnet, 1 : testnet) | | `program_id` | 0xb5 | variable | bytes | Program ID to use | | `program_checksum` | 0xc4 | 32 | field | Program checksum (OPTIONAL) | +| `r_hint ` | 0xc5 | 32 | scalar | r hint (OPTIONAL) | | `function_name` | 0xb6 | variable | bytes | Function name to call | | `nested_calls_count` | 0xba | 1 | u8 | The number of nested calls (INTENT ONLY) | | `input_count` | 0xb7 | 1 | u8 | The number of inputs | diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 2a860d4..f0f008a 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -40,6 +40,7 @@ target_include_directories( ${APP_SRC} ${APP_SRC}/account ${APP_SRC}/crypto + ${APP_SRC}/db ${APP_SRC}/handler ${APP_SRC}/helper ${APP_SRC}/transaction diff --git a/src/account/account.c b/src/account/account.c index 1d1dbbf..288088f 100644 --- a/src/account/account.c +++ b/src/account/account.c @@ -234,7 +234,7 @@ int account_get_address_string(const uint32_t *path, uint8_t path_len, char addr bn_reverse(address_bn); bn_print(address_bn); - uint8_t data[64]; + uint8_t data[ADDRESS_LEN + 1]; size_t datalen = 0; if ((status = bech32_convert_bits(data, &datalen, sizeof(data), 5, address_bn, 32, 8, 1)) < 0) { goto end; @@ -300,7 +300,9 @@ int account_get_view_key_string(const uint32_t *path, uint8_t path_len, char vie int account_generate_keys(const uint32_t *path, uint8_t path_len, account_t *account) { - int status = 0; + int status = 0; + bigint_256_t address_big_int; + uint8_t address_bn[32]; LEDGER_ASSERT(path != NULL, "NULL path"); LEDGER_ASSERT(account != NULL, "NULL account"); @@ -329,6 +331,28 @@ int account_generate_keys(const uint32_t *path, uint8_t path_len, account_t *acc if ((status = graph_key_from_view_key(&account->view_key, &account->graph_key)) < 0) { goto error; } + + field_to_big_int(&account->address.x, &address_big_int); + big_int_to_bn(&address_big_int, address_bn); + + // Reverse bn + bn_reverse(address_bn); + bn_print(address_bn); + + uint8_t data[ADDRESS_LEN + 1]; + size_t datalen = 0; + memset(account->address_str, 0, ADDRESS_LEN + 1); + if ((status = bech32_convert_bits( + data, &datalen, sizeof(data), 5, address_bn, sizeof(address_bn), 8, 1)) + < 0) { + goto error; + } + if ((status = bech32_encode( + account->address_str, ADDRESS_PREFIX, data, datalen, BECH32_ENCODING_BECH32M)) + < 0) { + goto error; + } + return 0; error: diff --git a/src/account/account.h b/src/account/account.h index f34d271..c3b1c3a 100644 --- a/src/account/account.h +++ b/src/account/account.h @@ -29,7 +29,7 @@ typedef struct { scalar_t view_key; group_t address; field_t graph_key; - + char address_str[ADDRESS_LEN + 1]; } account_t; typedef struct { diff --git a/src/account/signature.c b/src/account/signature.c index 51c38c8..841eb2d 100644 --- a/src/account/signature.c +++ b/src/account/signature.c @@ -348,7 +348,7 @@ static void display_progression(uint8_t step) } else if (G_context.signing_state == SIGNING_STATE_NESTED_CALL) { text = "Prepare Tx"; - current_step += step + ((1 + G_context.nested_call_offset) * 5); + current_step += step + (G_context.nested_call_offset * 5); } else { text = "Prepare Tx"; @@ -383,18 +383,29 @@ int sign_prepared_request(account_t *account, prepared_request_t *request) display_progression(1); - // Compute a `r` as `HashToScalar(sk_sig || nonce)`. Note: This is the transition secret key - // `tsk`. - _Static_assert(HASH_INPUT_MAX_LENGTH >= 7, "hash_input size won't fit"); - memset(hash_input, 0, sizeof(hash_input)); - memcpy(&hash_input[4], &SERIAL_NUMBER_DOMAIN, sizeof(field_t)); - scalar_to_field(&account->private_key.sk_sig, &hash_input[5]); - memcpy(&hash_input[6], &nonce, sizeof(field_t)); - if ((status = hash_to_scalar_psd4(hash_input, 4 + 3, &request->r)) < 0) { - goto end; + if (request->r_hint) { + // Use preprocessed 'r' from the request + bigint_256_t s; + bn_reverse(request->r_hint); + bn_to_big_int(request->r_hint, &s); + scalar_from_big_int(&request->r, &s); + PRINTF("r_hint : "); + scalar_println(&request->r); + } + else { + // Compute a `r` as `HashToScalar(sk_sig || nonce)`. Note: This is the transition secret key + // `tsk`. + _Static_assert(HASH_INPUT_MAX_LENGTH >= 7, "hash_input size won't fit"); + memset(hash_input, 0, sizeof(hash_input)); + memcpy(&hash_input[4], &SERIAL_NUMBER_DOMAIN, sizeof(field_t)); + scalar_to_field(&account->private_key.sk_sig, &hash_input[5]); + memcpy(&hash_input[6], &nonce, sizeof(field_t)); + if ((status = hash_to_scalar_psd4(hash_input, 4 + 3, &request->r)) < 0) { + goto end; + } + PRINTF("r : "); + scalar_println(&request->r); } - PRINTF("r : "); - scalar_println(&request->r); display_progression(2); // Compute `g_r` as `r * G`. Note: This is the transition public key `tpk`. @@ -431,40 +442,7 @@ int sign_prepared_request(account_t *account, prepared_request_t *request) } // Compute the function ID. - function_id_datas_t function_id_datas; - memset(&function_id_datas, 0, sizeof(function_id_datas)); - function_id_datas.network_id = request->network_id; - uint8_t is_name = 1; - uint8_t offset = 0; - for (size_t i = 0; i < request->program_id_length; i++) { - if (request->program_id[i] != '.') { - if (is_name) { - if (offset >= sizeof(function_id_datas.program_id_name)) { - status = -1; - goto end; - } - function_id_datas.program_id_name[offset++] = request->program_id[i]; - } - else { - if (offset >= sizeof(function_id_datas.program_id_network)) { - status = -1; - goto end; - } - function_id_datas.program_id_network[offset++] = request->program_id[i]; - } - } - else { - is_name = 0; - offset = 0; - } - } - if (request->function_name_length >= sizeof(function_id_datas.function_name)) { - status = -1; - goto end; - } - memcpy(function_id_datas.function_name, request->function_name, request->function_name_length); - - if ((status = bhp_1024_hash_function_id(&function_id_datas, &request->function_id)) < 0) { + if ((status = bhp_1024_hash_function_id(request)) < 0) { goto end; } PRINTF("function_id : "); diff --git a/src/app_main.c b/src/app_main.c index 1709eb2..ee177db 100644 --- a/src/app_main.c +++ b/src/app_main.c @@ -114,7 +114,9 @@ void app_ticker_event_callback(void) G_context.fees_waiting_time_ms += 100; if (G_context.fees_waiting_time_ms > 15 * 1000) { G_context.signing_state = SIGNING_STATE_WAIT_INTENT; +#ifndef FUZZ nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_menu_main); +#endif // FUZZ } } } diff --git a/src/constants.h b/src/constants.h index c90cb38..602f7e2 100644 --- a/src/constants.h +++ b/src/constants.h @@ -53,7 +53,7 @@ /** * Maximum number of inputs for a single signature. */ -#define MAX_NB_OF_INPUTS (8) +#define MAX_NB_OF_INPUTS (16) /** * Maximum number of records for a single signature. diff --git a/src/crypto/bhp_1024.c b/src/crypto/bhp_1024.c index f7ba0ad..2e9ad2d 100644 --- a/src/crypto/bhp_1024.c +++ b/src/crypto/bhp_1024.c @@ -25,38 +25,29 @@ #include "os_utils.h" #include "cx.h" -#include "bhp_1024_parameters.h" +#include "db_program_function.h" #include "bhp_1024.h" -int bhp_1024_hash_function_id(const function_id_datas_t *data, field_t *hash) +int bhp_1024_hash_function_id(prepared_request_t *request) { - size_t index = 0; - size_t program_index = 0; - function_hashes_t *functions = NULL; + size_t index = 0; + size_t program_index = 0; + function_parameters_t *functions = NULL; - LEDGER_ASSERT(data != NULL, "NULL data"); - LEDGER_ASSERT(hash != NULL, "NULL hash"); + LEDGER_ASSERT(request != NULL, "NULL request"); - if (data->network_id >= NETWORK_ID_COUNT) { + if (request->network_id >= NETWORK_ID_COUNT) { return -1; } + // Find program for (index = 0; index < NB_OF_PROGRAMS; index++) { - if (strlen(data->program_id_name) != strlen(PIC(bhp_1024_parameters[index].program_id))) { + if (request->program_id_length != strlen(PIC(program_parameters[index].program_id))) { continue; } - if (memcmp(data->program_id_name, - PIC(bhp_1024_parameters[index].program_id), - strlen(data->program_id_name))) { - continue; - } - if (strlen(data->program_id_network) - != strlen(PIC(bhp_1024_parameters[index].program_id_network))) { - continue; - } - if (memcmp(data->program_id_network, - PIC(bhp_1024_parameters[index].program_id_network), - strlen(data->program_id_network))) { + if (memcmp(request->program_id, + PIC(program_parameters[index].program_id), + request->program_id_length)) { continue; } break; @@ -65,18 +56,23 @@ int bhp_1024_hash_function_id(const function_id_datas_t *data, field_t *hash) if (index >= NB_OF_PROGRAMS) { return -1; } + + // Find program's function program_index = index; - functions = PIC(bhp_1024_parameters[program_index].functions); + functions = PIC(program_parameters[program_index].functions); - for (index = 0; index < bhp_1024_parameters[program_index].nb_of_functions; index++) { - if (strlen(data->function_name) != strlen(PIC(functions[index].string))) { + for (index = 0; index < program_parameters[program_index].nb_of_functions; index++) { + if (request->function_name_length != strlen(PIC(functions[index].string))) { continue; } - if (memcmp( - data->function_name, PIC(functions[index].string), strlen(data->function_name))) { + if (memcmp(request->function_name, + PIC(functions[index].string), + request->function_name_length)) { continue; } - memcpy(hash, PIC(&functions[index].hashes[data->network_id]), sizeof(field_t)); + memcpy(&request->function_id, + PIC(&functions[index].bhp_1024_hashes[request->network_id]), + sizeof(field_t)); return 0; } diff --git a/src/crypto/bhp_1024.h b/src/crypto/bhp_1024.h index d461c91..b0fe351 100644 --- a/src/crypto/bhp_1024.h +++ b/src/crypto/bhp_1024.h @@ -3,14 +3,6 @@ #include // uint*_t #include "constants.h" -#include "field.h" +#include "types.h" -typedef struct { - uint16_t network_id; - char program_id_name[PROGRAM_ID_NAME_MAX_LEN + 1]; - char program_id_network[PROGRAM_ID_NETWORK_MAX_LEN + 1]; - char function_name[FUNCTION_NAME_MAX_LEN + 1]; - -} function_id_datas_t; - -extern int bhp_1024_hash_function_id(const function_id_datas_t *data, field_t *hash); +extern int bhp_1024_hash_function_id(prepared_request_t *request); diff --git a/src/crypto/bhp_1024_parameters.c b/src/crypto/bhp_1024_parameters.c deleted file mode 100644 index 366d943..0000000 --- a/src/crypto/bhp_1024_parameters.c +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * Ledger App Aleo. - * (c) 2025 Ledger SAS. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *****************************************************************************/ - -#include "bhp_1024_parameters.h" - -#define NB_OF_CREDITS_ALEO_FUNCTIONS (8) -const function_hashes_t credits_aleo[NB_OF_CREDITS_ALEO_FUNCTIONS] = { - {.string = "transfer_public", - .hashes - = {{.big.u64 - = {0x405245447621401a, 0x51c07b62a9c53d26, 0xb928e2f9112d0953, 0x0f511e31d6855446}}, - {.big.u64 - = {0x1a45c36fff8ff4a4, 0x69712402399b89f1, 0xb3e921a03d522403, 0x0b8deb3e586ce4f4}}}}, - {.string = "transfer_private", - .hashes - = {{.big.u64 - = {0x57853955ec65e959, 0xc04dacceb1a2026a, 0x0b8c74f5b07ee388, 0x0913b0e1e8289dba}}, - {.big.u64 - = {0x14050f83d8bc8ad5, 0x68c1128533fd9691, 0xb5bfd0497dcbe60d, 0x061bcb7383584d42}}}}, - {.string = "transfer_private_to_public", - .hashes - = {{.big.u64 - = {0x2ed6c22fde6f93b0, 0x7673e8d503d0995f, 0x6ec97fff81556086, 0x099abee7b8c03597}}, - {.big.u64 - = {0x7c27587b57c5d2d4, 0x78e193e449543290, 0xf4e07ed6a53dea1e, 0x018801c51078171d}}}}, - {.string = "transfer_public_to_private", - .hashes - = {{.big.u64 - = {0x6e2c39b3c306d0f5, 0x1dc66c4befdfbc77, 0x0e2106ac3953c377, 0x0d3c811de289fd10}}, - {.big.u64 - = {0x116b3d6259fc8332, 0x3b6f6a1a5b3344dd, 0x66c3bccc5ed9580b, 0x0b218600c10bd9a3}}}}, - {.string = "fee_public", - .hashes - = {{.big.u64 - = {0xf9bcb7f7a577a934, 0x98f4346a10f70cf8, 0x8f26408e9addc51b, 0x0aa82c82d4ff15a4}}, - {.big.u64 - = {0x8d31084295c605ef, 0xbfdc39996575504e, 0xae32c9cce746275e, 0x0bbfb3251558eee9}}}}, - {.string = "fee_private", - .hashes - = {{.big.u64 - = {0xccf5dc9907364acc, 0x1cf2578ad1d69649, 0x95c4227bca877a48, 0x0c218239cc930255}}, - {.big.u64 - = {0xc3c204d98b5e12b2, 0x318d93a9b12ba7c9, 0x9d42d8fb1c715281, 0x01505646987444fa}}}}, - {.string = "split", - .hashes - = {{.big.u64 - = {0x842cb43ec1d6bbe9, 0xa2c33251d4bded16, 0x0fe74f79fc7c63d4, 0x022fb51a7d2acc90}}, - {.big.u64 - = {0x0bb53e032f965178, 0x6cd697d8b5df7efc, 0x12e2736c492f2495, 0x0529c62123003bca}}}}, - {.string = "join", - .hashes - = {{.big.u64 - = {0xb56e347d9733de05, 0x29c0febaeb2bee52, 0x6c4d0ed1285f19fd, 0x0ec48ec3bdf25eb8}}, - {.big.u64 - = {0x921936604e6eddfe, 0x429d23effcfce58b, 0x072b665308c3d12b, 0x1241fcb49a8a9b72}}}} -}; - -const bhp_1024_parameter_t bhp_1024_parameters[NB_OF_PROGRAMS] = { - {.program_id = "credits", - .program_id_network = "aleo", - .nb_of_functions = NB_OF_CREDITS_ALEO_FUNCTIONS, - .functions = credits_aleo} -}; \ No newline at end of file diff --git a/src/crypto/bhp_1024_parameters.h b/src/crypto/bhp_1024_parameters.h deleted file mode 100644 index 525d516..0000000 --- a/src/crypto/bhp_1024_parameters.h +++ /dev/null @@ -1,24 +0,0 @@ - -#include // size_t -#include "field.h" - -typedef enum { - NETWORK_ID_MAINNET = 0, - NETWORK_ID_TESTNET = 1, - NETWORK_ID_COUNT = 2, -} network_id_e; - -typedef struct { - const char *string; - field_t hashes[NETWORK_ID_COUNT]; -} function_hashes_t; - -typedef struct { - const char *program_id; - const char *program_id_network; - size_t nb_of_functions; - const function_hashes_t *functions; -} bhp_1024_parameter_t; - -#define NB_OF_PROGRAMS (1) -extern const bhp_1024_parameter_t bhp_1024_parameters[NB_OF_PROGRAMS]; \ No newline at end of file diff --git a/src/db/db_program_function.c b/src/db/db_program_function.c new file mode 100644 index 0000000..7bbf758 --- /dev/null +++ b/src/db/db_program_function.c @@ -0,0 +1,342 @@ +/***************************************************************************** + * Ledger App Aleo. + * (c) 2025 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#include "db_program_function.h" + +#define NB_OF_CREDITS_ALEO_FUNCTIONS (8) +const function_parameters_t credits_aleo[NB_OF_CREDITS_ALEO_FUNCTIONS] = { + {.string = "transfer_public", + .tx_type = TX_ALEO_TRANSFER_PUBLIC, + .input_count = 2, + .bhp_1024_hashes + = {{.big.u64 + = {0x405245447621401a, 0x51c07b62a9c53d26, 0xb928e2f9112d0953, 0x0f511e31d6855446}}, + {.big.u64 + = {0x1a45c36fff8ff4a4, 0x69712402399b89f1, 0xb3e921a03d522403, 0x0b8deb3e586ce4f4}}}}, + {.string = "transfer_private", + .tx_type = TX_ALEO_TRANSFER_PRIVATE, + .input_count = 3, + .bhp_1024_hashes + = {{.big.u64 + = {0x57853955ec65e959, 0xc04dacceb1a2026a, 0x0b8c74f5b07ee388, 0x0913b0e1e8289dba}}, + {.big.u64 + = {0x14050f83d8bc8ad5, 0x68c1128533fd9691, 0xb5bfd0497dcbe60d, 0x061bcb7383584d42}}}}, + {.string = "transfer_private_to_public", + .tx_type = TX_ALEO_TRANSFER_PRIVATE_TO_PUBLIC, + .input_count = 3, + .bhp_1024_hashes + = {{.big.u64 + = {0x2ed6c22fde6f93b0, 0x7673e8d503d0995f, 0x6ec97fff81556086, 0x099abee7b8c03597}}, + {.big.u64 + = {0x7c27587b57c5d2d4, 0x78e193e449543290, 0xf4e07ed6a53dea1e, 0x018801c51078171d}}}}, + {.string = "transfer_public_to_private", + .tx_type = TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE, + .input_count = 2, + .bhp_1024_hashes + = {{.big.u64 + = {0x6e2c39b3c306d0f5, 0x1dc66c4befdfbc77, 0x0e2106ac3953c377, 0x0d3c811de289fd10}}, + {.big.u64 + = {0x116b3d6259fc8332, 0x3b6f6a1a5b3344dd, 0x66c3bccc5ed9580b, 0x0b218600c10bd9a3}}}}, + {.string = "fee_public", + .tx_type = TX_FEE_PUBLIC, + .input_count = 3, + .bhp_1024_hashes + = {{.big.u64 + = {0xf9bcb7f7a577a934, 0x98f4346a10f70cf8, 0x8f26408e9addc51b, 0x0aa82c82d4ff15a4}}, + {.big.u64 + = {0x8d31084295c605ef, 0xbfdc39996575504e, 0xae32c9cce746275e, 0x0bbfb3251558eee9}}}}, + {.string = "fee_private", + .tx_type = TX_FEE_PRIVATE, + .input_count = 4, + .bhp_1024_hashes + = {{.big.u64 + = {0xccf5dc9907364acc, 0x1cf2578ad1d69649, 0x95c4227bca877a48, 0x0c218239cc930255}}, + {.big.u64 + = {0xc3c204d98b5e12b2, 0x318d93a9b12ba7c9, 0x9d42d8fb1c715281, 0x01505646987444fa}}}}, + {.string = "split", + .tx_type = TX_UNKNOWN, + .input_count = 2, + .bhp_1024_hashes + = {{.big.u64 + = {0x842cb43ec1d6bbe9, 0xa2c33251d4bded16, 0x0fe74f79fc7c63d4, 0x022fb51a7d2acc90}}, + {.big.u64 + = {0x0bb53e032f965178, 0x6cd697d8b5df7efc, 0x12e2736c492f2495, 0x0529c62123003bca}}}}, + {.string = "join", + .tx_type = TX_UNKNOWN, + .input_count = 2, + .bhp_1024_hashes + = {{.big.u64 + = {0xb56e347d9733de05, 0x29c0febaeb2bee52, 0x6c4d0ed1285f19fd, 0x0ec48ec3bdf25eb8}}, + {.big.u64 + = {0x921936604e6eddfe, 0x429d23effcfce58b, 0x072b665308c3d12b, 0x1241fcb49a8a9b72}}}}, +}; + +#define NB_OF_LDGBATCHER_P28_ALEO_FUNCTIONS (7) +const function_parameters_t ldgbatcher_p28_aleo[NB_OF_LDGBATCHER_P28_ALEO_FUNCTIONS] = { + {.string = "transfer_private_2", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 4, + .bhp_1024_hashes + = {{.big.u64 + = {0x711bd2f0fd3b8860, 0x2140898228c34911, 0x0aae5605d3b999fe, 0x0487b38e575e54a4}}, + {.big.u64 + = {0x94fe7832f23f69f8, 0x79ed7c0a94a507b8, 0x19375744cd4d66cf, 0x0a0d8242d888337b}}}}, + {.string = "transfer_private_3", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 5, + .bhp_1024_hashes + = {{.big.u64 + = {0xc52d556215ca8d42, 0xdd6855255a8999fc, 0x96a0067debdae976, 0x05457b2b07ff2258}}, + {.big.u64 + = {0xaa089e65aad01997, 0x3c449656a3f1cfb6, 0x034a6d7ada794cc6, 0x0e0823456dc1865e}}}}, + {.string = "transfer_private_4", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 6, + .bhp_1024_hashes + = {{.big.u64 + = {0x5a549bc57d7ed08e, 0x57081afbde550716, 0xfd460bb66b8552f7, 0x0d98770ff6216767}}, + {.big.u64 + = {0x6bcc11ae56749122, 0x260e2b57d5d5fbef, 0xce5371258b939c59, 0x0884f29ecd7a4f1f}}}}, + {.string = "transfer_private_5", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 7, + .bhp_1024_hashes + = {{.big.u64 + = {0x224995cd589d1640, 0x6373aaa70a095470, 0xdf9bc58530309041, 0x01f320b522e45a10}}, + {.big.u64 + = {0xfec2e5eb27e81ed1, 0x30342feb79e7b799, 0x895988e43a223100, 0x0d77f3954dc2bd3a}}}}, + {.string = "transfer_private_6", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 8, + .bhp_1024_hashes + = {{.big.u64 + = {0xbc81a96cea70096d, 0x8b056fb89161bad6, 0x63cacb85d316cadb, 0x0e3562712c147531}}, + {.big.u64 + = {0xdd5ec7c602f5a9db, 0xc846d46174e69814, 0xcb0457c70b198957, 0x1178e2cfd2c4f6de}}}}, + {.string = "transfer_private_7", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 9, + .bhp_1024_hashes + = {{.big.u64 + = {0x433f8bef1e650481, 0x10d600f6d41e3197, 0xe862611390273369, 0x0158dab93d6cbea6}}, + {.big.u64 + = {0x080a8386e49889ef, 0xb896be0d0173b849, 0x74fe7461b27002f1, 0x0002580b37e0e04f}}}}, + {.string = "transfer_private_8", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 10, + .bhp_1024_hashes + = {{.big.u64 + = {0x738c7d8d9546e4c7, 0xb3a42c93014c13b5, 0xa7bfbaa1fdbfaedf, 0x0cdd3604cfb57700}}, + {.big.u64 + = {0x963d210f3ca0a9c6, 0xdef5b86772cb88ae, 0xc937f1616d1cabbb, 0x0050e835094c6a46}}}}, +}; + +#define NB_OF_LDGBATCHER_P910_ALEO_FUNCTIONS (2) +const function_parameters_t ldgbatcher_p910_aleo[NB_OF_LDGBATCHER_P910_ALEO_FUNCTIONS] = { + {.string = "transfer_private_9", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 11, + .bhp_1024_hashes + = {{.big.u64 + = {0x98aa9cc1c8ee2642, 0xbe62182fbb92ffca, 0x35a23ab833271ffa, 0x03310b27a0d00370}}, + {.big.u64 + = {0x32ee6dde1ebe65de, 0xb8c26f628d1e6f21, 0xe1c2b67275d1b93f, 0x0e9e1d8fc177dd94}}}}, + {.string = "transfer_private_10", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 12, + .bhp_1024_hashes + = {{.big.u64 + = {0x186d4555fde9475c, 0x2e8cef1de078b120, 0x5fdccdbe70ef5a5d, 0x02ffa736d1f5dee5}}, + {.big.u64 + = {0x348fed2e2ebff55a, 0xaaa512a36c5161d1, 0xc15f74c614285ada, 0x011281933285eae8}}}}, +}; + +#define NB_OF_LDGBATCHER_P1114_ALEO_FUNCTIONS (4) +const function_parameters_t ldgbatcher_p1114_aleo[NB_OF_LDGBATCHER_P1114_ALEO_FUNCTIONS] = { + {.string = "transfer_private_11", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 13, + .bhp_1024_hashes + = {{.big.u64 + = {0x3ff43124394dbd33, 0x531338625ef6c666, 0x65e5e9895329685f, 0x07f68d6b21f8e833}}, + {.big.u64 + = {0x328851886470667b, 0x64e21d37f7925b67, 0x35ac4567af808ffe, 0x0026ad7b8ee7aff7}}}}, + {.string = "transfer_private_12", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 14, + .bhp_1024_hashes + = {{.big.u64 + = {0x6d1d3896bd2839bb, 0xbd8958b0462624bd, 0xe860528af9002653, 0x112a53bacbcbe7ce}}, + {.big.u64 + = {0xedcad1eb8b147d4f, 0x02fde54d519738c2, 0x9341ee3381358a1c, 0x044020e3a68d76a0}}}}, + {.string = "transfer_private_13", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 15, + .bhp_1024_hashes + = {{.big.u64 + = {0x09c5f6f27cbbfec9, 0xbab4c48888eaf220, 0x9881a77c0de86ec0, 0x02755a441a2744cc}}, + {.big.u64 + = {0xb1e64caf9634b655, 0xb3ac2e6fbabf1940, 0x172b5caf1d663d14, 0x11ae9762c3f6d96a}}}}, + {.string = "transfer_private_14", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE, + .input_count = 16, + .bhp_1024_hashes + = {{.big.u64 + = {0xe3c90261c06a4b1c, 0x4fc657a9764c2ac9, 0x9447c78f2fd4ad7e, 0x0d89d16a0d9cede8}}, + {.big.u64 + = {0x8dbb40d608335e21, 0x7dafcd5c7a42044e, 0x7ed046b72a0ba325, 0x0e6ae1d15f10345d}}}}, +}; + +#define NB_OF_LDGBATCHER_PPUB_28_ALEO_FUNCTIONS (7) +const function_parameters_t ldgbatcher_ppub_28_aleo[NB_OF_LDGBATCHER_PPUB_28_ALEO_FUNCTIONS] = { + {.string = "transfer_private_to_public_2", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 3, + .bhp_1024_hashes + = {{.big.u64 + = {0x2e202cb29f237ff0, 0x95ac470726eec1b3, 0xf926efce4965f631, 0x06994f0de2afbbea}}, + {.big.u64 + = {0x8431ac482d71262b, 0x9dacedbb722faa48, 0x3e1242530da85257, 0x0245170992fe443b}}}}, + {.string = "transfer_private_to_public_3", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 4, + .bhp_1024_hashes + = {{.big.u64 + = {0xaefa4d43e173e47b, 0xf892da4a203a50f6, 0xc17a7f8fbcd997ff, 0x08e12aff2b496e8a}}, + {.big.u64 + = {0x7e9e6d6b849d78bf, 0xbfd7d207a7377c9c, 0x5ba17e7a2e1be0a6, 0x08d41f5f3403286b}}}}, + {.string = "transfer_private_to_public_4", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 5, + .bhp_1024_hashes + = {{.big.u64 + = {0x93a2213762b0c65a, 0x37c2eca9b7cdb3bc, 0xd56c8e5821e80bb8, 0x0e0bbd6c7cda39dd}}, + {.big.u64 + = {0x9faad67addfda98e, 0x6474f6f56eeaf3f4, 0x4afc955e45b7ed88, 0x0798b94074ccbfe9}}}}, + {.string = "transfer_private_to_public_5", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 6, + .bhp_1024_hashes + = {{.big.u64 + = {0x46c9f29a42fd6235, 0x0dafa85eae9bc356, 0x61270bbf636f934d, 0x0abaa6f52a6752f4}}, + {.big.u64 + = {0xde629954b703d153, 0xfa19518c7613adef, 0x8b30ab7453281da2, 0x07a0b6a68395b6d3}}}}, + {.string = "transfer_private_to_public_6", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 7, + .bhp_1024_hashes + = {{.big.u64 + = {0xc60fc62388df8ebf, 0xd3c8011e59977462, 0xdb14b83ca2c2aa2f, 0x0fd917a652fccd6e}}, + {.big.u64 + = {0xb273d3ef3dab4efe, 0x6b29647fd309a74e, 0x7dd0861bfb88d6f9, 0x019ce7551644284e}}}}, + {.string = "transfer_private_to_public_7", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 8, + .bhp_1024_hashes + = {{.big.u64 + = {0x81fa4f7e550ba2ed, 0x289971c5a59e4103, 0xf4a759009ea50b6b, 0x0e7841f6e4f0c7db}}, + {.big.u64 + = {0x18c759f9c7d74e44, 0x461615c31b180ffd, 0x249204dc159e6e3a, 0x06c67c9e4647b153}}}}, + {.string = "transfer_private_to_public_8", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 9, + .bhp_1024_hashes + = {{.big.u64 + = {0x795cd03fd2f21bdf, 0x549cc5aea39d33a7, 0xfc64e46494fa936f, 0x066701f2776b7405}}, + {.big.u64 + = {0xf1565b606c1c9499, 0xf2a03bcadef84933, 0x9fc2c83fd4bcdb24, 0x1138c6e52a18ec91}}}}, +}; + +#define NB_OF_LDGBATCHER_PPUB_910_ALEO_FUNCTIONS (2) +const function_parameters_t ldgbatcher_ppub_910_aleo[NB_OF_LDGBATCHER_PPUB_910_ALEO_FUNCTIONS] = { + {.string = "transfer_private_to_public_9", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 10, + .bhp_1024_hashes + = {{.big.u64 + = {0x7e850aeff72bb532, 0x15c669e3b28d43d5, 0xa4288c550b1594c6, 0x0e54f0a78144077e}}, + {.big.u64 + = {0xef17e6595ac6125b, 0x7466d5a59c926aac, 0xb45d4c306ed5e79c, 0x03e930b3cc66d8b0}}}}, + {.string = "transfer_private_to_public_10", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 11, + .bhp_1024_hashes + = {{.big.u64 + = {0x19ecd93e5ef4470f, 0x79ef784335bdb4f1, 0xd40b7d452fb2e12c, 0x0c8b7f636f512f7e}}, + {.big.u64 + = {0x09c61c1cc4a9d941, 0x2bb6a709e1206773, 0xd5d9f01ae2a054c5, 0x0298a0f6469bf062}}}}, +}; + +#define NB_OF_LDGBATCHER_PPUB_1114_ALEO_FUNCTIONS (4) +const function_parameters_t ldgbatcher_ppub_1114_aleo[NB_OF_LDGBATCHER_PPUB_1114_ALEO_FUNCTIONS] = { + {.string = "transfer_private_to_public_11", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 12, + .bhp_1024_hashes + = {{.big.u64 + = {0x09afac9c39dbe1a4, 0x332e976f09cfb1f9, 0x9e00dbc824e9c873, 0x0517c8fa9f8e7c73}}, + {.big.u64 + = {0x84c054b961ad3545, 0x90012849112b8372, 0x02bcc43090085e6e, 0x10c431e4797574f9}}}}, + {.string = "transfer_private_to_public_12", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 13, + .bhp_1024_hashes + = {{.big.u64 + = {0xc34709ce79a3316b, 0xadcc93b1033a32cf, 0x3a7e7b678fcf44bc, 0x06ed307f460eed06}}, + {.big.u64 + = {0xa0c9fd2a537c2527, 0x0e7e6bfde27a2b39, 0xe2ab55373b8bb9ba, 0x116c58d8c843ace2}}}}, + {.string = "transfer_private_to_public_13", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 14, + .bhp_1024_hashes + = {{.big.u64 + = {0x75b716b410306dfb, 0x949674d9d47fad9b, 0xb5d06a456c8e0d66, 0x0a7b39e70b31ebf1}}, + {.big.u64 + = {0x83b3d743b20a8705, 0x2aa74341421735a1, 0x11e5432f70a9aeef, 0x05eb29ec75591e75}}}}, + {.string = "transfer_private_to_public_14", + .tx_type = TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + .input_count = 15, + .bhp_1024_hashes + = {{.big.u64 + = {0x98b984950f7992b2, 0x73c090056cf218e4, 0x828e5cd005ee2c11, 0x008ad35fcadfa529}}, + {.big.u64 + = {0x31c3c3359850db6f, 0x58b6708d903b569a, 0xc494d0b8138e6b30, 0x0ff69533a0201287}}}}, +}; + +const program_parameter_t program_parameters[NB_OF_PROGRAMS] = { + {.program_id = "credits.aleo", + .nb_of_functions = NB_OF_CREDITS_ALEO_FUNCTIONS, + .functions = credits_aleo }, + {.program_id = "ldgbatcher_p28.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_P28_ALEO_FUNCTIONS, + .functions = ldgbatcher_p28_aleo }, + {.program_id = "ldgbatcher_p910.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_P910_ALEO_FUNCTIONS, + .functions = ldgbatcher_p910_aleo }, + {.program_id = "ldgbatcher_p1114.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_P1114_ALEO_FUNCTIONS, + .functions = ldgbatcher_p1114_aleo }, + {.program_id = "ldgbatcher_ppub_28.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_PPUB_28_ALEO_FUNCTIONS, + .functions = ldgbatcher_ppub_28_aleo }, + {.program_id = "ldgbatcher_ppub_910.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_PPUB_910_ALEO_FUNCTIONS, + .functions = ldgbatcher_ppub_910_aleo }, + {.program_id = "ldgbatcher_ppub_1114.aleo", + .nb_of_functions = NB_OF_LDGBATCHER_PPUB_1114_ALEO_FUNCTIONS, + .functions = ldgbatcher_ppub_1114_aleo}, +}; diff --git a/src/db/db_program_function.h b/src/db/db_program_function.h new file mode 100644 index 0000000..dd5950c --- /dev/null +++ b/src/db/db_program_function.h @@ -0,0 +1,26 @@ +#include // size_t + +#include "types.h" +#include "field.h" + +typedef enum { + NETWORK_ID_MAINNET = 0, + NETWORK_ID_TESTNET = 1, + NETWORK_ID_COUNT = 2, +} network_id_e; + +typedef struct { + const char *string; + tx_type_e tx_type; + uint8_t input_count; + field_t bhp_1024_hashes[NETWORK_ID_COUNT]; +} function_parameters_t; + +typedef struct { + const char *program_id; + size_t nb_of_functions; + const function_parameters_t *functions; +} program_parameter_t; + +#define NB_OF_PROGRAMS (7) +extern const program_parameter_t program_parameters[NB_OF_PROGRAMS]; diff --git a/src/handler/sign_transaction.c b/src/handler/sign_transaction.c index d2e9e97..c8a918b 100644 --- a/src/handler/sign_transaction.c +++ b/src/handler/sign_transaction.c @@ -23,6 +23,8 @@ #include "os.h" #include "cx.h" #include "ledger_assert.h" +#include "nbgl_use_case.h" +#include "menu.h" #include "io.h" #include "buffer.h" #include "crypto_helpers.h" @@ -37,7 +39,7 @@ #include "signature.h" #include "tx.h" -static uint8_t rx_transaction_array[512]; +static uint8_t rx_transaction_array[1024]; static buffer_t apdu_rx_buffer; static int sign_root_tx(buffer_t *cdata) @@ -56,6 +58,9 @@ static int sign_root_tx(buffer_t *cdata) = account_generate_keys(G_context.bip32_path, G_context.bip32_path_len, &G_context.account); if (status < 0) { explicit_bzero(&G_context.account, sizeof(G_context.account)); +#ifndef FUZZ + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_menu_main); +#endif // FUZZ return io_send_sw(SW_DISPLAY_BIP32_PATH_FAIL); } @@ -68,6 +73,9 @@ static int sign_root_tx(buffer_t *cdata) // Extract intent if ((status = tx_extract_intent(cdata)) < 0) { explicit_bzero(&G_context.account, sizeof(G_context.account)); +#ifndef FUZZ + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_menu_main); +#endif // FUZZ goto end; } G_context.sign_transaction_datas.prepared_request.is_root = true; @@ -77,6 +85,9 @@ static int sign_root_tx(buffer_t *cdata) // Parse intent if ((status = tx_parse(&G_context.sign_transaction_datas, &G_context.tx)) < 0) { explicit_bzero(&G_context.account, sizeof(G_context.account)); +#ifndef FUZZ + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_menu_main); +#endif // FUZZ goto end; } @@ -85,6 +96,9 @@ static int sign_root_tx(buffer_t *cdata) // Display & sign transaction if ((status = ui_display_transaction()) < 0) { explicit_bzero(&G_context.account, sizeof(G_context.account)); +#ifndef FUZZ + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_menu_main); +#endif // FUZZ } end: @@ -101,6 +115,7 @@ static int sign_nested_call_tx(buffer_t *cdata) } if (G_context.signing_state != SIGNING_STATE_NESTED_CALL) { + PRINTF("sign_nested_call_tx wrong state : %d\n", G_context.signing_state); explicit_bzero(&G_context.account, sizeof(G_context.account)); return io_send_sw(SWO_CONDITIONS_NOT_SATISFIED); } @@ -139,9 +154,19 @@ static int sign_nested_call_tx(buffer_t *cdata) } G_context.nested_call_offset++; - if (G_context.nested_call_offset == G_context.nested_call_count) { - G_context.fees_waiting_time_ms = 0; - G_context.signing_state = SIGNING_STATE_WAIT_FEES; + if (G_context.nested_call_offset >= G_context.nested_call_count) { + if ((G_context.sign_transaction_datas.max_base_fee != 0) + || (G_context.sign_transaction_datas.max_priority_fee != 0)) { + G_context.fees_waiting_time_ms = 0; + G_context.signing_state = SIGNING_STATE_WAIT_FEES; +#ifndef FUZZ + nbgl_useCaseSpinner("Calculating fees"); +#endif // FUZZ + } + else { + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_menu_main); + G_context.signing_state = SIGNING_STATE_WAIT_INTENT; + } } end: @@ -153,6 +178,7 @@ static int sign_fee_tx(buffer_t *cdata) int status = 0; if (G_context.signing_state != SIGNING_STATE_WAIT_FEES) { + PRINTF("sign_fee_tx wrong state : %d\n", G_context.signing_state); explicit_bzero(&G_context.account, sizeof(G_context.account)); return io_send_sw(SWO_CONDITIONS_NOT_SATISFIED); } diff --git a/src/transaction/tx_extract.c b/src/transaction/tx_extract.c index 75d7abe..3871c5a 100644 --- a/src/transaction/tx_extract.c +++ b/src/transaction/tx_extract.c @@ -52,6 +52,7 @@ static void print_signature_data(sign_transaction_datas_t *data) } PRINTF("\n"); } + PRINTF("nested_call_count : %d\n", data->prepared_request.nested_call_count); if (data->prepared_request.program_checksum) { PRINTF("program_checksum : "); for (int j = 0; j < 32; j++) { @@ -59,6 +60,13 @@ static void print_signature_data(sign_transaction_datas_t *data) } PRINTF("\n"); } + if (data->prepared_request.r_hint) { + PRINTF("r_hint : "); + for (int j = 0; j < 32; j++) { + PRINTF("%02x", data->prepared_request.r_hint[j]); + } + PRINTF("\n"); + } } #else // !HAVE_PRINTF #define print_signature_data(...) @@ -144,12 +152,23 @@ static bool get_program_checksum(const tlv_data_t *data, prepared_request_t *coo return true; } +static bool get_r_hint(const tlv_data_t *data, prepared_request_t *cookie) +{ + buffer_t buff; + if (!get_buffer_from_tlv_data(data, &buff, sizeof(scalar_t), sizeof(scalar_t))) { + return false; + } + cookie->r_hint = (uint8_t *) buff.ptr; + return true; +} + #define PREPARED_REQUEST_TLV_TAGS(X) \ X(0x01, TAG_PREPARED_REQUEST_STRUCTURE_TYPE, NULL, ENFORCE_UNIQUE_TAG) \ X(0x02, TAG_PREPARED_REQUEST_VERSION, NULL, ENFORCE_UNIQUE_TAG) \ X(0xc3, TAG_PREPARED_REQUEST_NETWORK_ID, get_network_id, ENFORCE_UNIQUE_TAG) \ X(0xb5, TAG_PREPARED_REQUEST_PROGRAM_ID, get_program_id, ENFORCE_UNIQUE_TAG) \ X(0xc4, TAG_PREPARED_REQUEST_PROGRAM_CHECKSUM, get_program_checksum, ENFORCE_UNIQUE_TAG) \ + X(0xc5, TAG_PREPARED_REQUEST_R_HINT, get_r_hint, ENFORCE_UNIQUE_TAG) \ X(0xb6, TAG_PREPARED_REQUEST_FUNCTION_NAME, get_function_name, ENFORCE_UNIQUE_TAG) \ X(0xba, TAG_PREPARED_REQUEST_NESTED_CALL_COUNT, get_nested_call_count, ENFORCE_UNIQUE_TAG) \ X(0xb7, TAG_PREPARED_REQUEST_INPUT_COUNT, get_input_count, ENFORCE_UNIQUE_TAG) \ diff --git a/src/transaction/tx_parse.c b/src/transaction/tx_parse.c index a3deafe..5036044 100644 --- a/src/transaction/tx_parse.c +++ b/src/transaction/tx_parse.c @@ -26,6 +26,8 @@ #include "bech32.h" #include "account.h" + +#include "db_program_function.h" #include "tx_types.h" #include "tx.h" @@ -34,8 +36,6 @@ #define ADDRESS_TYPE_LENGTH (3) #define ADDRESS_VALUE_LENGTH sizeof(field_t) -#define NB_OF_PROGRAMS (6) - typedef struct { const char *string; uint8_t string_length; @@ -47,58 +47,15 @@ typedef struct { static int get_u64(input_t *input, bool is_private, uint64_t *value); static int get_address(input_t *input, bool is_private, char address[ADDRESS_LEN + 1]); -static int parse_transfer_public(sign_transaction_datas_t *data, tx_t *tx); -static int parse_transfer_private(sign_transaction_datas_t *data, tx_t *tx); -static int parse_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx); -static int parse_transfer_private_to_public(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_transfer_public(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_transfer_private(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_batch_transfer_private(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_batch_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx); +static int parse_aleo_transfer_private_to_public(sign_transaction_datas_t *data, tx_t *tx); static int parse_fee_public(sign_transaction_datas_t *data, tx_t *tx); static int parse_fee_private(sign_transaction_datas_t *data, tx_t *tx); -static const program_infos_t program_infos[NB_OF_PROGRAMS] = { - { - .string = "transfer_public", - .string_length = 15, - .tx_type = TX_TRANSFER, - .input_count = 2, - .parse_fn = parse_transfer_public, - }, - { - .string = "transfer_private", - .string_length = 16, - .tx_type = TX_TRANSFER, - .input_count = 3, - .parse_fn = parse_transfer_private, - }, - { - .string = "transfer_public_to_private", - .string_length = 26, - .tx_type = TX_TRANSFER, - .input_count = 2, - .parse_fn = parse_transfer_public_to_private, - }, - { - .string = "transfer_private_to_public", - .string_length = 26, - .tx_type = TX_TRANSFER, - .input_count = 3, - .parse_fn = parse_transfer_private_to_public, - }, - { - .string = "fee_public", - .string_length = 10, - .tx_type = TX_FEE, - .input_count = 3, - .parse_fn = parse_fee_public, - }, - { - .string = "fee_private", - .string_length = 11, - .tx_type = TX_FEE, - .input_count = 4, - .parse_fn = parse_fee_private, - }, -}; - static int get_u64(input_t *input, bool is_private, uint64_t *value) { int status = 0; @@ -158,9 +115,8 @@ static int get_address(input_t *input, bool is_private, char address[ADDRESS_LEN return status; } -static int parse_transfer_public(sign_transaction_datas_t *data, tx_t *tx) +static int parse_aleo_transfer_public(sign_transaction_datas_t *data, tx_t *tx) { - tx->transfer.type = TX_TRANSFER_PUBLIC; int status = get_address(&data->prepared_request.inputs[0], false, tx->transfer.address_to); if (status == 0) { status = get_u64(&data->prepared_request.inputs[1], false, &tx->transfer.amount); @@ -169,9 +125,8 @@ static int parse_transfer_public(sign_transaction_datas_t *data, tx_t *tx) return status; } -static int parse_transfer_private(sign_transaction_datas_t *data, tx_t *tx) +static int parse_aleo_transfer_private(sign_transaction_datas_t *data, tx_t *tx) { - tx->transfer.type = TX_TRANSFER_PRIVATE; int status = get_address(&data->prepared_request.inputs[1], true, tx->transfer.address_to); if (status == 0) { status = get_u64(&data->prepared_request.inputs[2], true, &tx->transfer.amount); @@ -180,9 +135,21 @@ static int parse_transfer_private(sign_transaction_datas_t *data, tx_t *tx) return status; } -static int parse_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx) +static int parse_aleo_batch_transfer_private(sign_transaction_datas_t *data, tx_t *tx) +{ + uint8_t inputs_count = data->prepared_request.inputs_count; + int status = get_address( + &data->prepared_request.inputs[inputs_count - 2], true, tx->transfer.address_to); + if (status == 0) { + status + = get_u64(&data->prepared_request.inputs[inputs_count - 1], true, &tx->transfer.amount); + } + + return status; +} + +static int parse_aleo_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx) { - tx->transfer.type = TX_TRANSFER_PUBLIC_TO_PRIVATE; int status = get_address(&data->prepared_request.inputs[0], true, tx->transfer.address_to); if (status == 0) { status = get_u64(&data->prepared_request.inputs[1], false, &tx->transfer.amount); @@ -191,9 +158,18 @@ static int parse_transfer_public_to_private(sign_transaction_datas_t *data, tx_t return status; } -static int parse_transfer_private_to_public(sign_transaction_datas_t *data, tx_t *tx) +static int parse_aleo_batch_transfer_public_to_private(sign_transaction_datas_t *data, tx_t *tx) +{ + uint8_t inputs_count = data->prepared_request.inputs_count; + int status + = get_u64(&data->prepared_request.inputs[inputs_count - 1], false, &tx->transfer.amount); + memset(tx->transfer.address_to, 0, sizeof(tx->transfer.address_to)); + + return status; +} + +static int parse_aleo_transfer_private_to_public(sign_transaction_datas_t *data, tx_t *tx) { - tx->transfer.type = TX_TRANSFER_PRIVATE_TO_PUBLIC; int status = get_address(&data->prepared_request.inputs[1], false, tx->transfer.address_to); if (status == 0) { status = get_u64(&data->prepared_request.inputs[2], false, &tx->transfer.amount); @@ -204,8 +180,7 @@ static int parse_transfer_private_to_public(sign_transaction_datas_t *data, tx_t static int parse_fee_public(sign_transaction_datas_t *data, tx_t *tx) { - tx->fee.type = TX_FEE_PUBLIC; - int status = get_u64(&data->prepared_request.inputs[0], false, &tx->fee.base_fee); + int status = get_u64(&data->prepared_request.inputs[0], false, &tx->fee.base_fee); if (status == 0) { status = get_u64(&data->prepared_request.inputs[1], false, &tx->fee.priority_fee); } @@ -215,8 +190,7 @@ static int parse_fee_public(sign_transaction_datas_t *data, tx_t *tx) static int parse_fee_private(sign_transaction_datas_t *data, tx_t *tx) { - tx->fee.type = TX_FEE_PRIVATE; - int status = get_u64(&data->prepared_request.inputs[1], false, &tx->fee.base_fee); + int status = get_u64(&data->prepared_request.inputs[1], false, &tx->fee.base_fee); if (status == 0) { status = get_u64(&data->prepared_request.inputs[2], false, &tx->fee.priority_fee); } @@ -229,42 +203,89 @@ int tx_parse(sign_transaction_datas_t *data, tx_t *tx) LEDGER_ASSERT(data != NULL, "NULL data"); LEDGER_ASSERT(tx != NULL, "NULL tx"); + size_t index = 0; + size_t program_index = 0; + function_parameters_t *functions = NULL; + if (!data->prepared_request.program_id) { return -1; } if (!data->prepared_request.function_name) { return -1; } - if (memcmp(data->prepared_request.program_id, - "credits.aleo", - data->prepared_request.program_id_length)) { - // Unknown transaction + + // Find program + for (index = 0; index < NB_OF_PROGRAMS; index++) { + if (data->prepared_request.program_id_length + != strlen(PIC(program_parameters[index].program_id))) { + continue; + } + if (memcmp(data->prepared_request.program_id, + PIC(program_parameters[index].program_id), + data->prepared_request.program_id_length)) { + continue; + } + break; + } + + if (index >= NB_OF_PROGRAMS) { return -1; } - tx->type = TX_UNKNOWN; - for (uint8_t i = 0; i < NB_OF_PROGRAMS; i++) { - if (data->prepared_request.function_name_length != program_infos[i].string_length) { + + // Find program's function + program_index = index; + functions = PIC(program_parameters[program_index].functions); + + for (index = 0; index < program_parameters[program_index].nb_of_functions; index++) { + if (data->prepared_request.function_name_length != strlen(PIC(functions[index].string))) { continue; } - - if (!memcmp(data->prepared_request.function_name, - PIC(program_infos[i].string), - data->prepared_request.function_name_length)) { - tx->type = program_infos[i].tx_type; - if (program_infos[i].input_count != data->prepared_request.inputs_count) { - return -1; - } - int (*parse_fn)(sign_transaction_datas_t *, tx_t *) = PIC(program_infos[i].parse_fn); - if (parse_fn(data, tx) < 0) { - return -1; - } - break; + if (memcmp(data->prepared_request.function_name, + PIC(functions[index].string), + data->prepared_request.function_name_length)) { + continue; } + break; } - if (tx->type == TX_UNKNOWN) { + if (index >= program_parameters[program_index].nb_of_functions) { return -1; } - return 0; + if (functions[index].input_count != data->prepared_request.inputs_count) { + return -1; + } + + tx->type = functions[index].tx_type; + + switch (tx->type) { + case TX_ALEO_TRANSFER_PUBLIC: + return parse_aleo_transfer_public(data, tx); + + case TX_ALEO_TRANSFER_PRIVATE: + return parse_aleo_transfer_private(data, tx); + + case TX_ALEO_TRANSFER_BATCH_PRIVATE: + return parse_aleo_batch_transfer_private(data, tx); + + case TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE: + return parse_aleo_transfer_public_to_private(data, tx); + + case TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC: + return parse_aleo_batch_transfer_public_to_private(data, tx); + + case TX_ALEO_TRANSFER_PRIVATE_TO_PUBLIC: + return parse_aleo_transfer_private_to_public(data, tx); + + case TX_FEE_PUBLIC: + return parse_fee_public(data, tx); + + case TX_FEE_PRIVATE: + return parse_fee_private(data, tx); + + default: + break; + } + + return -1; } diff --git a/src/types.h b/src/types.h index 0042f03..f701672 100644 --- a/src/types.h +++ b/src/types.h @@ -70,6 +70,7 @@ typedef struct { uint8_t inputs_count; input_t inputs[MAX_NB_OF_INPUTS]; uint8_t *program_checksum; + uint8_t *r_hint; uint8_t nested_call_count; // internal (for parsing) @@ -103,32 +104,28 @@ typedef struct { typedef enum { TX_UNKNOWN, - TX_TRANSFER, - TX_FEE, -} tx_type_e; - -typedef enum { - TX_TRANSFER_PUBLIC, - TX_TRANSFER_PRIVATE, - TX_TRANSFER_PUBLIC_TO_PRIVATE, - TX_TRANSFER_PRIVATE_TO_PUBLIC, -} tx_transfer_type_e; - -typedef enum { - TX_FEE_PUBLIC, + TX_TRANSFER_START, + TX_ALEO_TRANSFER_PUBLIC = TX_TRANSFER_START, + TX_ALEO_TRANSFER_PRIVATE, + TX_ALEO_TRANSFER_BATCH_PRIVATE, + TX_ALEO_TRANSFER_PRIVATE_TO_PUBLIC, + TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC, + TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE, + TX_ALEO_TRANSFER_END = TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE, + TX_FEE_START, + TX_FEE_PUBLIC = TX_FEE_START, TX_FEE_PRIVATE, -} tx_fee_type_e; + TX_FEE_END = TX_FEE_PRIVATE, +} tx_type_e; typedef struct { - tx_transfer_type_e type; - char address_to[ADDRESS_LEN + 1]; - uint64_t amount; + char address_to[ADDRESS_LEN + 1]; + uint64_t amount; } tx_transfer_t; typedef struct { - tx_fee_type_e type; - uint64_t base_fee; - uint64_t priority_fee; + uint64_t base_fee; + uint64_t priority_fee; } tx_fee_t; typedef struct { diff --git a/src/ui/nbgl_display_transaction.c b/src/ui/nbgl_display_transaction.c index bf9e5f4..065c86e 100644 --- a/src/ui/nbgl_display_transaction.c +++ b/src/ui/nbgl_display_transaction.c @@ -72,20 +72,26 @@ static int display_review_transaction(void) uint8_t pair_index = 0; char amount[50 + MAX_TICKER_SIZE] = {0}; const char *review_subtitle = NULL; - if (G_context.tx.transfer.type == TX_TRANSFER_PUBLIC) { + if (G_context.tx.type == TX_ALEO_TRANSFER_PUBLIC) { review_subtitle = "Public transfer"; } - else if (G_context.tx.transfer.type == TX_TRANSFER_PRIVATE) { + else if (G_context.tx.type == TX_ALEO_TRANSFER_PRIVATE) { review_subtitle = "Private transfer"; } - else if (G_context.tx.transfer.type == TX_TRANSFER_PUBLIC_TO_PRIVATE) { - review_subtitle = "Transfer from public to private address"; + else if (G_context.tx.type == TX_ALEO_TRANSFER_BATCH_PRIVATE) { + review_subtitle = "Private batch transfer"; } - else if (G_context.tx.transfer.type == TX_TRANSFER_PRIVATE_TO_PUBLIC) { + else if (G_context.tx.type == TX_ALEO_TRANSFER_PRIVATE_TO_PUBLIC) { review_subtitle = "Transfer from private to public address"; } + else if (G_context.tx.type == TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC) { + review_subtitle = "Batch transfer from public to private address"; + } + else if (G_context.tx.type == TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE) { + review_subtitle = "Transfer from public to private address"; + } else { - return io_send_sw(SWO_INCORRECT_DATA); + return -1; } // Format amount @@ -93,7 +99,7 @@ static int display_review_transaction(void) explicit_bzero(g_amount, sizeof(g_amount)); if (!format_fpu64( amount, sizeof(amount), G_context.tx.transfer.amount, EXPONENT_SMALLEST_UNIT)) { - return io_send_sw(SWO_INCORRECT_DATA); + return -1; } snprintf(g_amount, sizeof(g_amount), "%.*s ALEO", (int) strlen(amount), amount); @@ -101,7 +107,7 @@ static int display_review_transaction(void) + G_context.sign_transaction_datas.max_priority_fee; explicit_bzero(g_amount_2, sizeof(g_amount_2)); if (!format_fpu64(amount, sizeof(amount), total_fees, EXPONENT_SMALLEST_UNIT)) { - return io_send_sw(SWO_INCORRECT_DATA); + return -1; } snprintf(g_amount_2, sizeof(g_amount_2), "%.*s ALEO", (int) strlen(amount), amount); @@ -111,8 +117,13 @@ static int display_review_transaction(void) pair_index++; // To address - pairs[pair_index].item = "To"; - pairs[pair_index].value = G_context.tx.transfer.address_to; + pairs[pair_index].item = "To"; + if (strlen(G_context.tx.transfer.address_to) > 0) { + pairs[pair_index].value = G_context.tx.transfer.address_to; + } + else { + pairs[pair_index].value = G_context.account.address_str; + } pair_index++; // Fees @@ -150,17 +161,10 @@ static int display_review_transaction(void) // Flow used to display a clear-signed transaction int ui_display_transaction(void) { - if (memcmp(G_context.sign_transaction_datas.fee_program_id, - "credits.aleo", - G_context.sign_transaction_datas.fee_program_id_length)) { - // We currently don't support other token than ALEO - return -1; - } - - if (G_context.tx.type == TX_TRANSFER) { + if ((G_context.tx.type >= TX_TRANSFER_START) && (G_context.tx.type <= TX_ALEO_TRANSFER_END)) { return display_review_transaction(); } - else if (G_context.tx.type == TX_FEE) { + else if ((G_context.tx.type >= TX_FEE_START) && (G_context.tx.type <= TX_FEE_PRIVATE)) { validate_transaction(true); nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_menu_main); G_context.signing_state = SIGNING_STATE_WAIT_INTENT; diff --git a/tests/application_client/transaction.py b/tests/application_client/transaction.py index 9206057..30c2ce8 100644 --- a/tests/application_client/transaction.py +++ b/tests/application_client/transaction.py @@ -62,7 +62,7 @@ def forge_tlv(t: TlvTypes, v: str) -> str: elif t.value <= 255: val += f"81{t.value:02x}" else: - val += f"82{t.value:02x}" + val += f"82{t.value:04x}" # length length = len(v)//2 @@ -71,7 +71,7 @@ def forge_tlv(t: TlvTypes, v: str) -> str: elif length <= 255: val += f"81{length:02x}" else: - val += f"82{length:02x}" + val += f"82{length:04x}" # value val += v diff --git a/tests/standalone/snapshots/apex_p/test_app_mainmenu/00001.png b/tests/standalone/snapshots/apex_p/test_app_mainmenu/00001.png index dd90982..b7482a3 100644 Binary files a/tests/standalone/snapshots/apex_p/test_app_mainmenu/00001.png and b/tests/standalone/snapshots/apex_p/test_app_mainmenu/00001.png differ diff --git a/tests/standalone/snapshots/flex/test_app_mainmenu/00001.png b/tests/standalone/snapshots/flex/test_app_mainmenu/00001.png index 7b5ce0e..19d3b7d 100644 Binary files a/tests/standalone/snapshots/flex/test_app_mainmenu/00001.png and b/tests/standalone/snapshots/flex/test_app_mainmenu/00001.png differ diff --git a/tests/standalone/snapshots/nanosp/test_app_mainmenu/00002.png b/tests/standalone/snapshots/nanosp/test_app_mainmenu/00002.png index dc14192..68fffb2 100644 Binary files a/tests/standalone/snapshots/nanosp/test_app_mainmenu/00002.png and b/tests/standalone/snapshots/nanosp/test_app_mainmenu/00002.png differ diff --git a/tests/standalone/snapshots/nanox/test_app_mainmenu/00002.png b/tests/standalone/snapshots/nanox/test_app_mainmenu/00002.png index dc14192..68fffb2 100644 Binary files a/tests/standalone/snapshots/nanox/test_app_mainmenu/00002.png and b/tests/standalone/snapshots/nanox/test_app_mainmenu/00002.png differ diff --git a/tests/standalone/snapshots/stax/test_app_mainmenu/00001.png b/tests/standalone/snapshots/stax/test_app_mainmenu/00001.png index eee894e..0fa249e 100644 Binary files a/tests/standalone/snapshots/stax/test_app_mainmenu/00001.png and b/tests/standalone/snapshots/stax/test_app_mainmenu/00001.png differ diff --git a/tools/python/gen_apdu.py b/tools/python/gen_apdu.py deleted file mode 100644 index f258235..0000000 --- a/tools/python/gen_apdu.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env python3 - - -from crypto.codecs.bech32m import BECH32M -from crypto.bigint_256 import BigInteger256 -import argparse -import json -from enum import Enum -from itertools import islice - -class TlvTypes(Enum): - STRUCTURE_TYPE = 0x01 - VERSION = 0x02 - SIGNATURE = 0x15 - MAX_BASE_FEE = 0xb0 - MAX_PRIORITY_FEE = 0xb1 - FEE_FUNCTION_NAME = 0xb2 - FEE_PROGRAM_ID = 0xb3 - REQUEST = 0xb4 - NETWORK_ID = 0xc3 - PROGRAM_ID = 0xb5 - PROGRAM_CHECKSUM = 0xc4 - FUNCTION_NAME = 0xb6 - NESTED_CALL_COUNT = 0xba - INPUT_COUNT = 0xb7 - INPUT_TYPES = 0xb9 - INPUT_VALUES = 0xb8 - TVK = 0xbf - TPK = 0xc0 - GAMMAS_COUNT = 0xc1 - GAMMAS = 0xc2 - - -def get_tlv(t, v): - val = '' - # type - if t.value <= 127: - val += '{:02x}'.format(t.value) - elif t.value <= 255: - val += '81{:02x}'.format(t.value) - else: - val += '82{:04x}'.format(t.value) - - # length - length = len(v)//2 - if length <= 127: - val += '{:02x}'.format(length) - elif length <= 255: - val += '81{:02x}'.format(length) - else: - val += '82{:04x}'.format(length) - - # value - val += v - - return val - -def gen_chunks(lst, n): - it = iter(lst) - return iter(lambda: tuple(islice(it, n)), ()) - -def gen_apdu_array(cla, ins, p1, cmd): - batch_index = 0 - apdus = [] - for chunk in list(gen_chunks(cmd, 255*2)): - chunk = ''.join(chunk) - if batch_index == 0: - apdu = cla + ins + p1 + '00' - else: - apdu = cla + ins + p1 + '01' - apdu += '{:02x}'.format(len(chunk)//2) - apdu += chunk - apdus.append(apdu) - batch_index += 1 - return apdus - - -def get_literal_type_from_string(literal_type): - if literal_type == 'address': - return '00' - elif literal_type == 'boolean': - return '01' - elif literal_type == 'field': - return '02' - elif literal_type == 'group': - return '03' - elif literal_type == 'i8': - return '04' - elif literal_type == 'i16': - return '05' - elif literal_type == 'i32': - return '06' - elif literal_type == 'i64': - return '07' - elif literal_type == 'i128': - return '08' - elif literal_type == 'u8': - return '09' - elif literal_type == 'u16': - return '0a' - elif literal_type == 'u32': - return '0b' - elif literal_type == 'u64': - return '0c' - elif literal_type == 'u128': - return '0d' - elif literal_type == 'scalar': - return '0e' - elif literal_type == 'signature': - return '0f' - elif literal_type == 'string': - return '10' - return None - - -def get_plaintext_type_from_string(plaintext_type): - val = get_literal_type_from_string(plaintext_type) - if val: - return '00'+val - - return '01{:02x}{}'.format(len(plaintext_type), plaintext_type.encode("ascii").hex()) - - -def get_input_type_from_string(input_type): - val = '' - sp_input_type = input_type.split('.') - if sp_input_type[-1] == 'constant': - val += '00' + get_plaintext_type_from_string(sp_input_type[0]) - elif sp_input_type[-1] == 'public': - val += '01' + get_plaintext_type_from_string(sp_input_type[0]) - elif sp_input_type[-1] == 'private': - val += '02' + get_plaintext_type_from_string(sp_input_type[0]) - elif sp_input_type[-1] == 'record': - val += '03' + '{:02x}{}'.format(len(sp_input_type[0]), sp_input_type[0].encode("ascii").hex()) - - return val - - - -def generate_request_apdu(request, is_root, nested_call_count=0): - val = '' - # Structure type - val += get_tlv(TlvTypes.STRUCTURE_TYPE, '29') - # Version - val += get_tlv(TlvTypes.VERSION, '01') - # Network_id - if request['network_id'] == 'mainnet': - val += get_tlv(TlvTypes.NETWORK_ID, '0000') - else: - val += get_tlv(TlvTypes.NETWORK_ID, '0001') - # Program id - val += get_tlv(TlvTypes.PROGRAM_ID, '{}'.format(request['program_id'].encode().hex())) - # Function name - val += get_tlv(TlvTypes.FUNCTION_NAME, '{}'.format(request['function_name'].encode().hex())) - # Input count - val += get_tlv(TlvTypes.INPUT_COUNT, '{:02x}'.format(len(request['inputs']))) - # Input values & types - for input in request['inputs']: - val += get_tlv(TlvTypes.INPUT_TYPES, get_input_type_from_string(input['type'])) - input_val = '' - if 'address' in input['type']: - hrp = [] - data = [] - BECH32M.decode(hrp, data, [ord(n) for n in input['value']]) - res = [] - BECH32M.convert_bits(res, 8, data, 5, False) - for item in res: - input_val += '{:02x}'.format(item) - elif 'field' in input['type']: - value = int(input['value'].split('field')[0]) - big = BigInteger256(int(value)) - input_val += big.to_int().to_bytes(32, 'little').hex() - elif 'record' in input['type']: - for in_val in input['value']: - value = int(in_val.split('field')[0]) - big = BigInteger256(int(value)) - input_val += big.to_int().to_bytes(32, 'little').hex() - elif 'u64' in input['type']: - input_val += input['value'].to_bytes(8, 'little').hex() - else: - input_val += input['value'] - val += get_tlv(TlvTypes.INPUT_VALUES, input_val) - # Nested call count - if is_root: - val += get_tlv(TlvTypes.NESTED_CALL_COUNT, '{:02x}'.format(nested_call_count)) - - if len(request['program_checksum']): - val += get_tlv(TlvTypes.PROGRAM_CHECKSUM, request['program_checksum']) - - return val - - -def generate_root_apdu(cmd, nested_call_count): - - req = '' - # Structure type - req += get_tlv(TlvTypes.STRUCTURE_TYPE, '28') - # Version - req += get_tlv(TlvTypes.VERSION, '01') - # max_base_fee - req += get_tlv(TlvTypes.MAX_BASE_FEE, '{:08x}'.format(cmd['max_base_fee'])) - # max_priority_fee - req += get_tlv(TlvTypes.MAX_PRIORITY_FEE, '{:08x}'.format(cmd['max_priority_fee'])) - # fee_function_name - req += get_tlv(TlvTypes.FEE_FUNCTION_NAME, cmd['fee_function_name'].encode().hex()) - # fee_program_id - req += get_tlv(TlvTypes.FEE_PROGRAM_ID, cmd['fee_program_id'].encode().hex()) - # request - req += get_tlv(TlvTypes.REQUEST, generate_request_apdu(cmd['request'], 1, nested_call_count)) - - # Derivation path - req_start = '058000002c800002ab800000000000000000000000' - # Intent length - req_start += '{:04x}'.format(len(req)//2) - - apdus = gen_apdu_array('e0', '06', '00', req_start+req) - - return apdus - - -def generate_fee_apdu(cmd): - - req = '' - # request - req += generate_request_apdu(cmd['request'], 1, 0) - - # Request length - req_start = '{:04x}'.format(len(req)//2) - - apdus = gen_apdu_array('e0', '06', '02', req_start+req) - - return apdus - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser() - parser.add_argument("--file", help="json file", default=None) - args = parser.parse_args() - - if args.file == None: - exit(-1) - - json_file = open(args.file) - data = json.load(json_file) - cmds = data['cmds'] - - for cmd in cmds: - print(cmd) - if cmd['type'] == 'root': - apdu = generate_root_apdu(cmd, 0) - for item in apdu: - print('echo {} | python3 -m ledgerblue.runScript --apdu'.format(item)) - elif cmd['type'] == 'nested_call': - pass - elif cmd['type'] == 'fee': - apdu = generate_fee_apdu(cmd) - for item in apdu: - print('echo {} | python3 -m ledgerblue.runScript --apdu'.format(item)) - pass - - exit(0) diff --git a/tools/python/gen_function_id.py b/tools/python/gen_function_id.py deleted file mode 100644 index 61e0a16..0000000 --- a/tools/python/gen_function_id.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 - - -import argparse - -from algorithms.bhp import BHP_1024 - -if __name__ == "__main__": - - parser = argparse.ArgumentParser() - parser.add_argument('-n', '--network-id', help="Network id : mainnet or testnet", default="mainnet") - parser.add_argument("-p", "--program-id", help="Program ID (name.network)", default=None) - parser.add_argument("-f", "--function-name", help="Function name", default=None) - args = parser.parse_args() - - # Sanity checks - if args.program_id == None: - print("Program ID is missing") - exit(-1) - - sp_program_id = args.program_id.split('.') - if len(sp_program_id) != 2: - print("Program ID not well formatted : " + args.program_id) - exit(-1) - - if args.function_name == None: - print("Function name is missing") - exit(-1) - - if len(args.function_name) == 0: - print("Empty function name") - exit(-1) - - program_id_name = sp_program_id[0] - program_id_network = sp_program_id[1] - function_name = args.function_name - if args.network_id == "mainnet": - network_id = 0 - else: - network_id = 1 - - input = network_id.to_bytes(2, byteorder='little') - input += (len(program_id_name)*8).to_bytes(1, byteorder='little') - input += program_id_name.encode("utf-8") - input += (len(program_id_network)*8).to_bytes(1, byteorder='little') - input += program_id_network.encode("utf-8") - input += (len(function_name)*8).to_bytes(1, byteorder='little') - input += function_name.encode("utf-8") - - print('input len : ' + str(len(input))) - print('input: ' + ''.join('{:02x}'.format(x) for x in input)) - print(' else if ((offset == {:d})'.format(len(input))) - print(' && (!memcmp(bhp_buffer,') - print(' "'+ ''.join('\\x{:02x}'.format(x) for x in input) + '", offset))) {') - print(' // {:d}/{}.{}/{}'.format(network_id, program_id_name, program_id_network, function_name)) - input = (len(input)*8).to_bytes(8, byteorder='little')+input - bhp = BHP_1024() - digest = bhp.hash(input, len(input)*8) - - print(' hash->big.u64[0] = 0x{:016x};'.format(digest.value.value[0])) - print(' hash->big.u64[1] = 0x{:016x};'.format(digest.value.value[1])) - print(' hash->big.u64[2] = 0x{:016x};'.format(digest.value.value[2])) - print(' hash->big.u64[3] = 0x{:016x};'.format(digest.value.value[3])) - print(' return 0;') - print(' }') diff --git a/tools/python/gen_program_function.py b/tools/python/gen_program_function.py new file mode 100644 index 0000000..c288151 --- /dev/null +++ b/tools/python/gen_program_function.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +import json +import argparse + +from algorithms.bhp import BHP_1024 + +def add_c_header(c_file): + print('/*****************************************************************************', file=c_file) + print(' * Ledger App Aleo.', file=c_file) + print(' * (c) 2025 Ledger SAS.', file=c_file) + print(' *', file=c_file) + print(' * Licensed under the Apache License, Version 2.0 (the "License");', file=c_file) + print(' * you may not use this file except in compliance with the License.', file=c_file) + print(' * You may obtain a copy of the License at', file=c_file) + print(' *', file=c_file) + print(' * http://www.apache.org/licenses/LICENSE-2.0', file=c_file) + print(' *', file=c_file) + print(' * Unless required by applicable law or agreed to in writing, software', file=c_file) + print(' * distributed under the License is distributed on an "AS IS" BASIS,', file=c_file) + print(' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.', file=c_file) + print(' * See the License for the specific language governing permissions and', file=c_file) + print(' * limitations under the License.', file=c_file) + print(' *****************************************************************************/', file=c_file) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument("-f", "--file", help="json file", default=None) + args = parser.parse_args() + + # Sanity checks + if args.file == None: + exit(-1) + + json_file = open(args.file) + programs = json.load(json_file) + + h_file = open('db_program_function.h', 'w') + + print('#include // size_t', file=h_file) + print('', file=h_file) + print('#include "types.h"', file=h_file) + print('#include "field.h"', file=h_file) + print('', file=h_file) + + print('typedef enum {', file=h_file) + print(' NETWORK_ID_MAINNET = 0,', file=h_file) + print(' NETWORK_ID_TESTNET = 1,', file=h_file) + print(' NETWORK_ID_COUNT = 2,', file=h_file) + print('} network_id_e;', file=h_file) + print('', file=h_file) + + print('typedef struct {', file=h_file) + print(' const char *string;', file=h_file) + print(' tx_type_e tx_type;', file=h_file) + print(' uint8_t input_count;', file=h_file) + print(' field_t bhp_1024_hashes[NETWORK_ID_COUNT];', file=h_file) + print('} function_parameters_t;', file=h_file) + print('', file=h_file) + + print('typedef struct {', file=h_file) + print(' const char *program_id;', file=h_file) + print(' size_t nb_of_functions;', file=h_file) + print(' const function_parameters_t *functions;', file=h_file) + print('} program_parameter_t;', file=h_file) + print('', file=h_file) + + print('#define NB_OF_PROGRAMS ({:d})'.format(len(programs)), file=h_file) + print('extern const program_parameter_t program_parameters[NB_OF_PROGRAMS];', file=h_file) + #print('', file=h_file) + + h_file.close() + + c_file = open('db_program_function.c', 'w') + + add_c_header(c_file) + print('', file=c_file) + print('#include "db_program_function.h"', file=c_file) + print('', file=c_file) + + for program_id in programs.keys(): + print(program_id) + sp_program_id = program_id.split('.') + program_id_name = sp_program_id[0] + program_id_network = sp_program_id[1] + str_program_id = program_id_name + '_' + program_id_network + print('#define NB_OF_{}_FUNCTIONS ({:d})'.format(str_program_id.upper(), len(programs[program_id])), file=c_file) + print('const function_parameters_t {}[NB_OF_{}_FUNCTIONS] = {{'.format(str_program_id, str_program_id.upper()), file=c_file) + for item in programs[program_id]: + function_name = item['function'] + print(' ' + function_name) + print(' {{.string = "{}",'.format(function_name), file=c_file) + print(' .tx_type = {},'.format(item['tx_type']), file=c_file) + print(' .input_count = {:d},'.format(item['input_count']), file=c_file) + print(' .bhp_1024_hashes', file=c_file) + item['hashes'] = [] + for network_id in range(0, 2): + if network_id == 0: + print(' = {{.big.u64', file=c_file) + else: + print(' {.big.u64', file=c_file) + + input = network_id.to_bytes(2, byteorder='little') + input += (len(program_id_name)*8).to_bytes(1, byteorder='little') + input += program_id_name.encode("utf-8") + input += (len(program_id_network)*8).to_bytes(1, byteorder='little') + input += program_id_network.encode("utf-8") + input += (len(function_name)*8).to_bytes(1, byteorder='little') + input += function_name.encode("utf-8") + input = (len(input)*8).to_bytes(8, byteorder='little')+input + bhp = BHP_1024() + digest = bhp.hash(input, len(input)*8) + item['hashes'].append(digest) + + if network_id == 1: + print(' = {{0x{:016x}, 0x{:016x}, 0x{:016x}, 0x{:016x}}}}}}}}},'.format(digest.value.value[0], digest.value.value[1], digest.value.value[2], digest.value.value[3]), file=c_file) + else: + print(' = {{0x{:016x}, 0x{:016x}, 0x{:016x}, 0x{:016x}}}}},'.format(digest.value.value[0], digest.value.value[1], digest.value.value[2], digest.value.value[3]), file=c_file) + + print('};', file=c_file) + print('', file=c_file) + + print('const program_parameter_t program_parameters[NB_OF_PROGRAMS] = {', file=c_file) + max_len = 0 + for program_id in programs.keys(): + if len(program_id) > max_len: + max_len = len(program_id) + for program_id in programs.keys(): + str_program_id = program_id.replace('.', '_') + print(' {{.program_id = "{}",'.format(program_id), file=c_file) + print(' .nb_of_functions = NB_OF_{}_FUNCTIONS,'.format(str_program_id.upper()), file=c_file) + print(' .functions = {}{}}},'.format(str_program_id, ' '*(max_len-len(str_program_id))), file=c_file) + print('};', file=c_file) + c_file.close() diff --git a/tools/python/program_function.json b/tools/python/program_function.json new file mode 100644 index 0000000..9862643 --- /dev/null +++ b/tools/python/program_function.json @@ -0,0 +1,118 @@ +{ + "credits.aleo" : [ + {"function" : "transfer_public", + "tx_type" : "TX_ALEO_TRANSFER_PUBLIC", + "input_count" : 2}, + {"function" : "transfer_private", + "tx_type" : "TX_ALEO_TRANSFER_PRIVATE", + "input_count" : 3}, + {"function" : "transfer_private_to_public", + "tx_type" : "TX_ALEO_TRANSFER_PRIVATE_TO_PUBLIC", + "input_count" : 3}, + {"function" : "transfer_public_to_private", + "tx_type" : "TX_ALEO_TRANSFER_PUBLIC_TO_PRIVATE", + "input_count" : 2}, + {"function" : "fee_public", + "tx_type" : "TX_FEE_PUBLIC", + "input_count" : 3}, + {"function" : "fee_private", + "tx_type" : "TX_FEE_PRIVATE", + "input_count" : 4}, + {"function" : "split", + "tx_type" : "TX_UNKNOWN", + "input_count" : 2}, + {"function" : "join", + "tx_type" : "TX_UNKNOWN", + "input_count" : 2} + ], + "ldgbatcher_p28.aleo" : [ + {"function" : "transfer_private_2", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 4}, + {"function" : "transfer_private_3", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 5}, + {"function" : "transfer_private_4", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 6}, + {"function" : "transfer_private_5", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 7}, + {"function" : "transfer_private_6", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 8}, + {"function" : "transfer_private_7", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 9}, + {"function" : "transfer_private_8", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 10} + ], + "ldgbatcher_p910.aleo" : [ + {"function" : "transfer_private_9", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 11}, + {"function" : "transfer_private_10", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 12} + ], + "ldgbatcher_p1114.aleo" : [ + {"function" : "transfer_private_11", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 13}, + {"function" : "transfer_private_12", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 14}, + {"function" : "transfer_private_13", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 15}, + {"function" : "transfer_private_14", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE", + "input_count" : 16} + ], + "ldgbatcher_ppub_28.aleo" : [ + {"function" : "transfer_private_to_public_2", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 3}, + {"function" : "transfer_private_to_public_3", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 4}, + {"function" : "transfer_private_to_public_4", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 5}, + {"function" : "transfer_private_to_public_5", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 6}, + {"function" : "transfer_private_to_public_6", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 7}, + {"function" : "transfer_private_to_public_7", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 8}, + {"function" : "transfer_private_to_public_8", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 9} + ], + "ldgbatcher_ppub_910.aleo" : [ + {"function" : "transfer_private_to_public_9", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 10}, + {"function" : "transfer_private_to_public_10", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 11} + ], + "ldgbatcher_ppub_1114.aleo" : [ + {"function" : "transfer_private_to_public_11", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 12}, + {"function" : "transfer_private_to_public_12", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 13}, + {"function" : "transfer_private_to_public_13", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 14}, + {"function" : "transfer_private_to_public_14", + "tx_type" : "TX_ALEO_TRANSFER_BATCH_PRIVATE_TO_PUBLIC", + "input_count" : 15} + ] +} diff --git a/tools/python/test_apdu.py b/tools/python/test_apdu.py new file mode 100644 index 0000000..9a57ba3 --- /dev/null +++ b/tools/python/test_apdu.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import argparse +import json + +import sys + +from ledgerblue.comm import getDongle + +sys.path.append("../../") +from tests.application_client.transaction import Transaction + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument("--file", help="json file", default=None) + parser.add_argument("--dry-run", help="just print apdus", action='store_true') + args = parser.parse_args() + + if args.file == None: + exit(-1) + + json_file = open(args.file) + data = json.load(json_file) + cmds = data['cmds'] + + tx = Transaction() + + if args.dry_run == False: + dongle = getDongle(True) + + for cmd in cmds: + apdus = tx.gen_apdus_tx(cmd) + print('{} : {}.{}'.format(cmd['type'], cmd['request']['program_id'], cmd['request']['function_name'])) + for apdu in apdus: + if args.dry_run: + print('echo {} | python3 -m ledgerblue.runScript --apdu'.format(apdu)) + else: + result = dongle.exchange(bytes.fromhex(apdu)) + print() diff --git a/tools/python/test_batch.json b/tools/python/test_batch.json new file mode 100644 index 0000000..4897fd7 --- /dev/null +++ b/tools/python/test_batch.json @@ -0,0 +1,62 @@ +{ + "cmds" : [ + { + "type" : "intent", + "path" : "m/44'/683'/0'/0'", + "max_base_fee" : 0, + "max_priority_fee" : 0, + "fee_program_id" : "credits.aleo", + "fee_function_name" : "fee_public", + "request" : { + "network_id" : "mainnet", + "program_id" : "ldgbatcher_p28.aleo", + "function_name" : "transfer_private_2", + "inputs" : [ + {"type" : "credits.record", "value" : ["3614797564276936744957924747041031196891698846785520060979425601577054464500field", + "2426895214035216932245297778850989035038538961658726507442215877484415082794field", + "0220642863446832956019507279394572297489712696240584424406852292692897199577field"]}, + {"type" : "credits.record", "value" : ["3614797564276936744957924747041031196891698846785520060979425601577054464500field", + "2426895214035216932245297778850989035038538961658726507442215877484415082794field", + "0220642863446832956019507279394572297489712696240584424406852292692897199577field"]}, + {"type" : "address.private", "value" : "aleo1sfydt6z6cnqjx3hcgk9ajw03ecj6uqlfcm9u3p3gdhckzcc2w5xqv3v3pe"}, + {"type" : "u64.private", "value" : 1000} + ], + "program_checksum" : "", + "nested_call_count" : 2 + } + }, + { + "type" : "nested_call", + "request" : { + "network_id" : "mainnet", + "program_id" : "credits.aleo", + "function_name" : "join", + "inputs" : [ + {"type" : "credits.record", "value" : ["3614797564276936744957924747041031196891698846785520060979425601577054464500field", + "2426895214035216932245297778850989035038538961658726507442215877484415082794field", + "0220642863446832956019507279394572297489712696240584424406852292692897199577field"]}, + {"type" : "credits.record", "value" : ["3614797564276936744957924747041031196891698846785520060979425601577054464500field", + "2426895214035216932245297778850989035038538961658726507442215877484415082794field", + "0220642863446832956019507279394572297489712696240584424406852292692897199577field"]} + ], + "program_checksum" : "" + } + }, + { + "type" : "nested_call", + "request" : { + "network_id" : "mainnet", + "program_id" : "credits.aleo", + "function_name" : "transfer_private", + "inputs" : [ + {"type" : "credits.record", "value" : ["3614797564276936744957924747041031196891698846785520060979425601577054464500field", + "2426895214035216932245297778850989035038538961658726507442215877484415082794field", + "0220642863446832956019507279394572297489712696240584424406852292692897199577field"]}, + {"type" : "address.private", "value" : "aleo1sfydt6z6cnqjx3hcgk9ajw03ecj6uqlfcm9u3p3gdhckzcc2w5xqv3v3pe"}, + {"type" : "u64.private", "value" : 1000} + ], + "program_checksum" : "" + } + } + ] +} \ No newline at end of file diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index e01bf1b..10fbde2 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -87,6 +87,7 @@ include_directories(.) include_directories(../src) include_directories(../src/crypto) include_directories(../src/account) +include_directories(../src/db) include_directories(../src/helper) include_directories(../src/transaction) include_directories($ENV{BOLOS_SDK}/lib_standard_app) @@ -133,10 +134,10 @@ add_library(scalar SHARED ../src/crypto/scalar.c) add_library(group SHARED ../src/crypto/group.c) add_library(poseidon SHARED ../src/crypto/poseidon.c ../src/crypto/poseidon_parameters.c) add_library(bech32 SHARED ../src/crypto/bech32.c) -add_library(bhp_1024 SHARED ../src/crypto/bhp_1024.c ../src/crypto/bhp_1024_parameters.c) +add_library(bhp_1024 SHARED ../src/crypto/bhp_1024.c ../src/db/db_program_function.c) add_library(account SHARED ../src/account/account.c) add_library(signature SHARED ../src/account/signature.c) -add_library(transaction SHARED ../src/transaction/tx_extract.c ../src/transaction/tx_parse.c) +add_library(transaction SHARED ../src/transaction/tx_extract.c ../src/transaction/tx_parse.c ../src/db/db_program_function.c) add_library(send_response SHARED ../src/helper/send_response.c) # Common link set for tests that use TLV parsing diff --git a/unit-tests/test_bhp_1024.c b/unit-tests/test_bhp_1024.c index 4130540..b6a54a2 100644 --- a/unit-tests/test_bhp_1024.c +++ b/unit-tests/test_bhp_1024.c @@ -8,21 +8,23 @@ #include #include "os.h" +#include "types.h" #include "bhp_1024.h" typedef struct { - int status; - function_id_datas_t data; - field_t hash[2]; + int status; + prepared_request_t request; + field_t hash[2]; } bhp_test_t; static bhp_test_t bhp_tests[] = { { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "transfer_public"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "transfer_public", + .function_name_length = 15}, .hash = {{.big.u64 = {0x405245447621401a, 0x51c07b62a9c53d26, 0xb928e2f9112d0953, 0x0f511e31d6855446}}, @@ -30,11 +32,12 @@ static bhp_test_t bhp_tests[] = { = {0x1a45c36fff8ff4a4, 0x69712402399b89f1, 0xb3e921a03d522403, 0x0b8deb3e586ce4f4}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "transfer_private"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "transfer_private", + .function_name_length = 16}, .hash = {{.big.u64 = {0x57853955ec65e959, 0xc04dacceb1a2026a, 0x0b8c74f5b07ee388, 0x0913b0e1e8289dba}}, @@ -42,11 +45,12 @@ static bhp_test_t bhp_tests[] = { = {0x14050f83d8bc8ad5, 0x68c1128533fd9691, 0xb5bfd0497dcbe60d, 0x061bcb7383584d42}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "transfer_private_to_public"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "transfer_private_to_public", + .function_name_length = 26}, .hash = {{.big.u64 = {0x2ed6c22fde6f93b0, 0x7673e8d503d0995f, 0x6ec97fff81556086, 0x099abee7b8c03597}}, @@ -54,11 +58,12 @@ static bhp_test_t bhp_tests[] = { = {0x7c27587b57c5d2d4, 0x78e193e449543290, 0xf4e07ed6a53dea1e, 0x018801c51078171d}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "transfer_public_to_private"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "transfer_public_to_private", + .function_name_length = 26}, .hash = {{.big.u64 = {0x6e2c39b3c306d0f5, 0x1dc66c4befdfbc77, 0x0e2106ac3953c377, 0x0d3c811de289fd10}}, @@ -66,11 +71,12 @@ static bhp_test_t bhp_tests[] = { = {0x116b3d6259fc8332, 0x3b6f6a1a5b3344dd, 0x66c3bccc5ed9580b, 0x0b218600c10bd9a3}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "fee_public"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "fee_public", + .function_name_length = 10}, .hash = {{.big.u64 = {0xf9bcb7f7a577a934, 0x98f4346a10f70cf8, 0x8f26408e9addc51b, 0x0aa82c82d4ff15a4}}, @@ -78,11 +84,12 @@ static bhp_test_t bhp_tests[] = { = {0x8d31084295c605ef, 0xbfdc39996575504e, 0xae32c9cce746275e, 0x0bbfb3251558eee9}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "fee_private"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "fee_private", + .function_name_length = 11}, .hash = {{.big.u64 = {0xccf5dc9907364acc, 0x1cf2578ad1d69649, 0x95c4227bca877a48, 0x0c218239cc930255}}, @@ -90,25 +97,118 @@ static bhp_test_t bhp_tests[] = { = {0xc3c204d98b5e12b2, 0x318d93a9b12ba7c9, 0x9d42d8fb1c715281, 0x01505646987444fa}}}, }, { - .status = 0, - .data = {.network_id = 0, - .program_id_name = "credits", - .program_id_network = "aleo", - .function_name = "split"}, + .status = 0, + .request = {.network_id = 0, + .program_id = "credits.aleo", + .program_id_length = 12, + .function_name = "split", + .function_name_length = 5}, .hash = {{.big.u64 = {0x842cb43ec1d6bbe9, 0xa2c33251d4bded16, 0x0fe74f79fc7c63d4, 0x022fb51a7d2acc90}}, {.big.u64 = {0x0bb53e032f965178, 0x6cd697d8b5df7efc, 0x12e2736c492f2495, 0x0529c62123003bca}}}, }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_2", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0x711bd2f0fd3b8860, 0x2140898228c34911, 0x0aae5605d3b999fe, 0x0487b38e575e54a4}}, + {.big.u64 + = {0x94fe7832f23f69f8, 0x79ed7c0a94a507b8, 0x19375744cd4d66cf, 0x0a0d8242d888337b}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_3", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0xc52d556215ca8d42, 0xdd6855255a8999fc, 0x96a0067debdae976, 0x05457b2b07ff2258}}, + {.big.u64 + = {0xaa089e65aad01997, 0x3c449656a3f1cfb6, 0x034a6d7ada794cc6, 0x0e0823456dc1865e}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_4", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0x5a549bc57d7ed08e, 0x57081afbde550716, 0xfd460bb66b8552f7, 0x0d98770ff6216767}}, + {.big.u64 + = {0x6bcc11ae56749122, 0x260e2b57d5d5fbef, 0xce5371258b939c59, 0x0884f29ecd7a4f1f}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_5", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0x224995cd589d1640, 0x6373aaa70a095470, 0xdf9bc58530309041, 0x01f320b522e45a10}}, + {.big.u64 + = {0xfec2e5eb27e81ed1, 0x30342feb79e7b799, 0x895988e43a223100, 0x0d77f3954dc2bd3a}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_6", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0xbc81a96cea70096d, 0x8b056fb89161bad6, 0x63cacb85d316cadb, 0x0e3562712c147531}}, + {.big.u64 + = {0xdd5ec7c602f5a9db, 0xc846d46174e69814, 0xcb0457c70b198957, 0x1178e2cfd2c4f6de}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_7", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0x433f8bef1e650481, 0x10d600f6d41e3197, 0xe862611390273369, 0x0158dab93d6cbea6}}, + {.big.u64 + = {0x080a8386e49889ef, 0xb896be0d0173b849, 0x74fe7461b27002f1, 0x0002580b37e0e04f}}}, + }, + { + .status = 0, + .request = {.network_id = 0, + .program_id = "ldgbatcher_p28.aleo", + .program_id_length = 19, + .function_name = "transfer_private_8", + .function_name_length = 18}, + .hash + = {{.big.u64 + = {0x738c7d8d9546e4c7, 0xb3a42c93014c13b5, 0xa7bfbaa1fdbfaedf, 0x0cdd3604cfb57700}}, + {.big.u64 + = {0x963d210f3ca0a9c6, 0xdef5b86772cb88ae, 0xc937f1616d1cabbb, 0x0050e835094c6a46}}}, + }, // failure { - .status = -1, - .data = {.network_id = 0, - .program_id_name = "null", - .program_id_network = "null", - .function_name = "null"}, + .status = -1, + .request = {.network_id = 0, + .program_id = "null", + .program_id_length = 5, + .function_name = "null", + .function_name_length = 5}, }, // End @@ -127,21 +227,20 @@ static void test_bhp_1024(void **state) { (void) state; - field_t hash; - int index = 0; while (bhp_tests[index].status != -1111) { - bhp_tests[index].data.network_id = 0; - assert_int_equal(bhp_1024_hash_function_id(&bhp_tests[index].data, &hash), + print_message("index %d\n", index); + bhp_tests[index].request.network_id = 0; + assert_int_equal(bhp_1024_hash_function_id(&bhp_tests[index].request), bhp_tests[index].status); if (bhp_tests[index].status == 0) { - check_field(&hash, &bhp_tests[index].hash[0]); + check_field(&bhp_tests[index].request.function_id, &bhp_tests[index].hash[0]); } - bhp_tests[index].data.network_id = 1; - assert_int_equal(bhp_1024_hash_function_id(&bhp_tests[index].data, &hash), + bhp_tests[index].request.network_id = 1; + assert_int_equal(bhp_1024_hash_function_id(&bhp_tests[index].request), bhp_tests[index].status); if (bhp_tests[index].status == 0) { - check_field(&hash, &bhp_tests[index].hash[1]); + check_field(&bhp_tests[index].request.function_id, &bhp_tests[index].hash[1]); } index++; } diff --git a/unit-tests/test_signature.c b/unit-tests/test_signature.c index b91d028..04f7538 100644 --- a/unit-tests/test_signature.c +++ b/unit-tests/test_signature.c @@ -207,6 +207,23 @@ static void test_signature(void **state) .big.u64 = {0xa302f8c4e97b2cb7, 0xc41ec07b5815e53f, 0x168ca6d7bdc9365e, 0x3a6f4913f6a850c} }; + request.r_hint = NULL; + prepare_random_ok(random_bn); + prepare_scalar_mult_ok(); + prepare_scalar_mult_ok(); + assert_int_equal(sign_prepared_request(&account, &request), 0); + assert_int_equal(request.gammas_count, 0); + check_scalar(&request.r, &r_1); + check_field(&request.tvk, &tvk_1); + check_group(&request.tpk, &tpk_1); + check_field(&request.tcm, &tcm_1); + check_scalar(&request.challenge, &challenge_1); + check_scalar(&request.response, &response_1); + + uint8_t r_hint[32] + = "\x6c\xad\xd0\x1e\xbc\xbc\x7d\x81\x6b\x58\x60\x01\x54\x72\x94\xdc\xd5\x04\x09\x45\xbe\x9d" + "\xf2\x32\xcd\xc2\x53\x2d\xa2\x76\x8f\x00"; + request.r_hint = r_hint; prepare_random_ok(random_bn); prepare_scalar_mult_ok(); prepare_scalar_mult_ok(); @@ -226,6 +243,7 @@ static void test_signature(void **state) .big.u64 = {0x1821a9a8969fd50d, 0x25a0a26f70d168f0, 0x4cd4d6d76b60ce3e, 0x45f6663ec4bbcce} }; request.is_root = false; + request.r_hint = NULL; prepare_random_ok(random_bn); prepare_scalar_mult_ok(); prepare_scalar_mult_ok(); diff --git a/unit-tests/test_transaction.c b/unit-tests/test_transaction.c index b8ddc7f..e863a5d 100644 --- a/unit-tests/test_transaction.c +++ b/unit-tests/test_transaction.c @@ -93,9 +93,11 @@ static void test_tx_extract(void **state) tx_extract_prepared_request(&buffer, &G_context.sign_transaction_datas.prepared_request), -1); - uint8_t input_values[36] + uint8_t input_values[78] = "\x81\xb8\x01\x01\x81\xb8\x01\x02\x81\xb8\x01\x03\x81\xb8\x01\x04\x81\xb8\x01\x05\x81\xb8" - "\x01\x06\x81\xb8\x01\x07\x81\xb8\x01\x08\x81\xb8\x01\x09"; + "\x01\x06\x81\xb8\x01\x07\x81\xb8\x01\x08\x81\xb8\x01\x09\x81\xb8\x01\x0a\x81\xb8\x01\x0b" + "\x81\xb8\x01\x0c\x81\xb8\x01\x0d\x81\xb8\x01\x0e\x81\xb8\x01\x0f\x81\xb8\x01\x10\x81\xb8" + "\x01\x11"; buffer.ptr = input_values; buffer.size = sizeof(input_values); buffer.offset = 0; @@ -118,9 +120,11 @@ static void test_tx_extract(void **state) tx_extract_prepared_request(&buffer, &G_context.sign_transaction_datas.prepared_request), -1); - uint8_t input_types[36] + uint8_t input_types[78] = "\x81\xb9\x01\x01\x81\xb9\x01\x02\x81\xb9\x01\x03\x81\xb9\x01\x04\x81\xb9\x01\x05\x81\xb9" - "\x01\x06\x81\xb9\x01\x07\x81\xb9\x01\x08\x81\xb9\x01\x09"; + "\x01\x06\x81\xb9\x01\x07\x81\xb9\x01\x08\x81\xb9\x01\x09\x81\xb9\x01\x0a\x81\xb9\x01\x0b" + "\x81\xb9\x01\x0c\x81\xb9\x01\x0d\x81\xb9\x01\x0e\x81\xb9\x01\x0f\x81\xb9\x01\x10\x81\xb9" + "\x01\x11"; buffer.ptr = input_types; buffer.size = sizeof(input_types); buffer.offset = 0; @@ -147,6 +151,26 @@ static void test_tx_extract(void **state) assert_int_equal( tx_extract_prepared_request(&buffer, &G_context.sign_transaction_datas.prepared_request), -1); + + uint8_t r_hint[35] + = "\x81\xc5\x20\x01\x81\xb9\x01\x02\x81\xb9\x01\x03\x81\xb9\x01\x04\x81\xb9\x01\x05\x81\xb9" + "\x01\x06\x81\xb9\x01\x07\x81\xb9\x01\x08\x81\xb9\x01"; + buffer.ptr = r_hint; + buffer.size = sizeof(r_hint); + buffer.offset = 0; + assert_int_equal( + tx_extract_prepared_request(&buffer, &G_context.sign_transaction_datas.prepared_request), + 0); + + uint8_t r_hint_2[36] + = "\x81\xc5\x21\x01\x81\xb9\x01\x02\x81\xb9\x01\x03\x81\xb9\x01\x04\x81\xb9\x01\x05\x81\xb9" + "\x01\x06\x81\xb9\x01\x07\x81\xb9\x01\x08\x81\xb9\x01\x51"; + buffer.ptr = r_hint_2; + buffer.size = sizeof(r_hint_2); + buffer.offset = 0; + assert_int_equal( + tx_extract_prepared_request(&buffer, &G_context.sign_transaction_datas.prepared_request), + -1); } static void test_tx_parse(void **state)