From c780b4be9ffb558639197bbb9a349668acce4062 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 31 Oct 2024 09:07:47 +0100 Subject: [PATCH 01/17] Implement Trusted Name support: get challenge APDU --- src/globals.h | 3 ++- src/handle_get_challenge.c | 34 ++++++++++++++++++++++++++++++++++ src/handle_get_challenge.h | 10 ++++++++++ src/main.c | 8 ++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/handle_get_challenge.c create mode 100644 src/handle_get_challenge.h diff --git a/src/globals.h b/src/globals.h index ee138595..462dcd7a 100644 --- a/src/globals.h +++ b/src/globals.h @@ -49,7 +49,8 @@ typedef enum InstructionCode { InsGetAppConfiguration = 0x04, InsGetPubkey = 0x05, InsSignMessage = 0x06, - InsSignOffchainMessage = 0x07 + InsSignOffchainMessage = 0x07, + InsTrustedNameGetChallenge = 0x20, } InstructionCode; extern volatile bool G_called_from_swap; diff --git a/src/handle_get_challenge.c b/src/handle_get_challenge.c new file mode 100644 index 00000000..64020c71 --- /dev/null +++ b/src/handle_get_challenge.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "apdu.h" +#include "handle_get_challenge.h" + +static uint32_t challenge; + +/** + * Generate a new challenge from the Random Number Generator + */ +void roll_challenge(void) { + challenge = cx_rng_u32(); +} + +/** + * Get the current challenge + * + * @return challenge + */ +uint32_t get_challenge(void) { + return challenge; +} + +/** + * Send back the current challenge + */ +void handle_get_challenge(volatile unsigned int *tx) { + roll_challenge(); + PRINTF("New challenge -> %u\n", challenge); + U4BE_ENCODE(G_io_apdu_buffer, 0, challenge); + *tx += 4; + THROW(ApduReplySuccess); +} \ No newline at end of file diff --git a/src/handle_get_challenge.h b/src/handle_get_challenge.h new file mode 100644 index 00000000..4279d35b --- /dev/null +++ b/src/handle_get_challenge.h @@ -0,0 +1,10 @@ +#ifndef TRUSTED_NAME_CHALLENGE_H_ +#define TRUSTED_NAME_CHALLENGE_H_ + +#include + +void roll_challenge(void); +uint32_t get_challenge(void); +void handle_get_challenge(volatile unsigned int *tx); + +#endif // TRUSTED_NAME_CHALLENGE_H_ \ No newline at end of file diff --git a/src/main.c b/src/main.c index cdd3a13e..385febce 100644 --- a/src/main.c +++ b/src/main.c @@ -19,6 +19,7 @@ #include "handle_get_pubkey.h" #include "handle_sign_message.h" #include "handle_sign_offchain_message.h" +#include "handle_get_challenge.h" #include "apdu.h" #include "ui_api.h" @@ -87,6 +88,10 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) handle_sign_offchain_message(flags, tx); break; + case InsTrustedNameGetChallenge: + handle_get_challenge(tx); + break; + default: THROW(ApduReplyUnimplementedInstruction); } @@ -213,6 +218,9 @@ void coin_main(void) { BLE_power(1, NULL); #endif // HAVE_BLE + // to prevent it from having a fixed value at boot + roll_challenge(); + app_main(); } CATCH(ApduReplySdkExceptionIoReset) { From 6b4988b7f836467783e2ef358cd32002b664a637 Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 8 Nov 2024 18:20:21 +0100 Subject: [PATCH 02/17] TVL parsing and signature check OK + display token account owner --- Makefile | 8 +- libsol/spl_token_instruction.c | 5 + src/apdu.c | 43 +- src/apdu.h | 2 + src/globals.h | 3 +- src/handle_get_challenge.c | 2 +- src/handle_get_challenge.h | 6 +- src/handle_provide_trusted_info.c | 878 +++ src/handle_provide_trusted_info.h | 21 + src/ledger_pki.c | 77 + src/ledger_pki.h | 29 + src/main.c | 7 +- test_pki_certificate_flex.dat | 1 + test_pki_certificate_nanosp.dat | 3 + test_pki_certificate_nanox.dat | 1 + test_pki_certificate_stax.dat | 1 + test_tlv_apdu.dat | 1 + test_transfert.dat | 2 + tests/python/apps/keychain/trusted_name.pem | 8 + tests/python/apps/solana.py | 98 +- tests/python/apps/solana_keychain.py | 30 + tests/python/apps/solana_tlv.py | 42 + tests/python/requirements.txt | 1 + tests/python/test_solana.py | 23 + tools/rust/Cargo.lock | 5431 +++++++++++++++++++ tools/rust/Cargo.toml | 11 + tools/rust/src/main.rs | 180 + tools/rust/target/.rustc_info.json | 1 + tools/rust/target/CACHEDIR.TAG | 3 + 29 files changed, 6893 insertions(+), 25 deletions(-) create mode 100644 src/handle_provide_trusted_info.c create mode 100644 src/handle_provide_trusted_info.h create mode 100644 src/ledger_pki.c create mode 100644 src/ledger_pki.h create mode 100644 test_pki_certificate_flex.dat create mode 100644 test_pki_certificate_nanosp.dat create mode 100644 test_pki_certificate_nanox.dat create mode 100644 test_pki_certificate_stax.dat create mode 100644 test_tlv_apdu.dat create mode 100644 test_transfert.dat create mode 100644 tests/python/apps/keychain/trusted_name.pem create mode 100644 tests/python/apps/solana_keychain.py create mode 100644 tests/python/apps/solana_tlv.py create mode 100644 tools/rust/Cargo.lock create mode 100644 tools/rust/Cargo.toml create mode 100644 tools/rust/src/main.rs create mode 100644 tools/rust/target/.rustc_info.json create mode 100644 tools/rust/target/CACHEDIR.TAG diff --git a/Makefile b/Makefile index e7c99d0e..3f1c0975 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ VARIANT_PARAM = COIN VARIANT_VALUES = solana # Enabling DEBUG flag will enable PRINTF and disable optimizations -#DEBUG = 1 +DEBUG = 1 ######################################## # Application custom permissions # @@ -106,4 +106,10 @@ ifneq ($(WITH_LIBSOL),0) DEFINES += NDEBUG endif +# Trusted Name +TRUSTED_NAME_TEST_KEY ?= 0 +ifneq ($(TRUSTED_NAME_TEST_KEY),0) + DEFINES += HAVE_TRUSTED_NAME_TEST_KEY +endif + include $(BOLOS_SDK)/Makefile.standard_app diff --git a/libsol/spl_token_instruction.c b/libsol/spl_token_instruction.c index 7dae2df8..9772a9f7 100644 --- a/libsol/spl_token_instruction.c +++ b/libsol/spl_token_instruction.c @@ -484,6 +484,8 @@ static int print_spl_token_initialize_multisig_info(const char* primary_title, return 0; } +extern Pubkey g_trusted_token_account_owner_pubkey; + int print_spl_token_transfer_info(const SplTokenTransferInfo* info, const PrintConfig* print_config, bool primary) { @@ -502,6 +504,9 @@ int print_spl_token_transfer_info(const SplTokenTransferInfo* info, symbol, info->body.decimals); + item = transaction_summary_general_item(); + summary_item_set_pubkey(item, "To", &g_trusted_token_account_owner_pubkey); + item = transaction_summary_general_item(); summary_item_set_pubkey(item, "Token address", info->mint_account); diff --git a/src/apdu.c b/src/apdu.c index 3432b357..759c4eb6 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -1,5 +1,6 @@ #include "apdu.h" #include "utils.h" +#include "handle_provide_trusted_info.h" /** * Deserialize APDU into ApduCommand structure. @@ -65,7 +66,9 @@ int apdu_handle_message(const uint8_t* apdu_message, case InsGetAppConfiguration: case InsGetPubkey: case InsSignMessage: - case InsSignOffchainMessage: { + case InsSignOffchainMessage: + case InsTrustedInfoGetChallenge: + case InsTrustedInfoProvideInfo: { // must at least hold a full modern header if (apdu_message_len < OFFSET_CDATA) { return ApduReplySolanaInvalidMessageSize; @@ -99,7 +102,8 @@ int apdu_handle_message(const uint8_t* apdu_message, const bool first_data_chunk = !(header.p2 & P2_EXTEND); if (header.instruction == InsDeprecatedGetAppConfiguration || - header.instruction == InsGetAppConfiguration) { + header.instruction == InsGetAppConfiguration || + header.instruction == InsTrustedInfoGetChallenge) { // return early if no data is expected for the command explicit_bzero(apdu_command, sizeof(ApduCommand)); apdu_command->state = ApduStatePayloadComplete; @@ -122,12 +126,13 @@ int apdu_handle_message(const uint8_t* apdu_message, } else { explicit_bzero(apdu_command, sizeof(ApduCommand)); } - } else { + } + else { explicit_bzero(apdu_command, sizeof(ApduCommand)); } - // read derivation path - if (first_data_chunk) { + if ((first_data_chunk) && (header.instruction != InsTrustedInfoProvideInfo)) { + // read derivation path if (!header.deprecated_host && header.instruction != InsGetPubkey) { if (!header.data_length) { return ApduReplySolanaInvalidMessageSize; @@ -143,9 +148,9 @@ int apdu_handle_message(const uint8_t* apdu_message, apdu_command->num_derivation_paths = 1; } const int ret = read_derivation_path(header.data, - header.data_length, - apdu_command->derivation_path, - &apdu_command->derivation_path_length); + header.data_length, + apdu_command->derivation_path, + &apdu_command->derivation_path_length); if (ret) { return ret; } @@ -170,17 +175,23 @@ int apdu_handle_message(const uint8_t* apdu_message, if (header.data_length != data_len) { return ApduReplySolanaInvalidMessageSize; } - } - + } if (header.data) { - if (apdu_command->message_length + header.data_length > MAX_MESSAGE_LENGTH) { - return ApduReplySolanaInvalidMessageSize; + /*if (header.instruction == InsTrustedInfoProvideInfo) { + const int ret = handle_provide_trusted_info(first_data_chunk, header.data, header.data_length); + if (ret != 0) + return ApduReplySolanaInvalidTrustedInfo; } + else*/ { + if (apdu_command->message_length + header.data_length > MAX_MESSAGE_LENGTH) { + return ApduReplySolanaInvalidMessageSize; + } - memcpy(apdu_command->message + apdu_command->message_length, - header.data, - header.data_length); - apdu_command->message_length += header.data_length; + memcpy(apdu_command->message + apdu_command->message_length, + header.data, + header.data_length); + apdu_command->message_length += header.data_length; + } } else if (header.instruction != InsDeprecatedGetPubkey && header.instruction != InsGetPubkey) { return ApduReplySolanaInvalidMessageSize; } diff --git a/src/apdu.h b/src/apdu.h index 59e14ab3..ccf98615 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -47,6 +47,8 @@ typedef enum ApduReply { ApduReplySolanaSummaryFinalizeFailed = 0x6f00, ApduReplySolanaSummaryUpdateFailed = 0x6f01, + ApduReplySolanaInvalidTrustedInfo = 0x6c00, + ApduReplyUnimplementedInstruction = 0x6d00, ApduReplyInvalidCla = 0x6e00, diff --git a/src/globals.h b/src/globals.h index 462dcd7a..1bac3e34 100644 --- a/src/globals.h +++ b/src/globals.h @@ -50,7 +50,8 @@ typedef enum InstructionCode { InsGetPubkey = 0x05, InsSignMessage = 0x06, InsSignOffchainMessage = 0x07, - InsTrustedNameGetChallenge = 0x20, + InsTrustedInfoGetChallenge = 0x20, + InsTrustedInfoProvideInfo = 0x21, } InstructionCode; extern volatile bool G_called_from_swap; diff --git a/src/handle_get_challenge.c b/src/handle_get_challenge.c index 64020c71..00400e81 100644 --- a/src/handle_get_challenge.c +++ b/src/handle_get_challenge.c @@ -11,6 +11,7 @@ static uint32_t challenge; */ void roll_challenge(void) { challenge = cx_rng_u32(); + challenge = 0xdeadbeef; } /** @@ -26,7 +27,6 @@ uint32_t get_challenge(void) { * Send back the current challenge */ void handle_get_challenge(volatile unsigned int *tx) { - roll_challenge(); PRINTF("New challenge -> %u\n", challenge); U4BE_ENCODE(G_io_apdu_buffer, 0, challenge); *tx += 4; diff --git a/src/handle_get_challenge.h b/src/handle_get_challenge.h index 4279d35b..879cceaa 100644 --- a/src/handle_get_challenge.h +++ b/src/handle_get_challenge.h @@ -1,5 +1,5 @@ -#ifndef TRUSTED_NAME_CHALLENGE_H_ -#define TRUSTED_NAME_CHALLENGE_H_ +#ifndef TRUSTED_INFO_CHALLENGE_H_ +#define TRUSTED_INFO_CHALLENGE_H_ #include @@ -7,4 +7,4 @@ void roll_challenge(void); uint32_t get_challenge(void); void handle_get_challenge(volatile unsigned int *tx); -#endif // TRUSTED_NAME_CHALLENGE_H_ \ No newline at end of file +#endif // TRUSTED_INFO_CHALLENGE_H_ \ No newline at end of file diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c new file mode 100644 index 00000000..cca26962 --- /dev/null +++ b/src/handle_provide_trusted_info.c @@ -0,0 +1,878 @@ +#include +#include +#include +#include + +#include "globals.h" +#include "utils.h" +#include "handle_provide_trusted_info.h" +#include "handle_get_challenge.h" + +#include "sol/printer.h" + +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif + +#include "ledger_pki.h" + +#define STRUCT_TYPE_TRUSTED_NAME 0x03 +#define ALGO_SECP256K1 1 + +#define DER_LONG_FORM_FLAG 0x80 // 8th bit set +#define DER_FIRST_BYTE_VALUE_MASK 0x7f + +#define INT256_LENGTH 32 + +typedef enum { TLV_TAG, TLV_LENGTH, TLV_VALUE } e_tlv_step; + +// This enum needs to be ordered the same way as the e_tlv_tag one ! +typedef enum { + STRUCT_TYPE_RCV_BIT = 0, + STRUCT_VERSION_RCV_BIT, + TRUSTED_NAME_TYPE_RCV_BIT, + TRUSTED_NAME_SOURCE_RCV_BIT, + TRUSTED_NAME_RCV_BIT, + CHAIN_ID_RCV_BIT, + ADDRESS_RCV_BIT, + SOURCE_CONTRACT_RCV_BIT, + CHALLENGE_RCV_BIT, + SIGNER_KEY_ID_RCV_BIT, + SIGNER_ALGO_RCV_BIT, + SIGNATURE_RCV_BIT, +} e_tlv_rcv_bit; + +#define RCV_FLAG(a) (1 << a) + +/* +trusted_name_descriptor = tlv(TAG_STRUCTURE_TYPE, u8(TYPE_TRUSTED_NAME)) 3 bytes + + & tlv(TAG_VERSION, u8(0x02)) 3 bytes + + & tlv(TAG_TRUSTED_NAME_TYPE, 0x04) 3 bytes + + & tlv(TAG_TRUSTED_NAME_SOURCE, 0x06) 3 bytes + + & tlv(TAG_TRUSTED_NAME, trusted_name) 2 + 44 bytes + + & tlv(TAG_CHAIN_ID, chain_id) 2 + 8 bytes + + & tlv(TAG_ADDRESS, address) 2 + 44 bytes + + & tlv(TAG_SOURCE_CONTRACT, source_contract)* 2 + 44 bytes + + & tlv(TAG_CHALLENGE, challenge) 2 + 4 bytes + + & tlv(TAG_SIGNER_KEY_ID, key_id) 2 + 2 bytes + + & tlv(TAG_SIGNER_ALGORITHM, signature_algorithm) 2 + 1 byte + + & tlv(TAG_SIGNATURE, signature(~,~)) 2 + 72 bytes => Total = 247 bytes + +T L V +01 01 03 TAG_STRUCTURE_TYPE +02 01 02 TAG_VERSION +70 01 06 TAG_TRUSTED_NAME_TYPE +71 01 06 TAG_TRUSTED_NAME_SOURCE +20 20 276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9db TAG_TRUSTED_NAME +23 01 65 TAG_CHAIN_ID +22 20 606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b5 TAG_ADDRESS +73 20 c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61 TAG_SOURCE_CONTRACT +12 04 deadbeef TAG_CHALLENGE +13 01 03 TAG_SIGNER_KEY_ID +14 01 01 TAG_SIGNER_ALGORITHM +15 47 3045022100ac06a740744dac01b4b848ca2730c507e2a7a93f92952a0c9757bb12d8e6de490220262a529c8d809b9b2538bce34ecaa03b5c54f602656fd210f01c304a3da0b52e + + +01 01 03 +02 01 02 +70 01 06 +71 01 06 +20 20 276497BA0BB8659172B72EDD8C66E18F561764D9C86A610A3A7E0F79C0BAF9DB +23 01 65 +22 20 606501B302E1801892F80A2979F585F8855D0F2034790A2455F744FAC503D7B5 +73 20 C6FA7AF3BEDBAD3A3D65F36AABC97431B1BBE4C2D2F6E0E47CA60203452F5D61 +12 04 DEADBEEF +13 01 00 +14 01 01 +15 47 3045022100B559CD96CCCDA78CA393CE5D4A300E52177ABCC18F5E674FE9D4088322628ADD02200EAA84D21EE275DEC82F5D747ADAA408816AC03CC133BD722DC26016F7FA92CF + +*/ + +#define TLV_BUFFER_LENGTH 255 /* >= 247, APDU max payload */ +static uint8_t tlv_buffer[TLV_BUFFER_LENGTH] = {0}; + +typedef enum { + STRUCT_TYPE = 0x01, + STRUCT_VERSION = 0x02, + TRUSTED_NAME_TYPE = 0x70, + TRUSTED_NAME_SOURCE = 0x71, + TRUSTED_NAME = 0x20, + CHAIN_ID = 0x23, + ADDRESS = 0x22, + SOURCE_CONTRACT = 0x73, + CHALLENGE = 0x12, + SIGNER_KEY_ID = 0x13, + SIGNER_ALGO = 0x14, + SIGNATURE = 0x15, +} e_tlv_tag; + +typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id; + +typedef struct { + uint8_t *buf; + uint8_t size; + uint8_t expected_size; +} s_tlv_payload; + +typedef struct { + e_tlv_tag tag; + uint8_t length; + const uint8_t *value; +} s_tlv_data; + +typedef struct { + uint32_t rcv_flags; + bool valid; + uint8_t struct_version; + uint8_t token_account[MAX_ADDRESS_LENGTH]; + uint8_t* owner; + uint8_t spl_token[MAX_ADDRESS_LENGTH]; + uint64_t chain_id; + uint8_t name_type; + uint8_t name_source; +} s_trusted_name_info; + +typedef struct { + e_key_id key_id; + uint8_t input_sig_size; + const uint8_t *input_sig; + cx_sha256_t hash_ctx; +} s_sig_ctx; + +typedef bool(t_tlv_handler)(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx); + +typedef struct { + e_tlv_tag tag; + t_tlv_handler *func; + e_tlv_rcv_bit rcv_bit; +} s_tlv_handler; + +static s_tlv_payload g_tlv_payload = {0}; +static s_trusted_name_info g_trusted_name_info = {0}; + +Pubkey g_trusted_token_account_owner_pubkey = {0}; + +/** + * Checks if a trusted name matches the given parameters + * + * Does not care about the trusted name source for now. + * Always wipes the content of \ref g_trusted_name_info + * + * @param[in] types_count number of given trusted name types + * @param[in] types given trusted name types + * @param[in] chain_id given chain ID + * @param[in] addr given address + * @return whether there is or not + */ +bool has_trusted_name(uint8_t types_count, + const uint64_t *chain_id, + const uint8_t *addr) { + bool ret = false; + + (void) types_count; + (void) addr; + + if (g_trusted_name_info.rcv_flags != 0) { + switch (g_trusted_name_info.struct_version) { + case 2: + if (*chain_id == g_trusted_name_info.chain_id) { + ret = true; + } + break; + default: + ret = false; + } + explicit_bzero(&g_trusted_name_info, sizeof(g_trusted_name_info)); + } + return ret; +} + +/** + * Get uint from tlv data + * + * Get an unsigned integer from variable length tlv data (up to 4 bytes) + * + * @param[in] data tlv data + * @param[out] value the returned value + * @return whether it was successful + */ +static bool get_uint_from_data(const s_tlv_data *data, uint32_t *value) { + uint8_t size_diff; + uint8_t buffer[sizeof(uint32_t)]; + + if (data->length > sizeof(buffer)) { + PRINTF("Unexpectedly long value (%u bytes) for tag 0x%x\n", data->length, data->tag); + return false; + } + size_diff = sizeof(buffer) - data->length; + memset(buffer, 0, size_diff); + memcpy(buffer + size_diff, data->value, data->length); + *value = U4BE(buffer, 0); + return true; +} + +/** + * Handler for tag \ref STRUCT_TYPE + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_struct_type(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) trusted_name_info; + (void) sig_ctx; + if (!get_uint_from_data(data, &value)) { + return false; + } + return (value == STRUCT_TYPE_TRUSTED_NAME); +} + +/** + * Handler for tag \ref STRUCT_VERSION + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_struct_version(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) sig_ctx; + if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) { + return false; + } + trusted_name_info->struct_version = value; + return true; +} + +/** + * Handler for tag \ref CHALLENGE + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_challenge(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + (void) trusted_name_info; + (void) sig_ctx; + + if (!get_uint_from_data(data, &value)) { + return false; + } + return (value == get_challenge()); +} + +/** + * Handler for tag \ref SIGNER_KEY_ID + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_sign_key_id(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + (void) trusted_name_info; + + if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) { + return false; + } + sig_ctx->key_id = value; + return true; +} + +/** + * Handler for tag \ref SIGNER_ALGO + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_sign_algo(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) trusted_name_info; + (void) sig_ctx; + if (!get_uint_from_data(data, &value)) { + return false; + } + return (value == ALGO_SECP256K1); +} + +/** + * Handler for tag \ref SIGNATURE + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_signature(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + (void) trusted_name_info; + sig_ctx->input_sig_size = data->length; + sig_ctx->input_sig = data->value; + return true; +} + +/** + * Handler for tag \ref SOURCE_CONTRACT + * + * @param[in] data the tlv data + * @param[] trusted_name_info the trusted name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_source_contract(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + if (data->length > MAX_ADDRESS_LENGTH) { + PRINTF("SPL Token address too long! (%u)\n", data->length); + return false; + } + + memcpy(trusted_name_info->spl_token, data->value, data->length); + + trusted_name_info->spl_token[data->length] = '\0'; + return true; +} + +/** + * Tests if the given account name character is valid (in our subset of allowed characters) + * + * @param[in] c given character + * @return whether the character is valid + */ +/*static bool is_valid_account_character(char c) { + if (isalpha((int) c)) { + if (!islower((int) c)) { + return false; + } + } else if (!isdigit((int) c)) { + switch (c) { + case '.': + case '-': + case '_': + break; + default: + return false; + } + } + return true; +}*/ + +/** + * Handler for tag \ref TRUSTED_NAME + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_trusted_name(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + if (data->length > MAX_ADDRESS_LENGTH) { + PRINTF("Token Account address too long! (%u)\n", data->length); + return false; + } + + memcpy(trusted_name_info->token_account, data->value, data->length); + + trusted_name_info->token_account[data->length] = '\0'; + return true; +} + +/** + * Handler for tag \ref ADDRESS + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_address(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + if (data->length > MAX_ADDRESS_LENGTH) { + PRINTF("Address too long! (%u)\n", data->length); + return false; + } + memcpy(trusted_name_info->owner, data->value, data->length); + //trusted_name_info->owner[data->length] = '\0'; + return true; +} + +/** + * Handler for tag \ref CHAIN_ID + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_chain_id(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + bool res = false; + + switch (data->length) { + case 1: + { + trusted_name_info->chain_id = data->value[0]; + res = true; + break; + } + case 2: + { + trusted_name_info->chain_id = (data->value[0] << 8) | data->value[1]; + res = true; + break; + } + default: + PRINTF("Error while parsing chain ID: length = %d\n", data->length); + } + return res; +} + +/** + * Handler for tag \ref TRUSTED_NAME_TYPE + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_trusted_name_type(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) trusted_name_info; + (void) sig_ctx; + if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) { + return false; + } + + if (value != TYPE_ADDRESS) { + PRINTF("Error: unsupported trusted name type (%u)!\n", value); + return false; + } + trusted_name_info->name_type = value; + return true; +} + +/** + * Handler for tag \ref TRUSTED_NAME_SOURCE + * + * @param[in] data the tlv data + * @param[out] trusted_name_info the trusted name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_trusted_name_source(const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) trusted_name_info; + (void) sig_ctx; + if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) { + return false; + } + + if (value != TYPE_DYN_RESOLVER) { + PRINTF("Error: unsupported trusted name source (%u)!\n", value); + return false; + } + + trusted_name_info->name_source = value; + return true; +} + +/** + * Verify the signature context + * + * Verify the SHA-256 hash of the payload against the public key + * + * @param[in] sig_ctx the signature context + * @return whether it was successful + */ +static bool verify_signature(const s_sig_ctx *sig_ctx) { + uint8_t hash[INT256_LENGTH]; + cx_err_t error = CX_INTERNAL_ERROR; + +#ifdef HAVE_TRUSTED_NAME_TEST_KEY + e_key_id valid_key_id = KEY_ID_TEST; +#else + e_key_id valid_key_id = KEY_ID_PROD; +#endif + bool ret_code = false; + + if (sig_ctx->key_id != valid_key_id) { + PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); + return false; + } + + CX_CHECK( + cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); + + CX_CHECK(check_signature_with_pubkey("Trusted Name", + hash, + sizeof(hash), + TRUSTED_NAME_PUB_KEY, + sizeof(TRUSTED_NAME_PUB_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME, +#endif + (uint8_t *) (sig_ctx->input_sig), + sig_ctx->input_sig_size)); + + ret_code = true; +end: + return ret_code; +} + +/** + * Calls the proper handler for the given TLV data + * + * Checks if there is a proper handler function for the given TLV tag and then calls it + * + * @param[in] handlers list of tag / handler function pairs + * @param[in] handler_count number of handlers + * @param[in] data the TLV data + * @param[out] trusted_name_info the trusted name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_tlv_data(s_tlv_handler *handlers, + int handler_count, + const s_tlv_data *data, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + t_tlv_handler *fptr; + + // check if a handler exists for this tag + for (int idx = 0; idx < handler_count; ++idx) { + if (handlers[idx].tag == data->tag) { + trusted_name_info->rcv_flags |= RCV_FLAG(handlers[idx].rcv_bit); + fptr = PIC(handlers[idx].func); + if (!(*fptr)(data, trusted_name_info, sig_ctx)) { + PRINTF("Error while handling tag 0x%x\n", handlers[idx].tag); + return false; + } + break; + } + } + return true; +} + +/** + * Verify the validity of the received trusted struct + * + * @param[in] trusted_name_info the trusted name information + * @return whether the struct is valid + */ +static bool verify_struct(const s_trusted_name_info *trusted_name_info) { + uint32_t required_flags; + + + if (!(RCV_FLAG(STRUCT_VERSION_RCV_BIT) & trusted_name_info->rcv_flags)) { + PRINTF("Error: no struct version specified!\n"); + return false; + } + required_flags = RCV_FLAG(STRUCT_TYPE_RCV_BIT) | RCV_FLAG(STRUCT_VERSION_RCV_BIT) | + RCV_FLAG(TRUSTED_NAME_TYPE_RCV_BIT) | RCV_FLAG(TRUSTED_NAME_SOURCE_RCV_BIT) | + RCV_FLAG(TRUSTED_NAME_RCV_BIT) | RCV_FLAG(CHAIN_ID_RCV_BIT) | + RCV_FLAG(ADDRESS_RCV_BIT) | RCV_FLAG(SOURCE_CONTRACT_RCV_BIT) | + RCV_FLAG(CHALLENGE_RCV_BIT) | RCV_FLAG(SIGNER_KEY_ID_RCV_BIT) | + RCV_FLAG(SIGNER_ALGO_RCV_BIT) | RCV_FLAG(SIGNATURE_RCV_BIT); + + switch (trusted_name_info->struct_version) { + case 2: + if ((trusted_name_info->rcv_flags & required_flags) != required_flags) { + PRINTF("Error: missing required fields in struct version 2\n"); + return false; + } + switch (trusted_name_info->name_type) { + case TYPE_ADDRESS: + if (trusted_name_info->name_source != TYPE_DYN_RESOLVER) { + PRINTF("Error: unsupported trusted name source (%u)!\n", trusted_name_info->name_source); + return false; + } + break; + default: + PRINTF("Error: unsupported trusted name type (%u)!\n", trusted_name_info->name_type); + return false; + } + break; + default: + PRINTF("Error: unsupported trusted name struct version (%u) !\n", + trusted_name_info->struct_version); + return false; + } + return true; +} + +/** Parse DER-encoded value + * + * Parses a DER-encoded value (up to 4 bytes long) + * https://en.wikipedia.org/wiki/X.690 + * + * @param[in] payload the TLV payload + * @param[in,out] offset the payload offset + * @param[out] value the parsed value + * @return whether it was successful + */ +static bool parse_der_value(const s_tlv_payload *payload, size_t *offset, uint32_t *value) { + bool ret = false; + uint8_t byte_length; + uint8_t buf[sizeof(*value)]; + + if (value != NULL) { + if (payload->buf[*offset] & DER_LONG_FORM_FLAG) { // long form + byte_length = payload->buf[*offset] & DER_FIRST_BYTE_VALUE_MASK; + *offset += 1; + if ((*offset + byte_length) > payload->size) { + PRINTF("TLV payload too small for DER encoded value\n"); + } else { + if (byte_length > sizeof(buf) || byte_length == 0) { + PRINTF("Unexpectedly long DER-encoded value (%u bytes)\n", byte_length); + } else { + memset(buf, 0, (sizeof(buf) - byte_length)); + memcpy(buf + (sizeof(buf) - byte_length), &payload->buf[*offset], byte_length); + *value = U4BE(buf, 0); + *offset += byte_length; + ret = true; + } + } + } else { // short form + *value = payload->buf[*offset]; + *offset += 1; + ret = true; + } + } + return ret; +} + +/** + * Get DER-encoded value as an uint8 + * + * Parses the value and checks if it fits in the given \ref uint8_t value + * + * @param[in] payload the TLV payload + * @param[in,out] offset + * @param[out] value the parsed value + * @return whether it was successful + */ +static bool get_der_value_as_uint8(const s_tlv_payload *payload, size_t *offset, uint8_t *value) { + bool ret = false; + uint32_t tmp_value; + + if (value != NULL) { + if (!parse_der_value(payload, offset, &tmp_value)) { + } else { + if (tmp_value <= UINT8_MAX) { + *value = tmp_value; + ret = true; + } else { + PRINTF("TLV DER-encoded value larger than 8 bits\n"); + } + } + } + return ret; +} + +/** + * Parse the TLV payload + * + * Does the TLV parsing but also the SHA-256 hash of the payload. + * + * @param[in] payload the raw TLV payload + * @param[out] trusted_name_info the trusted name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool parse_tlv(const s_tlv_payload *payload, + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { + s_tlv_handler handlers[] = { + {.tag = STRUCT_TYPE, .func = &handle_struct_type}, + {.tag = STRUCT_VERSION, .func = &handle_struct_version}, + {.tag = TRUSTED_NAME_TYPE, .func = &handle_trusted_name_type}, + {.tag = TRUSTED_NAME_SOURCE, .func = &handle_trusted_name_source}, + {.tag = TRUSTED_NAME, .func = &handle_trusted_name}, + {.tag = CHAIN_ID, .func = &handle_chain_id}, + {.tag = ADDRESS, .func = &handle_address}, + {.tag = SOURCE_CONTRACT, .func = &handle_source_contract}, + {.tag = CHALLENGE, .func = &handle_challenge}, + {.tag = SIGNER_KEY_ID, .func = &handle_sign_key_id}, + {.tag = SIGNER_ALGO, .func = &handle_sign_algo}, + {.tag = SIGNATURE, .func = &handle_signature}, + }; + e_tlv_step step = TLV_TAG; + s_tlv_data data; + size_t offset = 0; + size_t tag_start_off; + + for (size_t i = 0; i < ARRAYLEN(handlers); ++i) handlers[i].rcv_bit = i; + cx_sha256_init(&sig_ctx->hash_ctx); + // handle TLV payload + while (offset < payload->size) { + switch (step) { + case TLV_TAG: + tag_start_off = offset; + if (!get_der_value_as_uint8(payload, &offset, &data.tag)) { + return false; + } + step = TLV_LENGTH; + break; + + case TLV_LENGTH: + if (!get_der_value_as_uint8(payload, &offset, &data.length)) { + return false; + } + step = TLV_VALUE; + break; + + case TLV_VALUE: + if ((offset + data.length) > payload->size) { + PRINTF("Error: value would go beyond the TLV payload!\n"); + return false; + } + data.value = &payload->buf[offset]; + if (!handle_tlv_data(handlers, + (sizeof(handlers)/sizeof(handlers[0])), + &data, + trusted_name_info, + sig_ctx)) { + return false; + } + offset += data.length; + if (data.tag != SIGNATURE) { // the signature wasn't computed on itself + CX_ASSERT(cx_hash_no_throw( + (cx_hash_t *) &sig_ctx->hash_ctx, + 0, + &payload->buf[tag_start_off], + (offset - tag_start_off), NULL, 0)); + } + step = TLV_TAG; + break; + + default: + return false; + } + } + if (step != TLV_TAG) { + PRINTF("Error: unexpected data at the end of the TLV payload!\n"); + return false; + } + return verify_struct(trusted_name_info); +} + +/** + * Deallocate and unassign TLV payload + * + * @param[in] payload payload structure + */ +static void free_payload(s_tlv_payload *payload) { + memset(tlv_buffer, 0, sizeof(tlv_buffer)); + memset(payload, 0, sizeof(*payload)); +} + +static bool init_tlv_payload(uint8_t length, s_tlv_payload *payload) { + + // check if no payload is already in memory + if (payload->buf != NULL) { + free_payload(payload); + return false; + } + + payload->buf = tlv_buffer; + payload->expected_size = length; + + return true; +} + +/** + * Handle provide trusted info APDU + * + * @param[in] is_first_chunk first APDU instruction parameter + * @param[in] data APDU payload + * @param[in] length payload size + */ +void handle_provide_trusted_info(void) { + s_sig_ctx sig_ctx; + + uint8_t *data = G_command.message; + uint8_t data_length = G_command.message_length; + + PRINTF("Received chunk of trusted info, length = %d\n", data_length); + if (!init_tlv_payload(data_length, &g_tlv_payload)) { + free_payload(&g_tlv_payload); + PRINTF("Error while initializing TLV payload\n"); + THROW(ApduReplySolanaInvalidTrustedInfo); + } + + PRINTF("Expected size of trusted info: %d\n", g_tlv_payload.expected_size); + + if ((g_tlv_payload.size + data_length) > g_tlv_payload.expected_size) { + free_payload(&g_tlv_payload); + PRINTF("TLV payload size mismatch!\n"); + THROW(ApduReplySolanaInvalidTrustedInfo); + } + // feed into tlv payload + memcpy(g_tlv_payload.buf + g_tlv_payload.size, data, data_length); + g_tlv_payload.size += data_length; + + PRINTF("Received %d bytes of trusted info\n", g_tlv_payload.size); + + // everything has been received + if (g_tlv_payload.size == g_tlv_payload.expected_size) { + g_trusted_name_info.owner = g_trusted_token_account_owner_pubkey.data; + if (!parse_tlv(&g_tlv_payload, &g_trusted_name_info, &sig_ctx) || + !verify_signature(&sig_ctx)) { + free_payload(&g_tlv_payload); + roll_challenge(); // prevent brute-force guesses + g_trusted_name_info.rcv_flags = 0; + THROW(ApduReplySolanaInvalidTrustedInfo); + } + { + char token_account[45]; + char owner[45]; + + encode_base58(g_trusted_name_info.owner, 32, owner, sizeof(owner)); + encode_base58(g_trusted_name_info.token_account, 32, token_account, sizeof(token_account)); + + PRINTF("Token account : %s owned by %s\n", token_account,owner); + } + free_payload(&g_tlv_payload); + roll_challenge(); // prevent replays + THROW(ApduReplySuccess); + } + THROW(ApduReplySolanaInvalidTrustedInfo); +} \ No newline at end of file diff --git a/src/handle_provide_trusted_info.h b/src/handle_provide_trusted_info.h new file mode 100644 index 00000000..fab466fc --- /dev/null +++ b/src/handle_provide_trusted_info.h @@ -0,0 +1,21 @@ +#ifndef TRUSTED_INFO_H_ +#define TRUSTED_INFO_H_ + +#include +#include + +#include "sol/parser.h" + +#define MAX_ADDRESS_LENGTH 32 + +#define TYPE_ADDRESS 0x06 +#define TYPE_DYN_RESOLVER 0x06 + +bool has_trusted_info(uint8_t types_count, + const uint64_t *chain_id, + const uint8_t *addr); +void handle_provide_trusted_info(void); + +extern Pubkey g_trusted_token_account_owner_pubkey; + +#endif // TRUSTED_INFO_H_ \ No newline at end of file diff --git a/src/ledger_pki.c b/src/ledger_pki.c new file mode 100644 index 00000000..b5fe2b04 --- /dev/null +++ b/src/ledger_pki.c @@ -0,0 +1,77 @@ +#include "apdu.h" +#include "ledger_pki.h" +#include "cx.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif + +#define KEY_USAGE_STR(x) \ + (x == CERTIFICATE_PUBLIC_KEY_USAGE_GENUINE_CHECK ? "GENUINE_CHECK" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_EXCHANGE_PAYLOAD ? "EXCHANGE_PAYLOAD" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA ? "NFT_METADATA" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME ? "TRUSTED_NAME" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_BACKUP_PROVIDER ? "BACKUP_PROVIDER" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_RECOVER_ORCHESTRATOR ? "RECOVER_ORCHESTRATOR" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA ? "PLUGIN_METADATA" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META ? "COIN_META" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_SEED_ID_AUTH ? "SEED_ID_AUTH" \ + : "Unknown") + +int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t *PubKey, + const uint8_t keyLen, +#ifdef HAVE_LEDGER_PKI + const uint8_t keyUsageExp, +#endif + uint8_t *signature, + const uint8_t sigLen) { + UNUSED(tag); + cx_ecfp_public_key_t verif_key = {0}; + cx_err_t error = CX_INTERNAL_ERROR; +#ifdef HAVE_LEDGER_PKI + uint8_t key_usage = 0; + size_t trusted_name_len = 0; + uint8_t trusted_name[CERTIFICATE_TRUSTED_NAME_MAXLEN] = {0}; + cx_ecfp_384_public_key_t public_key = {0}; +#endif + + PRINTF( + "[%s] " + "=======================================================================================\n", + tag); +#ifdef HAVE_LEDGER_PKI + error = os_pki_get_info(&key_usage, trusted_name, &trusted_name_len, &public_key); + if ((error == 0) && (key_usage == keyUsageExp)) { + PRINTF("[%s] Certificate '%s' loaded for usage 0x%x (%s)\n", + tag, + trusted_name, + key_usage, + KEY_USAGE_STR(key_usage)); + + // Checking the signature with PKI + if (!os_pki_verify(buffer, bufLen, signature, sigLen)) { + PRINTF("%s: Invalid signature\n", tag); +#ifndef HAVE_BYPASS_SIGNATURES + error = ApduReplySolanaInvalidTrustedInfo; + goto end; +#endif + } + } else +#endif + { + PRINTF("[%s] ********** No certificate loaded. Using legacy path **********\n", tag); + CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, PubKey, keyLen, &verif_key)); + if (!cx_ecdsa_verify_no_throw(&verif_key, buffer, bufLen, signature, sigLen)) { + PRINTF("%s: Invalid signature\n", tag); +#ifndef HAVE_BYPASS_SIGNATURES + error = ApduReplySolanaInvalidTrustedInfo; + goto end; +#endif + } + } + error = CX_OK; +end: + return error; +} \ No newline at end of file diff --git a/src/ledger_pki.h b/src/ledger_pki.h new file mode 100644 index 00000000..a2a13aaa --- /dev/null +++ b/src/ledger_pki.h @@ -0,0 +1,29 @@ +#pragma once +#include + +static const uint8_t TRUSTED_NAME_PUB_KEY[] = { +#ifdef HAVE_TRUSTED_NAME_TEST_KEY + 0x04, 0xb9, 0x1f, 0xbe, 0xc1, 0x73, 0xe3, 0xba, 0x4a, 0x71, 0x4e, 0x01, 0x4e, 0xbc, + 0x82, 0x7b, 0x6f, 0x89, 0x9a, 0x9f, 0xa7, 0xf4, 0xac, 0x76, 0x9c, 0xde, 0x28, 0x43, + 0x17, 0xa0, 0x0f, 0x4f, 0x65, 0x0f, 0x09, 0xf0, 0x9a, 0xa4, 0xff, 0x5a, 0x31, 0x76, + 0x02, 0x55, 0xfe, 0x5d, 0xfc, 0x81, 0x13, 0x29, 0xb3, 0xb5, 0x0b, 0xe9, 0x91, 0x94, + 0xfc, 0xa1, 0x16, 0x19, 0xe6, 0x5f, 0x2e, 0xdf, 0xea +#else + 0x04, 0x6a, 0x94, 0xe7, 0xa4, 0x2c, 0xd0, 0xc3, 0x3f, 0xdf, 0x44, 0x0c, 0x8e, 0x2a, + 0xb2, 0x54, 0x2c, 0xef, 0xbe, 0x5d, 0xb7, 0xaa, 0x0b, 0x93, 0xa9, 0xfc, 0x81, 0x4b, + 0x9a, 0xcf, 0xa7, 0x5e, 0xb4, 0xe5, 0x3d, 0x6f, 0x00, 0x25, 0x94, 0xbd, 0xb6, 0x05, + 0xd9, 0xb5, 0xbd, 0xa9, 0xfa, 0x4b, 0x4b, 0xf3, 0xa5, 0x49, 0x6f, 0xd3, 0x16, 0x4b, + 0xae, 0xf5, 0xaf, 0xcf, 0x90, 0xe8, 0x40, 0x88, 0x71 +#endif +}; + +extern int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t *PubKey, + const uint8_t keyLen, +#ifdef HAVE_LEDGER_PKI + const uint8_t keyUsageExp, +#endif + uint8_t *signature, + const uint8_t sigLen); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 385febce..9f9d92e8 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ #include "handle_sign_message.h" #include "handle_sign_offchain_message.h" #include "handle_get_challenge.h" +#include "handle_provide_trusted_info.h" #include "apdu.h" #include "ui_api.h" @@ -88,9 +89,13 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) handle_sign_offchain_message(flags, tx); break; - case InsTrustedNameGetChallenge: + case InsTrustedInfoGetChallenge: handle_get_challenge(tx); break; + + case InsTrustedInfoProvideInfo: + handle_provide_trusted_info(); + THROW(ApduReplySuccess); default: THROW(ApduReplyUnimplementedInstruction); diff --git a/test_pki_certificate_flex.dat b/test_pki_certificate_flex.dat new file mode 100644 index 00000000..9956b956 --- /dev/null +++ b/test_pki_certificate_flex.dat @@ -0,0 +1 @@ +B0060400A601010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100A35942AD66FEBD1899C52BB3EE3A5CB3802C4C2BE6C6521EB590D32ADC152E380220210F7BAB9A62501134D513CFD127A72BA1EB0D9F956E3EC7E553BF460F505810 \ No newline at end of file diff --git a/test_pki_certificate_nanosp.dat b/test_pki_certificate_nanosp.dat new file mode 100644 index 00000000..dceb931e --- /dev/null +++ b/test_pki_certificate_nanosp.dat @@ -0,0 +1,3 @@ +B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350103154630440220328886305590C895D119105849A87835BF531B26E646B815E0E8A5528DF480950220155747BAF14A26870B09622330F24DD120EB1AE1662C4A734E73C20395892F48 + + diff --git a/test_pki_certificate_nanox.dat b/test_pki_certificate_nanox.dat new file mode 100644 index 00000000..7b6b6da7 --- /dev/null +++ b/test_pki_certificate_nanox.dat @@ -0,0 +1 @@ +B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010215463044022034B002268EA97826A44E2704514CB0F8B70353DE4D465F50116A5CB3131E3C1E02202387F059A6F701361A960DB61D5749F25EE390C505A09DD4CBD868A1C4042A1C \ No newline at end of file diff --git a/test_pki_certificate_stax.dat b/test_pki_certificate_stax.dat new file mode 100644 index 00000000..67dcfb57 --- /dev/null +++ b/test_pki_certificate_stax.dat @@ -0,0 +1 @@ +B0060400A601010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221009DCD14004A1C6F8A6A56F91FD253865F255E83FD316CB3E6B9AF585B12FBD78A02206DFA969336E82C93C1F2EF863CFAC19F88ECE1F38C900791FFFD46B9C9E02279 \ No newline at end of file diff --git a/test_tlv_apdu.dat b/test_tlv_apdu.dat new file mode 100644 index 00000000..ba676a2f --- /dev/null +++ b/test_tlv_apdu.dat @@ -0,0 +1 @@ +e0210000CA0101030201027001067101062020276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9db2301652220606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b57320c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d611204deadbeef13010314010115473045022100ac06a740744dac01b4b848ca2730c507e2a7a93f92952a0c9757bb12d8e6de490220262a529c8d809b9b2538bce34ecaa03b5c54f602656fd210f01c304a3da0b52e diff --git a/test_transfert.dat b/test_transfert.dat new file mode 100644 index 00000000..b6241bb5 --- /dev/null +++ b/test_transfert.dat @@ -0,0 +1,2 @@ +e00500000d038000002c800001f580003039 +e0060100a401038000002c800001f5800030390200010321a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7940268ac4c37ea0bc96c9c40ef33ace07a3034d650c43737fea9568b8c91da540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020200010c0200000080c3db7b00000000 diff --git a/tests/python/apps/keychain/trusted_name.pem b/tests/python/apps/keychain/trusted_name.pem new file mode 100644 index 00000000..9c0384b3 --- /dev/null +++ b/tests/python/apps/keychain/trusted_name.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIHfwyko1dEHTTQ7es7EUy2ajZo1IRRcEC8/9b+MDOzUaoAcGBSuBBAAK +oUQDQgAEuR++wXPjukpxTgFOvIJ7b4man6f0rHac3ihDF6APT2UPCfCapP9aMXYC +Vf5d/IETKbO1C+mRlPyhFhnmXy7f6g== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/tests/python/apps/solana.py b/tests/python/apps/solana.py index 19e09420..506595ca 100644 --- a/tests/python/apps/solana.py +++ b/tests/python/apps/solana.py @@ -1,9 +1,13 @@ -from typing import List, Generator +from typing import List, Generator, Optional from enum import IntEnum from contextlib import contextmanager from ragger.backend.interface import BackendInterface, RAPDU +from ragger.firmware import Firmware +from ragger.error import ExceptionRAPDU +from .solana_tlv import FieldTag, format_tlv +from .solana_keychain import Key, sign_data class INS(IntEnum): # DEPRECATED - Use non "16" suffixed variants below @@ -15,6 +19,8 @@ class INS(IntEnum): INS_GET_PUBKEY = 0x05 INS_SIGN_MESSAGE = 0x06 INS_SIGN_OFFCHAIN_MESSAGE = 0x07 + INS_GET_CHALLENGE = 0x20 + INS_TRUSTED_INFO = 0x21 CLA = 0xE0 @@ -69,13 +75,101 @@ def _extend_and_serialize_multiple_derivations_paths(derivations_paths: List[byt serialized += derivations_path return serialized +class StatusWord(IntEnum): + OK = 0x9000 + ERROR_NO_INFO = 0x6a00 + INVALID_DATA = 0x6a80 + INSUFFICIENT_MEMORY = 0x6a84 + INVALID_INS = 0x6d00 + INVALID_P1_P2 = 0x6b00 + CONDITION_NOT_SATISFIED = 0x6985 + REF_DATA_NOT_FOUND = 0x6a88 + EXCEPTION_OVERFLOW = 0x6807 + NOT_IMPLEMENTED = 0x911c + +class PKIClient: + _CLA: int = 0xB0 + _INS: int = 0x06 + + def __init__(self, client: BackendInterface) -> None: + self._client = client + + def send_certificate(self, payload: bytes) -> RAPDU: + try: + response = self.send_raw(payload) + assert response.status == StatusWord.OK + except ExceptionRAPDU as err: + if err.status == StatusWord.NOT_IMPLEMENTED: + print("Ledger-PKI APDU not yet implemented. Legacy path will be used") + + def send_raw(self, payload: bytes) -> RAPDU: + header = bytearray() + header.append(self._CLA) + header.append(self._INS) + header.append(0x04) # PubKeyUsage = 0x04 + header.append(0x00) + header.append(len(payload)) + return self._client.exchange_raw(header + payload) + class SolanaClient: client: BackendInterface def __init__(self, client: BackendInterface): self._client = client - + self._pki_client: Optional[PKIClient] = None + if self._client.firmware != Firmware.NANOS: + # LedgerPKI not supported on Nanos + self._pki_client = PKIClient(self._client) + + def provide_trusted_name(self, + source_contract: bytes, + trusted_name: bytes, + address: bytes, + chain_id: int, + challenge: Optional[int] = None): + + payload = format_tlv(FieldTag.TAG_STRUCTURE_TYPE, 3) + payload += format_tlv(FieldTag.TAG_VERSION, 2) + payload += format_tlv(FieldTag.TAG_TRUSTED_NAME_TYPE, 0x06) + payload += format_tlv(FieldTag.TAG_TRUSTED_NAME_SOURCE, 0x06) + payload += format_tlv(FieldTag.TAG_TRUSTED_NAME, trusted_name) + payload += format_tlv(FieldTag.TAG_CHAIN_ID, chain_id) + payload += format_tlv(FieldTag.TAG_ADDRESS, address) + payload += format_tlv(FieldTag.TAG_TRUSTED_NAME_SOURCE_CONTRACT, source_contract) + if challenge is not None: + payload += format_tlv(FieldTag.TAG_CHALLENGE, challenge) + payload += format_tlv(FieldTag.TAG_SIGNER_KEY_ID, 0) # test key + payload += format_tlv(FieldTag.TAG_SIGNER_ALGO, 1) # secp256k1 + payload += format_tlv(FieldTag.TAG_DER_SIGNATURE, + sign_data(Key.TRUSTED_NAME, payload)) + + # send PKI certificate + if self._pki_client is None: + print(f"Ledger-PKI Not supported on '{self._client.firmware.name}'") + else: + # pylint: disable=line-too-long + if self._client.firmware == Firmware.NANOSP: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350103154630440220328886305590C895D119105849A87835BF531B26E646B815E0E8A5528DF480950220155747BAF14A26870B09622330F24DD120EB1AE1662C4A734E73C20395892F48" # noqa: E501 + elif self._client.firmware == Firmware.NANOX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010215463044022034B002268EA97826A44E2704514CB0F8B70353DE4D465F50116A5CB3131E3C1E02202387F059A6F701361A960DB61D5749F25EE390C505A09DD4CBD868A1C4042A1C" # noqa: E501 + elif self._client.firmware == Firmware.STAX: + cert_apdu = "01010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221009DCD14004A1C6F8A6A56F91FD253865F255E83FD316CB3E6B9AF585B12FBD78A02206DFA969336E82C93C1F2EF863CFAC19F88ECE1F38C900791FFFD46B9C9E02279" # noqa: E501 + elif self._client.firmware == Firmware.FLEX: + cert_apdu = "01010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100A35942AD66FEBD1899C52BB3EE3A5CB3802C4C2BE6C6521EB590D32ADC152E380220210F7BAB9A62501134D513CFD127A72BA1EB0D9F956E3EC7E553BF460F505810" # noqa: E501 + # pylint: enable=line-too-long + + self._pki_client.send_certificate(bytes.fromhex(cert_apdu)) + + # send TLV trusted info + res: RAPDU = self._client.exchange(CLA, INS.INS_TRUSTED_INFO, P1_NON_CONFIRM, P2_NONE, payload) + assert res.status == StatusWord.OK + + def get_challenge(self) -> bytes: + challenge: RAPDU = self._client.exchange(CLA, INS.INS_GET_CHALLENGE,P1_NON_CONFIRM, P2_NONE) + + assert challenge.status == StatusWord.OK + return challenge.data def get_public_key(self, derivation_path: bytes) -> bytes: public_key: RAPDU = self._client.exchange(CLA, INS.INS_GET_PUBKEY, diff --git a/tests/python/apps/solana_keychain.py b/tests/python/apps/solana_keychain.py new file mode 100644 index 00000000..e630a6df --- /dev/null +++ b/tests/python/apps/solana_keychain.py @@ -0,0 +1,30 @@ +import os +import hashlib +from ecdsa import SigningKey +from ecdsa.util import sigencode_der +from enum import Enum, auto + + +# Private key PEM files have to be named the same (lowercase) as their corresponding enum entries +# Example: for an entry in the Enum named DEV, its PEM file must be at keychain/dev.pem +class Key(Enum): + TRUSTED_NAME = auto() + + +_keys: dict[Key, SigningKey] = dict() + + +# Open the corresponding PEM file and load its key in the global dict +def _init_key(key: Key): + global _keys + with open("%s/keychain/%s.pem" % (os.path.dirname(__file__), key.name.lower())) as pem_file: + _keys[key] = SigningKey.from_pem(pem_file.read(), hashlib.sha256) + assert (key in _keys) and (_keys[key] is not None) + + +# Generate a SECP256K1 signature of the given data with the given key +def sign_data(key: Key, data: bytes) -> bytes: + global _keys + if key not in _keys: + _init_key(key) + return _keys[key].sign_deterministic(data, sigencode=sigencode_der) \ No newline at end of file diff --git a/tests/python/apps/solana_tlv.py b/tests/python/apps/solana_tlv.py new file mode 100644 index 00000000..f22fa45b --- /dev/null +++ b/tests/python/apps/solana_tlv.py @@ -0,0 +1,42 @@ +from typing import Union +from enum import IntEnum + +def der_encode(value: int) -> bytes: + # max() to have minimum length of 1 + value_bytes = value.to_bytes(max(1, (value.bit_length() + 7) // 8), 'big') + if value >= 0x80: + value_bytes = (0x80 | len(value_bytes)).to_bytes(1, 'big') + value_bytes + return value_bytes + +# https://ledgerhq.atlassian.net/wiki/spaces/TrustServices/pages/3736863735/LNS+Arch+Nano+Trusted+Names+Descriptor+Format+APIs#TLV-description +class FieldTag(IntEnum): + TAG_STRUCTURE_TYPE = 0x01 + TAG_VERSION = 0x02 + TAG_TRUSTED_NAME_TYPE = 0x70 + TAG_TRUSTED_NAME_SOURCE = 0x71 + TAG_TRUSTED_NAME = 0x20 + TAG_CHAIN_ID = 0x23 + TAG_ADDRESS = 0x22 + TAG_TRUSTED_NAME_NFT_ID = 0x72 + TAG_TRUSTED_NAME_SOURCE_CONTRACT = 0x73 + TAG_CHALLENGE = 0x12 + TAG_NOT_VALID_AFTER = 0x10 + TAG_SIGNER_KEY_ID = 0x13 + TAG_SIGNER_ALGO = 0x14 + TAG_DER_SIGNATURE = 0x15 + +def format_tlv(tag: int, value: Union[int, str, bytes]) -> bytes: + if isinstance(value, int): + # max() to have minimum length of 1 + value = value.to_bytes(max(1, (value.bit_length() + 7) // 8), 'big') + elif isinstance(value, str): + value = value.encode() + + assert isinstance(value, bytes), f"Unhandled TLV formatting for type : {type(value)}" + + tlv = bytearray() + tlv += der_encode(tag) + tlv += der_encode(len(value)) + tlv += value + return tlv + diff --git a/tests/python/requirements.txt b/tests/python/requirements.txt index 391b52bb..73b8cbe7 100644 --- a/tests/python/requirements.txt +++ b/tests/python/requirements.txt @@ -1,2 +1,3 @@ base58 +ecdsa ragger[tests,speculos] diff --git a/tests/python/test_solana.py b/tests/python/test_solana.py index f71a724e..57b3fc51 100644 --- a/tests/python/test_solana.py +++ b/tests/python/test_solana.py @@ -202,3 +202,26 @@ def test_ledger_sign_offchain_message_utf8_expert_refused(self, backend, scenari rapdu: RAPDU = sol.get_async_response() assert rapdu.status == ErrorType.USER_CANCEL +# Values used across Trusted Name test +CHAIN_ID = 101 +ADDRESS = bytes.fromhex("606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b5") +TRUSTED_NAME = bytes.fromhex("276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9db") +SOURCE_CONTRACT = bytes.fromhex("c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61") + +class TestTrustedName: + + def test_solana_trusted_name(self, backend, scenario_navigator): + sol = SolanaClient(backend) + + challenge = sol.get_challenge() + + sol.provide_trusted_name(SOURCE_CONTRACT, + TRUSTED_NAME, + ADDRESS, + CHAIN_ID, + challenge=challenge) + + + + + diff --git a/tools/rust/Cargo.lock b/tools/rust/Cargo.lock new file mode 100644 index 00000000..592cdec0 --- /dev/null +++ b/tools/rust/Cargo.lock @@ -0,0 +1,5431 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5327f6c99920069d1fe374aa743be1af0031dea9f250852cdf1ae6a0861ee24" +dependencies = [ + "borsh-derive 1.5.2", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10aedd8f1a81a8aafbfde924b0e3061cd6fedd6f6bbcfc6a76e6fd426d7bfe26" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.87", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "governor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls 0.21.12", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quanta" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.16", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.16", + "rustls-platform-verifier", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-cpuid" +version = "11.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bincode", + "hex", + "solana-client", + "solana-sdk", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-platform-verifier" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.16", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-roots 0.26.6", + "winapi", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint 0.4.6", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "serde", + "serde_derive", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solana-account" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730219420b206253977b8cc8fd7846ffe021ab2e2c718e70db420efbd2775547" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-program", +] + +[[package]] +name = "solana-account-decoder" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e5b1c167335942b659d077552607f79b2eca3472e40eeed97a2c55838b84ef" +dependencies = [ + "Inflector", + "base64 0.22.1", + "bincode", + "bs58", + "bv", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-config-program", + "solana-sdk", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", + "thiserror", + "zstd", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee0750d2f106ecbee6d4508b6e2029e6946cb5f67288bf002b5a62f9f451c43" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6abe81cfc4a75f71a510c6856b03a7d8525e416af3c69d55daef62e6078b8d40" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391b795afcdcad39ddc6c938d64b789d036cdfe00d9dc5ff83024cf2da9f066f" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-bincode" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85cb5961c356345a61378163fd9057011b35540f8bcdd8d8a09cb10117264f" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-bn254" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39c4030db26ad618f7e18fb5284df19fd52a68e092a1ca58db857108c4cc777" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "solana-borsh" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d526f3525ab22a3ada3f9a1d642664dafac00dc9208326b701a2045514eb04" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.2", +] + +[[package]] +name = "solana-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9a40b8e9e11604e8c05e8b5fcdb89359235db47d1aae84dcba0fc98e95dd0c" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap", + "indicatif", + "log", + "quinn", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-sdk", + "solana-streamer", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-clock" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7848171e53fa528efd41dd4b3ab919f47b851f8bb4a827d63ff95678f08737fc" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-compute-budget" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf2f023f471bd1195b7f420e13ffc2422592dd48e71104b4901300b49ac493e" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-config-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a035a01970ebbf40a244b3b79af533329ac8d48d80b0b98e166e23e35aa88171" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-short-vec", +] + +[[package]] +name = "solana-connection-cache" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f45dd2a6d5d55ed951781486231d0d2ee9ff7047fdafaed01ee021e236319d0" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap", + "log", + "rand 0.8.5", + "rayon", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25c536ad0ce25d84a64f48dedcb773e764827e0ef781eda41fa1fa35f5d64b38" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f934d38b6f2a940fb1e1d8eaa17a14ffd3773b37be9fb29fa4bcec1bac5e4591" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-program", + "thiserror", +] + +[[package]] +name = "solana-decode-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a431f532d030098e81d120877f2dddbd3dd90bea5b259198a6aae4ff6456c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7062ae1de58e294d3bee5fd2c89efc155b7f7383ddce4cb88345dfafaaabc5bd" + +[[package]] +name = "solana-derivation-path" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12080d9bf8eecd559c6f40b5aaf9e47f7f28f515218087f83f02e493b46d8388" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c4cf7d7c266d353169cf4feeada5e4bba3a55f33715535fa1ef49080eac3e0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-feature-set" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cebf45992982065a0b01b4e109bf039b2ebf6394b21672382fd951516d4c9b0" +dependencies = [ + "lazy_static", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2befe056ece2eb5807298c2b569a35ee52f79df859bdd16a1f97869f8224a28" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1807bc4e9e1d25271514167d5a1e698ce5a330bce547a368242dd63b355b5faa" +dependencies = [ + "borsh 1.5.2", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a60b572cdf0ec8fcf5a53e5ba4e3e19814dd96c2b9c156d5828be68d0d2e7103" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24c9c6590e4eaf91efa887b2689b2941fe4b324bccd9a95f77853168f3d9a88" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfef689e06e5c7cb6206d4dc61ac77733de4f72d754e0d531393206abc27dbe4" +dependencies = [ + "bincode", + "borsh 1.5.2", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3186feae497bdfd2e77bfa56caed38b1cb1b0f389506666e3331f0b9ae799cb" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-log-collector" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b529f5736a6c0794a885dac2e091138d3db6d924335906f117a62b58b0d3b5dc" +dependencies = [ + "log", +] + +[[package]] +name = "solana-measure" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b2047a2f588082b71080b060918f107c3330ae1505f759c3b2d74bae9d9c88" + +[[package]] +name = "solana-metrics" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6319c74238e8ed4f7159fd37c693a574ab8316d03b053103f9cc83dce13f1d5c" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-msg" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7551f85064bc7299d56dbd7126258b084a2d78d0325b1579324f818b405123" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0c4074f5fc67574dabd8f30fe6e51e290a812d88326b19b49c462058e23340" + +[[package]] +name = "solana-net-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbac19474a4c4f91cb264c2fccead8a1a4f65384ce650b24360d9df5650e65bc" +dependencies = [ + "bincode", + "crossbeam-channel", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-sdk", + "tokio", + "url", +] + +[[package]] +name = "solana-packet" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dafc2d84e57dbfe32583fe915962bd2ca3af6be496628a871db3c3d697b38d7" +dependencies = [ + "bincode", + "bitflags 2.6.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8299f1ba518f9888da8cafa861addc6ffdd639c689e3ce219ae08212c0dcd0e" +dependencies = [ + "ahash", + "bincode", + "bv", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-metrics", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-short-vec", + "solana-vote-program", +] + +[[package]] +name = "solana-precompile-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30ab58b9e37cde4e5577282670f30df71b97b6b06dbdb420e9b84e57b831227" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9040decf2f295d35da22557eeab3768ab8dfca8aed9afe668663c8fa0e97d60e" +dependencies = [ + "base64 0.22.1", + "bincode", + "bitflags 2.6.0", + "blake3", + "borsh 0.10.4", + "borsh 1.5.2", + "bs58", + "bv", + "bytemuck", + "bytemuck_derive", + "console_error_panic_hook", + "console_log", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "sha3", + "solana-account-info", + "solana-atomic-u64", + "solana-bincode", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-transaction-error", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb90f3fa3e979b912451a404508f1f90bb6e5c1d7767625f622b20016fb9fde" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd089caeef26dd07bd12b7b67d45e92faddc2fc67a960f316df7ae4776a2f3d5" +dependencies = [ + "borsh 1.5.2", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4bc044dc2b49c323aeff04aec03c908a052e278c2edf2f7616f32fc0f1bcd9" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3babbdffd81994c043fc9a61458ce87496218825d6e9a303de643c0a53089b9a" + +[[package]] +name = "solana-program-pack" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fb28439d23e1f505e59c7a14ed5012365ab7aa0f20dc7bda048e02ff231cf6" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-program-runtime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1de51df173401d50c0f4cf750f5070d7a4c82125a03c1aec9622dc041b0b54" +dependencies = [ + "base64 0.22.1", + "bincode", + "enum-iterator", + "itertools 0.12.1", + "libc", + "log", + "num-derive", + "num-traits", + "percentage", + "rand 0.8.5", + "serde", + "solana-compute-budget", + "solana-feature-set", + "solana-log-collector", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-pubkey" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea3215775fcedf200d47590c7e2ce9a3a46bc2b7d3f77d0eae9c6edf0a39aec" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.2", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d28adf5ff89c19ef3cb24d0f484afa05852697881c2e4ef12aec190d61f76d8" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259c6d420c0b7620557700f13fbbdb00afbb1b82274485c27ba30dd660ea921b" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.16", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c69806ad1a7b0986f750134e13e55d83919631d81a2328a588615740e14ed0a" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-rent" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab3f4a270196c38d62c3bb3c7a2f07732af2c772b50da49c9b1e2c9d2ace286" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", +] + +[[package]] +name = "solana-rpc-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b05822aceeb484074a72d82a1b289da9fc3383f9ba3f55ce4bfd003bf9d62e6" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9c6e64f01cfafef9b2d43d6adb02979bb22f579ec8ee88b77796259acce92e" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-inline-spl", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0ab2d1ca3769c5058c689b438d35eb1cb7d2a32fc4b2b7c16fe72fa187927c" +dependencies = [ + "solana-rpc-client", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-sanitize" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203b90994371db8cade8e885f74ec9f68ee02a32b25d514594158b2551a4e5ed" + +[[package]] +name = "solana-sdk" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524604d94185c189616296e5b7da1014cc96d1e446bd2b26f247f00708b9225a" +dependencies = [ + "bincode", + "bitflags 2.6.0", + "borsh 1.5.2", + "bs58", + "bytemuck", + "bytemuck_derive", + "byteorder", + "chrono", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "getrandom 0.1.16", + "hmac 0.12.1", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive", + "num-traits", + "num_enum", + "pbkdf2", + "rand 0.7.3", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3", + "siphasher", + "solana-account", + "solana-bn254", + "solana-decode-error", + "solana-derivation-path", + "solana-feature-set", + "solana-inflation", + "solana-instruction", + "solana-native-token", + "solana-packet", + "solana-precompile-error", + "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-short-vec", + "solana-signature", + "solana-transaction-error", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd2265b93dce9d3dcf9f395abf1a85b5e06e4da4aa60ca147620003ac3abc67" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2eef5a00a75648273c3fb6e3d85b0c8c02fcc1e36c4271664dcc39b6b128d41" +dependencies = [ + "borsh 1.5.2", + "libsecp256k1", + "solana-define-syscall", + "thiserror", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-serde-varint" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aeb51d3c20e2a61db0ef72617f3b8c9207a342a867af454a95f17add9f6c262" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfb0b57c6a431fb15ff33053caadb6c36aed4e1ce74bea9adfc459a710b3626" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd115f3a1136314b0183235080d29023530c3a0a5df60505fdb7ea620eff9fd6" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e55330b694db1139dcdf2a1ea7781abe8bd994dec2ab29e36abfd06e4e9274" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad9784d110f195a3a4fe423479d18f05b01a1c380a1430644a3b3038fdbe2f0" +dependencies = [ + "bs58", + "ed25519-dalek", + "generic-array", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d216c0ebf00e95acaf2b1e227e6cc900a5ce50fb81fa0743272851e88a788d" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", +] + +[[package]] +name = "solana-slot-history" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cbcdf767891c6a40116a5ef8f7241000f074ece4ba80c8f00b4f62705fc8a4" +dependencies = [ + "bv", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-stable-layout" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5305ca88fb5deb219cd88f04e24f3a131769417d7fcb11a8da1126a8f98d23" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-streamer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff771524872781eca074e0ba221d72b07fa0800cc1a7ffa400a9eb3e125fb922" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap", + "itertools 0.12.1", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.16", + "smallvec", + "socket2", + "solana-measure", + "solana-metrics", + "solana-perf", + "solana-sdk", + "solana-transaction-metrics-tracker", + "thiserror", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-thin-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10314ae3e0889cf38140902862d2c2ea481895c82c19f51dc4457b7dfa3aa6d0" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-timings" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a8e2f926d488c1e2a65cbc05544dcb68cfa88deb4d50f89db5bfbda7ff2419" +dependencies = [ + "eager", + "enum-iterator", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516cbed8800cd36fb3ecc9a65df1e76bf8251929aa32e9b10497e8d6612de605" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-transaction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a4bea6d80b34fe6e785d19bf928fe103928d1f6c9935ec23bb6a9d4d7a33d2" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b668c986a83e6b2eb8f130039045b54abc37ee821853250755386d26c1c668" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-perf", + "solana-sdk", + "solana-short-vec", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb35fb678fec581e9bdf6350d2c7f5829951a6280038fc06949b1589a9605e1" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-sdk", + "solana-signature", + "thiserror", +] + +[[package]] +name = "solana-type-overrides" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2066f25d460d63801f91436c2640aaba4f2dc95aa18fe1e76f7f2c063e981d4e" +dependencies = [ + "lazy_static", + "rand 0.8.5", +] + +[[package]] +name = "solana-udp-client" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ec0cbc2d5e3379fafb2c1493f2358f07c09e76e2081c44e3a8c36da12fbd40" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-version" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7310708b642fb83c04f44934509f4f149ffd69d0cd4cf76d9645c991177d7ea0" +dependencies = [ + "semver", + "serde", + "serde_derive", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab46788981765ee706094ca53ad8421aae0286a6b948e892fa7db88992a5373" +dependencies = [ + "itertools 0.12.1", + "log", + "serde", + "serde_derive", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-vote-program" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637cadc921725d1804a451ea7d2dff83310a12b75e0b6c83a8bb67ebc02d10f1" +dependencies = [ + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-feature-set", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed293089d8eebd6b5c1b53ee4ad6817889fea254274ddb34cb01ad35a2f817cb" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "byteorder", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-curve25519", + "solana-derivation-path", + "solana-program", + "solana-sdk", + "subtle", + "thiserror", + "zeroize", +] + +[[package]] +name = "solana_rbpf" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spl-discriminator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.87", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.87", + "thiserror", +] + +[[package]] +name = "spl-memo" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" +dependencies = [ + "borsh 1.5.2", + "bytemuck", + "bytemuck_derive", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" +dependencies = [ + "num-derive", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.87", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-token" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" +dependencies = [ + "borsh 1.5.2", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/tools/rust/Cargo.toml b/tools/rust/Cargo.toml new file mode 100644 index 00000000..1db619af --- /dev/null +++ b/tools/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] +base64 = "0.22.1" +bincode = "1.3.3" +hex = "0.4.3" +solana-client = "2.1.0" +solana-sdk = "2.1.0" diff --git a/tools/rust/src/main.rs b/tools/rust/src/main.rs new file mode 100644 index 00000000..e1c644ea --- /dev/null +++ b/tools/rust/src/main.rs @@ -0,0 +1,180 @@ +// use base64; +//use solana_sdk::{ +// client::SyncClient, +// commitment_config::CommitmentConfig, +// message::Message, +// pubkey::Pubkey, +// signature::{Keypair, Signer}, +// system_instruction, +// transaction::Transaction, +// }; + +use solana_client::rpc_client::RpcClient; + +use solana_sdk::{ + message::Message, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +fn main() { + // Create a connection to the Solana devnet + let rpc_url = "https://api.devnet.solana.com"; + //let client = RpcClient::new_with_commitment(rpc_url.to_string(), CommitmentConfig::confirmed()); + let client = RpcClient::new(rpc_url.to_string()); + + // Get a recent blockhash + let recent_blockhash = client.get_latest_blockhash().unwrap(); + + // Generate a new keypair for the sender (for demonstration purposes) + let sender = Keypair::new(); + + // Generate a new keypair for the recipient (for demonstration purposes) + let recipient = Keypair::new(); + + // print the sender and recipient public keys + println!("Sender Public Key: {}", sender.pubkey()); + println!("Recipient Public Key: {}", recipient.pubkey()); + + // Create a transfer instruction + let transfer_instruction = system_instruction::transfer( + &sender.pubkey(), + &recipient.pubkey(), + 1_000_000, // Transfer 1,000,000 lamports (0.001 SOL) + ); + + // Create a transaction + let message = Message::new(&[transfer_instruction], Some(&sender.pubkey())); + + // Print message serialize + println!("Message: {}", hex::encode(message.serialize())); + + let mut transaction = Transaction::new_unsigned(message); + transaction.try_sign(&[&sender], recent_blockhash).unwrap(); + + // Display the transaction + println!("Transaction: {:?}", transaction); + + // Serialize the transaction + // let serialized_transaction = bincode::serialize(&transaction).unwrap(); + + // Convert the serialized transaction to a hexadecimal string + // let hex_dump = hex::encode(&serialized_transaction); + + // Convert the serialized transaction to a base64 string + // let base64_dump = base64::encode(&serialized_transaction); + + // println!("Serialized Transaction (Hex): {}", hex_dump); + // println!("Serialized Transaction (Base64): {}", base64_dump); + + // Optionally, send the serialized transaction + // let signature = client.send_transaction(&transaction).unwrap(); + // client.confirm_transaction(&signature).unwrap(); + + // println!("Transaction signature: {}", signature); +} + +// use solana_sdk::{ +// client::SyncClient, +// commitment_config::CommitmentConfig, +// message::Message, +// pubkey::Pubkey, +// signature::{Keypair, Signer}, +// transaction::Transaction, +// }; +// use solana_client::rpc_client::RpcClient; +// use spl_token::instruction::transfer; +// use spl_token::state::Account as TokenAccount; +// use base64; + +// fn main() { +// // Create a connection to the Solana devnet +// let rpc_url = "https://api.devnet.solana.com"; +// let client = RpcClient::new_with_commitment(rpc_url.to_string(), CommitmentConfig::confirmed()); + +// // Generate a new keypair for the sender (for demonstration purposes) +// let sender = Keypair::new(); + +// // Generate a new keypair for the recipient (for demonstration purposes) +// let recipient = Keypair::new(); + +// // Generate a new keypair for the mint authority (for demonstration purposes) +// let mint_authority = Keypair::new(); + +// // Airdrop some SOL to the sender's account (for demonstration purposes) +// let airdrop_amount = 1_000_000_000; // 1 SOL in lamports +// let airdrop_signature = client.request_airdrop(&sender.pubkey(), airdrop_amount).unwrap(); +// client.confirm_transaction(&airdrop_signature).unwrap(); + +// // Create a new mint +// let mint = spl_token::state::Mint::new( +// &client, +// &mint_authority, +// &sender.pubkey(), +// None, +// 9, // Decimals +// ).unwrap(); + +// // Create associated token accounts for the sender and recipient +// let sender_token_account = spl_token::state::Account::new( +// &client, +// &mint.pubkey(), +// &sender.pubkey(), +// &sender, +// ).unwrap(); + +// let recipient_token_account = spl_token::state::Account::new( +// &client, +// &mint.pubkey(), +// &recipient.pubkey(), +// &sender, +// ).unwrap(); + +// // Mint some tokens to the sender's token account +// let mint_amount = 1_000_000_000; // 1 token with 9 decimals +// spl_token::instruction::mint_to( +// &client, +// &mint.pubkey(), +// &sender_token_account.pubkey(), +// &mint_authority.pubkey(), +// &mint_authority, +// mint_amount, +// ).unwrap(); + +// // Get a recent blockhash +// let recent_blockhash = client.get_recent_blockhash().unwrap().0; + +// // Create a transfer instruction +// let transfer_instruction = transfer( +// &spl_token::id(), +// &sender_token_account.pubkey(), +// &recipient_token_account.pubkey(), +// &sender.pubkey(), +// &[], +// 500_000_000, // Transfer 0.5 tokens with 9 decimals +// ).unwrap(); + +// // Create a transaction +// let message = Message::new(&[transfer_instruction], Some(&sender.pubkey())); +// let mut transaction = Transaction::new_unsigned(message); +// transaction.try_sign(&[&sender], recent_blockhash).unwrap(); + +// // Serialize the transaction +// let serialized_transaction = bincode::serialize(&transaction).unwrap(); + +// // Convert the serialized transaction to a hexadecimal string +// let hex_dump = hex::encode(&serialized_transaction); + +// // Convert the serialized transaction to a base64 string +// let base64_dump = base64::encode(&serialized_transaction); + +// println!("Serialized Transaction (Hex): {}", hex_dump); +// println!("Serialized Transaction (Base64): {}", base64_dump); + +// // Optionally, send the serialized transaction +// let signature = client.send_transaction(&transaction).unwrap(); +// client.confirm_transaction(&signature).unwrap(); + +// println!("Transaction signature: {}", signature); +// } diff --git a/tools/rust/target/.rustc_info.json b/tools/rust/target/.rustc_info.json new file mode 100644 index 00000000..2eb362b6 --- /dev/null +++ b/tools/rust/target/.rustc_info.json @@ -0,0 +1 @@ +{"rustc_fingerprint":14969634273812012838,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.82.0 (f6e511eec 2024-10-15)\nbinary: rustc\ncommit-hash: f6e511eec7342f59a25f7c0534f1dbea00d01b14\ncommit-date: 2024-10-15\nhost: aarch64-apple-darwin\nrelease: 1.82.0\nLLVM version: 19.1.1\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/jerome.caporossi/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/tools/rust/target/CACHEDIR.TAG b/tools/rust/target/CACHEDIR.TAG new file mode 100644 index 00000000..20d7c319 --- /dev/null +++ b/tools/rust/target/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/ From f3cbfdb6dc3164b38a9b14d894d29e4a3756ffff Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 12 Nov 2024 17:26:03 +0100 Subject: [PATCH 03/17] Ragger tests on Stax OK --- Makefile | 10 +- libsol/spl_token_instruction.c | 7 +- src/apdu.c | 21 +- src/handle_get_challenge.c | 5 +- src/handle_provide_trusted_info.c | 49 +---- src/handle_provide_trusted_info.h | 1 + src/ledger_pki.c | 29 +-- src/ledger_pki.h | 20 -- test_pki_certificate_flex.dat | 1 - test_pki_certificate_stax.dat | 1 - test_transfert.dat | 2 - .../ledgercomm/test_pki_certificate_flex.dat | 1 + .../test_pki_certificate_nanosp.dat | 3 +- .../ledgercomm/test_pki_certificate_nanox.dat | 2 +- .../ledgercomm/test_pki_certificate_stax.dat | 1 + .../ledgercomm/test_tlv_apdu.dat | 0 tests/ledgercomm/test_transfert.dat | 1 + tests/ledgercomm/test_transfert_OK.dat | 2 + tests/ledgercomm/test_transfert_SPL.dat | 3 + tests/ledgercomm/test_transfert_SPL_2.dat | 3 + tests/python/apps/solana.py | 28 ++- .../stax/test_solana_trusted_name/00000.png | Bin 0 -> 8809 bytes .../stax/test_solana_trusted_name/00001.png | Bin 0 -> 21433 bytes .../stax/test_solana_trusted_name/00002.png | Bin 0 -> 30608 bytes .../stax/test_solana_trusted_name/00003.png | Bin 0 -> 5484 bytes .../stax/test_solana_trusted_name/00004.png | Bin 0 -> 11376 bytes .../stax/test_solana_trusted_name/00005.png | Bin 0 -> 6218 bytes .../stax/test_solana_trusted_name/00006.png | Bin 0 -> 10815 bytes tests/python/test_solana.py | 19 +- tools/{rust => apdu_generator}/Cargo.lock | 40 ++-- tools/{rust => apdu_generator}/Cargo.toml | 5 +- tools/apdu_generator/src/main.rs | 73 +++++++ .../target/.rustc_info.json | 0 .../target/CACHEDIR.TAG | 0 tools/rust/src/main.rs | 180 ------------------ 35 files changed, 179 insertions(+), 328 deletions(-) delete mode 100644 test_pki_certificate_flex.dat delete mode 100644 test_pki_certificate_stax.dat delete mode 100644 test_transfert.dat create mode 100644 tests/ledgercomm/test_pki_certificate_flex.dat rename test_pki_certificate_nanosp.dat => tests/ledgercomm/test_pki_certificate_nanosp.dat (56%) rename test_pki_certificate_nanox.dat => tests/ledgercomm/test_pki_certificate_nanox.dat (56%) create mode 100644 tests/ledgercomm/test_pki_certificate_stax.dat rename test_tlv_apdu.dat => tests/ledgercomm/test_tlv_apdu.dat (100%) create mode 100644 tests/ledgercomm/test_transfert.dat create mode 100644 tests/ledgercomm/test_transfert_OK.dat create mode 100644 tests/ledgercomm/test_transfert_SPL.dat create mode 100644 tests/ledgercomm/test_transfert_SPL_2.dat create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00000.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00001.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00002.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00003.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00004.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00005.png create mode 100644 tests/python/snapshots/stax/test_solana_trusted_name/00006.png rename tools/{rust => apdu_generator}/Cargo.lock (99%) rename tools/{rust => apdu_generator}/Cargo.toml (70%) create mode 100644 tools/apdu_generator/src/main.rs rename tools/{rust => apdu_generator}/target/.rustc_info.json (100%) rename tools/{rust => apdu_generator}/target/CACHEDIR.TAG (100%) delete mode 100644 tools/rust/src/main.rs diff --git a/Makefile b/Makefile index 3f1c0975..4867a57f 100644 --- a/Makefile +++ b/Makefile @@ -106,10 +106,12 @@ ifneq ($(WITH_LIBSOL),0) DEFINES += NDEBUG endif -# Trusted Name -TRUSTED_NAME_TEST_KEY ?= 0 -ifneq ($(TRUSTED_NAME_TEST_KEY),0) - DEFINES += HAVE_TRUSTED_NAME_TEST_KEY +####################################### +# Trusted Name Test Mode # +####################################### +TRUSTED_NAME_TEST ?= 0 +ifneq ($(TRUSTED_NAME_TEST),0) + DEFINES += HAVE_TRUSTED_NAME_TEST endif include $(BOLOS_SDK)/Makefile.standard_app diff --git a/libsol/spl_token_instruction.c b/libsol/spl_token_instruction.c index 9772a9f7..4869f461 100644 --- a/libsol/spl_token_instruction.c +++ b/libsol/spl_token_instruction.c @@ -485,6 +485,7 @@ static int print_spl_token_initialize_multisig_info(const char* primary_title, } extern Pubkey g_trusted_token_account_owner_pubkey; +extern bool g_trusted_token_account_owner_pubkey_set; int print_spl_token_transfer_info(const SplTokenTransferInfo* info, const PrintConfig* print_config, @@ -504,8 +505,10 @@ int print_spl_token_transfer_info(const SplTokenTransferInfo* info, symbol, info->body.decimals); - item = transaction_summary_general_item(); - summary_item_set_pubkey(item, "To", &g_trusted_token_account_owner_pubkey); + if (g_trusted_token_account_owner_pubkey_set) { + item = transaction_summary_general_item(); + summary_item_set_pubkey(item, "To", &g_trusted_token_account_owner_pubkey); + } item = transaction_summary_general_item(); summary_item_set_pubkey(item, "Token address", info->mint_account); diff --git a/src/apdu.c b/src/apdu.c index 759c4eb6..44217c3c 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -177,21 +177,14 @@ int apdu_handle_message(const uint8_t* apdu_message, } } if (header.data) { - /*if (header.instruction == InsTrustedInfoProvideInfo) { - const int ret = handle_provide_trusted_info(first_data_chunk, header.data, header.data_length); - if (ret != 0) - return ApduReplySolanaInvalidTrustedInfo; - } - else*/ { - if (apdu_command->message_length + header.data_length > MAX_MESSAGE_LENGTH) { - return ApduReplySolanaInvalidMessageSize; - } - - memcpy(apdu_command->message + apdu_command->message_length, - header.data, - header.data_length); - apdu_command->message_length += header.data_length; + if (apdu_command->message_length + header.data_length > MAX_MESSAGE_LENGTH) { + return ApduReplySolanaInvalidMessageSize; } + + memcpy(apdu_command->message + apdu_command->message_length, + header.data, + header.data_length); + apdu_command->message_length += header.data_length; } else if (header.instruction != InsDeprecatedGetPubkey && header.instruction != InsGetPubkey) { return ApduReplySolanaInvalidMessageSize; } diff --git a/src/handle_get_challenge.c b/src/handle_get_challenge.c index 00400e81..3f3cce09 100644 --- a/src/handle_get_challenge.c +++ b/src/handle_get_challenge.c @@ -10,8 +10,11 @@ static uint32_t challenge; * Generate a new challenge from the Random Number Generator */ void roll_challenge(void) { - challenge = cx_rng_u32(); +#ifdef HAVE_TRUSTED_NAME_TEST challenge = 0xdeadbeef; +#else + challenge = cx_rng_u32(); +#endif } /** diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index cca26962..e66e28fc 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -10,9 +10,7 @@ #include "sol/printer.h" -#ifdef HAVE_LEDGER_PKI #include "os_pki.h" -#endif #include "ledger_pki.h" @@ -153,41 +151,7 @@ static s_tlv_payload g_tlv_payload = {0}; static s_trusted_name_info g_trusted_name_info = {0}; Pubkey g_trusted_token_account_owner_pubkey = {0}; - -/** - * Checks if a trusted name matches the given parameters - * - * Does not care about the trusted name source for now. - * Always wipes the content of \ref g_trusted_name_info - * - * @param[in] types_count number of given trusted name types - * @param[in] types given trusted name types - * @param[in] chain_id given chain ID - * @param[in] addr given address - * @return whether there is or not - */ -bool has_trusted_name(uint8_t types_count, - const uint64_t *chain_id, - const uint8_t *addr) { - bool ret = false; - - (void) types_count; - (void) addr; - - if (g_trusted_name_info.rcv_flags != 0) { - switch (g_trusted_name_info.struct_version) { - case 2: - if (*chain_id == g_trusted_name_info.chain_id) { - ret = true; - } - break; - default: - ret = false; - } - explicit_bzero(&g_trusted_name_info, sizeof(g_trusted_name_info)); - } - return ret; -} +bool g_trusted_token_account_owner_pubkey_set = false; /** * Get uint from tlv data @@ -526,7 +490,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { uint8_t hash[INT256_LENGTH]; cx_err_t error = CX_INTERNAL_ERROR; -#ifdef HAVE_TRUSTED_NAME_TEST_KEY +#ifdef HAVE_TRUSTED_NAME_TEST e_key_id valid_key_id = KEY_ID_TEST; #else e_key_id valid_key_id = KEY_ID_PROD; @@ -544,11 +508,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK(check_signature_with_pubkey("Trusted Name", hash, sizeof(hash), - TRUSTED_NAME_PUB_KEY, - sizeof(TRUSTED_NAME_PUB_KEY), -#ifdef HAVE_LEDGER_PKI CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME, -#endif (uint8_t *) (sig_ctx->input_sig), sig_ctx->input_sig_size)); @@ -854,13 +814,17 @@ void handle_provide_trusted_info(void) { // everything has been received if (g_tlv_payload.size == g_tlv_payload.expected_size) { g_trusted_name_info.owner = g_trusted_token_account_owner_pubkey.data; + g_trusted_token_account_owner_pubkey_set = true; if (!parse_tlv(&g_tlv_payload, &g_trusted_name_info, &sig_ctx) || !verify_signature(&sig_ctx)) { free_payload(&g_tlv_payload); roll_challenge(); // prevent brute-force guesses g_trusted_name_info.rcv_flags = 0; + memset(g_trusted_token_account_owner_pubkey.data, 0, sizeof(g_trusted_token_account_owner_pubkey.data)); + g_trusted_token_account_owner_pubkey_set = false; THROW(ApduReplySolanaInvalidTrustedInfo); } +#ifdef DEBUG { char token_account[45]; char owner[45]; @@ -870,6 +834,7 @@ void handle_provide_trusted_info(void) { PRINTF("Token account : %s owned by %s\n", token_account,owner); } +#endif // DEBUG free_payload(&g_tlv_payload); roll_challenge(); // prevent replays THROW(ApduReplySuccess); diff --git a/src/handle_provide_trusted_info.h b/src/handle_provide_trusted_info.h index fab466fc..98af1b1d 100644 --- a/src/handle_provide_trusted_info.h +++ b/src/handle_provide_trusted_info.h @@ -17,5 +17,6 @@ bool has_trusted_info(uint8_t types_count, void handle_provide_trusted_info(void); extern Pubkey g_trusted_token_account_owner_pubkey; +extern bool g_trusted_token_account_owner_pubkey_set; #endif // TRUSTED_INFO_H_ \ No newline at end of file diff --git a/src/ledger_pki.c b/src/ledger_pki.c index b5fe2b04..2d467dc5 100644 --- a/src/ledger_pki.c +++ b/src/ledger_pki.c @@ -1,9 +1,7 @@ #include "apdu.h" #include "ledger_pki.h" #include "cx.h" -#ifdef HAVE_LEDGER_PKI #include "os_pki.h" -#endif #define KEY_USAGE_STR(x) \ (x == CERTIFICATE_PUBLIC_KEY_USAGE_GENUINE_CHECK ? "GENUINE_CHECK" \ @@ -20,28 +18,21 @@ int check_signature_with_pubkey(const char *tag, uint8_t *buffer, const uint8_t bufLen, - const uint8_t *PubKey, - const uint8_t keyLen, -#ifdef HAVE_LEDGER_PKI const uint8_t keyUsageExp, -#endif uint8_t *signature, const uint8_t sigLen) { UNUSED(tag); - cx_ecfp_public_key_t verif_key = {0}; cx_err_t error = CX_INTERNAL_ERROR; -#ifdef HAVE_LEDGER_PKI uint8_t key_usage = 0; size_t trusted_name_len = 0; uint8_t trusted_name[CERTIFICATE_TRUSTED_NAME_MAXLEN] = {0}; cx_ecfp_384_public_key_t public_key = {0}; -#endif PRINTF( "[%s] " "=======================================================================================\n", tag); -#ifdef HAVE_LEDGER_PKI + error = os_pki_get_info(&key_usage, trusted_name, &trusted_name_len, &public_key); if ((error == 0) && (key_usage == keyUsageExp)) { PRINTF("[%s] Certificate '%s' loaded for usage 0x%x (%s)\n", @@ -53,23 +44,13 @@ int check_signature_with_pubkey(const char *tag, // Checking the signature with PKI if (!os_pki_verify(buffer, bufLen, signature, sigLen)) { PRINTF("%s: Invalid signature\n", tag); -#ifndef HAVE_BYPASS_SIGNATURES - error = ApduReplySolanaInvalidTrustedInfo; - goto end; -#endif - } - } else -#endif - { - PRINTF("[%s] ********** No certificate loaded. Using legacy path **********\n", tag); - CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, PubKey, keyLen, &verif_key)); - if (!cx_ecdsa_verify_no_throw(&verif_key, buffer, bufLen, signature, sigLen)) { - PRINTF("%s: Invalid signature\n", tag); -#ifndef HAVE_BYPASS_SIGNATURES error = ApduReplySolanaInvalidTrustedInfo; goto end; -#endif } + } else { + PRINTF("[%s] ********** Issue when loading PKI certificate, cannot check signature **********\n", tag); + error = ApduReplySolanaInvalidTrustedInfo; + goto end; } error = CX_OK; end: diff --git a/src/ledger_pki.h b/src/ledger_pki.h index a2a13aaa..7c3958da 100644 --- a/src/ledger_pki.h +++ b/src/ledger_pki.h @@ -1,29 +1,9 @@ #pragma once #include -static const uint8_t TRUSTED_NAME_PUB_KEY[] = { -#ifdef HAVE_TRUSTED_NAME_TEST_KEY - 0x04, 0xb9, 0x1f, 0xbe, 0xc1, 0x73, 0xe3, 0xba, 0x4a, 0x71, 0x4e, 0x01, 0x4e, 0xbc, - 0x82, 0x7b, 0x6f, 0x89, 0x9a, 0x9f, 0xa7, 0xf4, 0xac, 0x76, 0x9c, 0xde, 0x28, 0x43, - 0x17, 0xa0, 0x0f, 0x4f, 0x65, 0x0f, 0x09, 0xf0, 0x9a, 0xa4, 0xff, 0x5a, 0x31, 0x76, - 0x02, 0x55, 0xfe, 0x5d, 0xfc, 0x81, 0x13, 0x29, 0xb3, 0xb5, 0x0b, 0xe9, 0x91, 0x94, - 0xfc, 0xa1, 0x16, 0x19, 0xe6, 0x5f, 0x2e, 0xdf, 0xea -#else - 0x04, 0x6a, 0x94, 0xe7, 0xa4, 0x2c, 0xd0, 0xc3, 0x3f, 0xdf, 0x44, 0x0c, 0x8e, 0x2a, - 0xb2, 0x54, 0x2c, 0xef, 0xbe, 0x5d, 0xb7, 0xaa, 0x0b, 0x93, 0xa9, 0xfc, 0x81, 0x4b, - 0x9a, 0xcf, 0xa7, 0x5e, 0xb4, 0xe5, 0x3d, 0x6f, 0x00, 0x25, 0x94, 0xbd, 0xb6, 0x05, - 0xd9, 0xb5, 0xbd, 0xa9, 0xfa, 0x4b, 0x4b, 0xf3, 0xa5, 0x49, 0x6f, 0xd3, 0x16, 0x4b, - 0xae, 0xf5, 0xaf, 0xcf, 0x90, 0xe8, 0x40, 0x88, 0x71 -#endif -}; - extern int check_signature_with_pubkey(const char *tag, uint8_t *buffer, const uint8_t bufLen, - const uint8_t *PubKey, - const uint8_t keyLen, -#ifdef HAVE_LEDGER_PKI const uint8_t keyUsageExp, -#endif uint8_t *signature, const uint8_t sigLen); \ No newline at end of file diff --git a/test_pki_certificate_flex.dat b/test_pki_certificate_flex.dat deleted file mode 100644 index 9956b956..00000000 --- a/test_pki_certificate_flex.dat +++ /dev/null @@ -1 +0,0 @@ -B0060400A601010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100A35942AD66FEBD1899C52BB3EE3A5CB3802C4C2BE6C6521EB590D32ADC152E380220210F7BAB9A62501134D513CFD127A72BA1EB0D9F956E3EC7E553BF460F505810 \ No newline at end of file diff --git a/test_pki_certificate_stax.dat b/test_pki_certificate_stax.dat deleted file mode 100644 index 67dcfb57..00000000 --- a/test_pki_certificate_stax.dat +++ /dev/null @@ -1 +0,0 @@ -B0060400A601010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221009DCD14004A1C6F8A6A56F91FD253865F255E83FD316CB3E6B9AF585B12FBD78A02206DFA969336E82C93C1F2EF863CFAC19F88ECE1F38C900791FFFD46B9C9E02279 \ No newline at end of file diff --git a/test_transfert.dat b/test_transfert.dat deleted file mode 100644 index b6241bb5..00000000 --- a/test_transfert.dat +++ /dev/null @@ -1,2 +0,0 @@ -e00500000d038000002c800001f580003039 -e0060100a401038000002c800001f5800030390200010321a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7940268ac4c37ea0bc96c9c40ef33ace07a3034d650c43737fea9568b8c91da540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020200010c0200000080c3db7b00000000 diff --git a/tests/ledgercomm/test_pki_certificate_flex.dat b/tests/ledgercomm/test_pki_certificate_flex.dat new file mode 100644 index 00000000..21c6c5c6 --- /dev/null +++ b/tests/ledgercomm/test_pki_certificate_flex.dat @@ -0,0 +1 @@ +B0060400A601010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100CEF28780DCAFA3A485D83406D519F9AC12FD9B9C3AA7AE798896013F07DD178D022020F01B1AB1D2AAEDA70357F615EAC55E17FE94EC36DF9DE850CEFACBC98D16C8 \ No newline at end of file diff --git a/test_pki_certificate_nanosp.dat b/tests/ledgercomm/test_pki_certificate_nanosp.dat similarity index 56% rename from test_pki_certificate_nanosp.dat rename to tests/ledgercomm/test_pki_certificate_nanosp.dat index dceb931e..285aa7d4 100644 --- a/test_pki_certificate_nanosp.dat +++ b/tests/ledgercomm/test_pki_certificate_nanosp.dat @@ -1,3 +1,2 @@ -B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350103154630440220328886305590C895D119105849A87835BF531B26E646B815E0E8A5528DF480950220155747BAF14A26870B09622330F24DD120EB1AE1662C4A734E73C20395892F48 - +B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010315463044022057C6D3A3434F37700E5F65A4E64D3DE9F7E1BC27728DF32419ADF0CAD3DCB47D02202CB34838D915199956EFC0388E46EF7D1C8A7F26097D176AA75658423C324F39 diff --git a/test_pki_certificate_nanox.dat b/tests/ledgercomm/test_pki_certificate_nanox.dat similarity index 56% rename from test_pki_certificate_nanox.dat rename to tests/ledgercomm/test_pki_certificate_nanox.dat index 7b6b6da7..0532d9cf 100644 --- a/test_pki_certificate_nanox.dat +++ b/tests/ledgercomm/test_pki_certificate_nanox.dat @@ -1 +1 @@ -B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010215463044022034B002268EA97826A44E2704514CB0F8B70353DE4D465F50116A5CB3131E3C1E02202387F059A6F701361A960DB61D5749F25EE390C505A09DD4CBD868A1C4042A1C \ No newline at end of file +B0060400A501010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F653401013501021546304402207FCD665B94B43A6E838E8CD68BE52403D38A7E6A98E2CE291AB1C5D24A41101D02207AB1863E5CB127D9E8A680AC63FF2F2CBEA79CE76652A72832EF154BF1AD6477 \ No newline at end of file diff --git a/tests/ledgercomm/test_pki_certificate_stax.dat b/tests/ledgercomm/test_pki_certificate_stax.dat new file mode 100644 index 00000000..89a904a8 --- /dev/null +++ b/tests/ledgercomm/test_pki_certificate_stax.dat @@ -0,0 +1 @@ +B0060400A601010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221008F8FB0117C8D51F0D13A77680C18CA98B4B317C3D6C67F23BF9198410BEDF1A1022023B1052CA43E86E2411831990C64B1E027D85E142AD39F480948E3EF9517E55E \ No newline at end of file diff --git a/test_tlv_apdu.dat b/tests/ledgercomm/test_tlv_apdu.dat similarity index 100% rename from test_tlv_apdu.dat rename to tests/ledgercomm/test_tlv_apdu.dat diff --git a/tests/ledgercomm/test_transfert.dat b/tests/ledgercomm/test_transfert.dat new file mode 100644 index 00000000..e532f2f5 --- /dev/null +++ b/tests/ledgercomm/test_transfert.dat @@ -0,0 +1 @@ +e0060100A401038000002c800001f5800030390100010321a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a70f0af334a295c38d3daef5c7169223f3cd746492498b7eeed9dcdf4686bc84460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020200010c0200000040420f0000000000 \ No newline at end of file diff --git a/tests/ledgercomm/test_transfert_OK.dat b/tests/ledgercomm/test_transfert_OK.dat new file mode 100644 index 00000000..c8651966 --- /dev/null +++ b/tests/ledgercomm/test_transfert_OK.dat @@ -0,0 +1,2 @@ +e00500000d038000002c800001f580003039 +E0060100A401038000002C800001F5800030390200010321A36FE74E1234C35E62BFD700FD247B92C4D4E0E538401AC51F5C4AE97657A7940268AC4C37EA0BC96C9C40EF33ACE07A3034D650C43737FEA9568B8C91DA540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001020200010C0200000080C3DB7B00000000 diff --git a/tests/ledgercomm/test_transfert_SPL.dat b/tests/ledgercomm/test_transfert_SPL.dat new file mode 100644 index 00000000..316d3423 --- /dev/null +++ b/tests/ledgercomm/test_transfert_SPL.dat @@ -0,0 +1,3 @@ +e00601020E01038000002c800001f580003039 +e0060101F70100030621a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9dbc71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed120479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea332706ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9255d48dd25efecb25521c26432e1793bd1f2596054235663e9ae904251c94da7000000000000000000000000000000000000000000000000000000000000000001040501030205000a0c020000000000000006 + diff --git a/tests/ledgercomm/test_transfert_SPL_2.dat b/tests/ledgercomm/test_transfert_SPL_2.dat new file mode 100644 index 00000000..1c5cb53b --- /dev/null +++ b/tests/ledgercomm/test_transfert_SPL_2.dat @@ -0,0 +1,3 @@ +e00601020E01038000002c800001f580003039 +e0060101F70100030621a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9dbc71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed120479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea332706ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a938b19525b109c0e2517df8786389e33365afe2dc6bfabeb65458fd24a1ab5b13000000000000000000000000000000000000000000000000000000000000000001040501030205000a0c020000000000000006 + diff --git a/tests/python/apps/solana.py b/tests/python/apps/solana.py index 506595ca..1980bf23 100644 --- a/tests/python/apps/solana.py +++ b/tests/python/apps/solana.py @@ -94,13 +94,10 @@ class PKIClient: def __init__(self, client: BackendInterface) -> None: self._client = client - def send_certificate(self, payload: bytes) -> RAPDU: - try: - response = self.send_raw(payload) - assert response.status == StatusWord.OK - except ExceptionRAPDU as err: - if err.status == StatusWord.NOT_IMPLEMENTED: - print("Ledger-PKI APDU not yet implemented. Legacy path will be used") + def send_certificate(self, payload: bytes) -> RAPDU: + response = self.send_raw(payload) + assert response.status == StatusWord.OK + def send_raw(self, payload: bytes) -> RAPDU: header = bytearray() @@ -150,13 +147,13 @@ def provide_trusted_name(self, else: # pylint: disable=line-too-long if self._client.firmware == Firmware.NANOSP: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350103154630440220328886305590C895D119105849A87835BF531B26E646B815E0E8A5528DF480950220155747BAF14A26870B09622330F24DD120EB1AE1662C4A734E73C20395892F48" # noqa: E501 + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010315473045022100D494B106E217B46BB90BF20A4E9285529C4C8382D9B80FF462F74942579785F802202D68D0F85CD7CA36BDF351FD41332F310E93163BD175F6A92446C14A3329CC8B" # noqa: E501 elif self._client.firmware == Firmware.NANOX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010215463044022034B002268EA97826A44E2704514CB0F8B70353DE4D465F50116A5CB3131E3C1E02202387F059A6F701361A960DB61D5749F25EE390C505A09DD4CBD868A1C4042A1C" # noqa: E501 + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F653401013501021546304402207FCD665B94B43A6E838E8CD68BE52403D38A7E6A98E2CE291AB1C5D24A41101D02207AB1863E5CB127D9E8A680AC63FF2F2CBEA79CE76652A72832EF154BF1AD6477" # noqa: E501 elif self._client.firmware == Firmware.STAX: - cert_apdu = "01010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221009DCD14004A1C6F8A6A56F91FD253865F255E83FD316CB3E6B9AF585B12FBD78A02206DFA969336E82C93C1F2EF863CFAC19F88ECE1F38C900791FFFD46B9C9E02279" # noqa: E501 + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154730450221008F8FB0117C8D51F0D13A77680C18CA98B4B317C3D6C67F23BF9198410BEDF1A1022023B1052CA43E86E2411831990C64B1E027D85E142AD39F480948E3EF9517E55E" # noqa: E501 elif self._client.firmware == Firmware.FLEX: - cert_apdu = "01010102010111040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100A35942AD66FEBD1899C52BB3EE3A5CB3802C4C2BE6C6521EB590D32ADC152E380220210F7BAB9A62501134D513CFD127A72BA1EB0D9F956E3EC7E553BF460F505810" # noqa: E501 + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020004310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100CEF28780DCAFA3A485D83406D519F9AC12FD9B9C3AA7AE798896013F07DD178D022020F01B1AB1D2AAEDA70357F615EAC55E17FE94EC36DF9DE850CEFACBC98D16C8" # noqa: E501 # pylint: enable=line-too-long self._pki_client.send_certificate(bytes.fromhex(cert_apdu)) @@ -187,14 +184,13 @@ def send_public_key_with_confirm(self, derivation_path: bytes) -> bytes: yield - def split_and_prefix_message(self, derivation_path : bytes, message: bytes) -> List[bytes]: + def split_and_prefix_message(self, derivation_path: bytes, message: bytes) -> List[bytes]: assert len(message) <= 65535, "Message to send is too long" header: bytes = _extend_and_serialize_multiple_derivations_paths([derivation_path]) - # Check to see if this data needs to be split up and sent in chunks. - max_size = MAX_CHUNK_SIZE - len(header) + max_size = MAX_CHUNK_SIZE message_splited = [message[x:x + max_size] for x in range(0, len(message), max_size)] - # Add the header to every chunk - return [header + s for s in message_splited] + # The first chunk is the header, then all chunks with max size + return [header] + message_splited def send_first_message_batch(self, ins: INS, messages: List[bytes], p1: int) -> RAPDU: diff --git a/tests/python/snapshots/stax/test_solana_trusted_name/00000.png b/tests/python/snapshots/stax/test_solana_trusted_name/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..fc537864d2d3fccbc6cc2f49d9d3c852a4da8034 GIT binary patch literal 8809 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/stax/test_solana_trusted_name/00001.png b/tests/python/snapshots/stax/test_solana_trusted_name/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..9abb0498e8ccff828c8a6afba2395d6ecc00cacc GIT binary patch literal 21433 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

5cef$6IUa-e)NogW)fz#t^VdS-sz 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 W{c+E31XzZPA}gsRQU1<2@c#j`d)jIM literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/stax/test_solana_trusted_name/00003.png b/tests/python/snapshots/stax/test_solana_trusted_name/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..ae2149993f5e7f88e5ef1dc1a42843d6e8c1de1d GIT binary patch literal 5484 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 F@PEt{GQ+Q{4D3QJGXD}9Tqvv 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/stax/test_solana_trusted_name/00005.png b/tests/python/snapshots/stax/test_solana_trusted_name/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..392165d4fc71395ae212fb0ca017ebdd204c126b GIT binary patch literal 6218 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/stax/test_solana_trusted_name/00006.png b/tests/python/snapshots/stax/test_solana_trusted_name/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..c6586bd4522ea39d837077e9e0e6c749b221775c GIT binary patch literal 10815 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 literal 0 HcmV?d00001 diff --git a/tests/python/test_solana.py b/tests/python/test_solana.py index 57b3fc51..7fbea956 100644 --- a/tests/python/test_solana.py +++ b/tests/python/test_solana.py @@ -204,9 +204,12 @@ def test_ledger_sign_offchain_message_utf8_expert_refused(self, backend, scenari # Values used across Trusted Name test CHAIN_ID = 101 +# Token account address owner "7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE" ADDRESS = bytes.fromhex("606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b5") -TRUSTED_NAME = bytes.fromhex("276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9db") -SOURCE_CONTRACT = bytes.fromhex("c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61") +# Token account address "EQ96zptNAWwM23m5v2ByChCMTFu6zUmJgRtUrQV1uYNM" +TRUSTED_NAME = bytes.fromhex("c71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed12") +# SPL token address (JUP Token = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN") +SOURCE_CONTRACT = bytes.fromhex("0479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea3327") class TestTrustedName: @@ -220,6 +223,18 @@ def test_solana_trusted_name(self, backend, scenario_navigator): ADDRESS, CHAIN_ID, challenge=challenge) + + from_public_key = sol.get_public_key(SOL_PACKED_DERIVATION_PATH) + + # Create message + message: bytes = bytes.fromhex("0100030621a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9dbc71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed120479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea332706ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a938b19525b109c0e2517df8786389e33365afe2dc6bfabeb65458fd24a1ab5b13000000000000000000000000000000000000000000000000000000000000000001040501030205000a0c020000000000000006") + + with sol.send_async_sign_message(SOL_PACKED_DERIVATION_PATH, message): + scenario_navigator.review_approve(path=ROOT_SCREENSHOT_PATH) + + signature: bytes = sol.get_async_response().data + verify_signature(from_public_key, message, signature) + diff --git a/tools/rust/Cargo.lock b/tools/apdu_generator/Cargo.lock similarity index 99% rename from tools/rust/Cargo.lock rename to tools/apdu_generator/Cargo.lock index 592cdec0..9eb6b937 100644 --- a/tools/rust/Cargo.lock +++ b/tools/apdu_generator/Cargo.lock @@ -121,6 +121,16 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +[[package]] +name = "apdu_generator" +version = "0.1.0" +dependencies = [ + "hex", + "solana-client", + "solana-sdk", + "spl-token 7.0.0", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -2647,17 +2657,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rust" -version = "0.1.0" -dependencies = [ - "base64 0.22.1", - "bincode", - "hex", - "solana-client", - "solana-sdk", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3080,7 +3079,7 @@ dependencies = [ "solana-account-decoder-client-types", "solana-config-program", "solana-sdk", - "spl-token", + "spl-token 6.0.0", "spl-token-2022", "spl-token-group-interface", "spl-token-metadata-interface", @@ -4407,6 +4406,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror", +] + [[package]] name = "spl-token-2022" version = "4.0.0" @@ -4423,7 +4437,7 @@ dependencies = [ "solana-zk-token-sdk", "spl-memo", "spl-pod", - "spl-token", + "spl-token 6.0.0", "spl-token-group-interface", "spl-token-metadata-interface", "spl-transfer-hook-interface", diff --git a/tools/rust/Cargo.toml b/tools/apdu_generator/Cargo.toml similarity index 70% rename from tools/rust/Cargo.toml rename to tools/apdu_generator/Cargo.toml index 1db619af..a5430aaa 100644 --- a/tools/rust/Cargo.toml +++ b/tools/apdu_generator/Cargo.toml @@ -1,11 +1,10 @@ [package] -name = "rust" +name = "apdu_generator" version = "0.1.0" edition = "2021" [dependencies] -base64 = "0.22.1" -bincode = "1.3.3" hex = "0.4.3" solana-client = "2.1.0" solana-sdk = "2.1.0" +spl-token = "7.0.0" diff --git a/tools/apdu_generator/src/main.rs b/tools/apdu_generator/src/main.rs new file mode 100644 index 00000000..ebe74e51 --- /dev/null +++ b/tools/apdu_generator/src/main.rs @@ -0,0 +1,73 @@ +use solana_client::rpc_client::RpcClient; + +use solana_sdk::{ + message::Message, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +// Sender public key +const SENDER_PUB_KEY: &str = "3GJzvStsiYZonWE7WTsmt1BpWXkfcgWMGinaDwNs9HBc"; + +fn main() { + // Create a connection to the Solana devnet + let rpc_url = "https://api.devnet.solana.com"; + //let client = RpcClient::new_with_commitment(rpc_url.to_string(), CommitmentConfig::confirmed()); + let client = RpcClient::new(rpc_url.to_string()); + + // Get a recent blockhash + let _recent_blockhash = client.get_latest_blockhash().unwrap(); + + // Generate a new keypair for the sender (for demonstration purposes) + let sender_pubkey = Pubkey::from_str_const(SENDER_PUB_KEY); + //println!("Sender Public Key: {}", sender_pubkey); + + // Generate a new keypair for the recipient (for demonstration purposes) + let recipient = Keypair::new(); + //println!("Recipient Public Key: {}", recipient.pubkey()); + + // Create a SOL transfer instruction + println!("############################"); + println!("# SOL Transfer #"); + println!("############################"); + let transfer_instruction = system_instruction::transfer( + &sender_pubkey, + &recipient.pubkey(), + 1_000_000, // Transfer 1,000,000 lamports (0.001 SOL) + ); + let message = Message::new(&[transfer_instruction], Some(&sender_pubkey)); + println!("Message: {}", hex::encode(message.serialize())); + //let transaction = Transaction::new_unsigned(message); + //println!("Transaction: {:?}", transaction); + + // Create a SPL token transfer instruction + + // Generate a new keypair for the mint authority (for demonstration purposes) + let mint_authority = Keypair::new(); + let mint = Pubkey::from_str_const("JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"); + let recipient_token_account = + Pubkey::from_str_const("EQ96zptNAWwM23m5v2ByChCMTFu6zUmJgRtUrQV1uYNM"); + let sender_token_account = + Pubkey::from_str_const("3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa"); + + println!("############################"); + println!("# SPL Transfer #"); + println!("############################"); + let transfer_instruction = spl_token::instruction::transfer_checked( + &spl_token::ID, + &sender_token_account, + &mint, + &recipient_token_account, + &mint_authority.pubkey(), + &[&sender_pubkey], + 2, + 6, + ) + .unwrap(); + let message = Message::new(&[transfer_instruction], Some(&sender_pubkey)); + println!("Message: {}", hex::encode(message.serialize())); + //let transaction = Transaction::new_unsigned(message); + //println!("Transaction: {:?}", transaction); +} diff --git a/tools/rust/target/.rustc_info.json b/tools/apdu_generator/target/.rustc_info.json similarity index 100% rename from tools/rust/target/.rustc_info.json rename to tools/apdu_generator/target/.rustc_info.json diff --git a/tools/rust/target/CACHEDIR.TAG b/tools/apdu_generator/target/CACHEDIR.TAG similarity index 100% rename from tools/rust/target/CACHEDIR.TAG rename to tools/apdu_generator/target/CACHEDIR.TAG diff --git a/tools/rust/src/main.rs b/tools/rust/src/main.rs deleted file mode 100644 index e1c644ea..00000000 --- a/tools/rust/src/main.rs +++ /dev/null @@ -1,180 +0,0 @@ -// use base64; -//use solana_sdk::{ -// client::SyncClient, -// commitment_config::CommitmentConfig, -// message::Message, -// pubkey::Pubkey, -// signature::{Keypair, Signer}, -// system_instruction, -// transaction::Transaction, -// }; - -use solana_client::rpc_client::RpcClient; - -use solana_sdk::{ - message::Message, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, -}; - -fn main() { - // Create a connection to the Solana devnet - let rpc_url = "https://api.devnet.solana.com"; - //let client = RpcClient::new_with_commitment(rpc_url.to_string(), CommitmentConfig::confirmed()); - let client = RpcClient::new(rpc_url.to_string()); - - // Get a recent blockhash - let recent_blockhash = client.get_latest_blockhash().unwrap(); - - // Generate a new keypair for the sender (for demonstration purposes) - let sender = Keypair::new(); - - // Generate a new keypair for the recipient (for demonstration purposes) - let recipient = Keypair::new(); - - // print the sender and recipient public keys - println!("Sender Public Key: {}", sender.pubkey()); - println!("Recipient Public Key: {}", recipient.pubkey()); - - // Create a transfer instruction - let transfer_instruction = system_instruction::transfer( - &sender.pubkey(), - &recipient.pubkey(), - 1_000_000, // Transfer 1,000,000 lamports (0.001 SOL) - ); - - // Create a transaction - let message = Message::new(&[transfer_instruction], Some(&sender.pubkey())); - - // Print message serialize - println!("Message: {}", hex::encode(message.serialize())); - - let mut transaction = Transaction::new_unsigned(message); - transaction.try_sign(&[&sender], recent_blockhash).unwrap(); - - // Display the transaction - println!("Transaction: {:?}", transaction); - - // Serialize the transaction - // let serialized_transaction = bincode::serialize(&transaction).unwrap(); - - // Convert the serialized transaction to a hexadecimal string - // let hex_dump = hex::encode(&serialized_transaction); - - // Convert the serialized transaction to a base64 string - // let base64_dump = base64::encode(&serialized_transaction); - - // println!("Serialized Transaction (Hex): {}", hex_dump); - // println!("Serialized Transaction (Base64): {}", base64_dump); - - // Optionally, send the serialized transaction - // let signature = client.send_transaction(&transaction).unwrap(); - // client.confirm_transaction(&signature).unwrap(); - - // println!("Transaction signature: {}", signature); -} - -// use solana_sdk::{ -// client::SyncClient, -// commitment_config::CommitmentConfig, -// message::Message, -// pubkey::Pubkey, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; -// use solana_client::rpc_client::RpcClient; -// use spl_token::instruction::transfer; -// use spl_token::state::Account as TokenAccount; -// use base64; - -// fn main() { -// // Create a connection to the Solana devnet -// let rpc_url = "https://api.devnet.solana.com"; -// let client = RpcClient::new_with_commitment(rpc_url.to_string(), CommitmentConfig::confirmed()); - -// // Generate a new keypair for the sender (for demonstration purposes) -// let sender = Keypair::new(); - -// // Generate a new keypair for the recipient (for demonstration purposes) -// let recipient = Keypair::new(); - -// // Generate a new keypair for the mint authority (for demonstration purposes) -// let mint_authority = Keypair::new(); - -// // Airdrop some SOL to the sender's account (for demonstration purposes) -// let airdrop_amount = 1_000_000_000; // 1 SOL in lamports -// let airdrop_signature = client.request_airdrop(&sender.pubkey(), airdrop_amount).unwrap(); -// client.confirm_transaction(&airdrop_signature).unwrap(); - -// // Create a new mint -// let mint = spl_token::state::Mint::new( -// &client, -// &mint_authority, -// &sender.pubkey(), -// None, -// 9, // Decimals -// ).unwrap(); - -// // Create associated token accounts for the sender and recipient -// let sender_token_account = spl_token::state::Account::new( -// &client, -// &mint.pubkey(), -// &sender.pubkey(), -// &sender, -// ).unwrap(); - -// let recipient_token_account = spl_token::state::Account::new( -// &client, -// &mint.pubkey(), -// &recipient.pubkey(), -// &sender, -// ).unwrap(); - -// // Mint some tokens to the sender's token account -// let mint_amount = 1_000_000_000; // 1 token with 9 decimals -// spl_token::instruction::mint_to( -// &client, -// &mint.pubkey(), -// &sender_token_account.pubkey(), -// &mint_authority.pubkey(), -// &mint_authority, -// mint_amount, -// ).unwrap(); - -// // Get a recent blockhash -// let recent_blockhash = client.get_recent_blockhash().unwrap().0; - -// // Create a transfer instruction -// let transfer_instruction = transfer( -// &spl_token::id(), -// &sender_token_account.pubkey(), -// &recipient_token_account.pubkey(), -// &sender.pubkey(), -// &[], -// 500_000_000, // Transfer 0.5 tokens with 9 decimals -// ).unwrap(); - -// // Create a transaction -// let message = Message::new(&[transfer_instruction], Some(&sender.pubkey())); -// let mut transaction = Transaction::new_unsigned(message); -// transaction.try_sign(&[&sender], recent_blockhash).unwrap(); - -// // Serialize the transaction -// let serialized_transaction = bincode::serialize(&transaction).unwrap(); - -// // Convert the serialized transaction to a hexadecimal string -// let hex_dump = hex::encode(&serialized_transaction); - -// // Convert the serialized transaction to a base64 string -// let base64_dump = base64::encode(&serialized_transaction); - -// println!("Serialized Transaction (Hex): {}", hex_dump); -// println!("Serialized Transaction (Base64): {}", base64_dump); - -// // Optionally, send the serialized transaction -// let signature = client.send_transaction(&transaction).unwrap(); -// client.confirm_transaction(&signature).unwrap(); - -// println!("Transaction signature: {}", signature); -// } From b28d809b530ab6928b4a2d92a2e3c63a42c1ae04 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 13 Nov 2024 08:27:39 +0100 Subject: [PATCH 04/17] Ragger tests Stax/Flex OK --- src/handle_provide_trusted_info.c | 12 ++++++++- src/handle_provide_trusted_info.h | 13 ---------- src/ledger_pki.c | 23 ++++++++++++++++-- .../flex/test_solana_trusted_name/00000.png | Bin 0 -> 9364 bytes .../flex/test_solana_trusted_name/00001.png | Bin 0 -> 23605 bytes .../flex/test_solana_trusted_name/00002.png | Bin 0 -> 24842 bytes .../flex/test_solana_trusted_name/00003.png | Bin 0 -> 15560 bytes .../flex/test_solana_trusted_name/00004.png | Bin 0 -> 12223 bytes .../flex/test_solana_trusted_name/00005.png | Bin 0 -> 6357 bytes .../flex/test_solana_trusted_name/00006.png | Bin 0 -> 12350 bytes 10 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00000.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00001.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00002.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00003.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00004.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00005.png create mode 100644 tests/python/snapshots/flex/test_solana_trusted_name/00006.png diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index e66e28fc..635abb59 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -10,10 +10,16 @@ #include "sol/printer.h" +#ifdef HAVE_LEDGER_PKI #include "os_pki.h" +#endif #include "ledger_pki.h" +#define MAX_ADDRESS_LENGTH 32 +#define TYPE_ADDRESS 0x06 +#define TYPE_DYN_RESOLVER 0x06 + #define STRUCT_TYPE_TRUSTED_NAME 0x03 #define ALGO_SECP256K1 1 @@ -504,7 +510,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK( cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); - +#ifdef HAVE_LEDGER_PKI CX_CHECK(check_signature_with_pubkey("Trusted Name", hash, sizeof(hash), @@ -513,6 +519,10 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { sig_ctx->input_sig_size)); ret_code = true; +#else // HAVE_LEDGER_PKI + PRINTF("Error: Ledger PKI not available\n"); + ret_code = false; +#endif end: return ret_code; } diff --git a/src/handle_provide_trusted_info.h b/src/handle_provide_trusted_info.h index 98af1b1d..0aa0eb32 100644 --- a/src/handle_provide_trusted_info.h +++ b/src/handle_provide_trusted_info.h @@ -1,19 +1,6 @@ #ifndef TRUSTED_INFO_H_ #define TRUSTED_INFO_H_ -#include -#include - -#include "sol/parser.h" - -#define MAX_ADDRESS_LENGTH 32 - -#define TYPE_ADDRESS 0x06 -#define TYPE_DYN_RESOLVER 0x06 - -bool has_trusted_info(uint8_t types_count, - const uint64_t *chain_id, - const uint8_t *addr); void handle_provide_trusted_info(void); extern Pubkey g_trusted_token_account_owner_pubkey; diff --git a/src/ledger_pki.c b/src/ledger_pki.c index 2d467dc5..3865095c 100644 --- a/src/ledger_pki.c +++ b/src/ledger_pki.c @@ -1,6 +1,7 @@ #include "apdu.h" #include "ledger_pki.h" -#include "cx.h" +#include "cx.h" +#ifdef HAVE_LEDGER_PKI #include "os_pki.h" #define KEY_USAGE_STR(x) \ @@ -55,4 +56,22 @@ int check_signature_with_pubkey(const char *tag, error = CX_OK; end: return error; -} \ No newline at end of file +} + +#else // HAVE_LEDGER_PKI +int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t keyUsageExp, + uint8_t *signature, + const uint8_t sigLen) { + UNUSED(tag); + UNUSED(buffer); + UNUSED(bufLen); + UNUSED(keyUsageExp); + UNUSED(signature); + UNUSED(sigLen); + PRINTF("Error: Ledger PKI not available\n"); + return CX_INTERNAL_ERROR; +} +#endif // HAVE_LEDGER_PKI \ No newline at end of file diff --git a/tests/python/snapshots/flex/test_solana_trusted_name/00000.png b/tests/python/snapshots/flex/test_solana_trusted_name/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..04dcd94e137dc668bc9f13b9f90b8442ac72cf38 GIT binary patch literal 9364 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

}l+G>D| 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/flex/test_solana_trusted_name/00002.png b/tests/python/snapshots/flex/test_solana_trusted_name/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..7778b87f333296e74ed2bc50cf9f3ccfd81cb916 GIT binary patch literal 24842 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/flex/test_solana_trusted_name/00005.png b/tests/python/snapshots/flex/test_solana_trusted_name/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..be51a9d5595cf5ea25f8f90b684306d30395f329 GIT binary patch literal 6357 zcmeHM`&*J}w>D=cGc!A?<>~92sjNn`H1m{nGN-9DGtY`yjS?9uCa9b;D;pi9K1;_V zrqfuGQW+s4xXm##QZyt|PMHx3A_^fQr~NkjKiJp4_D}Qv!o_>wUC+Ajb+3Cp{CYAh z)OPvCz?nVF#!w3j$J(QZ51h`eRS4xdV~M?O5l@+X zi){xym;8KXO{Vq9tJ{`TT5R^)yx;ny<()G>zcSsM^ZH_aYnPQA5hUGNbSCy=X57ub zk32q~5Al&%tom#w@3XK7TMM~z($aR-&kaisTKnvGFIc*4^N_{8Z#Vwy&i-$%t@-ET zKS}t93IB_7c<{BlI^IIbV+usgKx+Hwv{o;KAs0xE?!}Fh2pS!n;pO-xpKi~zj#&#~ zRPlH`E|eVKx^b|buXqhM>(tFbzj!(RcBE+-GNM3qpS_c5w=!#XU%GG2c;+Eks#YNMCXd>N-vdYRz<|Ug%#s7#*{&B0lI^9KiBEz=^+pWCi6Y*{JI=zu0R=O!gjIOS93cu$}CTYjU(j#(Bevm6K zOsqfvuLJWeDQh98RuuJ41OVZWrX#d+8G@$Pp@Rv$Fdn3Fna}D!ITsYKj!^hQ7=@{) zB7I!(6#gYehdQ;rDy$h#JJnIUpThv*OkE5{bodm4Cf9VPi2CU3LY{z07fZ1iOwy0` zcm{Og)_%@YBNo@iT-=l6dAGE!&aWy_yINa ztig8=KOQJ_FvR4b+rbCwtU`5jp#%-S|wUM3ezUCyV2do}M&@=qJh zvk=P@Hc-^iUe8|fbYdNzCx$rwXLRV{-0azW?0Y(c zVKN!@kwqKZzP{|C%Ua4)m)2E~_>=PKBIPOugHa*J)f>VdWyfUY)ZvRhIr;!s-`>sf z#4#QZ?|rx7;4+^nsM~hk<6+qw(4mH-6aY@;zkPk;>vWaNd^{e|cPxx2WIFgRmgTf1 zy>h_y+T8iJ+CFht=*Qk8Vx(ACoVO(t`8Do`^x47@+fs)9cInt(QbhNWD{cTtJzN4O zkT*$lLz-T*177$8cf#U|C(k!2O>G|>NcNUnt$jTFz{Qi1ZrniFWv(Jeq|}nn4b3-P zxDMbJ-{erz*NinLHYs;EwfU;YX1p)0hKxlJMeCDy(RiTflr48?b0i^=?NK1esNSjyFY{F5^Ury8cO3yie? zvXf))EG;Yu;Mf=WK~A)`61gp!jEY6IG+d$Rp_!LlVOjgM`kUT9>_7kZ-I;*8L2Nfk z5$q6>Vp{641~PV<4-zU6F3ji3Pq3xw_DO&?7M^fJ>gD7aH7*F5L92CNNf z=s)G#IbWYLb!)2c?A*gbSH01s(P*?v@mIZT?oS4T(TcqVZwj}J5J0#x&{#~=y1p}B zlNz7^Nbbe5!3>?t4k8!YKKdw{c*ADfR$VD`A`tI7bD*I=%Cl^)<5%axo(~GeK#J{I z|Gy5j!6<hm zQ_(mafh~=>lkesDCbhjAXa3n+eDmB8I!5AjrDoty!ltTn8O=t5HK}2b{^U4F})>rd>HV^v8RpmTd;uvX$*!Gw_=C9B9?P zH5i3Og4&x>Js9q{be}8Us<3BnipZ6nEEtA-$})SbSX!t+&_>gNY=`?V*F}E4aoJ_* z8z&4I8Q;}l^6V7O^mlidpA)EDzrU8Ol7&tm5Cd!r=(?@}C_R%EzNMTCjjE5uRO-%9 z_#XBpe=q0tg;OCBz;DmxqGyVIYX;=$!(6hexfMd7m#`PVioUe#3grCv5`5x=QS3msZY49A91dDrfou2 z*SJLD({;L2=^>tu)UvK8(8Wrih@j*an2N%+zY~F&(QttH_acZInb$VmG*@&TKRqZ{02btkxC9JOh)&VljJ< zM6mfz1?!hXzX4>WCU@n3;u2v$NppkR>bl1}p@&*Ue$pF2U#;0|03QCdQzWl2&%V@6 z8{z%Y1k~F5?!|DFUGoUc90&stg>{I5;;P0O1zQ071Q-v3|3Fy7PI~vnf?%v;6k9Os zZl2wgfO_GRJV=$k>0kY>wpM~+y}~nbVV8DisH;HhCn*%lF<%3q%5c_R+6-2gNvyF8 zujHc^(y|*!BH4}^ZOdoORWNDm5Qybb5FB)~q|p)2lDu7Ycx~}>C zz^84@Wj{585?xsCW{=J5b#oEU5NBQ z@=NG{AKby&=q%Ms|FRIpFDD|_0XFf|bwc_V1qIzsR91d&ZByh{BqRk~qs7nOu<6bx zUZkK&yc)KY1%#0JZso~Z0|(5%2BYW!Lcw07Sa31f1tzU<&7|tW<3vwTkhDMPhV0P% z!dyN&gxq{s(VuDftrh&DUwVlA9nx7R?#21^K!xJ-#?$;V^%z* z`}qa;ehq{s*h${e8e-0ED$|ZSSz>A=0 zI!UqgiuN&I5f;E?5qsgiOvaE>Tif<@`VYmVYl?8WCX+aUG5`Jn?8RognjJ8m^4M3{ zGxAbhiLO6TXNp%!{TbJw%LWynL1#a4>3`gid*GLq9%<4q?Ofc>7-y$xURDjHN<9so z35-#$_E>Lp46@V7Q>{AWEcLvXLL_QYz0s$Wv2}XQjS~x1MSgDz881uSHuxQHlcArz z1^2FZsjp&Ip2WDvY_$}%<$WsBc-4TSb`jXDi5HYd=W?bWS4jkqveSssPsb~$GZh*0 zH}w*)8}L&?YJ1YcO*)Kdr$wpJ9WwEMWN#lj1gBSvLkuxhR>n-g)z;deXD6>?LYszD z-pXMVr((Aml$0rqo2=S5gl zi8~D`YHx?Q^^>8a3IyP?R|p)EbEweSOut7fQ=h~-o8kt8{Ixf`VV}6(IAi{5?s0T% zXQTV;VeDK|_Jk2Wt=bQQZ7v+Ul$+AD6a8JB#@pds=FN#sfO+6>B6Sf@Cd`*iLHwjU zEP1VdM11ziq*l*8<@_vIB|rU5-Lyid|I4i7>V*p*56wPIHZ&eVrP|q(Z!83m8snR^|lnLOPXrrv<<3{ zJmTtWi%isfvEoj}4%_G$0B*M&)^zK%b6j)YS} zpzi^o5$<(bOGW1dO0AvnTC61| zt+Gpo2AsOU0+_ylp()d^_V^ZQ{gbU}iGpC2%;$afhL)8N=iwclI}v@yR5EgSGpD>} zc5yMj&eM38vxLM*u8zX%qIr9IeygirKxCgyKf9t(9b`8%&9 zIy@CCx0d&h-+{Z_AKUEQa=Kpkcw-J{DWQ8_7I9T&Nz_kQK0+ZwW5hcLpyE>7S1dus*&>V`ZInww>hN#kBueJH{OgFrFbCL}Ehm~dyW zutBdv>460E1EhMpKbZ+QJjvD?qB4 zH)E`Sdz4jP--{aZu1ctziopZAAVA;Vf<3%0z@5d{5$Llvl*I+CQj@B^w``> z@5{#PLai2+WG&0XX1VZ^A@f(V*?iAoGoDKbYdg3O)fD(wA)EYC;F#-?i=2&j} z)|hUQNQC{o{fFd<*ADcw8rBTRI*7~3_eL{_o?i^l<4Yjlt$5QWbQ#2!h z3x|uqd539+S#S<}@kQTn%f=mj&>51no1Sq&|1~VlVD5q}h&qKZ^_#vyT=GHEptx)w zWC3~S;&G%Y;ayYhpZ5AaHt1KtUC6{I|Mu>8{%G;fHs?Qkz5i@@|6lF;n?M!e>X<;t UPsf12D=dzNgdJ`>c;@PV1L0-a-2eap literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/flex/test_solana_trusted_name/00006.png b/tests/python/snapshots/flex/test_solana_trusted_name/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..34a975b56a4d758c1b5c8498ad5abae3b6b44010 GIT binary patch literal 12350 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 literal 0 HcmV?d00001 From 736881c52d4fd219e6c03cb340dbc2edcd541a18 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 13 Nov 2024 13:04:53 +0100 Subject: [PATCH 05/17] Remove HAVE_LEDGER_PKI as it is useless (all devices should support PKI except Nano S) --- src/handle_provide_trusted_info.c | 8 +------- src/ledger_pki.c | 21 +-------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index 635abb59..9cab3f69 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -10,9 +10,7 @@ #include "sol/printer.h" -#ifdef HAVE_LEDGER_PKI #include "os_pki.h" -#endif #include "ledger_pki.h" @@ -510,7 +508,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK( cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); -#ifdef HAVE_LEDGER_PKI + CX_CHECK(check_signature_with_pubkey("Trusted Name", hash, sizeof(hash), @@ -519,10 +517,6 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { sig_ctx->input_sig_size)); ret_code = true; -#else // HAVE_LEDGER_PKI - PRINTF("Error: Ledger PKI not available\n"); - ret_code = false; -#endif end: return ret_code; } diff --git a/src/ledger_pki.c b/src/ledger_pki.c index 3865095c..91192281 100644 --- a/src/ledger_pki.c +++ b/src/ledger_pki.c @@ -1,7 +1,6 @@ #include "apdu.h" #include "ledger_pki.h" #include "cx.h" -#ifdef HAVE_LEDGER_PKI #include "os_pki.h" #define KEY_USAGE_STR(x) \ @@ -56,22 +55,4 @@ int check_signature_with_pubkey(const char *tag, error = CX_OK; end: return error; -} - -#else // HAVE_LEDGER_PKI -int check_signature_with_pubkey(const char *tag, - uint8_t *buffer, - const uint8_t bufLen, - const uint8_t keyUsageExp, - uint8_t *signature, - const uint8_t sigLen) { - UNUSED(tag); - UNUSED(buffer); - UNUSED(bufLen); - UNUSED(keyUsageExp); - UNUSED(signature); - UNUSED(sigLen); - PRINTF("Error: Ledger PKI not available\n"); - return CX_INTERNAL_ERROR; -} -#endif // HAVE_LEDGER_PKI \ No newline at end of file +} \ No newline at end of file From 6a63c1c06a8b11c7a60d42884eb915d7d2cfb69a Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 14 Nov 2024 13:09:47 +0100 Subject: [PATCH 06/17] All addresses from Trusted Name descriptor are base58 encoded --- libsol/spl_token_instruction.c | 4 ++-- src/handle_provide_trusted_info.c | 29 ++++++++++------------------- src/handle_provide_trusted_info.h | 4 +++- tests/python/test_solana.py | 18 +++++++++--------- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/libsol/spl_token_instruction.c b/libsol/spl_token_instruction.c index 4869f461..93298d4c 100644 --- a/libsol/spl_token_instruction.c +++ b/libsol/spl_token_instruction.c @@ -484,7 +484,7 @@ static int print_spl_token_initialize_multisig_info(const char* primary_title, return 0; } -extern Pubkey g_trusted_token_account_owner_pubkey; +extern uint8_t g_trusted_token_account_owner_pubkey[BASE58_PUBKEY_LENGTH]; extern bool g_trusted_token_account_owner_pubkey_set; int print_spl_token_transfer_info(const SplTokenTransferInfo* info, @@ -507,7 +507,7 @@ int print_spl_token_transfer_info(const SplTokenTransferInfo* info, if (g_trusted_token_account_owner_pubkey_set) { item = transaction_summary_general_item(); - summary_item_set_pubkey(item, "To", &g_trusted_token_account_owner_pubkey); + summary_item_set_string(item, "To", (char *)g_trusted_token_account_owner_pubkey); } item = transaction_summary_general_item(); diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index 9cab3f69..17a3118b 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -14,7 +14,6 @@ #include "ledger_pki.h" -#define MAX_ADDRESS_LENGTH 32 #define TYPE_ADDRESS 0x06 #define TYPE_DYN_RESOLVER 0x06 @@ -126,9 +125,9 @@ typedef struct { uint32_t rcv_flags; bool valid; uint8_t struct_version; - uint8_t token_account[MAX_ADDRESS_LENGTH]; + uint8_t token_account[MAX_ADDRESS_LENGTH + 1]; uint8_t* owner; - uint8_t spl_token[MAX_ADDRESS_LENGTH]; + uint8_t spl_token[MAX_ADDRESS_LENGTH + 1]; uint64_t chain_id; uint8_t name_type; uint8_t name_source; @@ -154,7 +153,7 @@ typedef struct { static s_tlv_payload g_tlv_payload = {0}; static s_trusted_name_info g_trusted_name_info = {0}; -Pubkey g_trusted_token_account_owner_pubkey = {0}; +uint8_t g_trusted_token_account_owner_pubkey[MAX_ADDRESS_LENGTH + 1] = {0}; bool g_trusted_token_account_owner_pubkey_set = false; /** @@ -390,7 +389,7 @@ static bool handle_address(const s_tlv_data *data, return false; } memcpy(trusted_name_info->owner, data->value, data->length); - //trusted_name_info->owner[data->length] = '\0'; + trusted_name_info->owner[data->length] = '\0'; return true; } @@ -508,7 +507,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK( cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); - + CX_CHECK(check_signature_with_pubkey("Trusted Name", hash, sizeof(hash), @@ -817,28 +816,20 @@ void handle_provide_trusted_info(void) { // everything has been received if (g_tlv_payload.size == g_tlv_payload.expected_size) { - g_trusted_name_info.owner = g_trusted_token_account_owner_pubkey.data; + g_trusted_name_info.owner = g_trusted_token_account_owner_pubkey; g_trusted_token_account_owner_pubkey_set = true; if (!parse_tlv(&g_tlv_payload, &g_trusted_name_info, &sig_ctx) || !verify_signature(&sig_ctx)) { free_payload(&g_tlv_payload); roll_challenge(); // prevent brute-force guesses g_trusted_name_info.rcv_flags = 0; - memset(g_trusted_token_account_owner_pubkey.data, 0, sizeof(g_trusted_token_account_owner_pubkey.data)); + memset(g_trusted_token_account_owner_pubkey, 0, sizeof(g_trusted_token_account_owner_pubkey)); g_trusted_token_account_owner_pubkey_set = false; THROW(ApduReplySolanaInvalidTrustedInfo); } -#ifdef DEBUG - { - char token_account[45]; - char owner[45]; - - encode_base58(g_trusted_name_info.owner, 32, owner, sizeof(owner)); - encode_base58(g_trusted_name_info.token_account, 32, token_account, sizeof(token_account)); - - PRINTF("Token account : %s owned by %s\n", token_account,owner); - } -#endif // DEBUG + + PRINTF("Token account : %s owned by %s\n", g_trusted_name_info.token_account, g_trusted_token_account_owner_pubkey); + free_payload(&g_tlv_payload); roll_challenge(); // prevent replays THROW(ApduReplySuccess); diff --git a/src/handle_provide_trusted_info.h b/src/handle_provide_trusted_info.h index 0aa0eb32..f8b8d1b8 100644 --- a/src/handle_provide_trusted_info.h +++ b/src/handle_provide_trusted_info.h @@ -3,7 +3,9 @@ void handle_provide_trusted_info(void); -extern Pubkey g_trusted_token_account_owner_pubkey; +#define MAX_ADDRESS_LENGTH 44 + +extern uint8_t g_trusted_token_account_owner_pubkey[MAX_ADDRESS_LENGTH + 1]; extern bool g_trusted_token_account_owner_pubkey_set; #endif // TRUSTED_INFO_H_ \ No newline at end of file diff --git a/tests/python/test_solana.py b/tests/python/test_solana.py index 7fbea956..6a315d1d 100644 --- a/tests/python/test_solana.py +++ b/tests/python/test_solana.py @@ -204,12 +204,12 @@ def test_ledger_sign_offchain_message_utf8_expert_refused(self, backend, scenari # Values used across Trusted Name test CHAIN_ID = 101 -# Token account address owner "7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE" -ADDRESS = bytes.fromhex("606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b5") -# Token account address "EQ96zptNAWwM23m5v2ByChCMTFu6zUmJgRtUrQV1uYNM" -TRUSTED_NAME = bytes.fromhex("c71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed12") -# SPL token address (JUP Token = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN") -SOURCE_CONTRACT = bytes.fromhex("0479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea3327") +# Token account address owner +ADDRESS = "7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE" +# Token account address +TRUSTED_NAME = "EQ96zptNAWwM23m5v2ByChCMTFu6zUmJgRtUrQV1uYNM" +# SPL token address (JUP Token) +SOURCE_CONTRACT = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" class TestTrustedName: @@ -218,9 +218,9 @@ def test_solana_trusted_name(self, backend, scenario_navigator): challenge = sol.get_challenge() - sol.provide_trusted_name(SOURCE_CONTRACT, - TRUSTED_NAME, - ADDRESS, + sol.provide_trusted_name(bytes(SOURCE_CONTRACT, 'utf-8'), + bytes(TRUSTED_NAME, 'utf-8'), + bytes(ADDRESS, 'utf-8'), CHAIN_ID, challenge=challenge) From 3ec5eb57aab8a624db0753819a45fed0c948eead Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 15 Nov 2024 10:16:38 +0100 Subject: [PATCH 07/17] Update doc --- Makefile | 4 +-- doc/api.md | 49 +++++++++++++++++++++++++++++++ src/handle_provide_trusted_info.c | 2 +- tests/python/test_solana.py | 2 +- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 4867a57f..26df3a24 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,8 @@ APPNAME = "Solana" # Application version APPVERSION_M = 1 -APPVERSION_N = 5 -APPVERSION_P = 6 +APPVERSION_N = 6 +APPVERSION_P = 0 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" # Application source files diff --git a/doc/api.md b/doc/api.md index 088a5b99..cc7c9138 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1,5 +1,9 @@ # Solana application : Common Technical Specifications +## 1.4.0 + +- Add support of Trusted Name descriptor (checked by PKI certificate) + ## 1.3.1 - Add support for versioned messages @@ -134,6 +138,51 @@ _This command signs a Solana Off-Chain Message after having the user validate th | ------------- | :------: | | Signature | 64 | +### GET CHALLENGE + +#### Description + +_This command returns a 32-bit challenge generated by the app + +##### Command + +| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _Le_ | +| ----- | :---: | ---: | ---- | :------: | -------: | +| E0 | 20 | 00 | 00 | 00 | N/A | + +##### Input data + +N/A + +##### Output data + +| _Description_ | _Length_ | +| ------------- | :------: | +| Challenge | 4 | + +### PROVIDE TRUSTED NAME TLV DESCRIPTOR + +#### Description + +_This command provides a [Solana Trusted Name TLV descriptor](https://ledgerhq.atlassian.net/wiki/spaces/BE/pages/5123145859/Solana+token+account+ownership) + +##### Command + +| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _Le_ | +| ----- | :---: | ---: | ---- | :------: | -------: | +| E0 | 20 | 00 | 00 | F7 (max) | variable | + +##### Input data + +| _Description_ | _Length_ | +| --------------------------------------------------- | :------: | +| Serialized signed TLV descriptor payload | variable | + + +##### Output data + +N/A + ## Transport protocol ### General transport description diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index 17a3118b..a40dcf6f 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -48,7 +48,7 @@ typedef enum { /* trusted_name_descriptor = tlv(TAG_STRUCTURE_TYPE, u8(TYPE_TRUSTED_NAME)) 3 bytes + & tlv(TAG_VERSION, u8(0x02)) 3 bytes + - & tlv(TAG_TRUSTED_NAME_TYPE, 0x04) 3 bytes + + & tlv(TAG_TRUSTED_NAME_TYPE, 0x06) 3 bytes + & tlv(TAG_TRUSTED_NAME_SOURCE, 0x06) 3 bytes + & tlv(TAG_TRUSTED_NAME, trusted_name) 2 + 44 bytes + & tlv(TAG_CHAIN_ID, chain_id) 2 + 8 bytes + diff --git a/tests/python/test_solana.py b/tests/python/test_solana.py index 6a315d1d..2bc64530 100644 --- a/tests/python/test_solana.py +++ b/tests/python/test_solana.py @@ -226,7 +226,7 @@ def test_solana_trusted_name(self, backend, scenario_navigator): from_public_key = sol.get_public_key(SOL_PACKED_DERIVATION_PATH) - # Create message + # Create message (SPL Token transfer) message: bytes = bytes.fromhex("0100030621a36fe74e1234c35e62bfd700fd247b92c4d4e0e538401ac51f5c4ae97657a7276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9dbc71573813ea96479a79e579af14646413602b9b3dcbdc51cbf8e064b5685ed120479d9c7cc1035de7211f99eb48c09d70b2bdf5bdf9e2e56b8a1fbb5a2ea332706ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a938b19525b109c0e2517df8786389e33365afe2dc6bfabeb65458fd24a1ab5b13000000000000000000000000000000000000000000000000000000000000000001040501030205000a0c020000000000000006") with sol.send_async_sign_message(SOL_PACKED_DERIVATION_PATH, message): From a9aded6f242ea3393359468184fdb61d9c47aeec Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 18 Nov 2024 10:28:31 +0100 Subject: [PATCH 08/17] Disable DEBUG mode --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 26df3a24..2dc54287 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ VARIANT_PARAM = COIN VARIANT_VALUES = solana # Enabling DEBUG flag will enable PRINTF and disable optimizations -DEBUG = 1 +# DEBUG = 1 ######################################## # Application custom permissions # From 2d48e47e032b2f0304e315096e849f19f28b7004 Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 18 Nov 2024 18:33:06 +0100 Subject: [PATCH 09/17] Fix lint issues --- .github/workflows/lint-workflow.yml | 2 +- libsol/spl_token_instruction.c | 2 +- src/apdu.c | 21 +- src/handle_provide_trusted_info.c | 87 ++--- src/ledger_pki.c | 7 +- src/main.c | 6 +- tests/Cargo.lock | 479 +++++++--------------------- 7 files changed, 179 insertions(+), 425 deletions(-) diff --git a/.github/workflows/lint-workflow.yml b/.github/workflows/lint-workflow.yml index 20715e25..dbcbbc4b 100644 --- a/.github/workflows/lint-workflow.yml +++ b/.github/workflows/lint-workflow.yml @@ -45,4 +45,4 @@ jobs: # Use Config file when the github action supports it builtin: clear,rare check_filenames: true - skip: ./libsol/printer_test.c,./tests/Cargo.lock + skip: ./libsol/printer_test.c,./tests/Cargo.lock,./tools/apdu_generator/Cargo.lock diff --git a/libsol/spl_token_instruction.c b/libsol/spl_token_instruction.c index 93298d4c..1860df14 100644 --- a/libsol/spl_token_instruction.c +++ b/libsol/spl_token_instruction.c @@ -507,7 +507,7 @@ int print_spl_token_transfer_info(const SplTokenTransferInfo* info, if (g_trusted_token_account_owner_pubkey_set) { item = transaction_summary_general_item(); - summary_item_set_string(item, "To", (char *)g_trusted_token_account_owner_pubkey); + summary_item_set_string(item, "To", (char*) g_trusted_token_account_owner_pubkey); } item = transaction_summary_general_item(); diff --git a/src/apdu.c b/src/apdu.c index 44217c3c..f3e17a09 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -102,7 +102,7 @@ int apdu_handle_message(const uint8_t* apdu_message, const bool first_data_chunk = !(header.p2 & P2_EXTEND); if (header.instruction == InsDeprecatedGetAppConfiguration || - header.instruction == InsGetAppConfiguration || + header.instruction == InsGetAppConfiguration || header.instruction == InsTrustedInfoGetChallenge) { // return early if no data is expected for the command explicit_bzero(apdu_command, sizeof(ApduCommand)); @@ -126,13 +126,12 @@ int apdu_handle_message(const uint8_t* apdu_message, } else { explicit_bzero(apdu_command, sizeof(ApduCommand)); } - } - else { + } else { explicit_bzero(apdu_command, sizeof(ApduCommand)); } if ((first_data_chunk) && (header.instruction != InsTrustedInfoProvideInfo)) { - // read derivation path + // read derivation path if (!header.deprecated_host && header.instruction != InsGetPubkey) { if (!header.data_length) { return ApduReplySolanaInvalidMessageSize; @@ -148,9 +147,9 @@ int apdu_handle_message(const uint8_t* apdu_message, apdu_command->num_derivation_paths = 1; } const int ret = read_derivation_path(header.data, - header.data_length, - apdu_command->derivation_path, - &apdu_command->derivation_path_length); + header.data_length, + apdu_command->derivation_path, + &apdu_command->derivation_path_length); if (ret) { return ret; } @@ -175,15 +174,15 @@ int apdu_handle_message(const uint8_t* apdu_message, if (header.data_length != data_len) { return ApduReplySolanaInvalidMessageSize; } - } + } if (header.data) { if (apdu_command->message_length + header.data_length > MAX_MESSAGE_LENGTH) { return ApduReplySolanaInvalidMessageSize; } - + memcpy(apdu_command->message + apdu_command->message_length, - header.data, - header.data_length); + header.data, + header.data_length); apdu_command->message_length += header.data_length; } else if (header.instruction != InsDeprecatedGetPubkey && header.instruction != InsGetPubkey) { return ApduReplySolanaInvalidMessageSize; diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index a40dcf6f..2d5af3b8 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -14,7 +14,7 @@ #include "ledger_pki.h" -#define TYPE_ADDRESS 0x06 +#define TYPE_ADDRESS 0x06 #define TYPE_DYN_RESOLVER 0x06 #define STRUCT_TYPE_TRUSTED_NAME 0x03 @@ -47,17 +47,17 @@ typedef enum { /* trusted_name_descriptor = tlv(TAG_STRUCTURE_TYPE, u8(TYPE_TRUSTED_NAME)) 3 bytes + - & tlv(TAG_VERSION, u8(0x02)) 3 bytes + + & tlv(TAG_VERSION, u8(0x02)) 3 bytes + & tlv(TAG_TRUSTED_NAME_TYPE, 0x06) 3 bytes + & tlv(TAG_TRUSTED_NAME_SOURCE, 0x06) 3 bytes + - & tlv(TAG_TRUSTED_NAME, trusted_name) 2 + 44 bytes + + & tlv(TAG_TRUSTED_NAME, trusted_name) 2 + 44 bytes + & tlv(TAG_CHAIN_ID, chain_id) 2 + 8 bytes + & tlv(TAG_ADDRESS, address) 2 + 44 bytes + & tlv(TAG_SOURCE_CONTRACT, source_contract)* 2 + 44 bytes + & tlv(TAG_CHALLENGE, challenge) 2 + 4 bytes + & tlv(TAG_SIGNER_KEY_ID, key_id) 2 + 2 bytes + & tlv(TAG_SIGNER_ALGORITHM, signature_algorithm) 2 + 1 byte + - & tlv(TAG_SIGNATURE, signature(~,~)) 2 + 72 bytes => Total = 247 bytes + & tlv(TAG_SIGNATURE, signature(~,~)) 2 + 72 bytes => 247 T L V 01 01 03 TAG_STRUCTURE_TYPE @@ -65,13 +65,13 @@ T L V 70 01 06 TAG_TRUSTED_NAME_TYPE 71 01 06 TAG_TRUSTED_NAME_SOURCE 20 20 276497ba0bb8659172b72edd8c66e18f561764d9c86a610a3a7e0f79c0baf9db TAG_TRUSTED_NAME -23 01 65 TAG_CHAIN_ID +23 01 65 TAG_CHAIN_ID 22 20 606501b302e1801892f80a2979f585f8855d0f2034790a2455f744fac503d7b5 TAG_ADDRESS 73 20 c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61 TAG_SOURCE_CONTRACT 12 04 deadbeef TAG_CHALLENGE 13 01 03 TAG_SIGNER_KEY_ID -14 01 01 TAG_SIGNER_ALGORITHM -15 47 3045022100ac06a740744dac01b4b848ca2730c507e2a7a93f92952a0c9757bb12d8e6de490220262a529c8d809b9b2538bce34ecaa03b5c54f602656fd210f01c304a3da0b52e +14 01 01 TAG_SIGNER_ALGORITHM +15 47 30..2e 01 01 03 @@ -85,7 +85,7 @@ T L V 12 04 DEADBEEF 13 01 00 14 01 01 -15 47 3045022100B559CD96CCCDA78CA393CE5D4A300E52177ABCC18F5E674FE9D4088322628ADD02200EAA84D21EE275DEC82F5D747ADAA408816AC03CC133BD722DC26016F7FA92CF +15 47 30..CF */ @@ -126,7 +126,7 @@ typedef struct { bool valid; uint8_t struct_version; uint8_t token_account[MAX_ADDRESS_LENGTH + 1]; - uint8_t* owner; + uint8_t *owner; uint8_t spl_token[MAX_ADDRESS_LENGTH + 1]; uint64_t chain_id; uint8_t name_type; @@ -311,16 +311,16 @@ static bool handle_signature(const s_tlv_data *data, * @return whether it was successful */ static bool handle_source_contract(const s_tlv_data *data, - s_trusted_name_info *trusted_name_info, - s_sig_ctx *sig_ctx) { + s_trusted_name_info *trusted_name_info, + s_sig_ctx *sig_ctx) { (void) sig_ctx; if (data->length > MAX_ADDRESS_LENGTH) { PRINTF("SPL Token address too long! (%u)\n", data->length); return false; } - + memcpy(trusted_name_info->spl_token, data->value, data->length); - + trusted_name_info->spl_token[data->length] = '\0'; return true; } @@ -365,9 +365,9 @@ static bool handle_trusted_name(const s_tlv_data *data, PRINTF("Token Account address too long! (%u)\n", data->length); return false; } - + memcpy(trusted_name_info->token_account, data->value, data->length); - + trusted_name_info->token_account[data->length] = '\0'; return true; } @@ -408,18 +408,16 @@ static bool handle_chain_id(const s_tlv_data *data, bool res = false; switch (data->length) { - case 1: - { - trusted_name_info->chain_id = data->value[0]; - res = true; - break; - } - case 2: - { - trusted_name_info->chain_id = (data->value[0] << 8) | data->value[1]; - res = true; - break; - } + case 1: { + trusted_name_info->chain_id = data->value[0]; + res = true; + break; + } + case 2: { + trusted_name_info->chain_id = (data->value[0] << 8) | data->value[1]; + res = true; + break; + } default: PRINTF("Error while parsing chain ID: length = %d\n", data->length); } @@ -563,7 +561,6 @@ static bool handle_tlv_data(s_tlv_handler *handlers, static bool verify_struct(const s_trusted_name_info *trusted_name_info) { uint32_t required_flags; - if (!(RCV_FLAG(STRUCT_VERSION_RCV_BIT) & trusted_name_info->rcv_flags)) { PRINTF("Error: no struct version specified!\n"); return false; @@ -584,12 +581,14 @@ static bool verify_struct(const s_trusted_name_info *trusted_name_info) { switch (trusted_name_info->name_type) { case TYPE_ADDRESS: if (trusted_name_info->name_source != TYPE_DYN_RESOLVER) { - PRINTF("Error: unsupported trusted name source (%u)!\n", trusted_name_info->name_source); + PRINTF("Error: unsupported trusted name source (%u)!\n", + trusted_name_info->name_source); return false; } break; default: - PRINTF("Error: unsupported trusted name type (%u)!\n", trusted_name_info->name_type); + PRINTF("Error: unsupported trusted name type (%u)!\n", + trusted_name_info->name_type); return false; } break; @@ -729,7 +728,7 @@ static bool parse_tlv(const s_tlv_payload *payload, } data.value = &payload->buf[offset]; if (!handle_tlv_data(handlers, - (sizeof(handlers)/sizeof(handlers[0])), + (sizeof(handlers) / sizeof(handlers[0])), &data, trusted_name_info, sig_ctx)) { @@ -737,11 +736,12 @@ static bool parse_tlv(const s_tlv_payload *payload, } offset += data.length; if (data.tag != SIGNATURE) { // the signature wasn't computed on itself - CX_ASSERT(cx_hash_no_throw( - (cx_hash_t *) &sig_ctx->hash_ctx, - 0, - &payload->buf[tag_start_off], - (offset - tag_start_off), NULL, 0)); + CX_ASSERT(cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, + 0, + &payload->buf[tag_start_off], + (offset - tag_start_off), + NULL, + 0)); } step = TLV_TAG; break; @@ -768,7 +768,6 @@ static void free_payload(s_tlv_payload *payload) { } static bool init_tlv_payload(uint8_t length, s_tlv_payload *payload) { - // check if no payload is already in memory if (payload->buf != NULL) { free_payload(payload); @@ -810,7 +809,7 @@ void handle_provide_trusted_info(void) { } // feed into tlv payload memcpy(g_tlv_payload.buf + g_tlv_payload.size, data, data_length); - g_tlv_payload.size += data_length; + g_tlv_payload.size += data_length; PRINTF("Received %d bytes of trusted info\n", g_tlv_payload.size); @@ -823,13 +822,17 @@ void handle_provide_trusted_info(void) { free_payload(&g_tlv_payload); roll_challenge(); // prevent brute-force guesses g_trusted_name_info.rcv_flags = 0; - memset(g_trusted_token_account_owner_pubkey, 0, sizeof(g_trusted_token_account_owner_pubkey)); + memset(g_trusted_token_account_owner_pubkey, + 0, + sizeof(g_trusted_token_account_owner_pubkey)); g_trusted_token_account_owner_pubkey_set = false; THROW(ApduReplySolanaInvalidTrustedInfo); } - - PRINTF("Token account : %s owned by %s\n", g_trusted_name_info.token_account, g_trusted_token_account_owner_pubkey); - + + PRINTF("Token account : %s owned by %s\n", + g_trusted_name_info.token_account, + g_trusted_token_account_owner_pubkey); + free_payload(&g_tlv_payload); roll_challenge(); // prevent replays THROW(ApduReplySuccess); diff --git a/src/ledger_pki.c b/src/ledger_pki.c index 91192281..44a9bd80 100644 --- a/src/ledger_pki.c +++ b/src/ledger_pki.c @@ -1,6 +1,6 @@ #include "apdu.h" #include "ledger_pki.h" -#include "cx.h" +#include "cx.h" #include "os_pki.h" #define KEY_USAGE_STR(x) \ @@ -48,7 +48,10 @@ int check_signature_with_pubkey(const char *tag, goto end; } } else { - PRINTF("[%s] ********** Issue when loading PKI certificate, cannot check signature **********\n", tag); + PRINTF( + "[%s] ********** Issue when loading PKI certificate, cannot check signature " + "**********\n", + tag); error = ApduReplySolanaInvalidTrustedInfo; goto end; } diff --git a/src/main.c b/src/main.c index 9f9d92e8..b991c528 100644 --- a/src/main.c +++ b/src/main.c @@ -92,10 +92,10 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) case InsTrustedInfoGetChallenge: handle_get_challenge(tx); break; - + case InsTrustedInfoProvideInfo: - handle_provide_trusted_info(); - THROW(ApduReplySuccess); + handle_provide_trusted_info(); + THROW(ApduReplySuccess); default: THROW(ApduReplyUnimplementedInstruction); diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 866d59fc..48c2caa6 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -85,97 +85,6 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" -[[package]] -name = "ark-bn254" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-ec" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ark-ff-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" -dependencies = [ - "num-bigint", - "num-traits", - "quote", - "syn", -] - -[[package]] -name = "ark-serialize" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" -dependencies = [ - "ark-std", - "digest 0.9.0", -] - -[[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "array-bytes" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" - [[package]] name = "arrayref" version = "0.3.6" @@ -188,12 +97,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" -[[package]] -name = "ascii" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" - [[package]] name = "assert_matches" version = "1.5.0" @@ -269,9 +172,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "895adc16c8b3273fbbc32685a7d55227705eda08c01e77704020f3491924b44b" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" dependencies = [ "arrayref", "arrayvec", @@ -326,7 +229,7 @@ dependencies = [ "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", "proc-macro2", - "syn", + "syn 1.0.103", ] [[package]] @@ -337,7 +240,7 @@ checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -348,7 +251,7 @@ checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -396,22 +299,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.12.3" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.3.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.87", ] [[package]] @@ -470,19 +373,6 @@ dependencies = [ "inout", ] -[[package]] -name = "combine" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -dependencies = [ - "ascii", - "byteorder", - "either", - "memchr", - "unreachable", -] - [[package]] name = "console" version = "0.15.2" @@ -519,9 +409,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.2.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cpufeatures" @@ -639,17 +529,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dialoguer" version = "0.10.2" @@ -704,7 +583,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand", "serde", "sha2 0.9.9", "zeroize", @@ -745,22 +624,22 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "1.2.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91a4ec26efacf4aeff80887a175a419493cb6f8b5480d26387eb0bd038976187" +checksum = "2953d1df47ac0eb70086ccabf0275aa8da8591a28bd358ee2b52bd9f9e3ff9e9" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "1.1.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" +checksum = "8958699f9359f0b04e691a13850d48b7de329138023876d07cbd024c2c820598" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -911,17 +790,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "goblin" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "h2" version = "0.3.15" @@ -941,15 +809,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.11.2" @@ -1215,7 +1074,7 @@ name = "ledger-app-solana-tests" version = "0.2.0" dependencies = [ "hex", - "rand 0.7.3", + "rand", "solana-logger", "solana-remote-wallet", "solana-sdk", @@ -1254,7 +1113,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand 0.7.3", + "rand", "serde", "sha2 0.9.9", "typenum", @@ -1380,17 +1239,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -1399,7 +1247,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1433,23 +1281,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate 1.2.1", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1487,12 +1335,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "paste" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" - [[package]] name = "pbkdf2" version = "0.4.0" @@ -1517,16 +1359,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "pest" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" -dependencies = [ - "thiserror", - "ucd-trie", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1545,12 +1377,6 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "polyval" version = "0.5.3" @@ -1591,9 +1417,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -1609,9 +1435,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1624,22 +1450,11 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha 0.2.2", + "rand_chacha", "rand_core 0.5.1", "rand_hc", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.2.2" @@ -1650,16 +1465,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_core" version = "0.5.1" @@ -1756,9 +1561,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" dependencies = [ "async-compression", "base64 0.13.1", @@ -1773,9 +1578,9 @@ dependencies = [ "hyper-rustls", "ipnet", "js-sys", + "lazy_static", "log", "mime", - "once_cell", "percent-encoding", "pin-project-lite", "rustls", @@ -1810,34 +1615,19 @@ dependencies = [ "winapi", ] -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver", ] [[package]] @@ -1879,26 +1669,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sct" version = "0.7.0" @@ -1909,30 +1679,12 @@ dependencies = [ "untrusted", ] -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" version = "1.0.147" @@ -1959,7 +1711,7 @@ checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2074,7 +1826,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623f65dae901566617eaf9255697c0fea8c012282e85ad86dd79c7133dff767" dependencies = [ "ahash", "blake3", @@ -2093,7 +1847,7 @@ dependencies = [ "memmap2", "once_cell", "rand_core 0.6.4", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_bytes", "serde_derive", @@ -2106,17 +1860,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f90f630bb756af28f703c217fd5e14661dd5ec33cf2471276d0279130feba74" dependencies = [ "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn", + "rustc_version", + "syn 1.0.103", ] [[package]] name = "solana-logger" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cadbbc900718637b8d0df476d71f3164d758058871007be52b94378db6025c0" dependencies = [ "env_logger", "lazy_static", @@ -2125,7 +1883,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7508f3c00c603e74ef3c4f5573eb16c95346abd5ecacd4f8a39ad067759c0d" dependencies = [ "log", "solana-sdk", @@ -2133,7 +1893,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290e46753130565328f3a29579d4e66500246cfc588baad0049d7f64b1c2b5fe" dependencies = [ "crossbeam-channel", "gethostname", @@ -2145,12 +1907,10 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19350699312e8c6f92d56c899cb40e45e86d97815b26608ea9bde69648548e44" dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "array-bytes", "base64 0.13.1", "bincode", "bitflags", @@ -2175,9 +1935,9 @@ dependencies = [ "num-derive", "num-traits", "parking_lot", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", + "rand", + "rand_chacha", + "rustc_version", "rustversion", "serde", "serde_bytes", @@ -2196,7 +1956,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2500588aecf80caac49748a78c394bf5b3ca35fba1c290bade952447837f4e87" dependencies = [ "base64 0.13.1", "bincode", @@ -2208,21 +1970,22 @@ dependencies = [ "log", "num-derive", "num-traits", - "rand 0.7.3", - "rustc_version 0.4.0", + "rand", + "rustc_version", "serde", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-measure", "solana-metrics", "solana-sdk", - "solana_rbpf", "thiserror", ] [[package]] name = "solana-remote-wallet" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "178522ee999b97a45e42dc2ebc8f1f112337774d24438fba7f54b489ba03af62" dependencies = [ "console", "dialoguer", @@ -2232,7 +1995,7 @@ dependencies = [ "num-traits", "parking_lot", "qstring", - "semver 1.0.14", + "semver", "solana-sdk", "thiserror", "uriparse", @@ -2240,7 +2003,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdde2c0b0e210fb013cbc0ecb73967ab77333e4304ce816a73cb258d4a2e1176" dependencies = [ "assert_matches", "base64 0.13.1", @@ -2265,12 +2030,11 @@ dependencies = [ "memmap2", "num-derive", "num-traits", - "num_enum", "pbkdf2 0.11.0", "qstring", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", + "rand", + "rand_chacha", + "rustc_version", "rustversion", "serde", "serde_bytes", @@ -2290,30 +2054,33 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42288b67d0f503ee6606777b3fb8ceeee7087ed7a8b3a0317edb1cd20d3d206b" dependencies = [ "bs58", "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.103", ] [[package]] name = "solana-vote-program" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5d2ba3c43c2af6439c4da844f1ea76e426e1306624cc747c1e6b777d0d66c42" dependencies = [ "bincode", "log", "num-derive", "num-traits", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_derive", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-metrics", - "solana-program", "solana-program-runtime", "solana-sdk", "thiserror", @@ -2321,7 +2088,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.15.0" +version = "1.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af14aa817cf4aadef7488d6e3df9403f4ea0cb91c83b60bc0bb20d34a68d05f2" dependencies = [ "aes-gcm-siv", "arrayref", @@ -2337,7 +2106,7 @@ dependencies = [ "merlin", "num-derive", "num-traits", - "rand 0.7.3", + "rand", "serde", "serde_json", "sha3 0.9.1", @@ -2348,24 +2117,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "solana_rbpf" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0669f9f5c355899600732451c65cc717d0ef0c53717749f03520337c824fd8a1" -dependencies = [ - "byteorder", - "combine", - "goblin", - "hash32", - "libc", - "log", - "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror", -] - [[package]] name = "spin" version = "0.5.2" @@ -2374,7 +2125,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spl-associated-token-account" -version = "1.1.1" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" dependencies = [ "assert_matches", "borsh", @@ -2389,6 +2142,8 @@ dependencies = [ [[package]] name = "spl-memo" version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" dependencies = [ "solana-program", ] @@ -2396,6 +2151,8 @@ dependencies = [ [[package]] name = "spl-token" version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" dependencies = [ "arrayref", "bytemuck", @@ -2408,7 +2165,9 @@ dependencies = [ [[package]] name = "spl-token-2022" -version = "0.4.3" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" dependencies = [ "arrayref", "bytemuck", @@ -2439,6 +2198,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -2447,7 +2217,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "unicode-xid", ] @@ -2501,7 +2271,7 @@ checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2514,7 +2284,7 @@ dependencies = [ "hmac 0.8.1", "once_cell", "pbkdf2 0.4.0", - "rand 0.7.3", + "rand", "rustc-hash", "sha2 0.9.9", "thiserror", @@ -2627,12 +2397,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -2676,15 +2440,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] - [[package]] name = "untrusted" version = "0.7.1" @@ -2718,12 +2473,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "want" version = "0.3.0" @@ -2767,7 +2516,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-shared", ] @@ -2801,7 +2550,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2955,6 +2704,6 @@ checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "synstructure", ] From e194428001fb81c20dfb80782b09b6211d835347 Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 29 Nov 2024 14:23:21 +0100 Subject: [PATCH 10/17] Ragger tests OK for NanoS+ and Nano X --- .../nanosp/test_solana_trusted_name/00000.png | Bin 0 -> 443 bytes .../nanosp/test_solana_trusted_name/00001.png | Bin 0 -> 776 bytes .../nanosp/test_solana_trusted_name/00002.png | Bin 0 -> 864 bytes .../nanosp/test_solana_trusted_name/00003.png | Bin 0 -> 925 bytes .../nanosp/test_solana_trusted_name/00004.png | Bin 0 -> 950 bytes .../nanosp/test_solana_trusted_name/00005.png | Bin 0 -> 810 bytes .../nanosp/test_solana_trusted_name/00006.png | Bin 0 -> 326 bytes .../nanosp/test_solana_trusted_name/00007.png | Bin 0 -> 364 bytes .../nanosp/test_solana_trusted_name/00008.png | Bin 0 -> 487 bytes .../nanox/test_solana_trusted_name/00000.png | Bin 0 -> 443 bytes .../nanox/test_solana_trusted_name/00001.png | Bin 0 -> 776 bytes .../nanox/test_solana_trusted_name/00002.png | Bin 0 -> 864 bytes .../nanox/test_solana_trusted_name/00003.png | Bin 0 -> 925 bytes .../nanox/test_solana_trusted_name/00004.png | Bin 0 -> 950 bytes .../nanox/test_solana_trusted_name/00005.png | Bin 0 -> 810 bytes .../nanox/test_solana_trusted_name/00006.png | Bin 0 -> 326 bytes .../nanox/test_solana_trusted_name/00007.png | Bin 0 -> 364 bytes .../nanox/test_solana_trusted_name/00008.png | Bin 0 -> 487 bytes 18 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00000.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00001.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00002.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00003.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00004.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00005.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00006.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00007.png create mode 100644 tests/python/snapshots/nanosp/test_solana_trusted_name/00008.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00000.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00001.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00002.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00003.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00004.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00005.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00006.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00007.png create mode 100644 tests/python/snapshots/nanox/test_solana_trusted_name/00008.png diff --git a/tests/python/snapshots/nanosp/test_solana_trusted_name/00000.png b/tests/python/snapshots/nanosp/test_solana_trusted_name/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5c98ba0d30ea7d6347602eb195a0f1902538ad31 GIT binary patch literal 443 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/nanosp/test_solana_trusted_name/00005.png b/tests/python/snapshots/nanosp/test_solana_trusted_name/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..78865e45894fb563c554937cf7feb48b12a570d1 GIT binary patch literal 810 zcmV+_1J(SAP)WGj72fYHQvbu>A;Secy%hKyq3ANmMd@qAe(f5 z3rmfWs;`KF)LH4rw{hwK#I-~ojNn)ECE`h>7v!W=eREGYGDG6HH$Ia_Ru06Z>7p** zx$6f4FdWtEJNo)06JkJynKKKKF&rl|2A87UJ90KuujeYg=I%kS3lDFp8mzaf4hR4{ zaiv&tKx2L!XXzZRkoR z#mxXg?RunT_BfhYs5-bjskj0I#%vaVD*!1^P5yP_8;H>R0Er%h+8Uf61p*OE^!(!{ zTrV9Ztzb+HQU@p3nr{U-Ve%C8OxSm3{_*tS5`_>#$ZM%m2s+Kul^{#sv^1Ng=9;|| zRhCVEX$oUiK!aH%=(U#quGHHY3;jv25ZSLu|C&2Na2~`=lijdoyPK*H>RWSS0i7{2 zCxC$^4KQtsm_3~*M}U5l6%hux8l1*i6DH$cjXNReTlaa}^%xHtfK^?({#ouJ+&VMb owdNVlwr)3r5kd$dgb*^qe}l^BKBj`g;s5{u07*qoM6N<$f?D-(OaK4? literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/nanosp/test_solana_trusted_name/00006.png b/tests/python/snapshots/nanosp/test_solana_trusted_name/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..b25efecadeabda0daccb6c4702e649afff33a7d6 GIT binary patch literal 326 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 literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/nanox/test_solana_trusted_name/00005.png b/tests/python/snapshots/nanox/test_solana_trusted_name/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..78865e45894fb563c554937cf7feb48b12a570d1 GIT binary patch literal 810 zcmV+_1J(SAP)WGj72fYHQvbu>A;Secy%hKyq3ANmMd@qAe(f5 z3rmfWs;`KF)LH4rw{hwK#I-~ojNn)ECE`h>7v!W=eREGYGDG6HH$Ia_Ru06Z>7p** zx$6f4FdWtEJNo)06JkJynKKKKF&rl|2A87UJ90KuujeYg=I%kS3lDFp8mzaf4hR4{ zaiv&tKx2L!XXzZRkoR z#mxXg?RunT_BfhYs5-bjskj0I#%vaVD*!1^P5yP_8;H>R0Er%h+8Uf61p*OE^!(!{ zTrV9Ztzb+HQU@p3nr{U-Ve%C8OxSm3{_*tS5`_>#$ZM%m2s+Kul^{#sv^1Ng=9;|| zRhCVEX$oUiK!aH%=(U#quGHHY3;jv25ZSLu|C&2Na2~`=lijdoyPK*H>RWSS0i7{2 zCxC$^4KQtsm_3~*M}U5l6%hux8l1*i6DH$cjXNReTlaa}^%xHtfK^?({#ouJ+&VMb owdNVlwr)3r5kd$dgb*^qe}l^BKBj`g;s5{u07*qoM6N<$f?D-(OaK4? literal 0 HcmV?d00001 diff --git a/tests/python/snapshots/nanox/test_solana_trusted_name/00006.png b/tests/python/snapshots/nanox/test_solana_trusted_name/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..b25efecadeabda0daccb6c4702e649afff33a7d6 GIT binary patch literal 326 zcmV-M0lEH(P)T(Fgd^T3bHXTKm^p zYut(6No#E^z+3r>KESrI1Jvr2fm;QtJz1eMTSP*M1W$VU1Z&2`(v5 zmD?;~hV)C40&G6N|24*an0TI{m!bgWL=DcbFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y$-UeMr<8)=&lr;6IZrJW$mC0+#D)L>000000PrMU+6J6pS(a1R z#~6hyxsg9@1D*~7D1!jXytNIuNTa004kC zqK`e#d8RUoWdW@GEv0`btH(R%uhwC^I0-5?fGu*o!P&p~Y(G^UD;bb;BsS~lmb6F^ za{{E2($}E=)p#GYh0&9+&DTn1cgf`%&g2fSZ`D_B#-XbFM|vH!Xl00000 d003Zq{sAD1I;j3hmJt8|002ovPDHLkV1l#!*U Date: Fri, 29 Nov 2024 14:27:59 +0100 Subject: [PATCH 11/17] Fix typo on INS value --- doc/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api.md b/doc/api.md index cc7c9138..b6f746fb 100644 --- a/doc/api.md +++ b/doc/api.md @@ -170,7 +170,7 @@ _This command provides a [Solana Trusted Name TLV descriptor](https://ledgerhq.a | _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _Le_ | | ----- | :---: | ---: | ---- | :------: | -------: | -| E0 | 20 | 00 | 00 | F7 (max) | variable | +| E0 | 21 | 00 | 00 | F7 (max) | variable | ##### Input data From e6ee84e022f06ace3c6d2879db77e45a79691551 Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 29 Nov 2024 14:52:24 +0100 Subject: [PATCH 12/17] Add compilation flags for Trusted Name tests --- .github/workflows/ci-workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 1556f75c..587866be 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -14,6 +14,7 @@ jobs: uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 with: upload_app_binaries_artifact: compiled_app_binaries + flags: "TRUSTED_NAME_TEST=1" ragger_tests: name: Run ragger tests using the reusable workflow From e41a5579579c648ea038712bcdb8714f6d095c00 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Tue, 10 Dec 2024 11:49:53 +0100 Subject: [PATCH 13/17] Add use case for compilation with test key in manifest --- ledger_app.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ledger_app.toml b/ledger_app.toml index 4c40ef09..8b37435e 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -3,5 +3,9 @@ build_directory = "./" sdk = "C" devices = ["nanox", "nanos+", "stax", "flex"] +[use_cases] +trusted_name_test = "TRUSTED_NAME_TEST=1" +dbg_trusted_name_test = "DEBUG=1 TRUSTED_NAME_TEST=1" + [tests] pytest_directory = "./tests/python" From b906743f0f9534f28dac7cbe86b906349237d981 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Tue, 10 Dec 2024 14:48:52 +0100 Subject: [PATCH 14/17] Remove unused CI --- .github/workflows/sonarcloud.yml | 44 -------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/sonarcloud.yml diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index 690a61dc..00000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Sonarcloud - -on: - push: - branches: - - master - - develop - pull_request: - -jobs: - sonarcloud: - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest - - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - steps: - - uses: actions/checkout@v3 - with: - # Disabling shallow clone is recommended for improving relevancy of reporting - fetch-depth: 0 - - name: Install dependencies - run: | - apt-get update -y - apt-get upgrade -y - DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata - apt-get install -y libcmocka-dev gcovr unzip - - name: Install sonar-scanner and build-wrapper - uses: sonarsource/sonarcloud-github-c-cpp@v2 - - - name: Generate code coverage - working-directory: libsol - run: | - make COVERAGE=1 - gcovr --root .. --sonarqube ../coverage.xml - - name: Run build-wrapper - run: | - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make clean all - - name: Run sonar-scanner - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" #Consult https://docs.sonarcloud.io/advanced-setup/ci-based-analysis/sonarscanner-cli/ for more information and options From ec56096807d0623fe85846c3e65a788c61047ec5 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Tue, 10 Dec 2024 14:53:13 +0100 Subject: [PATCH 15/17] Fix unit tests compilation --- libsol/spl_token_instruction.c | 4 ++-- src/handle_provide_trusted_info.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libsol/spl_token_instruction.c b/libsol/spl_token_instruction.c index 1860df14..e8bd694e 100644 --- a/libsol/spl_token_instruction.c +++ b/libsol/spl_token_instruction.c @@ -484,8 +484,8 @@ static int print_spl_token_initialize_multisig_info(const char* primary_title, return 0; } -extern uint8_t g_trusted_token_account_owner_pubkey[BASE58_PUBKEY_LENGTH]; -extern bool g_trusted_token_account_owner_pubkey_set; +uint8_t g_trusted_token_account_owner_pubkey[BASE58_PUBKEY_LENGTH]; +bool g_trusted_token_account_owner_pubkey_set; int print_spl_token_transfer_info(const SplTokenTransferInfo* info, const PrintConfig* print_config, diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index 2d5af3b8..32d1229c 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -153,8 +153,8 @@ typedef struct { static s_tlv_payload g_tlv_payload = {0}; static s_trusted_name_info g_trusted_name_info = {0}; -uint8_t g_trusted_token_account_owner_pubkey[MAX_ADDRESS_LENGTH + 1] = {0}; -bool g_trusted_token_account_owner_pubkey_set = false; +extern uint8_t g_trusted_token_account_owner_pubkey[MAX_ADDRESS_LENGTH + 1]; +extern bool g_trusted_token_account_owner_pubkey_set; /** * Get uint from tlv data @@ -838,4 +838,4 @@ void handle_provide_trusted_info(void) { THROW(ApduReplySuccess); } THROW(ApduReplySolanaInvalidTrustedInfo); -} \ No newline at end of file +} From db6737ae1657c5f2066455d3453883bb5fda3707 Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 16 Dec 2024 10:14:24 +0100 Subject: [PATCH 16/17] Use proper KEY_ID in PROD --- src/handle_provide_trusted_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handle_provide_trusted_info.c b/src/handle_provide_trusted_info.c index 32d1229c..8fabbb07 100644 --- a/src/handle_provide_trusted_info.c +++ b/src/handle_provide_trusted_info.c @@ -107,7 +107,7 @@ typedef enum { SIGNATURE = 0x15, } e_tlv_tag; -typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id; +typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x07 } e_key_id; typedef struct { uint8_t *buf; From dc37edc126d65767db0fe7d57a98b6a9cdb81b95 Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 16 Dec 2024 14:15:32 +0100 Subject: [PATCH 17/17] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2dc54287..cbb3d8c0 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ APPNAME = "Solana" # Application version APPVERSION_M = 1 APPVERSION_N = 6 -APPVERSION_P = 0 +APPVERSION_P = 1 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" # Application source files